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 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 __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\n", 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(); } } }
// Note: When using with 32 bit output buffers, the user of this function is responsible // for shifting the values to where they need to be manually. The fixed point depth of // the sample output is determined by the SndOutVolumeShift, which is the number of bits // to shift right to get a 16 bit result. template<typename T> void SndBuffer::ReadSamples(T* bData) { int nSamples = SndOutPacketSize; // 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 ); // WARNING: This code assumes there's only ONE reading process. int b1 = m_size - m_rpos; if(b1 > nSamples) b1 = nSamples; if (AdvancedVolumeControl) { // First part for (int i = 0; i < b1; i++) bData[i].AdjustFrom(m_buffer[i + m_rpos]); // Second part int b2 = nSamples - b1; for (int i = 0; i < b2; i++) bData[i + b1].AdjustFrom(m_buffer[i]); } else { // First part for (int i = 0; i < b1; i++) bData[i].ResampleFrom(m_buffer[i + m_rpos]); // Second part int b2 = nSamples - b1; for (int i = 0; i < b2; i++) bData[i + b1].ResampleFrom(m_buffer[i]); } _DropSamples_Internal(nSamples); } // 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(T) ); }
__releaseinline u8* __fastcall iopGetPhysPtr( u32 iopaddr ) { const uptr masked = iopaddr & AddressMask; const sptr tab = tbl_Translation.Contents[masked/PageSize]; jASSUME( tab > HandlerId_Maximum ); return (u8*)tab + (masked & PageMask); }
__forceinline s16* GetMemPtr(u32 addr) { #ifndef DEBUG_FAST // In case you're wondering, this assert is the reason SPU2-X // runs so incrediously slow in Debug mode. :P jASSUME( addr < 0x100000 ); #endif return (_spu2mem+addr); }
void TranslationTable::AssignHandler( uint startaddr, HandlerIdentifier handidx, uint bytesize ) { const uint startpage = startaddr / PageSize; const uint endpage = (startaddr + bytesize + (PageSize-1)) / PageSize; // rounded up. for( uint i=startpage; i<endpage; ++i ) { jASSUME( i < PageCount ); // really really fallible Contents[i] = handidx; } }
void* Thread::_internal_callback( void* itsme ) { jASSUME( itsme != NULL ); Thread& owner = *((Thread*)itsme); owner.m_returncode = owner.Callback(); owner.m_terminated = true; return NULL; }
// Parameter note: Size should always be a multiple of 128, thanks! static void CvtPacketToInt( StereoOut32* srcdest, uint size ) { jASSUME( (size & 127) == 0 ); const StereoOutFloat* src = (StereoOutFloat*)srcdest; StereoOut32* dest = srcdest; for( uint i=0; i<size; ++i, ++dest, ++src ) *dest = (StereoOut32)*src; }
void TranslationTable::AssignLookup( uint startaddr, u8* dest, uint bytesize ) { const uint startpage = startaddr / PageSize; const uint endpage = (startaddr + bytesize + (PageSize-1)) / PageSize; // rounded up. for( uint i=startpage; i<endpage; ++i, dest+=PageSize ) { jASSUME( i < PageCount ); // because I'm fallible. Contents[i] = (sptr)dest; } }
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_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); }
static void recRecompile() { // Look up the block... // (Mask the IOP address accordingly to account for the many various segments and // mirrors). u32 masked_pc = iopRegs.pc & IopMemory::AddressMask; if( masked_pc < 0x800000 ) masked_pc &= Ps2MemSize::IopRam-1; xBlocksMap::Blockmap_iterator blowme( g_PersState.xBlockMap.Map.find( masked_pc ) ); memzero_obj( g_BlockState ); //g_BlockState.pc = iopRegs.pc; if( blowme == g_PersState.xBlockMap.Map.end() ) { //Console::WriteLn( "IOP First-pass block at PC: 0x%08x (total blocks=%d)", params masked_pc, g_PersState.xBlockMap.Blocks.GetLength() ); recIR_FirstPassInterpreter(); jASSUME( iopRegs.evtCycleCountdown <= iopRegs.evtCycleDuration ); if( iopRegs.evtCycleCountdown <= 0 ) iopRegs.ExecutePendingEvents(); //if( !IsIopRamPage( masked_pc ) ) // disable block checking for non-ram (rom, rom1, etc) // m_blockspace.ramlen = 0; g_PersState.xBlockMap.Map[masked_pc] = g_PersState.xBlockMap.Blocks.GetLength(); g_PersState.xBlockMap.Blocks.New().Assign( m_blockspace ); } else { recBlockItem& mess( g_PersState.xBlockMap.Blocks[blowme->second] ); if( !mess.InstOptInfo.IsDisposed() ) { //Console::WriteLn( "IOP Second-pass block at PC: 0x%08x (total blocks=%d)", params masked_pc, g_PersState.xBlockMap.Blocks.GetLength() ); m_tempIR.GenerateIR( mess ); mess.InstOptInfo.Dispose(); m_x86blockstate.AssignBlock( m_tempIR ); m_x86blockstate.RegisterMapper(); g_BlockState.xBlockPtr = m_xBlock_CurPtr; m_x86blockstate.EmitSomeExecutableGoodness(); m_xBlock_CurPtr = xGetPtr(); uptr temp = m_tbl_TranslatePC[masked_pc>>XlatePC_PageBitShift]; uptr* dispatch_ptr = (uptr*)(temp + (masked_pc & XlatePC_PageMask)); *dispatch_ptr = (uptr)g_BlockState.xBlockPtr; } }
// ------------------------------------------------------------------------ // void xBlocksMap::AddLink( u32 pc, JccComparisonType cctype ) { recBlockItem& destItem( _getItem( pc ) ); const xJumpLink& newlink( destItem.DependentLinks.AddNew( xJumpLink( xGetPtr(), cctype ) ) ); newlink.SetTarget( m_xBlockLut[pc / 4] ); if( destItem.x86len != 0 ) { // Sanity Check: if block is already compiled, then the BlockPtr should *not* be dispatcher. jASSUME( m_xBlockLut[pc / 4] != DynFunc::Dispatcher ); } }
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 ); } }
void* Thread::_internal_callback( void* itsme ) { jASSUME( itsme != NULL ); pthread_win32_thread_attach_np(); Thread& owner = *((Thread*)itsme); owner.m_returncode = owner.Callback(); owner.m_terminated = true; pthread_win32_thread_detach_np(); return NULL; }
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 V_Core::WriteRegPS1( u32 mem, u16 value ) { jASSUME( Index == 0 ); // Valid on Core 0 only! 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) Voices[voice].Volume.Left.Mode = 0; Voices[voice].Volume.Left.RegSet( value << 1 ); Voices[voice].Volume.Left.Reg_VOL = value; break; case 1: //VOLR (Volume R) Voices[voice].Volume.Right.Mode = 0; Voices[voice].Volume.Right.RegSet( value << 1 ); Voices[voice].Volume.Right.Reg_VOL = value; break; case 2: Voices[voice].Pitch = value; break; case 3: Voices[voice].StartA = (u32)value<<8; break; case 4: // ADSR1 (Envelope) Voices[voice].ADSR.regADSR1 = value; break; case 5: // ADSR2 (Envelope) Voices[voice].ADSR.regADSR2 = value; break; case 6: Voices[voice].ADSR.Value = ((s32)value<<16) | value; ConLog( "* SPU2: Mysterious ADSR Volume Set to 0x%x", value ); break; case 7: Voices[voice].LoopStartA = (u32)value <<8; break; jNO_DEFAULT; } }
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; }
static __forceinline T _HwRead_16or32_Page1( u32 addr ) { HwAddrPrep( 1 ); // all addresses should be aligned to the data operand size: jASSUME( ( sizeof(T) == 2 && (addr & 1) == 0 ) || ( sizeof(T) == 4 && (addr & 3) == 0 ) ); u32 masked_addr = pgmsk( addr ); T ret; // ------------------------------------------------------------------------ // Counters, 16-bit varieties! // // Note: word reads/writes to the uppoer halfword of the 16 bit registers should // just map to the HW memory map (tested on real IOP) -- ie, a write to the upper // halfword of 0xcccc will have those upper values return 0xcccc always. // if( masked_addr >= 0x100 && masked_addr < 0x130 ) { int cntidx = ( masked_addr >> 4 ) & 0xf; switch( masked_addr & 0xf ) { case 0x0: ret = (T)IopCounters::ReadCount16( cntidx ); break; case 0x4: ret = IopCounters::ReadMode( cntidx ); break; case 0x8: ret = (T)IopCounters::ReadTarget16( cntidx ); break; default: ret = psxHu32(addr); break; } }
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); }
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 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); }
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! jASSUME( 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; }
BOOL CALLBACK DSound::DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext ) { jASSUME( DSoundOut != NULL ); return DS._DSEnumCallback( lpGuid, lpcstrDescription, lpcstrModule, lpContext ); }