psx - update to 0.9.38.1 level mednafen
This commit is contained in:
parent
2afcb29e35
commit
36f9145483
Binary file not shown.
|
@ -93,11 +93,7 @@
|
|||
<ItemGroup>
|
||||
<None Include="..\psx\cpu_bigswitch.inc" />
|
||||
<None Include="..\psx\cpu_computedgoto.inc" />
|
||||
<None Include="..\psx\gpu_command_table.inc" />
|
||||
<None Include="..\psx\gpu_common.inc" />
|
||||
<None Include="..\psx\gpu_line.inc" />
|
||||
<None Include="..\psx\gpu_polygon.inc" />
|
||||
<None Include="..\psx\gpu_sprite.inc" />
|
||||
<None Include="..\psx\spu_fir_table.inc" />
|
||||
<None Include="..\psx\spu_reverb.inc" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -229,21 +229,9 @@
|
|||
<None Include="..\psx\spu_reverb.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\gpu_command_table.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\gpu_common.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\gpu_line.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\gpu_polygon.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\gpu_sprite.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
<None Include="..\psx\cpu_computedgoto.inc">
|
||||
<Filter>psx</Filter>
|
||||
</None>
|
||||
|
|
|
@ -31,25 +31,29 @@
|
|||
[!!] psx/psx : LoadEXE/PSF1 changes (TODO - need these)
|
||||
[OK] psx/spu* : register renames and misc bugfixes
|
||||
0.9.37-UNSTABLE -> 0.9.37.1
|
||||
[NO] psx/cpu : fix some savestate problem with ReadAbsorbDummy, seems alarming
|
||||
[NO] psx/cpu : fix some savestate problem with ReadAbsorbDummy, seems alarming but maybe was just backwards compatibility
|
||||
[OK] psx/spu : clamp some sound output presumably messed up by prior reverb changes
|
||||
0.9.37.1 -> 0.9.38-UNSTABLE [not integrated yet]
|
||||
(major CDIF changes)
|
||||
(simplefifo refactored)
|
||||
[!!] psx/cdutility : substantial revisions to disc sector synthesis with respect to leadout, "UDAPP", and "TSRE" (thread-safe re-entrant) which I dont understand. Need to study for DiscSystem.
|
||||
[OK] required math_ops changes
|
||||
[OK] SimpleFifo changed to PSX-only FastFIFO (TOD)
|
||||
[OK] psx/cdc : set SoftReset Mode to 0x20
|
||||
[OK] psx/cdc : Edits to MakeStatus and BeginResults and ReadResult
|
||||
[OK] psx/cdc : in HandlePlayRead, handling of leadout sector synth moved to CDIF
|
||||
[OK] psx/cdc : in Update, Mode handling and reading of subcode changed
|
||||
[OK] psx/cdc : in Update, reading of subcode changed. This isn't very important, it just saved reading the 2352 sector bytes when it wasn't needed.
|
||||
[OK] psx/cdc : error handling in Command_Setloc
|
||||
[OK] psx/cdc : PreSeekHack edits
|
||||
[OK] psx/cdc : Command_GetTD improvements
|
||||
[OK] psx/cdc : Command_SeekL timing changes
|
||||
[OK] psx/cpu : helpful changes to case ranges and jump table
|
||||
[OK] psx/cpu : helpful changes to case ranges and jump table. double check for savestate changes.
|
||||
[OK] psx/dma : easy bugfixes
|
||||
[??] psx/gpu : display timing changes ?? study more
|
||||
[OK] psx/gpu : BlitterFifo changes, related to FBWrite/Read
|
||||
[OK] psx/gpu : a bunch of bugfixes
|
||||
[OK] psx/gpu : video standard mismatch warning suppressed during DisplayOff
|
||||
[OK] psx/gpu : be aware of savestate changes
|
||||
[OK] psx/gpu_line : easy bugfixes
|
||||
[OK] psx/gte : division bugfixes
|
||||
|
|
|
@ -45,41 +45,6 @@ typedef __uint8_t uint8;
|
|||
#define final
|
||||
#define noexcept
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
//http://stackoverflow.com/questions/355967/how-to-use-msvc-intrinsics-to-get-the-equivalent-of-this-gcc-code
|
||||
//if needed
|
||||
//uint32_t __inline ctz( uint32_t value )
|
||||
//{
|
||||
// DWORD trailing_zero = 0;
|
||||
//
|
||||
// if ( _BitScanForward( &trailing_zero, value ) )
|
||||
// {
|
||||
// return trailing_zero;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // This is undefined, I better choose 32 than 0
|
||||
// return 32;
|
||||
// }
|
||||
//}
|
||||
|
||||
uint32 __inline __builtin_clz( uint32_t value )
|
||||
{
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if ( _BitScanReverse( &leading_zero, value ) )
|
||||
{
|
||||
return 31 - leading_zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Same remarks as above
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#if MDFN_GCC_VERSION >= MDFN_MAKE_GCCV(4,7,0)
|
||||
// #define MDFN_ASSUME_ALIGNED(p, align) __builtin_assume_aligned((p), (align))
|
||||
//#else
|
||||
|
|
|
@ -1,6 +1,125 @@
|
|||
#pragma once
|
||||
|
||||
#include "emuware/emuware.h"
|
||||
#include <intrin.h>
|
||||
|
||||
//
|
||||
// Result is defined for all possible inputs(including 0).
|
||||
//
|
||||
static INLINE unsigned MDFN_lzcount32(uint32 v)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
||||
return v ? __builtin_clz(v) : 32;
|
||||
#elif defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long idx;
|
||||
|
||||
if(!v)
|
||||
return 32;
|
||||
|
||||
_BitScanReverse(&idx, v);
|
||||
|
||||
return 31 - idx;
|
||||
#else
|
||||
unsigned ret = 0;
|
||||
|
||||
if(!v)
|
||||
return(32);
|
||||
|
||||
if(!(v & 0xFFFF0000))
|
||||
{
|
||||
v <<= 16;
|
||||
ret += 16;
|
||||
}
|
||||
|
||||
if(!(v & 0xFF000000))
|
||||
{
|
||||
v <<= 8;
|
||||
ret += 8;
|
||||
}
|
||||
|
||||
if(!(v & 0xF0000000))
|
||||
{
|
||||
v <<= 4;
|
||||
ret += 4;
|
||||
}
|
||||
|
||||
if(!(v & 0xC0000000))
|
||||
{
|
||||
v <<= 2;
|
||||
ret += 2;
|
||||
}
|
||||
|
||||
if(!(v & 0x80000000))
|
||||
{
|
||||
v <<= 1;
|
||||
ret += 1;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Result is defined for all possible inputs(including 0).
|
||||
//
|
||||
static INLINE unsigned MDFN_lzcount64(uint64 v)
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(__ICC) || defined(__INTEL_COMPILER)
|
||||
return v ? __builtin_clzll(v) : 64;
|
||||
#elif defined(_MSC_VER) && defined(_WIN64)
|
||||
unsigned long idx;
|
||||
|
||||
if(!v)
|
||||
return 64;
|
||||
|
||||
_BitScanReverse64(&idx, v);
|
||||
|
||||
return 63 - idx;
|
||||
#else
|
||||
unsigned ret = 0;
|
||||
|
||||
if(!(v & 0xFFFFFFFFFFFFFFFFULL))
|
||||
return(64);
|
||||
|
||||
if(!(v & 0xFFFFFFFF00000000ULL))
|
||||
{
|
||||
v <<= 32;
|
||||
ret += 32;
|
||||
}
|
||||
|
||||
if(!(v & 0xFFFF000000000000ULL))
|
||||
{
|
||||
v <<= 16;
|
||||
ret += 16;
|
||||
}
|
||||
|
||||
if(!(v & 0xFF00000000000000ULL))
|
||||
{
|
||||
v <<= 8;
|
||||
ret += 8;
|
||||
}
|
||||
|
||||
if(!(v & 0xF000000000000000ULL))
|
||||
{
|
||||
v <<= 4;
|
||||
ret += 4;
|
||||
}
|
||||
|
||||
if(!(v & 0xC000000000000000ULL))
|
||||
{
|
||||
v <<= 2;
|
||||
ret += 2;
|
||||
}
|
||||
|
||||
if(!(v & 0x8000000000000000ULL))
|
||||
{
|
||||
v <<= 1;
|
||||
ret += 1;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
||||
// Rounds up to the nearest power of 2.
|
||||
|
@ -84,4 +203,3 @@ template<typename T, typename U, typename V> static INLINE void clamp(T *val, U
|
|||
*val = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef __MDFN_FASTFIFO_H
|
||||
#define __MDFN_FASTFIFO_H
|
||||
|
||||
// size should be a power of 2.
|
||||
template<typename T, size_t size>
|
||||
class FastFIFO
|
||||
{
|
||||
public:
|
||||
|
||||
FastFIFO()
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
INLINE ~FastFIFO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
INLINE void SaveStatePostLoad(void)
|
||||
{
|
||||
read_pos %= size;
|
||||
write_pos %= size;
|
||||
in_count %= (size + 1);
|
||||
}
|
||||
|
||||
INLINE uint32 CanRead(void)
|
||||
{
|
||||
return(in_count);
|
||||
}
|
||||
|
||||
INLINE uint32 CanWrite(void)
|
||||
{
|
||||
return(size - in_count);
|
||||
}
|
||||
|
||||
INLINE T Peek(void)
|
||||
{
|
||||
return data[read_pos];
|
||||
}
|
||||
|
||||
INLINE T Read(void)
|
||||
{
|
||||
T ret = data[read_pos];
|
||||
|
||||
read_pos = (read_pos + 1) & (size - 1);
|
||||
in_count--;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
INLINE void Write(const T& wr_data)
|
||||
{
|
||||
data[write_pos] = wr_data;
|
||||
write_pos = (write_pos + 1) & (size - 1);
|
||||
in_count++;
|
||||
}
|
||||
|
||||
INLINE void Flush(void)
|
||||
{
|
||||
read_pos = 0;
|
||||
write_pos = 0;
|
||||
in_count = 0;
|
||||
}
|
||||
|
||||
T data[size];
|
||||
uint32 read_pos; // Read position
|
||||
uint32 write_pos; // Write position
|
||||
uint32 in_count; // Number of units in the FIFO
|
||||
|
||||
template<bool isReader> void SyncState(EW::NewState *ns)
|
||||
{
|
||||
//I dont like this class...
|
||||
|
||||
NSS(data);
|
||||
NSS(read_pos);
|
||||
NSS(write_pos);
|
||||
NSS(in_count);
|
||||
|
||||
SaveStatePostLoad();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -214,7 +214,7 @@ void PS_CDC::SoftReset(void)
|
|||
PendingCommandPhase = 0;
|
||||
PendingCommandCounter = 0;
|
||||
|
||||
Mode = 0;
|
||||
Mode = 0x20;
|
||||
|
||||
HeaderBufValid = false;
|
||||
DriveStatus = DS_STOPPED;
|
||||
|
@ -375,67 +375,77 @@ void PS_CDC::WriteIRQ(uint8 V)
|
|||
RecalcIRQ();
|
||||
}
|
||||
|
||||
void PS_CDC::BeginResults(void)
|
||||
{
|
||||
//if(ResultsIn)
|
||||
// {
|
||||
// printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer);
|
||||
//}
|
||||
|
||||
// TODO: test semantics on real thing.
|
||||
ResultsIn = 0;
|
||||
ResultsWP = 0;
|
||||
ResultsRP = 0;
|
||||
}
|
||||
|
||||
void PS_CDC::WriteResult(uint8 V)
|
||||
{
|
||||
ResultsBuffer[ResultsWP] = V;
|
||||
ResultsWP = (ResultsWP + 1) & 0xF;
|
||||
ResultsIn = (ResultsIn + 1) & 0x1F;
|
||||
|
||||
if(!ResultsIn)
|
||||
PSX_WARNING("[CDC] Results buffer overflow!");
|
||||
}
|
||||
|
||||
uint8 PS_CDC::ReadResult(void)
|
||||
{
|
||||
uint8 ret = ResultsBuffer[ResultsRP];
|
||||
|
||||
ResultsRP = (ResultsRP + 1) & 0xF;
|
||||
ResultsIn = (ResultsIn - 1) & 0x1F;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 PS_CDC::MakeStatus(bool cmd_error)
|
||||
{
|
||||
uint8 ret = 0;
|
||||
|
||||
// Are these bit positions right?
|
||||
|
||||
if(DriveStatus == DS_PLAYING)
|
||||
ret |= 0x80;
|
||||
|
||||
if(DriveStatus == DS_SEEKING || DriveStatus == DS_SEEKING_LOGICAL)
|
||||
ret |= 0x40;
|
||||
|
||||
if(DriveStatus == DS_READING)
|
||||
ret |= 0x20;
|
||||
|
||||
// TODO: shell open and seek error
|
||||
if(!Cur_disc || DiscChanged)
|
||||
ret |= 0x10;
|
||||
|
||||
if(DriveStatus != DS_STOPPED)
|
||||
ret |= 0x02;
|
||||
|
||||
if(cmd_error)
|
||||
ret |= 0x01;
|
||||
|
||||
DiscChanged = false;
|
||||
|
||||
return(ret);
|
||||
void PS_CDC::BeginResults(void)
|
||||
{
|
||||
//if(ResultsIn)
|
||||
// {
|
||||
// printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer);
|
||||
//}
|
||||
|
||||
ResultsIn = 0;
|
||||
ResultsWP = 0;
|
||||
ResultsRP = 0;
|
||||
|
||||
memset(ResultsBuffer, 0x00, sizeof(ResultsBuffer));
|
||||
}
|
||||
|
||||
void PS_CDC::WriteResult(uint8 V)
|
||||
{
|
||||
ResultsBuffer[ResultsWP] = V;
|
||||
ResultsWP = (ResultsWP + 1) & 0xF;
|
||||
ResultsIn = (ResultsIn + 1) & 0x1F;
|
||||
|
||||
if(!ResultsIn)
|
||||
PSX_WARNING("[CDC] Results buffer overflow!");
|
||||
}
|
||||
|
||||
uint8 PS_CDC::ReadResult(void)
|
||||
{
|
||||
uint8 ret = ResultsBuffer[ResultsRP];
|
||||
|
||||
if(!ResultsIn)
|
||||
PSX_WARNING("[CDC] Results buffer underflow!");
|
||||
|
||||
ResultsRP = (ResultsRP + 1) & 0xF;
|
||||
ResultsIn = (ResultsIn - 1) & 0x1F;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 PS_CDC::MakeStatus(bool cmd_error)
|
||||
{
|
||||
uint8 ret = 0;
|
||||
|
||||
// Are these bit positions right?
|
||||
|
||||
if(DriveStatus == DS_PLAYING)
|
||||
ret |= 0x80;
|
||||
|
||||
// Probably will want to be careful with this HeaderBufValid versus seek/read bit business in the future as it is a bit fragile;
|
||||
// "Gran Turismo 1"'s music(or erroneous lack of) is a good test case.
|
||||
if(DriveStatus == DS_READING)
|
||||
{
|
||||
if(!HeaderBufValid)
|
||||
ret |= 0x40;
|
||||
else
|
||||
ret |= 0x20;
|
||||
}
|
||||
else if(DriveStatus == DS_SEEKING || DriveStatus == DS_SEEKING_LOGICAL)
|
||||
ret |= 0x40;
|
||||
|
||||
// TODO: shell open and seek error
|
||||
if(!Cur_CDIF || DiscChanged)
|
||||
ret |= 0x10;
|
||||
|
||||
if(DriveStatus != DS_STOPPED)
|
||||
ret |= 0x02;
|
||||
|
||||
if(cmd_error)
|
||||
ret |= 0x01;
|
||||
|
||||
DiscChanged = false;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
bool PS_CDC::DecodeSubQ(uint8 *subpw)
|
||||
|
@ -463,13 +473,13 @@ bool PS_CDC::DecodeSubQ(uint8 *subpw)
|
|||
|
||||
static const int16 CDADPCMImpulse[7][25] =
|
||||
{
|
||||
{ 0, -5, 17, -35, 70, -23, -68, 347, -839, 2062, -4681, 15367, 21472, -5882, 2810, -1352, 635, -235, 26, 43, -35, 16, -8, 2, 0, }, /* 0 */
|
||||
{ 0, -2, 10, -34, 65, -84, 52, 9, -266, 1024, -2680, 9036, 26516, -6016, 3021, -1571, 848, -365, 107, 10, -16, 17, -8, 3, -1, }, /* 1 */
|
||||
{ -2, 0, 3, -19, 60, -75, 162, -227, 306, -67, -615, 3229, 29883, -4532, 2488, -1471, 882, -424, 166, -27, 5, 6, -8, 3, -1, }, /* 2 */
|
||||
{ -1, 3, -2, -5, 31, -74, 179, -402, 689, -926, 1272, -1446, 31033, -1446, 1272, -926, 689, -402, 179, -74, 31, -5, -2, 3, -1, }, /* 3 */
|
||||
{ -1, 3, -8, 6, 5, -27, 166, -424, 882, -1471, 2488, -4532, 29883, 3229, -615, -67, 306, -227, 162, -75, 60, -19, 3, 0, -2, }, /* 4 */
|
||||
{ -1, 3, -8, 17, -16, 10, 107, -365, 848, -1571, 3021, -6016, 26516, 9036, -2680, 1024, -266, 9, 52, -84, 65, -34, 10, -2, 0, }, /* 5 */
|
||||
{ 0, 2, -8, 16, -35, 43, 26, -235, 635, -1352, 2810, -5882, 21472, 15367, -4681, 2062, -839, 347, -68, -23, 70, -35, 17, -5, 0, }, /* 6 */
|
||||
{ 0, -5, 17, -35, 70, -23, -68, 347, -839, 2062, -4681, 15367, 21472, -5882, 2810, -1352, 635, -235, 26, 43, -35, 16, -8, 2, 0, }, /* 0 */
|
||||
{ 0, -2, 10, -34, 65, -84, 52, 9, -266, 1024, -2680, 9036, 26516, -6016, 3021, -1571, 848, -365, 107, 10, -16, 17, -8, 3, -1, }, /* 1 */
|
||||
{ -2, 0, 3, -19, 60, -75, 162, -227, 306, -67, -615, 3229, 29883, -4532, 2488, -1471, 882, -424, 166, -27, 5, 6, -8, 3, -1, }, /* 2 */
|
||||
{ -1, 3, -2, -5, 31, -74, 179, -402, 689, -926, 1272, -1446, 31033, -1446, 1272, -926, 689, -402, 179, -74, 31, -5, -2, 3, -1, }, /* 3 */
|
||||
{ -1, 3, -8, 6, 5, -27, 166, -424, 882, -1471, 2488, -4532, 29883, 3229, -615, -67, 306, -227, 162, -75, 60, -19, 3, 0, -2, }, /* 4 */
|
||||
{ -1, 3, -8, 17, -16, 10, 107, -365, 848, -1571, 3021, -6016, 26516, 9036, -2680, 1024, -266, 9, 52, -84, 65, -34, 10, -2, 0, }, /* 5 */
|
||||
{ 0, 2, -8, 16, -35, 43, 26, -235, 635, -1352, 2810, -5882, 21472, 15367, -4681, 2062, -839, 347, -68, -23, 70, -35, 17, -5, 0, }, /* 6 */
|
||||
};
|
||||
|
||||
void PS_CDC::ReadAudioBuffer(int32 samples[2])
|
||||
|
@ -880,17 +890,11 @@ void PS_CDC::HandlePlayRead(void)
|
|||
if(CurSector >= (int32)toc.tracks[100].lba)
|
||||
{
|
||||
PSX_WARNING("[CDC] In leadout area: %u", CurSector);
|
||||
//ZERO TODO - this is the critical point for testing leadout-reading.
|
||||
}
|
||||
|
||||
// " Synthesis is a bit of a kludge " but we've taken it out of here
|
||||
//synth_leadout_sector_lba(0x02, toc, CurSector, read_buf);
|
||||
Cur_disc->ReadLBA2448(CurSector,read_buf); // FIXME: error out on error.
|
||||
}
|
||||
else
|
||||
{
|
||||
Cur_disc->ReadLBA2448(CurSector,read_buf); // FIXME: error out on error.
|
||||
}
|
||||
|
||||
DecodeSubQ(read_buf + 2352);
|
||||
Cur_disc->ReadLBA2448(CurSector,read_buf); // FIXME: error out on error.
|
||||
DecodeSubQ(read_buf + 2352);
|
||||
|
||||
|
||||
if(SubQBuf_Safe[1] == 0xAA && (DriveStatus == DS_PLAYING || (!(SubQBuf_Safe[0] & 0x40) && (Mode & MODE_CDDA))))
|
||||
|
@ -1109,7 +1113,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
|
|||
|
||||
if(PSRCounter > 0)
|
||||
{
|
||||
uint8 buf[2352 + 96];
|
||||
uint8 pwbuf[96];
|
||||
|
||||
PSRCounter -= chunk_clocks;
|
||||
|
||||
|
@ -1126,7 +1130,7 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
|
|||
SectorPipe_Pos = SectorPipe_In = 0;
|
||||
SectorsRead = 0;
|
||||
|
||||
Mode = 0;
|
||||
Mode = 0x20; // Confirmed(and see "This Is Football 2").
|
||||
CurSector = 0;
|
||||
CommandLoc = 0;
|
||||
|
||||
|
@ -1136,8 +1140,8 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
|
|||
else if(DriveStatus == DS_SEEKING)
|
||||
{
|
||||
CurSector = SeekTarget;
|
||||
Cur_disc->ReadLBA2448(CurSector,buf);
|
||||
DecodeSubQ(buf + 2352);
|
||||
Cur_disc->ReadLBA_PW(pwbuf,CurSector,false);
|
||||
DecodeSubQ(pwbuf);
|
||||
|
||||
DriveStatus = StatusAfterSeek;
|
||||
|
||||
|
@ -1146,26 +1150,25 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
|
|||
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
|
||||
}
|
||||
}
|
||||
else if(DriveStatus == DS_SEEKING_LOGICAL)
|
||||
{
|
||||
CurSector = SeekTarget;
|
||||
Cur_disc->ReadLBA2448(CurSector, buf);
|
||||
DecodeSubQ(buf + 2352);
|
||||
memcpy(HeaderBuf, buf + 12, 12);
|
||||
|
||||
DriveStatus = StatusAfterSeek;
|
||||
|
||||
if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
|
||||
{
|
||||
// TODO: SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04); when !(Mode & MODE_CDDA) and the sector isn't a data sector.
|
||||
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
|
||||
}
|
||||
}
|
||||
else if(DriveStatus == DS_READING || DriveStatus == DS_PLAYING)
|
||||
{
|
||||
HandlePlayRead();
|
||||
}
|
||||
}
|
||||
else if(DriveStatus == DS_SEEKING_LOGICAL)
|
||||
{
|
||||
CurSector = SeekTarget;
|
||||
Cur_disc->ReadLBA_PW(pwbuf, CurSector, false);
|
||||
DecodeSubQ(pwbuf);
|
||||
|
||||
DriveStatus = StatusAfterSeek;
|
||||
|
||||
if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
|
||||
{
|
||||
// TODO: SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04); when !(Mode & MODE_CDDA) and the sector isn't a data sector.
|
||||
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
|
||||
}
|
||||
}
|
||||
else if(DriveStatus == DS_READING || DriveStatus == DS_PLAYING)
|
||||
{
|
||||
HandlePlayRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(PendingCommandCounter > 0)
|
||||
|
@ -1552,22 +1555,32 @@ int32 PS_CDC::Command_Nop(const int arg_count, const uint8 *args)
|
|||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
|
||||
{
|
||||
uint8 m, s, f;
|
||||
|
||||
m = BCD_to_U8(args[0] & 0x7F);
|
||||
s = BCD_to_U8(args[1]);
|
||||
f = BCD_to_U8(args[2]);
|
||||
|
||||
CommandLoc = f + 75 * s + 75 * 60 * m - 150;
|
||||
CommandLoc_Dirty = true;
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
return(0);
|
||||
|
||||
int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
|
||||
{
|
||||
uint8 m, s, f;
|
||||
|
||||
if((args[0] & 0x0F) > 0x09 || args[0] > 0x99 ||
|
||||
(args[1] & 0x0F) > 0x09 || args[1] > 0x59 ||
|
||||
(args[2] & 0x0F) > 0x09 || args[2] > 0x74)
|
||||
{
|
||||
WriteResult(MakeStatus(true));
|
||||
WriteResult(ERRCODE_BAD_ARGVAL);
|
||||
WriteIRQ(CDCIRQ_DISC_ERROR);
|
||||
return(0);
|
||||
}
|
||||
|
||||
m = BCD_to_U8(args[0]);
|
||||
s = BCD_to_U8(args[1]);
|
||||
f = BCD_to_U8(args[2]);
|
||||
|
||||
CommandLoc = f + 75 * s + 75 * 60 * m - 150;
|
||||
CommandLoc_Dirty = true;
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
|
||||
|
@ -1624,34 +1637,27 @@ void PS_CDC::BeginSeek(uint32 target, int after_seek)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD
|
||||
// access code.
|
||||
void PS_CDC::PreSeekHack(bool logical, uint32 target)
|
||||
{
|
||||
uint8 buf[2352 + 96];
|
||||
int max_try = 32;
|
||||
bool NeedHBuf = logical;
|
||||
|
||||
CurSector = target; // If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek.
|
||||
|
||||
// If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1.
|
||||
if(target < toc.tracks[100].lba)
|
||||
{
|
||||
do
|
||||
{
|
||||
Cur_disc->ReadLBA2448(target++, buf);
|
||||
|
||||
// GetLocL related kludge, for Gran Turismo 1 music, perhaps others?
|
||||
if(NeedHBuf)
|
||||
{
|
||||
NeedHBuf = false;
|
||||
memcpy(HeaderBuf, buf + 12, 12);
|
||||
HeaderBufValid = true;
|
||||
}
|
||||
} while(!DecodeSubQ(buf + 2352) && --max_try > 0 && target < toc.tracks[100].lba);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD
|
||||
// access code.
|
||||
void PS_CDC::PreSeekHack(int32 target)
|
||||
{
|
||||
uint8 pwbuf[96];
|
||||
int max_try = 32;
|
||||
|
||||
CurSector = target; // If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek.
|
||||
|
||||
// If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1.
|
||||
do
|
||||
{
|
||||
Cur_disc->ReadLBA_PW(pwbuf, target++, true);
|
||||
} while(!DecodeSubQ(pwbuf) && --max_try > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Play command with a track argument that's not a valid BCD quantity causes interesting half-buggy behavior on an actual PS1(unlike some of the other commands,
|
||||
an error doesn't seem to be generated for a bad BCD argument).
|
||||
*/
|
||||
int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
|
||||
{
|
||||
if(!CommandCheckDiscPresent())
|
||||
|
@ -1675,7 +1681,7 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
|
|||
}
|
||||
else if(track > toc.last_track)
|
||||
{
|
||||
PSX_WARNING("[CDC] Attempt to play track before first track.");
|
||||
PSX_WARNING("[CDC] Attempt to play track after last track.");
|
||||
track = toc.last_track;
|
||||
}
|
||||
|
||||
|
@ -1690,7 +1696,7 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
|
|||
SeekTarget = toc.tracks[track].lba;
|
||||
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(false, SeekTarget);
|
||||
PreSeekHack(SeekTarget);
|
||||
|
||||
ReportLastF = 0xFF;
|
||||
|
||||
|
@ -1712,7 +1718,7 @@ int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
|
|||
|
||||
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(false, SeekTarget);
|
||||
PreSeekHack(SeekTarget);
|
||||
|
||||
ReportLastF = 0xFF;
|
||||
|
||||
|
@ -1785,7 +1791,7 @@ void PS_CDC::ReadBase(void)
|
|||
|
||||
PSRCounter = /*903168 * 1.5 +*/ CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(true, SeekTarget);
|
||||
PreSeekHack(SeekTarget);
|
||||
|
||||
DriveStatus = DS_SEEKING_LOGICAL;
|
||||
StatusAfterSeek = DS_READING;
|
||||
|
@ -2062,59 +2068,60 @@ int32 PS_CDC::Command_GetTN(const int arg_count, const uint8 *args)
|
|||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args)
|
||||
{
|
||||
if(!CommandCheckDiscPresent())
|
||||
return(0);
|
||||
|
||||
int track;
|
||||
uint8 m, s, f;
|
||||
|
||||
if(!args[0] || args[0] == 0xAA)
|
||||
track = 100;
|
||||
else
|
||||
{
|
||||
track= BCD_to_U8(args[0]);
|
||||
|
||||
if(track < toc.first_track || track > toc.last_track) // Error
|
||||
{
|
||||
WriteResult(MakeStatus(true));
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteResult(U8_to_BCD(m));
|
||||
WriteResult(U8_to_BCD(s));
|
||||
//WriteResult(U8_to_BCD(f));
|
||||
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
return(0);
|
||||
|
||||
int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args)
|
||||
{
|
||||
if(!CommandCheckDiscPresent())
|
||||
return(0);
|
||||
|
||||
int track;
|
||||
uint8 m, s, f;
|
||||
|
||||
if(!args[0])
|
||||
track = 100;
|
||||
else
|
||||
{
|
||||
track = BCD_to_U8(args[0]);
|
||||
|
||||
if(!BCD_is_valid(args[0]) || track < toc.first_track || track > toc.last_track) // Error
|
||||
{
|
||||
WriteResult(MakeStatus(true));
|
||||
WriteResult(ERRCODE_BAD_ARGVAL);
|
||||
WriteIRQ(CDCIRQ_DISC_ERROR);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteResult(U8_to_BCD(m));
|
||||
WriteResult(U8_to_BCD(s));
|
||||
//WriteResult(U8_to_BCD(f));
|
||||
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
|
||||
{
|
||||
if(!CommandCheckDiscPresent())
|
||||
return(0);
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
SeekTarget = CommandLoc;
|
||||
|
||||
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(true, SeekTarget);
|
||||
DriveStatus = DS_SEEKING_LOGICAL;
|
||||
StatusAfterSeek = DS_STANDBY;
|
||||
ClearAIP();
|
||||
|
||||
return(PSRCounter);
|
||||
|
||||
int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
|
||||
{
|
||||
if(!CommandCheckDiscPresent())
|
||||
return(0);
|
||||
|
||||
WriteResult(MakeStatus());
|
||||
WriteIRQ(CDCIRQ_ACKNOWLEDGE);
|
||||
|
||||
SeekTarget = CommandLoc;
|
||||
|
||||
PSRCounter = (33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1))) + CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(SeekTarget);
|
||||
DriveStatus = DS_SEEKING_LOGICAL;
|
||||
StatusAfterSeek = DS_STANDBY;
|
||||
ClearAIP();
|
||||
|
||||
return(PSRCounter);
|
||||
}
|
||||
|
||||
int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
|
||||
|
@ -2129,7 +2136,7 @@ int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
|
|||
|
||||
PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
|
||||
HeaderBufValid = false;
|
||||
PreSeekHack(false, SeekTarget);
|
||||
PreSeekHack(SeekTarget);
|
||||
DriveStatus = DS_SEEKING;
|
||||
StatusAfterSeek = DS_STANDBY;
|
||||
ClearAIP();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define __MDFN_PSX_CDC_H
|
||||
|
||||
#include "cdrom/CDUtility.h"
|
||||
#include "cdrom/SimpleFIFO.h"
|
||||
|
||||
class ShockDiscRef;
|
||||
|
||||
|
@ -232,8 +233,7 @@ class PS_CDC
|
|||
int32 (PS_CDC::*func2)(void);
|
||||
};
|
||||
|
||||
void BeginSeek(uint32 target);
|
||||
void PreSeekHack(bool logical, uint32 target);
|
||||
void PreSeekHack(int32 target);
|
||||
void ReadBase(void);
|
||||
|
||||
static CDC_CTEntry Commands[0x20];
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,264 +1,256 @@
|
|||
#ifndef __MDFN_PSX_CPU_H
|
||||
#define __MDFN_PSX_CPU_H
|
||||
|
||||
/*
|
||||
Load delay notes:
|
||||
|
||||
// Takes 1 less
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"or %0, %1, %1\n\t"
|
||||
|
||||
// cycle than this:
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"or %0, %1, %1\n\t"
|
||||
"nop\n\t"
|
||||
|
||||
|
||||
// Both of these
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"or %1, %0, %0\n\t"
|
||||
|
||||
// take same...(which is kind of odd).
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"or %1, %0, %0\n\t"
|
||||
"nop\n\t"
|
||||
*/
|
||||
|
||||
#include "gte.h"
|
||||
|
||||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
||||
#define PS_CPU_EMULATE_ICACHE 1
|
||||
|
||||
class PS_CPU
|
||||
{
|
||||
public:
|
||||
|
||||
PS_CPU() MDFN_COLD;
|
||||
~PS_CPU() MDFN_COLD;
|
||||
|
||||
template<bool isReader>void SyncState(EW::NewState *ns);
|
||||
|
||||
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
|
||||
// will always be multiples of 4.
|
||||
enum { FAST_MAP_SHIFT = 16 };
|
||||
enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT };
|
||||
|
||||
void SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size);
|
||||
|
||||
INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg)
|
||||
{
|
||||
next_event_ts = next_event_ts_arg;
|
||||
}
|
||||
|
||||
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode);
|
||||
|
||||
void Power(void) MDFN_COLD;
|
||||
|
||||
// which ranges 0-5, inclusive
|
||||
void AssertIRQ(unsigned which, bool asserted);
|
||||
|
||||
|
||||
void SetHalt(bool status);
|
||||
|
||||
// TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
|
||||
void SetBIU(uint32_t val);
|
||||
uint32_t GetBIU(void);
|
||||
|
||||
private:
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t GPR[32];
|
||||
uint32_t GPR_dummy; // Used in load delay simulation(indexing past the end of GPR)
|
||||
};
|
||||
uint32_t LO;
|
||||
uint32_t HI;
|
||||
|
||||
|
||||
uint32_t BACKED_PC;
|
||||
uint32_t BACKED_new_PC;
|
||||
uint32_t BACKED_new_PC_mask;
|
||||
|
||||
uint32_t IPCache;
|
||||
void RecalcIPCache(void);
|
||||
bool Halted;
|
||||
|
||||
uint32_t BACKED_LDWhich;
|
||||
uint32_t BACKED_LDValue;
|
||||
uint32_t LDAbsorb;
|
||||
|
||||
pscpu_timestamp_t next_event_ts;
|
||||
pscpu_timestamp_t gte_ts_done;
|
||||
pscpu_timestamp_t muldiv_ts_done;
|
||||
|
||||
uint32_t BIU;
|
||||
|
||||
struct __ICache
|
||||
{
|
||||
uint32_t TV;
|
||||
uint32_t Data;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
__ICache ICache[1024];
|
||||
uint32 ICache_Bulk[2048];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CP0REG_BPC = 3, // PC breakpoint address.
|
||||
CP0REG_BDA = 5, // Data load/store breakpoint address.
|
||||
CP0REG_TAR = 6, // Target address(???)
|
||||
CP0REG_DCIC = 7, // Cache control
|
||||
CP0REG_BDAM = 9, // Data load/store address mask.
|
||||
CP0REG_BPCM = 11, // PC breakpoint address mask.
|
||||
CP0REG_SR = 12,
|
||||
CP0REG_CAUSE = 13,
|
||||
CP0REG_EPC = 14,
|
||||
CP0REG_PRID = 15, // Product ID
|
||||
CP0REG_ERREG = 16
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t Regs[32];
|
||||
struct
|
||||
{
|
||||
uint32_t Unused00;
|
||||
uint32_t Unused01;
|
||||
uint32_t Unused02;
|
||||
uint32_t BPC; // RW
|
||||
uint32_t Unused04;
|
||||
uint32_t BDA; // RW
|
||||
uint32_t TAR;
|
||||
uint32_t DCIC; // RW
|
||||
uint32_t Unused08;
|
||||
uint32_t BDAM; // R/W
|
||||
uint32_t Unused0A;
|
||||
uint32_t BPCM; // R/W
|
||||
uint32_t SR; // R/W
|
||||
uint32_t CAUSE; // R/W(partial)
|
||||
uint32_t EPC; // R
|
||||
uint32_t PRID; // R
|
||||
uint32_t ERREG; // ?(may not exist, test)
|
||||
};
|
||||
};
|
||||
} CP0;
|
||||
|
||||
#if 1
|
||||
//uint32_t WrAbsorb;
|
||||
//uint8_t WrAbsorbShift;
|
||||
|
||||
// On read:
|
||||
//WrAbsorb = 0;
|
||||
//WrAbsorbShift = 0;
|
||||
|
||||
// On write:
|
||||
//WrAbsorb >>= (WrAbsorbShift >> 2) & 8;
|
||||
//WrAbsorbShift -= (WrAbsorbShift >> 2) & 8;
|
||||
|
||||
//WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift;
|
||||
//WrAbsorbShift += 8;
|
||||
#endif
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t ReadAbsorb[0x20];
|
||||
uint8_t ReadAbsorbDummy;
|
||||
};
|
||||
uint8_t ReadAbsorbWhich;
|
||||
uint8_t ReadFudge;
|
||||
|
||||
//uint32_t WriteAbsorb;
|
||||
//uint8_t WriteAbsorbCount;
|
||||
//uint8_t WriteAbsorbMonkey;
|
||||
uint8 MULT_Tab24[24];
|
||||
|
||||
MultiAccessSizeMem<1024, false> ScratchRAM;
|
||||
|
||||
//PS_GTE GTE;
|
||||
|
||||
uint8_t *FastMap[1 << (32 - FAST_MAP_SHIFT)];
|
||||
uint8_t DummyPage[FAST_MAP_PSIZE];
|
||||
|
||||
enum
|
||||
{
|
||||
EXCEPTION_INT = 0,
|
||||
EXCEPTION_MOD = 1,
|
||||
EXCEPTION_TLBL = 2,
|
||||
EXCEPTION_TLBS = 3,
|
||||
EXCEPTION_ADEL = 4, // Address error on load
|
||||
EXCEPTION_ADES = 5, // Address error on store
|
||||
EXCEPTION_IBE = 6, // Instruction bus error
|
||||
EXCEPTION_DBE = 7, // Data bus error
|
||||
EXCEPTION_SYSCALL = 8, // System call
|
||||
EXCEPTION_BP = 9, // Breakpoint
|
||||
EXCEPTION_RI = 10, // Reserved instruction
|
||||
EXCEPTION_COPU = 11, // Coprocessor unusable
|
||||
EXCEPTION_OV = 12 // Arithmetic overflow
|
||||
};
|
||||
|
||||
uint32_t Exception(uint32_t code, uint32_t PC, const uint32_t NPM) MDFN_WARN_UNUSED_RESULT;
|
||||
|
||||
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
|
||||
|
||||
template<typename T> T PeekMemory(uint32_t address) MDFN_COLD;
|
||||
template<typename T> T ReadMemory(pscpu_timestamp_t ×tamp, uint32_t address, bool DS24 = false, bool LWC_timing = false);
|
||||
template<typename T> void WriteMemory(pscpu_timestamp_t ×tamp, uint32_t address, uint32_t value, bool DS24 = false);
|
||||
|
||||
|
||||
//
|
||||
// Mednafen debugger stuff follows:
|
||||
//
|
||||
public:
|
||||
void SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception));
|
||||
void CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr);
|
||||
void* debug_GetScratchRAMPtr() { return ScratchRAM.data8; }
|
||||
void* debug_GetGPRPtr() { return GPR; }
|
||||
|
||||
enum
|
||||
{
|
||||
GSREG_GPR = 0,
|
||||
GSREG_PC = 32,
|
||||
GSREG_PC_NEXT,
|
||||
GSREG_IN_BD_SLOT,
|
||||
GSREG_LO,
|
||||
GSREG_HI,
|
||||
GSREG_SR,
|
||||
GSREG_CAUSE,
|
||||
GSREG_EPC,
|
||||
};
|
||||
|
||||
uint32_t GetRegister(unsigned int which, char *special, const uint32_t special_len);
|
||||
void SetRegister(unsigned int which, uint32_t value);
|
||||
bool PeekCheckICache(uint32_t PC, uint32_t *iw);
|
||||
uint8_t PeekMem8(uint32_t A);
|
||||
uint16_t PeekMem16(uint32_t A);
|
||||
uint32_t PeekMem32(uint32_t A);
|
||||
private:
|
||||
void (*CPUHook)(const pscpu_timestamp_t timestamp, uint32_t pc);
|
||||
void (*ADDBT)(uint32_t from, uint32_t to, bool exception);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef __MDFN_PSX_CPU_H
|
||||
#define __MDFN_PSX_CPU_H
|
||||
|
||||
/*
|
||||
Load delay notes:
|
||||
|
||||
// Takes 1 less
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"or %0, %1, %1\n\t"
|
||||
|
||||
// cycle than this:
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"or %0, %1, %1\n\t"
|
||||
"nop\n\t"
|
||||
|
||||
|
||||
// Both of these
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"nop\n\t"
|
||||
"or %1, %0, %0\n\t"
|
||||
|
||||
// take same...(which is kind of odd).
|
||||
".set noreorder\n\t"
|
||||
".set nomacro\n\t"
|
||||
"lw %0, 0(%2)\n\t"
|
||||
"nop\n\t"
|
||||
"or %1, %0, %0\n\t"
|
||||
"nop\n\t"
|
||||
*/
|
||||
|
||||
#include "gte.h"
|
||||
|
||||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
||||
#define PS_CPU_EMULATE_ICACHE 1
|
||||
|
||||
class PS_CPU
|
||||
{
|
||||
public:
|
||||
|
||||
PS_CPU() MDFN_COLD;
|
||||
~PS_CPU() MDFN_COLD;
|
||||
|
||||
template<bool isReader>void SyncState(EW::NewState *ns);
|
||||
|
||||
// FAST_MAP_* enums are in BYTES(8-bit), not in 32-bit units("words" in MIPS context), but the sizes
|
||||
// will always be multiples of 4.
|
||||
enum { FAST_MAP_SHIFT = 16 };
|
||||
enum { FAST_MAP_PSIZE = 1 << FAST_MAP_SHIFT };
|
||||
|
||||
void SetFastMap(void *region_mem, uint32 region_address, uint32 region_size);
|
||||
|
||||
INLINE void SetEventNT(const pscpu_timestamp_t next_event_ts_arg)
|
||||
{
|
||||
next_event_ts = next_event_ts_arg;
|
||||
}
|
||||
|
||||
pscpu_timestamp_t Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode);
|
||||
|
||||
void Power(void) MDFN_COLD;
|
||||
|
||||
// which ranges 0-5, inclusive
|
||||
void AssertIRQ(unsigned which, bool asserted);
|
||||
|
||||
void SetHalt(bool status);
|
||||
|
||||
// TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
|
||||
void SetBIU(uint32 val);
|
||||
uint32 GetBIU(void);
|
||||
|
||||
private:
|
||||
|
||||
uint32 GPR[32 + 1]; // GPR[32] Used as dummy in load delay simulation(indexing past the end of real GPR)
|
||||
|
||||
uint32 LO;
|
||||
uint32 HI;
|
||||
|
||||
|
||||
uint32 BACKED_PC;
|
||||
uint32 BACKED_new_PC;
|
||||
uint32 BACKED_new_PC_mask;
|
||||
|
||||
uint32 IPCache;
|
||||
void RecalcIPCache(void);
|
||||
bool Halted;
|
||||
|
||||
uint32 BACKED_LDWhich;
|
||||
uint32 BACKED_LDValue;
|
||||
uint32 LDAbsorb;
|
||||
|
||||
pscpu_timestamp_t next_event_ts;
|
||||
pscpu_timestamp_t gte_ts_done;
|
||||
pscpu_timestamp_t muldiv_ts_done;
|
||||
|
||||
uint32 BIU;
|
||||
|
||||
struct __ICache
|
||||
{
|
||||
uint32 TV;
|
||||
uint32 Data;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
__ICache ICache[1024];
|
||||
uint32 ICache_Bulk[2048];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CP0REG_BPC = 3, // PC breakpoint address.
|
||||
CP0REG_BDA = 5, // Data load/store breakpoint address.
|
||||
CP0REG_TAR = 6, // Target address(???)
|
||||
CP0REG_DCIC = 7, // Cache control
|
||||
CP0REG_BDAM = 9, // Data load/store address mask.
|
||||
CP0REG_BPCM = 11, // PC breakpoint address mask.
|
||||
CP0REG_SR = 12,
|
||||
CP0REG_CAUSE = 13,
|
||||
CP0REG_EPC = 14,
|
||||
CP0REG_PRID = 15, // Product ID
|
||||
CP0REG_ERREG = 16
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32 Regs[32];
|
||||
struct
|
||||
{
|
||||
uint32 Unused00;
|
||||
uint32 Unused01;
|
||||
uint32 Unused02;
|
||||
uint32 BPC; // RW
|
||||
uint32 Unused04;
|
||||
uint32 BDA; // RW
|
||||
uint32 TAR;
|
||||
uint32 DCIC; // RW
|
||||
uint32 Unused08;
|
||||
uint32 BDAM; // R/W
|
||||
uint32 Unused0A;
|
||||
uint32 BPCM; // R/W
|
||||
uint32 SR; // R/W
|
||||
uint32 CAUSE; // R/W(partial)
|
||||
uint32 EPC; // R
|
||||
uint32 PRID; // R
|
||||
uint32 ERREG; // ?(may not exist, test)
|
||||
};
|
||||
};
|
||||
} CP0;
|
||||
|
||||
#if 1
|
||||
//uint32 WrAbsorb;
|
||||
//uint8 WrAbsorbShift;
|
||||
|
||||
// On read:
|
||||
//WrAbsorb = 0;
|
||||
//WrAbsorbShift = 0;
|
||||
|
||||
// On write:
|
||||
//WrAbsorb >>= (WrAbsorbShift >> 2) & 8;
|
||||
//WrAbsorbShift -= (WrAbsorbShift >> 2) & 8;
|
||||
|
||||
//WrAbsorb |= (timestamp - pre_write_timestamp) << WrAbsorbShift;
|
||||
//WrAbsorbShift += 8;
|
||||
#endif
|
||||
|
||||
uint8 ReadAbsorb[0x20 + 1];
|
||||
uint8 ReadAbsorbWhich;
|
||||
uint8 ReadFudge;
|
||||
|
||||
//uint32 WriteAbsorb;
|
||||
//uint8 WriteAbsorbCount;
|
||||
//uint8 WriteAbsorbMonkey;
|
||||
uint8 MULT_Tab24[24];
|
||||
|
||||
MultiAccessSizeMem<1024, false> ScratchRAM;
|
||||
|
||||
//PS_GTE GTE;
|
||||
|
||||
uint8 *FastMap[1 << (32 - FAST_MAP_SHIFT)];
|
||||
uint8 DummyPage[FAST_MAP_PSIZE];
|
||||
|
||||
enum
|
||||
{
|
||||
EXCEPTION_INT = 0,
|
||||
EXCEPTION_MOD = 1,
|
||||
EXCEPTION_TLBL = 2,
|
||||
EXCEPTION_TLBS = 3,
|
||||
EXCEPTION_ADEL = 4, // Address error on load
|
||||
EXCEPTION_ADES = 5, // Address error on store
|
||||
EXCEPTION_IBE = 6, // Instruction bus error
|
||||
EXCEPTION_DBE = 7, // Data bus error
|
||||
EXCEPTION_SYSCALL = 8, // System call
|
||||
EXCEPTION_BP = 9, // Breakpoint
|
||||
EXCEPTION_RI = 10, // Reserved instruction
|
||||
EXCEPTION_COPU = 11, // Coprocessor unusable
|
||||
EXCEPTION_OV = 12 // Arithmetic overflow
|
||||
};
|
||||
|
||||
uint32 Exception(uint32 code, uint32 PC, const uint32 NPM) MDFN_WARN_UNUSED_RESULT;
|
||||
|
||||
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
|
||||
|
||||
template<typename T> T PeekMemory(uint32 address) MDFN_COLD;
|
||||
template<typename T> T ReadMemory(pscpu_timestamp_t ×tamp, uint32 address, bool DS24 = false, bool LWC_timing = false);
|
||||
template<typename T> void WriteMemory(pscpu_timestamp_t ×tamp, uint32 address, uint32 value, bool DS24 = false);
|
||||
|
||||
|
||||
//
|
||||
// Mednafen debugger stuff follows:
|
||||
//
|
||||
public:
|
||||
void SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception));
|
||||
void CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr);
|
||||
void* debug_GetScratchRAMPtr() { return ScratchRAM.data8; }
|
||||
void* debug_GetGPRPtr() { return GPR; }
|
||||
|
||||
enum
|
||||
{
|
||||
GSREG_GPR = 0,
|
||||
GSREG_PC = 32,
|
||||
GSREG_PC_NEXT,
|
||||
GSREG_IN_BD_SLOT,
|
||||
GSREG_LO,
|
||||
GSREG_HI,
|
||||
GSREG_SR,
|
||||
GSREG_CAUSE,
|
||||
GSREG_EPC,
|
||||
};
|
||||
|
||||
uint32 GetRegister(unsigned int which, char *special, const uint32 special_len);
|
||||
void SetRegister(unsigned int which, uint32 value);
|
||||
bool PeekCheckICache(uint32 PC, uint32 *iw);
|
||||
uint8 PeekMem8(uint32 A);
|
||||
uint16 PeekMem16(uint32 A);
|
||||
uint32 PeekMem32(uint32 A);
|
||||
private:
|
||||
void (*CPUHook)(const pscpu_timestamp_t timestamp, uint32 pc);
|
||||
void (*ADDBT)(uint32 from, uint32 to, bool exception);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
#include "cdc.h"
|
||||
#include "spu.h"
|
||||
|
||||
//#include <map>
|
||||
|
||||
// Notes: DMA tested to abort when
|
||||
|
||||
/* Notes:
|
||||
|
||||
Channel 4(SPU):
|
||||
|
@ -84,7 +80,7 @@ static Channel DMACH[7];
|
|||
static pscpu_timestamp_t lastts;
|
||||
|
||||
|
||||
static const char *PrettyChannelNames[7] = { "MDEC IN", "MDEC OUT", "GPU", "CDC", "SPU", "PIO", "OTC" };
|
||||
// static const char *PrettyChannelNames[7] = { "MDEC IN", "MDEC OUT", "GPU", "CDC", "SPU", "PIO", "OTC" };
|
||||
|
||||
void DMA_Init(void)
|
||||
{
|
||||
|
@ -96,17 +92,17 @@ void DMA_Kill(void)
|
|||
|
||||
}
|
||||
|
||||
static INLINE void RecalcIRQOut(void)
|
||||
{
|
||||
bool irqo;
|
||||
|
||||
irqo = (bool)DMAIntStatus;
|
||||
irqo &= (DMAIntControl >> 23) & 1;
|
||||
irqo |= (DMAIntControl >> 15) & 1;
|
||||
|
||||
IRQOut = irqo;
|
||||
IRQ_Assert(IRQ_DMA, irqo);
|
||||
}
|
||||
static INLINE void RecalcIRQOut(void)
|
||||
{
|
||||
bool irqo;
|
||||
|
||||
irqo = (bool)DMAIntStatus;
|
||||
irqo &= (DMAIntControl >> 23) & 1;
|
||||
irqo |= (DMAIntControl >> 15) & 1;
|
||||
|
||||
IRQOut = irqo;
|
||||
IRQ_Assert(IRQ_DMA, irqo);
|
||||
}
|
||||
|
||||
void DMA_ResetTS(void)
|
||||
{
|
||||
|
@ -127,8 +123,6 @@ void DMA_Power(void)
|
|||
RecalcIRQOut();
|
||||
}
|
||||
|
||||
void PSX_SetDMASuckSuck(unsigned);
|
||||
|
||||
static INLINE bool ChCan(const unsigned ch, const uint32 CRModeCache)
|
||||
{
|
||||
switch(ch)
|
||||
|
@ -226,19 +220,16 @@ static void RecalcHalt(void)
|
|||
if(tmp > 0)
|
||||
tmp--;
|
||||
|
||||
if(tmp > 200) // Due to 8-bit limitations in the CPU core.
|
||||
tmp = 200;
|
||||
|
||||
PSX_SetDMASuckSuck(tmp);
|
||||
PSX_SetDMACycleSteal(tmp);
|
||||
}
|
||||
else
|
||||
PSX_SetDMASuckSuck(0);
|
||||
PSX_SetDMACycleSteal(0);
|
||||
|
||||
CPU->SetHalt(Halt);
|
||||
}
|
||||
|
||||
|
||||
static INLINE void ChRW(const unsigned ch, const uint32 CRModeCache, uint32 *V, int32 *offset)
|
||||
static INLINE void ChRW(const unsigned ch, const uint32 CRModeCache, uint32 *V, uint32 *offset)
|
||||
{
|
||||
unsigned extra_cyc_overhead = 0;
|
||||
|
||||
|
@ -424,7 +415,7 @@ static INLINE void RunChannelI(const unsigned ch, const uint32 CRModeCache, int3
|
|||
//
|
||||
{
|
||||
uint32 vtmp;
|
||||
int32 voffs = 0;
|
||||
uint32 voffs = 0;
|
||||
|
||||
if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000))
|
||||
{
|
||||
|
@ -626,143 +617,142 @@ static void CheckLinkedList(uint32 addr)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
|
||||
{
|
||||
int ch = (A & 0x7F) >> 4;
|
||||
|
||||
//if(ch == 2 || ch == 7)
|
||||
//PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus);
|
||||
|
||||
// FIXME if we ever have "accurate" bus emulation
|
||||
V <<= (A & 3) * 8;
|
||||
|
||||
DMA_Update(timestamp);
|
||||
|
||||
if(ch == 7)
|
||||
{
|
||||
switch(A & 0xC)
|
||||
{
|
||||
case 0x0: //fprintf(stderr, "Global DMA control: 0x%08x\n", V);
|
||||
DMAControl = V;
|
||||
RecalcHalt();
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
DMAIntControl = V & 0x00ff803f;
|
||||
DMAIntStatus &= ~(V >> 24);
|
||||
RecalcIRQOut();
|
||||
break;
|
||||
|
||||
default: PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch(A & 0xC)
|
||||
{
|
||||
case 0x0: DMACH[ch].BaseAddr = V & 0xFFFFFF;
|
||||
break;
|
||||
|
||||
case 0x4: DMACH[ch].BlockControl = V;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0x8:
|
||||
{
|
||||
uint32 OldCC = DMACH[ch].ChanControl;
|
||||
|
||||
//printf("CHCR: %u, %08x --- 0x%08x\n", ch, V, DMACH[ch].BlockControl);
|
||||
//
|
||||
// Kludge for DMA timing granularity and other issues. Needs to occur before setting all bits of ChanControl to the new value, to accommodate the
|
||||
// case of a game cancelling DMA and changing the type of DMA(read/write, etc.) at the same time.
|
||||
//
|
||||
if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24)))
|
||||
{
|
||||
DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most.
|
||||
RunChannel(timestamp, 128 * 16, ch);
|
||||
DMACH[ch].WordCounter = 0;
|
||||
|
||||
#if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes)
|
||||
DMACH[ch].ClockCounter = (1 << 30);
|
||||
RunChannel(timestamp, 1, ch);
|
||||
DMACH[ch].ClockCounter = 0;
|
||||
#endif
|
||||
PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
|
||||
//MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
|
||||
}
|
||||
|
||||
if(ch == 6)
|
||||
DMACH[ch].ChanControl = (V & 0x51000000) | 0x2;
|
||||
else
|
||||
DMACH[ch].ChanControl = V & 0x71770703;
|
||||
|
||||
if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
|
||||
{
|
||||
//if(ch == 0 || ch == 1)
|
||||
// PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum());
|
||||
|
||||
DMACH[ch].WordCounter = 0;
|
||||
DMACH[ch].ClockCounter = 0;
|
||||
|
||||
//
|
||||
// Viewpoint starts a short MEM->GPU LL DMA and apparently has race conditions that can cause a crash if it doesn't finish almost immediately(
|
||||
// or at least very quickly, which the current DMA granularity has issues with, so run the channel ahead a bit to take of this issue and potentially
|
||||
// games with similar issues).
|
||||
//
|
||||
// Though, Viewpoint isn't exactly a good game, so maybe we shouldn't bother? ;)
|
||||
//
|
||||
// Also, it's needed for RecalcHalt() to work with some semblance of workiness.
|
||||
//
|
||||
RunChannel(timestamp, 64, ch); //std::max<int>(128 - DMACycleCounter, 1)); //64); //1); //128 - DMACycleCounter);
|
||||
}
|
||||
|
||||
RecalcHalt();
|
||||
}
|
||||
break;
|
||||
}
|
||||
PSX_SetEventNT(PSX_EVENT_DMA, timestamp + CalcNextEvent(0x10000000));
|
||||
}
|
||||
|
||||
uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
|
||||
{
|
||||
int ch = (A & 0x7F) >> 4;
|
||||
uint32 ret = 0;
|
||||
|
||||
if(ch == 7)
|
||||
{
|
||||
switch(A & 0xC)
|
||||
{
|
||||
default: PSX_WARNING("[DMA] Unknown read: %08x", A);
|
||||
break;
|
||||
|
||||
case 0x0: ret = DMAControl;
|
||||
break;
|
||||
|
||||
case 0x4: ret = DMAIntControl | (DMAIntStatus << 24) | (IRQOut << 31);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else switch(A & 0xC)
|
||||
{
|
||||
case 0x0: ret = DMACH[ch].BaseAddr;
|
||||
break;
|
||||
|
||||
case 0x4: ret = DMACH[ch].BlockControl;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0x8: ret = DMACH[ch].ChanControl;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ret >>= (A & 3) * 8;
|
||||
|
||||
//PSX_WARNING("[DMA] Read: %08x %08x", A, ret);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
|
||||
{
|
||||
int ch = (A & 0x7F) >> 4;
|
||||
|
||||
//if(ch == 2 || ch == 7)
|
||||
//PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus);
|
||||
|
||||
// FIXME if we ever have "accurate" bus emulation
|
||||
V <<= (A & 3) * 8;
|
||||
|
||||
DMA_Update(timestamp);
|
||||
|
||||
if(ch == 7)
|
||||
{
|
||||
switch(A & 0xC)
|
||||
{
|
||||
case 0x0: //fprintf(stderr, "Global DMA control: 0x%08x\n", V);
|
||||
DMAControl = V;
|
||||
RecalcHalt();
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
DMAIntControl = V & 0x00ff803f;
|
||||
DMAIntStatus &= ~(V >> 24);
|
||||
RecalcIRQOut();
|
||||
break;
|
||||
|
||||
default: PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch(A & 0xC)
|
||||
{
|
||||
case 0x0: DMACH[ch].BaseAddr = V & 0xFFFFFF;
|
||||
break;
|
||||
|
||||
case 0x4: DMACH[ch].BlockControl = V;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0x8:
|
||||
{
|
||||
uint32 OldCC = DMACH[ch].ChanControl;
|
||||
|
||||
//printf("CHCR: %u, %08x --- 0x%08x\n", ch, V, DMACH[ch].BlockControl);
|
||||
//
|
||||
// Kludge for DMA timing granularity and other issues. Needs to occur before setting all bits of ChanControl to the new value, to accommodate the
|
||||
// case of a game cancelling DMA and changing the type of DMA(read/write, etc.) at the same time.
|
||||
//
|
||||
if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24)))
|
||||
{
|
||||
DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most.
|
||||
RunChannel(timestamp, 128 * 16, ch);
|
||||
DMACH[ch].WordCounter = 0;
|
||||
|
||||
#if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes)
|
||||
DMACH[ch].ClockCounter = (1 << 30);
|
||||
RunChannel(timestamp, 1, ch);
|
||||
DMACH[ch].ClockCounter = 0;
|
||||
#endif
|
||||
PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
|
||||
//MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
|
||||
}
|
||||
|
||||
if(ch == 6)
|
||||
DMACH[ch].ChanControl = (V & 0x51000000) | 0x2;
|
||||
else
|
||||
DMACH[ch].ChanControl = V & 0x71770703;
|
||||
|
||||
if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
|
||||
{
|
||||
//if(ch == 0 || ch == 1)
|
||||
// PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum());
|
||||
|
||||
DMACH[ch].WordCounter = 0;
|
||||
DMACH[ch].ClockCounter = 0;
|
||||
|
||||
//
|
||||
// Viewpoint starts a short MEM->GPU LL DMA and apparently has race conditions that can cause a crash if it doesn't finish almost immediately(
|
||||
// or at least very quickly, which the current DMA granularity has issues with, so run the channel ahead a bit to take of this issue and potentially
|
||||
// games with similar issues).
|
||||
//
|
||||
// Though, Viewpoint isn't exactly a good game, so maybe we shouldn't bother? ;)
|
||||
//
|
||||
// Also, it's needed for RecalcHalt() to work with some semblance of workiness.
|
||||
//
|
||||
RunChannel(timestamp, 64, ch); //std::max<int>(128 - DMACycleCounter, 1)); //64); //1); //128 - DMACycleCounter);
|
||||
}
|
||||
|
||||
RecalcHalt();
|
||||
}
|
||||
break;
|
||||
}
|
||||
PSX_SetEventNT(PSX_EVENT_DMA, timestamp + CalcNextEvent(0x10000000));
|
||||
}
|
||||
|
||||
uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A)
|
||||
{
|
||||
int ch = (A & 0x7F) >> 4;
|
||||
uint32 ret = 0;
|
||||
|
||||
if(ch == 7)
|
||||
{
|
||||
switch(A & 0xC)
|
||||
{
|
||||
default: PSX_WARNING("[DMA] Unknown read: %08x", A);
|
||||
break;
|
||||
|
||||
case 0x0: ret = DMAControl;
|
||||
break;
|
||||
|
||||
case 0x4: ret = DMAIntControl | (DMAIntStatus << 24) | (IRQOut << 31);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else switch(A & 0xC)
|
||||
{
|
||||
case 0x0: ret = DMACH[ch].BaseAddr;
|
||||
break;
|
||||
|
||||
case 0x4: ret = DMACH[ch].BlockControl;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0x8: ret = DMACH[ch].ChanControl;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
ret >>= (A & 3) * 8;
|
||||
|
||||
//PSX_WARNING("[DMA] Read: %08x %08x", A, ret);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
void DMA_SyncState(bool isReader, EW::NewState *ns)
|
||||
|
|
|
@ -4,18 +4,16 @@
|
|||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
||||
bool DMA_GPUWriteActive(void);
|
||||
|
||||
pscpu_timestamp_t DMA_Update(const pscpu_timestamp_t timestamp);
|
||||
void DMA_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
|
||||
uint32 DMA_Read(const pscpu_timestamp_t timestamp, uint32 A);
|
||||
|
||||
void DMA_ResetTS(void);
|
||||
|
||||
void DMA_Power(void) MDFN_COLD;
|
||||
|
||||
void DMA_Init(void) MDFN_COLD;
|
||||
void DMA_Kill(void) MDFN_COLD;
|
||||
void DMA_Power(void) MDFN_COLD;
|
||||
|
||||
void DMA_Init(void) MDFN_COLD;
|
||||
void DMA_Kill(void) MDFN_COLD;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "psx.h"
|
||||
#include "frontio.h"
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "cdrom/SimpleFIFO.h"
|
||||
#include "FastFIFO.h"
|
||||
#include "git.h"
|
||||
|
||||
struct ShockRenderOptions;
|
||||
|
@ -72,7 +72,7 @@ class PS_GPU
|
|||
if(InCmd & (INCMD_FBREAD | INCMD_FBWRITE))
|
||||
return(false);
|
||||
|
||||
if(BlitterFIFO.CanRead() >= Commands[BlitterFIFO.ReadUnit(true) >> 24].fifo_fb_len)
|
||||
if(BlitterFIFO.CanRead() >= Commands[BlitterFIFO.Peek() >> 24].fifo_fb_len)
|
||||
return(false);
|
||||
|
||||
return(true);
|
||||
|
@ -155,18 +155,21 @@ class PS_GPU
|
|||
|
||||
int32 OffsX;
|
||||
int32 OffsY;
|
||||
|
||||
bool dtd;
|
||||
bool dfe;
|
||||
|
||||
uint32 MaskSetOR;
|
||||
uint32 MaskEvalAND;
|
||||
|
||||
uint8 tww, twh, twx, twy;
|
||||
|
||||
int32 TexPageX;
|
||||
int32 TexPageY;
|
||||
|
||||
|
||||
bool dtd;
|
||||
bool dfe;
|
||||
|
||||
uint32 MaskSetOR;
|
||||
uint32 MaskEvalAND;
|
||||
|
||||
bool TexDisable;
|
||||
bool TexDisableAllowChange;
|
||||
|
||||
uint8 tww, twh, twx, twy;
|
||||
|
||||
uint32 TexPageX;
|
||||
uint32 TexPageY;
|
||||
|
||||
uint32 SpriteFlip;
|
||||
|
||||
uint32 abr;
|
||||
|
@ -230,9 +233,9 @@ class PS_GPU
|
|||
static const CTEntry Commands_60_7F[0x20];
|
||||
static const CTEntry Commands_80_FF[0x80];
|
||||
|
||||
SimpleFIFO<uint32> BlitterFIFO;
|
||||
|
||||
uint32 DataReadBuffer;
|
||||
FastFIFO<uint32, 0x20> BlitterFIFO; // 0x10 on actual PS1 GPU, 0x20 here(see comment at top of gpu.h)
|
||||
uint32 DataReadBuffer;
|
||||
uint32 DataReadBufferEx;
|
||||
|
||||
bool IRQPending;
|
||||
//
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "psx.h"
|
||||
#include "gpu.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
@ -24,8 +25,8 @@ namespace MDFN_IEN_PSX
|
|||
|
||||
struct line_fxp_coord
|
||||
{
|
||||
int64 x, y;
|
||||
int32 r, g, b;
|
||||
uint64 x, y;
|
||||
uint32 r, g, b;
|
||||
};
|
||||
|
||||
struct line_fxp_step
|
||||
|
@ -40,8 +41,8 @@ enum { Line_RGB_FractBits = 12 };
|
|||
template<bool goraud>
|
||||
static INLINE void LinePointToFXPCoord(const line_point &point, const line_fxp_step &step, line_fxp_coord &coord)
|
||||
{
|
||||
coord.x = ((int64)point.x << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1));
|
||||
coord.y = ((int64)point.y << Line_XY_FractBits) | (1LL << (Line_XY_FractBits - 1));
|
||||
coord.x = ((uint64)point.x << Line_XY_FractBits) | (1ULL << (Line_XY_FractBits - 1));
|
||||
coord.y = ((uint64)point.y << Line_XY_FractBits) | (1ULL << (Line_XY_FractBits - 1));
|
||||
|
||||
coord.x -= 1024;
|
||||
|
||||
|
@ -56,10 +57,9 @@ static INLINE void LinePointToFXPCoord(const line_point &point, const line_fxp_s
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T, unsigned bits>
|
||||
static INLINE T LineDivide(T delta, int32 dk)
|
||||
static INLINE int64 LineDivide(int64 delta, int32 dk)
|
||||
{
|
||||
delta <<= bits;
|
||||
delta = (uint64)delta << Line_XY_FractBits;
|
||||
|
||||
if(delta < 0)
|
||||
delta -= dk - 1;
|
||||
|
@ -86,28 +86,28 @@ static INLINE void LinePointsToFXPStep(const line_point &point0, const line_poin
|
|||
return;
|
||||
}
|
||||
|
||||
step.dx_dk = LineDivide<int64, Line_XY_FractBits>(point1.x - point0.x, dk);
|
||||
step.dy_dk = LineDivide<int64, Line_XY_FractBits>(point1.y - point0.y, dk);
|
||||
step.dx_dk = LineDivide(point1.x - point0.x, dk);
|
||||
step.dy_dk = LineDivide(point1.y - point0.y, dk);
|
||||
|
||||
if(goraud)
|
||||
{
|
||||
step.dr_dk = ((point1.r - point0.r) << Line_RGB_FractBits) / dk;
|
||||
step.dg_dk = ((point1.g - point0.g) << Line_RGB_FractBits) / dk;
|
||||
step.db_dk = ((point1.b - point0.b) << Line_RGB_FractBits) / dk;
|
||||
step.dr_dk = (int32)((uint32)(point1.r - point0.r) << Line_RGB_FractBits) / dk;
|
||||
step.dg_dk = (int32)((uint32)(point1.g - point0.g) << Line_RGB_FractBits) / dk;
|
||||
step.db_dk = (int32)((uint32)(point1.b - point0.b) << Line_RGB_FractBits) / dk;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool goraud>
|
||||
static INLINE void AddLineStep(line_fxp_coord &point, const line_fxp_step &step, int32 count = 1)
|
||||
static INLINE void AddLineStep(line_fxp_coord &point, const line_fxp_step &step)
|
||||
{
|
||||
point.x += step.dx_dk * count;
|
||||
point.y += step.dy_dk * count;
|
||||
point.x += step.dx_dk;
|
||||
point.y += step.dy_dk;
|
||||
|
||||
if(goraud)
|
||||
{
|
||||
point.r += step.dr_dk * count;
|
||||
point.g += step.dg_dk * count;
|
||||
point.b += step.db_dk * count;
|
||||
point.r += step.dr_dk;
|
||||
point.g += step.dg_dk;
|
||||
point.b += step.db_dk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,19 +125,12 @@ void PS_GPU::DrawLine(line_point *points)
|
|||
k = (i_dx > i_dy) ? i_dx : i_dy;
|
||||
|
||||
if(i_dx >= 1024)
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "[GPU] Line too long: i_dx=%d\n", i_dx);
|
||||
return;
|
||||
}
|
||||
|
||||
if(i_dy >= 512)
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "[GPU] Line too long: i_dy=%d\n", i_dy);
|
||||
return;
|
||||
}
|
||||
|
||||
// May not be correct(do tests for the case of k == i_dy on real thing.
|
||||
if(points[0].x > points[1].x)
|
||||
if(points[0].x >= points[1].x && k)
|
||||
{
|
||||
line_point tmp = points[1];
|
||||
|
||||
|
@ -145,7 +138,7 @@ void PS_GPU::DrawLine(line_point *points)
|
|||
points[0] = tmp;
|
||||
}
|
||||
|
||||
DrawTimeAvail -= k * ((BlendMode >= 0) ? 2 : 1);
|
||||
DrawTimeAvail -= k * 2;
|
||||
|
||||
//
|
||||
//
|
||||
|
@ -181,7 +174,7 @@ void PS_GPU::DrawLine(line_point *points)
|
|||
b = points[0].b;
|
||||
}
|
||||
|
||||
if(goraud && dtd)
|
||||
if(dtd)
|
||||
{
|
||||
pix |= DitherLUT[y & 3][x & 3][r] << 0;
|
||||
pix |= DitherLUT[y & 3][x & 3][g] << 5;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "psx.h"
|
||||
#include "gpu.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
@ -406,7 +407,7 @@ INLINE void PS_GPU::DrawTriangle(tri_vertex *vertices)
|
|||
tp->x_step[right_facing] = bound_coord_us;
|
||||
tp->x_coord[!right_facing] = base_coord + ((vertices[vo].y - vertices[0].y) * base_step);
|
||||
tp->x_step[!right_facing] = base_step;
|
||||
tp->dec_mode = !!vo;
|
||||
tp->dec_mode = vo;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -418,7 +419,7 @@ INLINE void PS_GPU::DrawTriangle(tri_vertex *vertices)
|
|||
tp->x_step[right_facing] = bound_coord_ls;
|
||||
tp->x_coord[!right_facing] = base_coord + ((vertices[1 ^ vp].y - vertices[0].y) * base_step); //base_coord + ((vertices[1].y - vertices[0].y) * base_step);
|
||||
tp->x_step[!right_facing] = base_step;
|
||||
tp->dec_mode = !!vp;
|
||||
tp->dec_mode = vp;
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < 2; i++) //2; i++)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "psx.h"
|
||||
#include "gpu.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
namespace MDFN_IEN_PSX
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
// I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however)
|
||||
|
||||
#include <assert.h>
|
||||
#include "../psx.h"
|
||||
#include "../frontio.h"
|
||||
#include "memcard.h"
|
||||
|
@ -309,220 +310,215 @@ bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
|
|||
}
|
||||
|
||||
|
||||
switch(command_phase)
|
||||
{
|
||||
case 0:
|
||||
if(receive_buffer != 0x81)
|
||||
command_phase = -1;
|
||||
else
|
||||
{
|
||||
//printf("[MCR] Device selected\n");
|
||||
transmit_buffer = presence_new ? 0x08 : 0x00;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
command = receive_buffer;
|
||||
//printf("[MCR] Command received: %c\n", command);
|
||||
if(command == 'R' || command == 'W')
|
||||
{
|
||||
command_phase++;
|
||||
transmit_buffer = 0x5A;
|
||||
transmit_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(command == 'S')
|
||||
{
|
||||
PSX_WARNING("[MCR] Memcard S command unsupported.");
|
||||
}
|
||||
|
||||
command_phase = -1;
|
||||
transmit_buffer = 0;
|
||||
transmit_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
transmit_buffer = 0x5D;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
transmit_buffer = 0x00;
|
||||
transmit_count = 1;
|
||||
if(command == 'R')
|
||||
command_phase = 1000;
|
||||
else if(command == 'W')
|
||||
command_phase = 2000;
|
||||
break;
|
||||
|
||||
//
|
||||
// Read
|
||||
//
|
||||
case 1000:
|
||||
addr = receive_buffer << 8;
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case 1001:
|
||||
addr |= receive_buffer & 0xFF;
|
||||
transmit_buffer = '\\';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case 1002:
|
||||
//printf("[MCR] READ ADDR=0x%04x\n", addr);
|
||||
if(addr >= (sizeof(card_data) >> 7))
|
||||
addr = 0xFFFF;
|
||||
|
||||
calced_xor = 0;
|
||||
transmit_buffer = ']';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
|
||||
// TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
|
||||
//
|
||||
//dsr_pulse_delay = 32000;
|
||||
//goto SkipDPD;
|
||||
//
|
||||
|
||||
break;
|
||||
|
||||
case 1003:
|
||||
transmit_buffer = addr >> 8;
|
||||
calced_xor ^= transmit_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case 1004:
|
||||
transmit_buffer = addr & 0xFF;
|
||||
calced_xor ^= transmit_buffer;
|
||||
|
||||
if(addr == 0xFFFF)
|
||||
{
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
transmit_count = 1;
|
||||
command_phase = 1024;
|
||||
}
|
||||
break;
|
||||
|
||||
// Transmit actual 128 bytes data
|
||||
//case (1024 + 0) ... (1024 + 128 - 1):
|
||||
BIGCASE128(1024)
|
||||
transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)];
|
||||
calced_xor ^= transmit_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
// XOR
|
||||
case (1024 + 128):
|
||||
transmit_buffer = calced_xor;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
// End flag
|
||||
case (1024 + 129):
|
||||
transmit_buffer = 'G';
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
break;
|
||||
|
||||
//
|
||||
// Write
|
||||
//
|
||||
case 2000:
|
||||
calced_xor = receive_buffer;
|
||||
addr = receive_buffer << 8;
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case 2001:
|
||||
calced_xor ^= receive_buffer;
|
||||
addr |= receive_buffer & 0xFF;
|
||||
//printf("[MCR] WRITE ADDR=0x%04x\n", addr);
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase = 2048;
|
||||
break;
|
||||
|
||||
//case (2048 + 0) ... (2048 + 128 - 1):
|
||||
BIGCASE128(2048)
|
||||
calced_xor ^= receive_buffer;
|
||||
rw_buffer[command_phase - 2048] = receive_buffer;
|
||||
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case (2048 + 128): // XOR
|
||||
write_xor = receive_buffer;
|
||||
transmit_buffer = '\\';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case (2048 + 129):
|
||||
transmit_buffer = ']';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
break;
|
||||
|
||||
case (2048 + 130): // End flag
|
||||
//MDFN_DispMessage("%02x %02x", calced_xor, write_xor);
|
||||
//printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
|
||||
|
||||
if(calced_xor != write_xor)
|
||||
transmit_buffer = 'N';
|
||||
else if(addr >= (sizeof(card_data) >> 7))
|
||||
transmit_buffer = 0xFF;
|
||||
else
|
||||
{
|
||||
transmit_buffer = 'G';
|
||||
presence_new = false;
|
||||
|
||||
// If the current data is different from the data to be written, increment the dirty count.
|
||||
// memcpy()'ing over to card_data is also conditionalized here for a slight optimization.
|
||||
if(memcmp(&card_data[addr << 7], rw_buffer, 128))
|
||||
{
|
||||
memcpy(&card_data[addr << 7], rw_buffer, 128);
|
||||
dirty_count++;
|
||||
data_used = true;
|
||||
}
|
||||
}
|
||||
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//if(command_phase != -1 || transmit_count)
|
||||
// printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase);
|
||||
}
|
||||
|
||||
if(!bitpos && transmit_count)
|
||||
dsr_pulse_delay = 0x100;
|
||||
|
||||
//SkipDPD: ;
|
||||
|
||||
return(ret);
|
||||
|
||||
if(command_phase == 0)
|
||||
{
|
||||
if(receive_buffer != 0x81)
|
||||
command_phase = -1;
|
||||
else
|
||||
{
|
||||
//printf("[MCR] Device selected\n");
|
||||
transmit_buffer = presence_new ? 0x08 : 0x00;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
}
|
||||
else if(command_phase == 1)
|
||||
{
|
||||
command = receive_buffer;
|
||||
//printf("[MCR] Command received: %c\n", command);
|
||||
if(command == 'R' || command == 'W')
|
||||
{
|
||||
command_phase++;
|
||||
transmit_buffer = 0x5A;
|
||||
transmit_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(command == 'S')
|
||||
{
|
||||
PSX_WARNING("[MCR] Memcard S command unsupported.");
|
||||
}
|
||||
|
||||
command_phase = -1;
|
||||
transmit_buffer = 0;
|
||||
transmit_count = 0;
|
||||
}
|
||||
}
|
||||
else if(command_phase == 2)
|
||||
{
|
||||
transmit_buffer = 0x5D;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == 3)
|
||||
{
|
||||
transmit_buffer = 0x00;
|
||||
transmit_count = 1;
|
||||
if(command == 'R')
|
||||
command_phase = 1000;
|
||||
else if(command == 'W')
|
||||
command_phase = 2000;
|
||||
}
|
||||
//
|
||||
// Read
|
||||
//
|
||||
else if(command_phase == 1000)
|
||||
{
|
||||
addr = receive_buffer << 8;
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == 1001)
|
||||
{
|
||||
addr |= receive_buffer & 0xFF;
|
||||
transmit_buffer = '\\';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == 1002)
|
||||
{
|
||||
//printf("[MCR] READ ADDR=0x%04x\n", addr);
|
||||
if(addr >= (sizeof(card_data) >> 7))
|
||||
addr = 0xFFFF;
|
||||
|
||||
calced_xor = 0;
|
||||
transmit_buffer = ']';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
|
||||
// TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
|
||||
//
|
||||
//dsr_pulse_delay = 32000;
|
||||
//goto SkipDPD;
|
||||
//
|
||||
}
|
||||
else if(command_phase == 1003)
|
||||
{
|
||||
transmit_buffer = addr >> 8;
|
||||
calced_xor ^= transmit_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == 1004)
|
||||
{
|
||||
transmit_buffer = addr & 0xFF;
|
||||
calced_xor ^= transmit_buffer;
|
||||
|
||||
if(addr == 0xFFFF)
|
||||
{
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
transmit_count = 1;
|
||||
command_phase = 1024;
|
||||
}
|
||||
}
|
||||
// Transmit actual 128 bytes data
|
||||
else if(command_phase >= (1024 + 0) && command_phase <= (1024 + 128 - 1))
|
||||
{
|
||||
transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)];
|
||||
calced_xor ^= transmit_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
// XOR
|
||||
else if(command_phase == (1024 + 128))
|
||||
{
|
||||
transmit_buffer = calced_xor;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
// End flag
|
||||
else if(command_phase == (1024 + 129))
|
||||
{
|
||||
transmit_buffer = 'G';
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
}
|
||||
//
|
||||
// Write
|
||||
//
|
||||
else if(command_phase == 2000)
|
||||
{
|
||||
calced_xor = receive_buffer;
|
||||
addr = receive_buffer << 8;
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == 2001)
|
||||
{
|
||||
calced_xor ^= receive_buffer;
|
||||
addr |= receive_buffer & 0xFF;
|
||||
//printf("[MCR] WRITE ADDR=0x%04x\n", addr);
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase = 2048;
|
||||
}
|
||||
else if(command_phase >= (2048 + 0) && command_phase <= (2048 + 128 - 1))
|
||||
{
|
||||
calced_xor ^= receive_buffer;
|
||||
rw_buffer[command_phase - 2048] = receive_buffer;
|
||||
|
||||
transmit_buffer = receive_buffer;
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == (2048 + 128)) // XOR
|
||||
{
|
||||
write_xor = receive_buffer;
|
||||
transmit_buffer = '\\';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == (2048 + 129))
|
||||
{
|
||||
transmit_buffer = ']';
|
||||
transmit_count = 1;
|
||||
command_phase++;
|
||||
}
|
||||
else if(command_phase == (2048 + 130)) // End flag
|
||||
{
|
||||
//MDFN_DispMessage("%02x %02x", calced_xor, write_xor);
|
||||
//printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
|
||||
|
||||
if(calced_xor != write_xor)
|
||||
transmit_buffer = 'N';
|
||||
else if(addr >= (sizeof(card_data) >> 7))
|
||||
transmit_buffer = 0xFF;
|
||||
else
|
||||
{
|
||||
transmit_buffer = 'G';
|
||||
presence_new = false;
|
||||
|
||||
// If the current data is different from the data to be written, increment the dirty count.
|
||||
// memcpy()'ing over to card_data is also conditionalized here for a slight optimization.
|
||||
if(memcmp(&card_data[addr << 7], rw_buffer, 128))
|
||||
{
|
||||
memcpy(&card_data[addr << 7], rw_buffer, 128);
|
||||
dirty_count++;
|
||||
data_used = true;
|
||||
}
|
||||
}
|
||||
|
||||
transmit_count = 1;
|
||||
command_phase = -1;
|
||||
}
|
||||
|
||||
//if(command_phase != -1 || transmit_count)
|
||||
// printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase);
|
||||
}
|
||||
|
||||
if(!bitpos && transmit_count)
|
||||
dsr_pulse_delay = 0x100;
|
||||
|
||||
//SkipDPD: ;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
uint32 InputDevice_Memcard::GetNVSize(void)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "../psx.h"
|
||||
#include "../frontio.h"
|
||||
#include "multitap.h"
|
||||
|
@ -128,11 +129,12 @@ void InputDevice_Multitap::Power(void)
|
|||
full_mode = false;
|
||||
full_mode_setting = false;
|
||||
|
||||
prev_fm_success = false;
|
||||
memset(sb, 0, sizeof(sb));
|
||||
|
||||
fm_dp = 0;
|
||||
memset(fm_buffer, 0, sizeof(fm_buffer));
|
||||
fm_deferred_error_temp = false;
|
||||
fm_deferred_error = false;
|
||||
fm_command_error = false;
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -241,40 +243,50 @@ pscpu_timestamp_t InputDevice_Multitap::GPULineHook(const pscpu_timestamp_t line
|
|||
return(ret);
|
||||
}
|
||||
|
||||
void InputDevice_Multitap::SetDTR(bool new_dtr)
|
||||
{
|
||||
bool old_dtr = dtr;
|
||||
dtr = new_dtr;
|
||||
|
||||
if(!dtr)
|
||||
{
|
||||
if(old_dtr)
|
||||
{
|
||||
//printf("Multitap stop.\n");
|
||||
}
|
||||
|
||||
bit_counter = 0;
|
||||
receive_buffer = 0;
|
||||
selected_device = -1;
|
||||
mc_mode = false;
|
||||
full_mode = false;
|
||||
}
|
||||
|
||||
if(!old_dtr && dtr)
|
||||
{
|
||||
full_mode = full_mode_setting;
|
||||
|
||||
byte_counter = 0;
|
||||
|
||||
//if(full_mode)
|
||||
// printf("Multitap start: %d\n", full_mode);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
pad_devices[i]->SetDTR(dtr);
|
||||
mc_devices[i]->SetDTR(dtr);
|
||||
}
|
||||
|
||||
void InputDevice_Multitap::SetDTR(bool new_dtr)
|
||||
{
|
||||
bool old_dtr = dtr;
|
||||
dtr = new_dtr;
|
||||
|
||||
if(!dtr)
|
||||
{
|
||||
if(old_dtr)
|
||||
{
|
||||
//printf("Multitap stop.\n");
|
||||
}
|
||||
|
||||
bit_counter = 0;
|
||||
receive_buffer = 0;
|
||||
selected_device = -1;
|
||||
mc_mode = false;
|
||||
full_mode = false;
|
||||
}
|
||||
|
||||
if(!old_dtr && dtr)
|
||||
{
|
||||
full_mode = full_mode_setting;
|
||||
|
||||
if(!prev_fm_success)
|
||||
{
|
||||
memset(sb, 0, sizeof(sb));
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
sb[i][0] = 0x42;
|
||||
}
|
||||
|
||||
prev_fm_success = false;
|
||||
|
||||
byte_counter = 0;
|
||||
|
||||
//if(full_mode)
|
||||
// printf("Multitap start: %d\n", full_mode);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
pad_devices[i]->SetDTR(dtr);
|
||||
mc_devices[i]->SetDTR(dtr);
|
||||
}
|
||||
}
|
||||
|
||||
bool InputDevice_Multitap::GetDSR(void)
|
||||
|
@ -282,213 +294,209 @@ bool InputDevice_Multitap::GetDSR(void)
|
|||
return(0);
|
||||
}
|
||||
|
||||
bool InputDevice_Multitap::Clock(bool TxD, int32 &dsr_pulse_delay)
|
||||
{
|
||||
if(!dtr)
|
||||
return(1);
|
||||
|
||||
bool ret = 1;
|
||||
int32 tmp_pulse_delay[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
|
||||
|
||||
//printf("Receive bit: %d\n", TxD);
|
||||
//printf("TxD %d\n", TxD);
|
||||
|
||||
receive_buffer &= ~ (1 << bit_counter);
|
||||
receive_buffer |= TxD << bit_counter;
|
||||
|
||||
if(1)
|
||||
{
|
||||
if(byte_counter == 0)
|
||||
{
|
||||
bool mangled_txd = TxD;
|
||||
|
||||
if(bit_counter < 4)
|
||||
mangled_txd = (0x01 >> bit_counter) & 1;
|
||||
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]);
|
||||
mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter == 1)
|
||||
{
|
||||
ret = (0x80 >> bit_counter) & 1;
|
||||
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
fm_buffer[i][0] &= (pad_devices[i]->Clock(TxD, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
|
||||
}
|
||||
}
|
||||
else if(byte_counter == 2)
|
||||
{
|
||||
ret = (0x5A >> bit_counter) & 1;
|
||||
}
|
||||
// || byte_counter == (0x03 + 0x08 * 1) || byte_counter == (0x03 + 0x08 * 2) || byte_counter == (0x03 + 0x08 * 3))
|
||||
else if(byte_counter >= 0x03 && byte_counter < 0x03 + 0x08 * 4)
|
||||
{
|
||||
if(!fm_command_error && byte_counter >= (0x03 + 1) && byte_counter < (0x03 + 0x08))
|
||||
{
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
fm_buffer[i][byte_counter - 0x03] &= (pad_devices[i]->Clock(0, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
|
||||
}
|
||||
}
|
||||
ret &= ((&fm_buffer[0][0])[byte_counter - 0x03] >> bit_counter) & 1;
|
||||
}
|
||||
}
|
||||
else // to if(full_mode)
|
||||
{
|
||||
if((unsigned)selected_device < 4)
|
||||
{
|
||||
ret &= pad_devices[selected_device]->Clock(TxD, tmp_pulse_delay[0][selected_device]);
|
||||
ret &= mc_devices[selected_device]->Clock(TxD, tmp_pulse_delay[1][selected_device]);
|
||||
}
|
||||
}
|
||||
} // end else to if(byte_counter == 0)
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
bit_counter = (bit_counter + 1) & 0x7;
|
||||
if(bit_counter == 0)
|
||||
{
|
||||
//printf("Receive: 0x%02x\n", receive_buffer);
|
||||
if(byte_counter == 0)
|
||||
{
|
||||
mc_mode = (bool)(receive_buffer & 0xF0);
|
||||
if(mc_mode)
|
||||
full_mode = false;
|
||||
|
||||
//printf("Zoomba: 0x%02x\n", receive_buffer);
|
||||
//printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter);
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
memset(fm_buffer, 0xFF, sizeof(fm_buffer));
|
||||
selected_device = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Device select: %02x\n", receive_buffer);
|
||||
fm_deferred_error = false;
|
||||
selected_device = ((receive_buffer & 0xF) - 1) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if(byte_counter == 1)
|
||||
{
|
||||
command = receive_buffer;
|
||||
|
||||
//printf("Multitap sub-command: %02x\n", command);
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
if(command != 0x42)
|
||||
fm_command_error = true;
|
||||
else
|
||||
fm_command_error = fm_deferred_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
fm_command_error = false;
|
||||
}
|
||||
fm_deferred_error = false;
|
||||
}
|
||||
|
||||
if((!mc_mode || full_mode) && byte_counter == 2)
|
||||
{
|
||||
//printf("Full mode setting: %02x\n", receive_buffer);
|
||||
full_mode_setting = receive_buffer & 0x01;
|
||||
}
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter == (3 + 8 * 0) || byte_counter == (3 + 8 * 1) || byte_counter == (3 + 8 * 2) || byte_counter == (3 + 8 * 3))
|
||||
{
|
||||
unsigned index = (byte_counter - 3) >> 3;
|
||||
assert(index < 4);
|
||||
|
||||
if(index == 0)
|
||||
fm_deferred_error_temp = false;
|
||||
|
||||
if((fm_dp & (1U << index)) && receive_buffer != 0x42)
|
||||
{
|
||||
//printf("Multitap command check failed: %u, 0x%02x\n", byte_counter, receive_buffer);
|
||||
fm_deferred_error_temp = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(byte_counter == 33)
|
||||
fm_deferred_error = fm_deferred_error_temp;
|
||||
}
|
||||
|
||||
// Handle DSR stuff
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter == 0) // Next byte: 0x80
|
||||
{
|
||||
dsr_pulse_delay = 1000;
|
||||
|
||||
fm_dp = 0;
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
fm_dp |= (((bool)(tmp_pulse_delay[0][i])) << i);
|
||||
}
|
||||
else if(byte_counter == 1) // Next byte: 0x5A
|
||||
dsr_pulse_delay = 0x40;
|
||||
else if(byte_counter == 2) // Next byte(typically, controller-dependent): 0x41
|
||||
{
|
||||
if(fm_dp)
|
||||
dsr_pulse_delay = 0x40;
|
||||
else
|
||||
dsr_pulse_delay = 0;
|
||||
}
|
||||
else if(byte_counter >= 3 && byte_counter < 34) // Next byte when byte_counter==3 (typically, controller-dependent): 0x5A
|
||||
{
|
||||
if(byte_counter < 10)
|
||||
{
|
||||
int d = 0x40;
|
||||
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
if(tmp_pulse_delay[0][i] > d)
|
||||
d = tmp_pulse_delay[0][i];
|
||||
|
||||
dsr_pulse_delay = d;
|
||||
}
|
||||
else
|
||||
dsr_pulse_delay = 0x20;
|
||||
|
||||
if(byte_counter == 3 && fm_command_error)
|
||||
dsr_pulse_delay = 0;
|
||||
}
|
||||
} // end if(full_mode)
|
||||
else
|
||||
{
|
||||
if((unsigned)selected_device < 4)
|
||||
{
|
||||
dsr_pulse_delay = std::max<int32>(tmp_pulse_delay[0][selected_device], tmp_pulse_delay[1][selected_device]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//printf("Byte Counter Increment\n");
|
||||
if(byte_counter < 255)
|
||||
byte_counter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
}
|
||||
bool InputDevice_Multitap::Clock(bool TxD, int32 &dsr_pulse_delay)
|
||||
{
|
||||
if(!dtr)
|
||||
return(1);
|
||||
|
||||
bool ret = 1;
|
||||
int32 tmp_pulse_delay[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
|
||||
|
||||
//printf("Receive bit: %d\n", TxD);
|
||||
//printf("TxD %d\n", TxD);
|
||||
|
||||
receive_buffer &= ~ (1 << bit_counter);
|
||||
receive_buffer |= TxD << bit_counter;
|
||||
|
||||
if(1)
|
||||
{
|
||||
if(byte_counter == 0)
|
||||
{
|
||||
bool mangled_txd = TxD;
|
||||
|
||||
if(bit_counter < 4)
|
||||
mangled_txd = (0x01 >> bit_counter) & 1;
|
||||
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]);
|
||||
mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter == 1)
|
||||
ret = (0x80 >> bit_counter) & 1;
|
||||
else if(byte_counter == 2)
|
||||
ret = (0x5A >> bit_counter) & 1;
|
||||
else if(byte_counter >= 0x03 && byte_counter < 0x03 + 0x08 * 4)
|
||||
{
|
||||
if(!fm_command_error && byte_counter < (0x03 + 0x08))
|
||||
{
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
fm_buffer[i][byte_counter - 0x03] &= (pad_devices[i]->Clock((sb[i][byte_counter - 0x03] >> bit_counter) & 1, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
|
||||
}
|
||||
}
|
||||
ret &= ((&fm_buffer[0][0])[byte_counter - 0x03] >> bit_counter) & 1;
|
||||
}
|
||||
}
|
||||
else // to if(full_mode)
|
||||
{
|
||||
if((unsigned)selected_device < 4)
|
||||
{
|
||||
ret &= pad_devices[selected_device]->Clock(TxD, tmp_pulse_delay[0][selected_device]);
|
||||
ret &= mc_devices[selected_device]->Clock(TxD, tmp_pulse_delay[1][selected_device]);
|
||||
}
|
||||
}
|
||||
} // end else to if(byte_counter == 0)
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
bit_counter = (bit_counter + 1) & 0x7;
|
||||
if(bit_counter == 0)
|
||||
{
|
||||
//printf("MT Receive: 0x%02x\n", receive_buffer);
|
||||
if(byte_counter == 0)
|
||||
{
|
||||
mc_mode = (bool)(receive_buffer & 0xF0);
|
||||
if(mc_mode)
|
||||
full_mode = false;
|
||||
|
||||
//printf("Zoomba: 0x%02x\n", receive_buffer);
|
||||
//printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter);
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
memset(fm_buffer, 0xFF, sizeof(fm_buffer));
|
||||
selected_device = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Device select: %02x\n", receive_buffer);
|
||||
selected_device = ((receive_buffer & 0xF) - 1) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if(byte_counter == 1)
|
||||
{
|
||||
command = receive_buffer;
|
||||
|
||||
//printf("Multitap sub-command: %02x\n", command);
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
if(command != 0x42)
|
||||
fm_command_error = true;
|
||||
else
|
||||
fm_command_error = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fm_command_error = false;
|
||||
}
|
||||
}
|
||||
|
||||
if((!mc_mode || full_mode) && byte_counter == 2)
|
||||
{
|
||||
//printf("Full mode setting: %02x\n", receive_buffer);
|
||||
full_mode_setting = receive_buffer & 0x01;
|
||||
}
|
||||
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter >= 3 + 8 * 0 && byte_counter < (3 + 8 * 4))
|
||||
{
|
||||
const unsigned adjbi = byte_counter - 3;
|
||||
|
||||
sb[adjbi >> 3][adjbi & 0x7] = receive_buffer;
|
||||
}
|
||||
|
||||
if(byte_counter == 33)
|
||||
prev_fm_success = true;
|
||||
}
|
||||
|
||||
// Handle DSR stuff
|
||||
if(full_mode)
|
||||
{
|
||||
if(byte_counter == 0) // Next byte: 0x80
|
||||
{
|
||||
dsr_pulse_delay = 1000;
|
||||
|
||||
fm_dp = 0;
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
fm_dp |= (((bool)(tmp_pulse_delay[0][i])) << i);
|
||||
}
|
||||
else if(byte_counter == 1) // Next byte: 0x5A
|
||||
dsr_pulse_delay = 0x40;
|
||||
else if(byte_counter == 2) // Next byte(typically, controller-dependent): 0x41
|
||||
{
|
||||
if(fm_dp)
|
||||
dsr_pulse_delay = 0x40;
|
||||
else
|
||||
{
|
||||
byte_counter = 255;
|
||||
dsr_pulse_delay = 0;
|
||||
}
|
||||
}
|
||||
else if(byte_counter >= 3 && byte_counter < 34) // Next byte when byte_counter==3 (typically, controller-dependent): 0x5A
|
||||
{
|
||||
if(byte_counter < 10)
|
||||
{
|
||||
int d = 0x40;
|
||||
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
int32 tpd = tmp_pulse_delay[0][i];
|
||||
|
||||
if(byte_counter == 3 && (fm_dp & (1U << i)) && tpd == 0)
|
||||
{
|
||||
//printf("SNORG: %u %02x\n", i, sb[i][0]);
|
||||
fm_command_error = true;
|
||||
}
|
||||
|
||||
if(tpd > d)
|
||||
d = tpd;
|
||||
}
|
||||
|
||||
dsr_pulse_delay = d;
|
||||
}
|
||||
else
|
||||
dsr_pulse_delay = 0x20;
|
||||
|
||||
if(byte_counter == 3 && fm_command_error)
|
||||
{
|
||||
byte_counter = 255;
|
||||
dsr_pulse_delay = 0;
|
||||
}
|
||||
}
|
||||
} // end if(full_mode)
|
||||
else
|
||||
{
|
||||
if((unsigned)selected_device < 4)
|
||||
{
|
||||
dsr_pulse_delay = std::max<int32>(tmp_pulse_delay[0][selected_device], tmp_pulse_delay[1][selected_device]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//printf("Byte Counter Increment\n");
|
||||
if(byte_counter < 255)
|
||||
byte_counter++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,10 +39,13 @@ class InputDevice_Multitap final : public InputDevice
|
|||
|
||||
bool full_mode;
|
||||
bool mc_mode;
|
||||
bool prev_fm_success;
|
||||
|
||||
uint8 fm_dp; // Device-present.
|
||||
uint8 fm_buffer[4][8];
|
||||
|
||||
uint8 sb[4][8];
|
||||
|
||||
bool fm_deferred_error_temp;
|
||||
bool fm_deferred_error;
|
||||
bool fm_command_error;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
if(InFIFO.CanWrite())
|
||||
{
|
||||
InFIFO.WriteUnit(V);
|
||||
InFIFO.Write(V);
|
||||
|
||||
if(InCommand)
|
||||
{
|
||||
|
@ -57,9 +57,10 @@
|
|||
|
||||
#include "psx.h"
|
||||
#include "mdec.h"
|
||||
#include "FastFIFO.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
#include "masmem.h"
|
||||
#include "cdrom/SimpleFIFO.h"
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#include <xmmintrin.h>
|
||||
|
@ -79,8 +80,8 @@ namespace MDFN_IEN_PSX
|
|||
|
||||
static int32 ClockCounter;
|
||||
static unsigned MDRPhase;
|
||||
static SimpleFIFO<uint32> InFIFO(0x20);
|
||||
static SimpleFIFO<uint32> OutFIFO(0x20);
|
||||
static FastFIFO<uint32, 0x20> InFIFO;
|
||||
static FastFIFO<uint32, 0x20> OutFIFO;
|
||||
|
||||
static int8 block_y[8][8];
|
||||
static int8 block_cb[8][8]; // [y >> 1][x >> 1]
|
||||
|
@ -443,10 +444,10 @@ static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
|
|||
int ci = sign_10_to_s16(V & 0x3FF);
|
||||
int tmp;
|
||||
|
||||
if(q != 0)
|
||||
tmp = ((ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
|
||||
else
|
||||
tmp = (ci * 2) << 4;
|
||||
if(q != 0)
|
||||
tmp = (int32)((uint32)(ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
|
||||
else
|
||||
tmp = (uint32)(ci * 2) << 4;
|
||||
|
||||
// Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
|
||||
Coeff[ZigZag[0]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
|
||||
|
@ -476,10 +477,10 @@ static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
|
|||
int ci = sign_10_to_s16(V & 0x3FF);
|
||||
int tmp;
|
||||
|
||||
if(q != 0)
|
||||
tmp = (((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
|
||||
else
|
||||
tmp = (ci * 2) << 4;
|
||||
if(q != 0)
|
||||
tmp = (int32)((uint32)((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
|
||||
else
|
||||
tmp = (uint32)(ci * 2) << 4;
|
||||
|
||||
// Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
|
||||
Coeff[ZigZag[CoeffIndex]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
|
||||
|
@ -504,10 +505,12 @@ static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
|
|||
case 5: IDCT(Coeff, &block_y[0][0]); break;
|
||||
}
|
||||
|
||||
//
|
||||
// Approximate, actual timing seems to be a bit complex.
|
||||
//
|
||||
*eat_cycles += 341;
|
||||
//
|
||||
// Timing in the actual PS1 MDEC is complex due to (apparent) pipelining, but the average when decoding a large number of blocks is
|
||||
// about 512. We'll go with a lower value here to be conservative due to timing granularity and other timing deficiencies in Mednafen. BUT, don't
|
||||
// go lower than 460, or Parasite Eve 2's 3D models will stutter like crazy during FMV-background sequences.
|
||||
//
|
||||
*eat_cycles += 474;
|
||||
|
||||
if(DecodeWB >= 2)
|
||||
{
|
||||
|
@ -529,8 +532,8 @@ static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
|
|||
//
|
||||
#define MDEC_WAIT_COND(n) { case __COUNTER__: if(!(n)) { MDRPhase = __COUNTER__ - MDRPhaseBias - 1; return; } }
|
||||
|
||||
#define MDEC_WRITE_FIFO(n) { MDEC_WAIT_COND(OutFIFO.CanWrite()); OutFIFO.WriteUnit(n); }
|
||||
#define MDEC_READ_FIFO(n) { MDEC_WAIT_COND(InFIFO.CanRead()); n = InFIFO.ReadUnit(); }
|
||||
#define MDEC_WRITE_FIFO(n) { MDEC_WAIT_COND(OutFIFO.CanWrite()); OutFIFO.Write(n); }
|
||||
#define MDEC_READ_FIFO(n) { MDEC_WAIT_COND(InFIFO.CanRead()); n = InFIFO.Read(); }
|
||||
#define MDEC_EAT_CLOCKS(n) { ClockCounter -= (n); MDEC_WAIT_COND(ClockCounter > 0); }
|
||||
|
||||
void MDEC_Run(int32 clocks)
|
||||
|
@ -671,50 +674,52 @@ void MDEC_Run(int32 clocks)
|
|||
}
|
||||
#endif
|
||||
|
||||
void MDEC_DMAWrite(uint32 V)
|
||||
{
|
||||
if(InFIFO.CanWrite())
|
||||
{
|
||||
InFIFO.WriteUnit(V);
|
||||
MDEC_Run(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "Input FIFO DMA write overflow?!\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint32 MDEC_DMARead(int32* offs)
|
||||
{
|
||||
uint32 V = 0;
|
||||
|
||||
*offs = 0;
|
||||
|
||||
if(MDFN_LIKELY(OutFIFO.CanRead()))
|
||||
{
|
||||
V = OutFIFO.ReadUnit();
|
||||
|
||||
*offs = (RAMOffsetY & 0x7) * RAMOffsetWWS;
|
||||
|
||||
if(RAMOffsetY & 0x08)
|
||||
{
|
||||
*offs = (*offs - RAMOffsetWWS*7);
|
||||
}
|
||||
|
||||
RAMOffsetCounter--;
|
||||
if(!RAMOffsetCounter)
|
||||
{
|
||||
RAMOffsetCounter = RAMOffsetWWS;
|
||||
RAMOffsetY++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "[MDEC] BONUS GNOMES\n");
|
||||
V = rand();
|
||||
}
|
||||
|
||||
return(V);
|
||||
|
||||
void MDEC_DMAWrite(uint32 V)
|
||||
{
|
||||
if(InFIFO.CanWrite())
|
||||
{
|
||||
InFIFO.Write(V);
|
||||
MDEC_Run(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "[MDEC] DMA write when input FIFO is full!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
uint32 MDEC_DMARead(uint32* offs)
|
||||
{
|
||||
uint32 V = 0;
|
||||
|
||||
*offs = 0;
|
||||
|
||||
if(MDFN_LIKELY(OutFIFO.CanRead()))
|
||||
{
|
||||
V = OutFIFO.Read();
|
||||
|
||||
*offs = (RAMOffsetY & 0x7) * RAMOffsetWWS;
|
||||
|
||||
if(RAMOffsetY & 0x08)
|
||||
{
|
||||
*offs = (*offs - RAMOffsetWWS*7);
|
||||
}
|
||||
|
||||
RAMOffsetCounter--;
|
||||
if(!RAMOffsetCounter)
|
||||
{
|
||||
RAMOffsetCounter = RAMOffsetWWS;
|
||||
RAMOffsetY++;
|
||||
}
|
||||
|
||||
MDEC_Run(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PSX_DBG(PSX_DBG_WARNING, "[MDEC] DMA read when output FIFO is empty!\n");
|
||||
}
|
||||
|
||||
return(V);
|
||||
}
|
||||
|
||||
bool MDEC_DMACanWrite(void)
|
||||
|
@ -759,7 +764,7 @@ void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V)
|
|||
{
|
||||
if(InFIFO.CanWrite())
|
||||
{
|
||||
InFIFO.WriteUnit(V);
|
||||
InFIFO.Write(V);
|
||||
|
||||
if(!InCommand)
|
||||
{
|
||||
|
@ -799,7 +804,7 @@ uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A)
|
|||
else
|
||||
{
|
||||
if(OutFIFO.CanRead())
|
||||
ret = OutFIFO.ReadUnit();
|
||||
ret = OutFIFO.Read();
|
||||
}
|
||||
|
||||
//PSX_WARNING("[MDEC] Read: 0x%08x 0x%08x -- %d %d", A, ret, InputBuffer.CanRead(), InCounter);
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace MDFN_IEN_PSX
|
|||
|
||||
void MDEC_DMAWrite(uint32 V);
|
||||
|
||||
uint32 MDEC_DMARead(int32* offs);
|
||||
uint32 MDEC_DMARead(uint32* offs);
|
||||
|
||||
void MDEC_Write(const pscpu_timestamp_t timestamp, uint32 A, uint32 V);
|
||||
uint32 MDEC_Read(const pscpu_timestamp_t timestamp, uint32 A);
|
||||
|
|
|
@ -47,8 +47,8 @@ namespace MDFN_IEN_PSX
|
|||
{
|
||||
|
||||
|
||||
static unsigned psx_dbg_level = 0;
|
||||
#if PSX_DBGPRINT_ENABLE
|
||||
static unsigned psx_dbg_level = 0;
|
||||
|
||||
void PSX_DBG_BIOS_PUTC(uint8 c) noexcept
|
||||
{
|
||||
|
@ -81,9 +81,10 @@ void PSX_DBG(unsigned level, const char *format, ...) noexcept
|
|||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static unsigned const psx_dbg_level = 0;
|
||||
#endif
|
||||
|
||||
|
||||
struct MDFN_PseudoRNG // Based off(but not the same as) public-domain "JKISS" PRNG.
|
||||
{
|
||||
MDFN_PseudoRNG()
|
||||
|
@ -212,7 +213,16 @@ static struct
|
|||
};
|
||||
} SysControl;
|
||||
|
||||
|
||||
static unsigned DMACycleSteal = 0; // Doesn't need to be saved in save states, since it's recalculated in the ForceEventUpdates() call chain.
|
||||
|
||||
void PSX_SetDMACycleSteal(unsigned stealage)
|
||||
{
|
||||
if(stealage > 200) // Due to 8-bit limitations in the CPU core.
|
||||
stealage = 200;
|
||||
|
||||
DMACycleSteal = stealage;
|
||||
}
|
||||
|
||||
//
|
||||
// Event stuff
|
||||
//
|
||||
|
@ -337,43 +347,12 @@ void ForceEventUpdates(const pscpu_timestamp_t timestamp)
|
|||
bool PSX_EventHandler(const pscpu_timestamp_t timestamp)
|
||||
{
|
||||
event_list_entry *e = events[PSX_EVENT__SYNFIRST].next;
|
||||
#if PSX_EVENT_SYSTEM_CHECKS
|
||||
pscpu_timestamp_t prev_event_time = 0;
|
||||
#endif
|
||||
#if 0
|
||||
{
|
||||
printf("EventHandler - timestamp=%8d\n", timestamp);
|
||||
event_list_entry *moo = &events[PSX_EVENT__SYNFIRST];
|
||||
while(moo)
|
||||
{
|
||||
printf("%u: %8d\n", moo->which, moo->event_time);
|
||||
moo = moo->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PSX_EVENT_SYSTEM_CHECKS
|
||||
assert(Running == 0 || timestamp >= e->event_time); // If Running == 0, our EventHandler
|
||||
#endif
|
||||
|
||||
while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while
|
||||
{
|
||||
event_list_entry *prev = e->prev;
|
||||
pscpu_timestamp_t nt;
|
||||
|
||||
#if PSX_EVENT_SYSTEM_CHECKS
|
||||
// Sanity test to make sure events are being evaluated in temporal order.
|
||||
if(e->event_time < prev_event_time)
|
||||
abort();
|
||||
prev_event_time = e->event_time;
|
||||
#endif
|
||||
|
||||
//printf("Event: %u %8d\n", e->which, e->event_time);
|
||||
#if PSX_EVENT_SYSTEM_CHECKS
|
||||
if((timestamp - e->event_time) > 50)
|
||||
printf("Late: %u %d --- %8d\n", e->which, timestamp - e->event_time, timestamp);
|
||||
#endif
|
||||
|
||||
switch(e->which)
|
||||
{
|
||||
default: abort();
|
||||
|
@ -408,26 +387,6 @@ bool PSX_EventHandler(const pscpu_timestamp_t timestamp)
|
|||
e = prev->next;
|
||||
}
|
||||
|
||||
#if PSX_EVENT_SYSTEM_CHECKS
|
||||
for(int i = PSX_EVENT__SYNFIRST + 1; i < PSX_EVENT__SYNLAST; i++)
|
||||
{
|
||||
if(timestamp >= events[i].event_time)
|
||||
{
|
||||
printf("BUG: %u\n", i);
|
||||
|
||||
event_list_entry *moo = &events[PSX_EVENT__SYNFIRST];
|
||||
|
||||
while(moo)
|
||||
{
|
||||
printf("%u: %8d\n", moo->which, moo->event_time);
|
||||
moo = moo->next;
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return(Running);
|
||||
}
|
||||
|
||||
|
@ -443,14 +402,6 @@ void PSX_RequestMLExit(void)
|
|||
// End event stuff
|
||||
//
|
||||
|
||||
void DMA_CheckReadDebug(uint32 A);
|
||||
|
||||
static unsigned sucksuck = 0;
|
||||
void PSX_SetDMASuckSuck(unsigned suckage)
|
||||
{
|
||||
sucksuck = suckage;
|
||||
}
|
||||
|
||||
|
||||
// Remember to update MemPeek<>() when we change address decoding in MemRW()
|
||||
template<typename T, bool IsWrite, bool Access24> static INLINE void MemRW(pscpu_timestamp_t ×tamp, uint32 A, uint32 &V)
|
||||
|
@ -462,14 +413,10 @@ template<typename T, bool IsWrite, bool Access24> static INLINE void MemRW(pscpu
|
|||
printf("Read%d: %08x(orig=%08x)\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A);
|
||||
#endif
|
||||
|
||||
if(!IsWrite)
|
||||
timestamp += sucksuck;
|
||||
|
||||
//if(A == 0xa0 && IsWrite)
|
||||
// DBG_Break();
|
||||
if(!IsWrite)
|
||||
timestamp += DMACycleSteal;
|
||||
|
||||
if(A < 0x00800000)
|
||||
//if(A <= 0x1FFFFF)
|
||||
{
|
||||
if(IsWrite)
|
||||
{
|
||||
|
@ -480,8 +427,6 @@ template<typename T, bool IsWrite, bool Access24> static INLINE void MemRW(pscpu
|
|||
timestamp += 3;
|
||||
}
|
||||
|
||||
//DMA_CheckReadDebug(A);
|
||||
//assert(A <= 0x1FFFFF);
|
||||
if(Access24)
|
||||
{
|
||||
if(IsWrite)
|
||||
|
@ -797,7 +742,6 @@ void PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
|
|||
|
||||
void PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
|
||||
{
|
||||
//assert(0);
|
||||
MemRW<uint32, true, true>(timestamp, A, V);
|
||||
}
|
||||
|
||||
|
@ -2357,6 +2301,18 @@ Breakout:
|
|||
return SHOCK_OK;
|
||||
}
|
||||
|
||||
bool ShockDiscRef::ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread)
|
||||
{
|
||||
//TODO - whats that hint mean
|
||||
//TODO - should return false if out of range totally
|
||||
//reference: static const int32 LBA_Read_Minimum = -150;
|
||||
//reference: static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1
|
||||
u8 tmp[2448];
|
||||
ReadLBA2448(lba,tmp);
|
||||
memcpy(pwbuf96,tmp+2352,96);
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 ShockDiscRef::ReadLBA2448(s32 lba, void* dst2448)
|
||||
{
|
||||
return InternalReadLBA2448(lba, dst2448, true);
|
||||
|
|
|
@ -89,6 +89,8 @@ namespace MDFN_IEN_PSX
|
|||
#define PSX_EVENT_MAXTS 0x20000000
|
||||
void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp);
|
||||
|
||||
void PSX_SetDMACycleSteal(unsigned stealage);
|
||||
|
||||
void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
|
||||
|
||||
uint32 PSX_GetRandU32(uint32 mina, uint32 maxa);
|
||||
|
@ -237,8 +239,18 @@ public:
|
|||
return mcbReadTOC(mOpaque, read_target, tracks);
|
||||
}
|
||||
|
||||
//formerly ReadRawSector
|
||||
//Reads 2352 + 96
|
||||
s32 ReadLBA2448(s32 lba, void* dst2448);
|
||||
s32 ReadLBA2048(s32 lba, void* dst2048);
|
||||
|
||||
//formerly ReadRawSectorPWOnly
|
||||
//Reads 96 bytes (of raw subchannel PW data) into pwbuf.
|
||||
//Probably the same format as what's at the end of ReadLBA2448
|
||||
//TODO - reorder args
|
||||
bool ReadLBA_PW(uint8* pwbuf96, int32 lba, bool hint_fullread);
|
||||
|
||||
//only used by disc analysis stuff which should be refactored anyway. should eventually be removed
|
||||
s32 ReadLBA2048(s32 lba, void* dst2048);
|
||||
|
||||
private:
|
||||
s32 InternalReadLBA2448(s32 lba, void* dst2448, bool needSubcode);
|
||||
|
|
|
@ -846,6 +846,7 @@ while(sample_clocks > 0)
|
|||
accum[lr] += ((reverb[lr] * ReverbVol[lr]) >> 15);
|
||||
clamp(&accum[lr], -32768, 32767);
|
||||
output[lr] = (accum[lr] * GlobalSweep[lr].ReadVolume()) >> 15;
|
||||
clamp(&output[lr], -32768, 32767);
|
||||
}
|
||||
|
||||
if(IntermediateBufferPos < 4096) // Overflow might occur in some debugger use cases.
|
||||
|
@ -1304,6 +1305,10 @@ uint32 PS_SPU::GetRegister(unsigned int which, char *special, const uint32 speci
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if(which >= GSREG_FB_SRC_A && which <= GSREG_IN_COEF_R)
|
||||
{
|
||||
ret = ReverbRegs[which - GSREG_FB_SRC_A];
|
||||
}
|
||||
else switch(which)
|
||||
{
|
||||
case GSREG_SPUCONTROL:
|
||||
|
@ -1377,43 +1382,6 @@ uint32 PS_SPU::GetRegister(unsigned int which, char *special, const uint32 speci
|
|||
case GSREG_BLOCKEND:
|
||||
ret = BlockEnd;
|
||||
break;
|
||||
|
||||
|
||||
//case GSREG_FB_SRC_A ... GSREG_IN_COEF_R:
|
||||
case GSREG_FB_SRC_A:
|
||||
case GSREG_FB_SRC_B:
|
||||
case GSREG_IIR_ALPHA:
|
||||
case GSREG_ACC_COEF_A:
|
||||
case GSREG_ACC_COEF_B:
|
||||
case GSREG_ACC_COEF_C:
|
||||
case GSREG_ACC_COEF_D:
|
||||
case GSREG_IIR_COEF:
|
||||
case GSREG_FB_ALPHA:
|
||||
case GSREG_FB_X:
|
||||
case GSREG_IIR_DEST_A0:
|
||||
case GSREG_IIR_DEST_A1:
|
||||
case GSREG_ACC_SRC_A0:
|
||||
case GSREG_ACC_SRC_A1:
|
||||
case GSREG_ACC_SRC_B0:
|
||||
case GSREG_ACC_SRC_B1:
|
||||
case GSREG_IIR_SRC_A0:
|
||||
case GSREG_IIR_SRC_A1:
|
||||
case GSREG_IIR_DEST_B0:
|
||||
case GSREG_IIR_DEST_B1:
|
||||
case GSREG_ACC_SRC_C0:
|
||||
case GSREG_ACC_SRC_C1:
|
||||
case GSREG_ACC_SRC_D0:
|
||||
case GSREG_ACC_SRC_D1:
|
||||
case GSREG_IIR_SRC_B1:
|
||||
case GSREG_IIR_SRC_B0:
|
||||
case GSREG_MIX_DEST_A0:
|
||||
case GSREG_MIX_DEST_A1:
|
||||
case GSREG_MIX_DEST_B0:
|
||||
case GSREG_MIX_DEST_B1:
|
||||
case GSREG_IN_COEF_L:
|
||||
case GSREG_IN_COEF_R:
|
||||
ret = ReverbRegs[which - GSREG_FB_SRC_A];
|
||||
break;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
|
@ -1421,8 +1389,11 @@ uint32 PS_SPU::GetRegister(unsigned int which, char *special, const uint32 speci
|
|||
|
||||
void PS_SPU::SetRegister(unsigned int which, uint32 value)
|
||||
{
|
||||
|
||||
switch(which)
|
||||
if(which >= GSREG_FB_SRC_A && which <= GSREG_IN_COEF_R)
|
||||
{
|
||||
ReverbRegs[which - GSREG_FB_SRC_A] = value;
|
||||
}
|
||||
else switch(which)
|
||||
{
|
||||
case GSREG_SPUCONTROL:
|
||||
SPUControl = value;
|
||||
|
@ -1499,44 +1470,6 @@ void PS_SPU::SetRegister(unsigned int which, uint32 value)
|
|||
case GSREG_BLOCKEND:
|
||||
BlockEnd = value & 0xFFFFFF;
|
||||
break;
|
||||
|
||||
|
||||
//case GSREG_FB_SRC_A ... GSREG_IN_COEF_R:
|
||||
case GSREG_FB_SRC_A:
|
||||
case GSREG_FB_SRC_B:
|
||||
case GSREG_IIR_ALPHA:
|
||||
case GSREG_ACC_COEF_A:
|
||||
case GSREG_ACC_COEF_B:
|
||||
case GSREG_ACC_COEF_C:
|
||||
case GSREG_ACC_COEF_D:
|
||||
case GSREG_IIR_COEF:
|
||||
case GSREG_FB_ALPHA:
|
||||
case GSREG_FB_X:
|
||||
case GSREG_IIR_DEST_A0:
|
||||
case GSREG_IIR_DEST_A1:
|
||||
case GSREG_ACC_SRC_A0:
|
||||
case GSREG_ACC_SRC_A1:
|
||||
case GSREG_ACC_SRC_B0:
|
||||
case GSREG_ACC_SRC_B1:
|
||||
case GSREG_IIR_SRC_A0:
|
||||
case GSREG_IIR_SRC_A1:
|
||||
case GSREG_IIR_DEST_B0:
|
||||
case GSREG_IIR_DEST_B1:
|
||||
case GSREG_ACC_SRC_C0:
|
||||
case GSREG_ACC_SRC_C1:
|
||||
case GSREG_ACC_SRC_D0:
|
||||
case GSREG_ACC_SRC_D1:
|
||||
case GSREG_IIR_SRC_B1:
|
||||
case GSREG_IIR_SRC_B0:
|
||||
case GSREG_MIX_DEST_A0:
|
||||
case GSREG_MIX_DEST_A1:
|
||||
case GSREG_MIX_DEST_B0:
|
||||
case GSREG_MIX_DEST_B1:
|
||||
case GSREG_IN_COEF_L:
|
||||
case GSREG_IN_COEF_R:
|
||||
ReverbRegs[which - GSREG_FB_SRC_A] = value;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "psx.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
|
Loading…
Reference in New Issue