__fi void psxRcntWmode16( int index, u32 value ) { PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04X", index, value ); pxAssume( index >= 0 && index < 3 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; if( index == 2 ) { switch(value & 0x200) { case 0x000: psxCounters[2].rate = 1; break; case 0x200: psxCounters[2].rate = 8; break; jNO_DEFAULT; } if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { counter.mode |= IOPCNT_STOPPED; } } else { // Counters 0 and 1 can select PIXEL or HSYNC as an alternate source: counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = (index==0) ? PSXPIXEL : PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { // gated counters are added up as per the h/vblank timers. // (the PIXEL alt source becomes a vsync gate) counter.mode |= IOPCNT_STOPPED; PSXCNT_LOG( "IOP Counter[%d] Gate Check set, value = 0x%04X", index, value ); if( index == 0 ) psxhblankgate |= 1; // fixme: these gate flags should be one var >_< else psxvblankgate |= 1<<1; } else { if( index == 0 ) psxhblankgate &= ~1; else psxvblankgate &= ~(1<<1); } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffff; _rcntSet( index ); }
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; } } pxAssume( false ); } else { for(i = 0; i < ArraySize(pinst.readType); ++i) { if( pinst.readType[i] == XMMTYPE_TEMP ) { pinst.readType[i] = type; pinst.readReg[i] = reg; return; } } pxAssume( false ); } }
__fi void psxRcntWmode32( int index, u32 value ) { PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04x", index, value ); pxAssume( index >= 3 && index < 6 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; if( index == 3 ) { // Counter 3 has the HBlank as an alternate source. counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value); counter.mode |= IOPCNT_STOPPED; psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); } else { switch(value & 0x6000) { case 0x0000: counter.rate = 1; break; case 0x2000: counter.rate = 8; break; case 0x4000: counter.rate = 16; break; case 0x6000: counter.rate = 256; break; } // Need to set a rate and target if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { Console.WriteLn( "Gate set on IOP Counter %d, disabling", index ); counter.mode |= IOPCNT_STOPPED; } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffffffff; _rcntSet( index ); }
// Preps and invokes the _InternalCallback above. This provides a cdecl-compliant // entry point for our C++ified object state. :) static void ExternalCallback(snd_async_handler_t *pcm_call) { fprintf(stderr, "* SPU2-X:Iz in your external callback.\n"); AlsaMod *data = (AlsaMod *)snd_async_handler_get_callback_private(pcm_call); pxAssume(data != NULL); //pxAssume( data->handle == snd_async_handler_get_pcm(pcm_call) ); // Not sure if we just need an assert, or something like this: if (data->handle != snd_async_handler_get_pcm(pcm_call)) { fprintf(stderr, "* SPU2-X: Failed to handle sound.\n"); return; } data->_InternalCallback(); }
// returns the length of the formatted string, in characters (wxChars). static #ifndef __linux__ __ri #endif uint format_that_unicode_mess(CharBufferType &buffer, uint writepos, const wxChar *fmt, va_list argptr) { va_list args; while (true) { int size = buffer.GetLength() / sizeof(wxChar); va_copy(args, argptr); int len = wxVsnprintf((wxChar *)buffer.GetPtr(writepos * sizeof(wxChar)), size - writepos, fmt, args); va_end(args); // some implementations of vsnprintf() don't NUL terminate // the string if there is not enough space for it so // always do it manually ((wxChar *)buffer.GetPtr())[size - 1] = L'\0'; if (size >= MaxFormattedStringLength) return size - 1; // vsnprintf() may return either -1 (traditional Unix behavior) or the // total number of characters which would have been written if the // buffer were large enough (newer standards such as Unix98) if (len < 0) len = size + (size / 4); len += writepos; if (len < size) return len; buffer.Resize((len + 128) * sizeof(wxChar)); }; // performing an assertion or log of a truncated string is unsafe, so let's not; even // though it'd be kinda nice if we did. pxAssume(false); return 0; // unreachable. }
int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy) { int t0reg; g_xmmtypes[from] = XMMT_INT; if( candestroy ) { if( g_xmmtypes[from] == XMMT_FPS ) SSE_MOVSS_XMM_to_M32(to, from); else SSE2_MOVD_XMM_to_M32(to, from); SSE2_PSRAD_I8_to_XMM(from, 31); SSE2_MOVD_XMM_to_M32(to+4, from); return 1; } else { // can't destroy and type is int pxAssert( g_xmmtypes[from] == XMMT_INT ); if( _hasFreeXMMreg() ) { xmmregs[from].needed = 1; t0reg = _allocTempXMMreg(XMMT_INT, -1); SSEX_MOVDQA_XMM_to_XMM(t0reg, from); SSE2_PSRAD_I8_to_XMM(from, 31); SSE2_MOVD_XMM_to_M32(to, t0reg); SSE2_MOVD_XMM_to_M32(to+4, from); // swap xmm regs.. don't ask xmmregs[t0reg] = xmmregs[from]; xmmregs[from].inuse = 0; } else { SSE2_MOVD_XMM_to_M32(to+4, from); SSE2_MOVD_XMM_to_M32(to, from); SAR32ItoM(to+4, 31); } return 0; } pxAssume( false ); }
s32 Init() { numBuffers = Config_WaveOut.NumBuffers; MMRESULT woores; if (Test()) return -1; // TODO : Use dsound to determine the speaker configuration, and expand audio from there. #if 0 int speakerConfig; //if( StereoExpansionEnabled ) speakerConfig = 2; // better not mess with this in wavout :p (rama) // Any windows driver should support stereo at the software level, I should think! pxAssume( speakerConfig > 1 ); LPTHREAD_START_ROUTINE threadproc; switch( speakerConfig ) { case 2: ConLog( "* SPU2 > Using normal 2 speaker stereo output.\n" ); threadproc = (LPTHREAD_START_ROUTINE)&RThread<StereoOut16>; speakerConfig = 2; break; case 4: ConLog( "* SPU2 > 4 speaker expansion enabled [quadraphenia]\n" ); threadproc = (LPTHREAD_START_ROUTINE)&RThread<StereoQuadOut16>; speakerConfig = 4; break; case 6: case 7: ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" ); threadproc = (LPTHREAD_START_ROUTINE)&RThread<Stereo51Out16>; speakerConfig = 6; break; default: ConLog( "* SPU2 > 7.1 speaker expansion enabled.\n" ); threadproc = (LPTHREAD_START_ROUTINE)&RThread<Stereo51Out16>; speakerConfig = 8; break; } #endif 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 StereoOut16[BufferSize * numBuffers]; woores = waveOutOpen(&hwodevice, WAVE_MAPPER, &wformat, 0, 0, 0); if (woores != MMSYSERR_NOERROR) { waveOutGetErrorText(woores, (wchar_t *)&ErrText, 255); SysMessage("WaveOut Error: %s", ErrText); return -1; } const int BufferSizeBytes = wformat.nBlockAlign * BufferSize; for (u32 i = 0; i < numBuffers; i++) { whbuffer[i].dwBufferLength = BufferSizeBytes; whbuffer[i].dwBytesRecorded = BufferSizeBytes; whbuffer[i].dwFlags = 0; whbuffer[i].dwLoops = 0; whbuffer[i].dwUser = 0; whbuffer[i].lpData = (LPSTR)QBUFFER(i); whbuffer[i].lpNext = 0; whbuffer[i].reserved = 0; waveOutPrepareHeader(hwodevice, whbuffer + i, sizeof(WAVEHDR)); whbuffer[i].dwFlags |= WHDR_DONE; //avoid deadlock } // Start Thread // [Air]: The waveout code does not use wait objects, so setting a time critical // priority level is a bad idea. Standard priority will do fine. The buffer will get the // love it needs and won't suck resources idling pointlessly. Just don't try to // run it in uber-low-latency mode. waveout_running = true; thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RThread<StereoOut16>, this, 0, &tid); return 0; }
__fi void psxRcntWmode32( int index, u32 value ) { PSXCNT_LOG("32bit IOP Counter[%d] writeMode = 0x%04x", index, value ); int irqmode = 0; pxAssume( index >= 3 && index < 6 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; //IRQ enable if (value & (1 << 4)) { irqmode += 1; } if (value & (1 << 5)) { irqmode += 2; } if (value & (1 << 7)) { PSXCNT_LOG("32 Counter %d Toggle IRQ on %s", index, (irqmode & 3) == 1 ? "Target" : ((irqmode & 3) == 2 ? "Overflow" : "Target and Overflow")); } else { PSXCNT_LOG("32 Counter %d Pulsed IRQ on %s", index, (irqmode & 3) == 1 ? "Target" : ((irqmode & 3) == 2 ? "Overflow" : "Target and Overflow")); } if (!(value & (1 << 6))) { PSXCNT_LOG("32 Counter %d One Shot", index); } else { PSXCNT_LOG("32 Counter %d Repeat", index); } if( index == 3 ) { // Counter 3 has the HBlank as an alternate source. counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value); counter.mode |= IOPCNT_STOPPED; psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); } else { switch(value & 0x6000) { case 0x0000: counter.rate = 1; break; case 0x2000: counter.rate = 8; break; case 0x4000: counter.rate = 16; break; case 0x6000: counter.rate = 256; break; } // Need to set a rate and target if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { Console.WriteLn( "Gate set on IOP Counter %d, disabling", index ); counter.mode |= IOPCNT_STOPPED; } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffffffff; _rcntSet( index ); }