diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll
index 5e1ad60a3c..ff4b05eb8c 100644
Binary files a/output/dll/octoshock.dll and b/output/dll/octoshock.dll differ
diff --git a/psx/octoshock/bizhawk/octoshock.vcxproj b/psx/octoshock/bizhawk/octoshock.vcxproj
index 34e123e3ad..e4107108e7 100644
--- a/psx/octoshock/bizhawk/octoshock.vcxproj
+++ b/psx/octoshock/bizhawk/octoshock.vcxproj
@@ -93,11 +93,7 @@
-
-
-
-
diff --git a/psx/octoshock/bizhawk/octoshock.vcxproj.filters b/psx/octoshock/bizhawk/octoshock.vcxproj.filters
index 060c5e61e5..81b017d989 100644
--- a/psx/octoshock/bizhawk/octoshock.vcxproj.filters
+++ b/psx/octoshock/bizhawk/octoshock.vcxproj.filters
@@ -229,21 +229,9 @@
psx
-
- psx
-
psx
-
- psx
-
-
- psx
-
-
- psx
-
psx
diff --git a/psx/octoshock/docs/upstreaminfo.txt b/psx/octoshock/docs/upstreaminfo.txt
index 4701abf64a..4ebc3719ad 100644
--- a/psx/octoshock/docs/upstreaminfo.txt
+++ b/psx/octoshock/docs/upstreaminfo.txt
@@ -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
diff --git a/psx/octoshock/emuware/emuware.h b/psx/octoshock/emuware/emuware.h
index fe96bb65fa..20704c062e 100644
--- a/psx/octoshock/emuware/emuware.h
+++ b/psx/octoshock/emuware/emuware.h
@@ -45,41 +45,6 @@ typedef __uint8_t uint8;
#define final
#define noexcept
-#ifdef _MSC_VER
-#include
-//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
diff --git a/psx/octoshock/math_ops.h b/psx/octoshock/math_ops.h
index 09aa131365..de107b2856 100644
--- a/psx/octoshock/math_ops.h
+++ b/psx/octoshock/math_ops.h
@@ -1,6 +1,125 @@
#pragma once
-#include "emuware/emuware.h"
+#include
+
+//
+// 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 static INLINE void clamp(T *val, U
*val = maximum;
}
}
-
diff --git a/psx/octoshock/psx/FastFIFO.h b/psx/octoshock/psx/FastFIFO.h
new file mode 100644
index 0000000000..de995fdf32
--- /dev/null
+++ b/psx/octoshock/psx/FastFIFO.h
@@ -0,0 +1,88 @@
+#ifndef __MDFN_FASTFIFO_H
+#define __MDFN_FASTFIFO_H
+
+// size should be a power of 2.
+template
+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 void SyncState(EW::NewState *ns)
+ {
+ //I dont like this class...
+
+ NSS(data);
+ NSS(read_pos);
+ NSS(write_pos);
+ NSS(in_count);
+
+ SaveStatePostLoad();
+ }
+};
+
+
+#endif
diff --git a/psx/octoshock/psx/cdc.cpp b/psx/octoshock/psx/cdc.cpp
index 13e65c82db..cc20f13426 100644
--- a/psx/octoshock/psx/cdc.cpp
+++ b/psx/octoshock/psx/cdc.cpp
@@ -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();
diff --git a/psx/octoshock/psx/cdc.h b/psx/octoshock/psx/cdc.h
index ff50155a0e..1b88ab7078 100644
--- a/psx/octoshock/psx/cdc.h
+++ b/psx/octoshock/psx/cdc.h
@@ -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];
diff --git a/psx/octoshock/psx/cpu.cpp b/psx/octoshock/psx/cpu.cpp
index 463e4ade44..747b34141e 100644
--- a/psx/octoshock/psx/cpu.cpp
+++ b/psx/octoshock/psx/cpu.cpp
@@ -1,994 +1,2605 @@
-/* Mednafen - Multi-system Emulator
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "psx.h"
-#include "cpu.h"
-#include "gte.h"
-
-//not very organized, is it
-void* g_ShockTraceCallbackOpaque = NULL;
-ShockCallback_Trace g_ShockTraceCallback = NULL;
-
-/* TODO
- Make sure load delays are correct.
-
- Consider preventing IRQs being taken while in a branch delay slot, to prevent potential problems with games that like to be too clever and perform
- un-restartable sequences of instructions.
-*/
-
-#define BIU_ENABLE_ICACHE_S1 0x00000800 // Enable I-cache, set 1
-#define BIU_ENABLE_DCACHE 0x00000080 // Enable D-cache
-#define BIU_TAG_TEST_MODE 0x00000004 // Enable TAG test mode(IsC must be set to 1 as well presumably?)
-#define BIU_INVALIDATE_MODE 0x00000002 // Enable Invalidate mode(IsC must be set to 1 as well presumably?)
-#define BIU_LOCK 0x00000001 // Enable Lock mode(IsC must be set to 1 as well presumably?)
- // Does lock mode prevent the actual data payload from being modified, while allowing tags to be modified/updated???
-
-namespace MDFN_IEN_PSX
-{
-
-
-PS_CPU::PS_CPU()
-{
- Halted = false;
-
- memset(FastMap, 0, sizeof(FastMap));
- memset(DummyPage, 0xFF, sizeof(DummyPage)); // 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging.
-
- for(uint64 a = 0x00000000; a < (1ULL << 32); a += FAST_MAP_PSIZE)
- SetFastMap(DummyPage, a, FAST_MAP_PSIZE);
-
- CPUHook = NULL;
- ADDBT = NULL;
-
- GTE_Init();
-
- for(unsigned i = 0; i < 24; i++)
- {
- uint8 v = 7;
-
- if(i < 12)
- v += 4;
-
- if(i < 21)
- v += 3;
-
- MULT_Tab24[i] = v;
- }
-}
-
-PS_CPU::~PS_CPU()
-{
-
-
-}
-
-void PS_CPU::SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size)
-{
- uint64_t A;
- // FAST_MAP_SHIFT
- // FAST_MAP_PSIZE
-
- for(A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
- FastMap[A >> FAST_MAP_SHIFT] = ((uint8_t *)region_mem - region_address);
-}
-
-INLINE void PS_CPU::RecalcIPCache(void)
-{
- IPCache = 0;
-
- if(((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1)) || Halted)
- IPCache = 0x80;
-}
-
-void PS_CPU::SetHalt(bool status)
-{
- Halted = status;
- RecalcIPCache();
-}
-
-void PS_CPU::Power(void)
-{
- unsigned i;
-
- assert(sizeof(ICache) == sizeof(ICache_Bulk));
-
- memset(GPR, 0, sizeof(GPR));
- memset(&CP0, 0, sizeof(CP0));
- LO = 0;
- HI = 0;
-
- gte_ts_done = 0;
- muldiv_ts_done = 0;
-
- BACKED_PC = 0xBFC00000;
- BACKED_new_PC = 4;
- BACKED_new_PC_mask = ~0U;
-
- BACKED_LDWhich = 0x20;
- BACKED_LDValue = 0;
- LDAbsorb = 0;
- memset(ReadAbsorb, 0, sizeof(ReadAbsorb));
- ReadAbsorbWhich = 0;
- ReadFudge = 0;
-
- //WriteAbsorb = 0;
- //WriteAbsorbCount = 0;
- //WriteAbsorbMonkey = 0;
-
- CP0.SR |= (1 << 22); // BEV
- CP0.SR |= (1 << 21); // TS
-
- CP0.PRID = 0x2;
-
- RecalcIPCache();
-
-
- BIU = 0;
-
- memset(ScratchRAM.data8, 0, 1024);
-
- // Not quite sure about these poweron/reset values:
- for(i = 0; i < 1024; i++)
- {
- ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1);
- ICache[i].Data = 0;
- }
-
- GTE_Power();
-}
-
-void PS_CPU::AssertIRQ(unsigned which, bool asserted)
-{
- assert(which <= 5);
-
- CP0.CAUSE &= ~(1 << (10 + which));
-
- if(asserted)
- CP0.CAUSE |= 1 << (10 + which);
-
- RecalcIPCache();
-}
-
-void PS_CPU::SetBIU(uint32_t val)
-{
- unsigned i;
- const uint32_t old_BIU = BIU;
-
- BIU = val & ~(0x440);
-
- if((BIU ^ old_BIU) & 0x800)
- {
- if(BIU & 0x800) // ICache enabled
- {
- for(i = 0; i < 1024; i++)
- ICache[i].TV &= ~0x1;
- }
- else // ICache disabled
- {
- for(i = 0; i < 1024; i++)
- ICache[i].TV |= 0x1;
- }
- }
-
- PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU);
-}
-
-uint32_t PS_CPU::GetBIU(void)
-{
- return BIU;
-}
-
-static const uint32_t addr_mask[8] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
- 0x7FFFFFFF, 0x1FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-
-template
-INLINE T PS_CPU::PeekMemory(uint32_t address)
-{
- T ret;
- address &= addr_mask[address >> 29];
-
- if(address >= 0x1F800000 && address <= 0x1F8003FF)
- return ScratchRAM.Read(address & 0x3FF);
-
- //assert(!(CP0.SR & 0x10000));
-
- if(sizeof(T) == 1)
- ret = PSX_MemPeek8(address);
- else if(sizeof(T) == 2)
- ret = PSX_MemPeek16(address);
- else
- ret = PSX_MemPeek32(address);
-
- return(ret);
-}
-
-template
-INLINE T PS_CPU::ReadMemory(pscpu_timestamp_t ×tamp, uint32_t address, bool DS24, bool LWC_timing)
-{
- T ret;
-
- //WriteAbsorb >>= WriteAbsorbMonkey * 8;
- //WriteAbsorbCount -= WriteAbsorbMonkey;
- //WriteAbsorbMonkey = WriteAbsorbCount;
-
- ReadAbsorb[ReadAbsorbWhich] = 0;
- ReadAbsorbWhich = 0;
-
- address &= addr_mask[address >> 29];
-
- if(address >= 0x1F800000 && address <= 0x1F8003FF)
- {
- LDAbsorb = 0;
-
- if(DS24)
- return ScratchRAM.ReadU24(address & 0x3FF);
- else
- return ScratchRAM.Read(address & 0x3FF);
- }
-
- timestamp += (ReadFudge >> 4) & 2;
-
- //assert(!(CP0.SR & 0x10000));
-
- pscpu_timestamp_t lts = timestamp;
-
- if(sizeof(T) == 1)
- ret = PSX_MemRead8(lts, address);
- else if(sizeof(T) == 2)
- ret = PSX_MemRead16(lts, address);
- else
- {
- if(DS24)
- ret = PSX_MemRead24(lts, address) & 0xFFFFFF;
- else
- ret = PSX_MemRead32(lts, address);
- }
-
- if(LWC_timing)
- lts += 1;
- else
- lts += 2;
-
- LDAbsorb = (lts - timestamp);
- timestamp = lts;
-
- return(ret);
-}
-
-template
-INLINE void PS_CPU::WriteMemory(pscpu_timestamp_t ×tamp, uint32_t address, uint32_t value, bool DS24)
-{
- if(MDFN_LIKELY(!(CP0.SR & 0x10000)))
- {
- address &= addr_mask[address >> 29];
-
- if(address >= 0x1F800000 && address <= 0x1F8003FF)
- {
- if(DS24)
- ScratchRAM.WriteU24(address & 0x3FF, value);
- else
- ScratchRAM.Write(address & 0x3FF, value);
-
- return;
- }
-
- //if(WriteAbsorbCount == 4)
- //{
- // WriteAbsorb >>= 8;
- // WriteAbsorbCount--;
- //
- // if(WriteAbsorbMonkey)
- // WriteAbsorbMonkey--;
- //}
- //timestamp += 3;
- //WriteAbsorb |= (3U << (WriteAbsorbCount * 8));
- //WriteAbsorbCount++;
-
- if(sizeof(T) == 1)
- PSX_MemWrite8(timestamp, address, value);
- else if(sizeof(T) == 2)
- PSX_MemWrite16(timestamp, address, value);
- else
- {
- if(DS24)
- PSX_MemWrite24(timestamp, address, value);
- else
- PSX_MemWrite32(timestamp, address, value);
- }
- }
- else
- {
- if(BIU & 0x800) // Instruction cache is enabled/active
- {
- if(BIU & 0x4) // TAG test mode.
- {
- // TODO: Respect written value.
- __ICache *ICI = &ICache[((address & 0xFF0) >> 2)];
- const uint8_t valid_bits = 0x00;
-
- ICI[0].TV = ((valid_bits & 0x01) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
- ICI[1].TV = ((valid_bits & 0x02) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
- ICI[2].TV = ((valid_bits & 0x04) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
- ICI[3].TV = ((valid_bits & 0x08) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
- }
- else if(!(BIU & 0x1))
- {
- ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8);
- }
- }
-
- if((BIU & 0x081) == 0x080) // Writes to the scratchpad(TODO test)
- {
- if(DS24)
- ScratchRAM.WriteU24(address & 0x3FF, value);
- else
- ScratchRAM.Write(address & 0x3FF, value);
- }
- //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR);
- }
-}
-
-uint32_t PS_CPU::Exception(uint32_t code, uint32_t PC, const uint32_t NPM)
-{
- const bool InBDSlot = !(NPM & 0x3);
- uint32_t handler = 0x80000080;
-
- assert(code < 16);
-
- if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
- {
- PSX_DBG(PSX_DBG_WARNING, "Exception: %08x @ PC=0x%08x(IBDS=%d) -- IPCache=0x%02x -- IPEND=0x%02x -- SR=0x%08x ; IRQC_Status=0x%04x -- IRQC_Mask=0x%04x\n", code, PC, InBDSlot, IPCache, (CP0.CAUSE >> 8) & 0xFF, CP0.SR,
- IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0));
- }
-
- if(CP0.SR & (1 << 22)) // BEV
- handler = 0xBFC00180;
-
- CP0.EPC = PC;
- if(InBDSlot)
- CP0.EPC -= 4;
-
- if(ADDBT)
- ADDBT(PC, handler, true);
-
- // "Push" IEc and KUc(so that the new IEc and KUc are 0)
- CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F);
-
- // Setup cause register
- CP0.CAUSE &= 0x0000FF00;
- CP0.CAUSE |= code << 2;
-
- // If EPC was adjusted -= 4 because we were in a branch delay slot, set the bit.
- if(InBDSlot)
- CP0.CAUSE |= 0x80000000;
-
- RecalcIPCache();
-
- return(handler);
-}
-
-#define BACKING_TO_ACTIVE \
- PC = BACKED_PC; \
- new_PC = BACKED_new_PC; \
- new_PC_mask = BACKED_new_PC_mask; \
- LDWhich = BACKED_LDWhich; \
- LDValue = BACKED_LDValue;
-
-#define ACTIVE_TO_BACKING \
- BACKED_PC = PC; \
- BACKED_new_PC = new_PC; \
- BACKED_new_PC_mask = new_PC_mask; \
- BACKED_LDWhich = LDWhich; \
- BACKED_LDValue = LDValue;
-
-#define GPR_DEPRES_BEGIN { uint8_t back = ReadAbsorb[0];
-#define GPR_DEP(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
-#define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
-#define GPR_DEPRES_END ReadAbsorb[0] = back; }
-
-template
-pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
-{
- register pscpu_timestamp_t timestamp = timestamp_in;
-
- register uint32_t PC;
- register uint32_t new_PC;
- register uint32_t new_PC_mask;
- register uint32_t LDWhich;
- register uint32_t LDValue;
-
- //printf("%d %d\n", gte_ts_done, muldiv_ts_done);
-
- gte_ts_done += timestamp;
- muldiv_ts_done += timestamp;
-
- BACKING_TO_ACTIVE;
-
- do
- {
- //printf("Running: %d %d\n", timestamp, next_event_ts);
- while(MDFN_LIKELY(timestamp < next_event_ts))
- {
- uint32_t instr;
- uint32_t opf;
-
- // Zero must be zero...until the Master Plan is enacted.
- GPR[0] = 0;
-
- if(DebugMode && CPUHook)
- {
- ACTIVE_TO_BACKING;
-
- // For save states in step mode.
- gte_ts_done -= timestamp;
- muldiv_ts_done -= timestamp;
-
- CPUHook(timestamp, PC);
-
- // For save states in step mode.
- gte_ts_done += timestamp;
- muldiv_ts_done += timestamp;
-
- BACKING_TO_ACTIVE;
- }
-
-
- if(BIOSPrintMode)
- {
- if(PC == 0xB0)
- {
- if(MDFN_UNLIKELY(GPR[9] == 0x3D))
- {
- PSX_DBG_BIOS_PUTC(GPR[4]);
- }
- }
- }
-
- // We can't fold this into the ICache[] != PC handling, since the lower 2 bits of TV
- // are already used for cache management purposes and it assumes that the lower 2 bits of PC will be 0.
- if(MDFN_UNLIKELY(PC & 0x3))
- {
- // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working
- // than super-duper-accurate pipeline emulation, it shouldn't be a problem.
- new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
- new_PC_mask = 0;
- goto OpDone;
- }
-
- instr = ICache[(PC & 0xFFC) >> 2].Data;
-
- if(ICache[(PC & 0xFFC) >> 2].TV != PC)
- {
- //WriteAbsorb = 0;
- //WriteAbsorbCount = 0;
- //WriteAbsorbMonkey = 0;
- ReadAbsorb[ReadAbsorbWhich] = 0;
- ReadAbsorbWhich = 0;
-
- // FIXME: Handle executing out of scratchpad.
- if(PC >= 0xA0000000 || !(BIU & 0x800))
- {
- instr = MDFN_de32lsb(&FastMap[PC >> FAST_MAP_SHIFT][PC]);
- timestamp += 4; // Approximate best-case cache-disabled time, per PS1 tests(executing out of 0xA0000000+); it can be 5 in *some* sequences of code(like a lot of sequential "nop"s, probably other simple instructions too).
- }
- else
- {
- __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)];
- const uint8 *FMP = &FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF];
-
-
- // | 0x2 to simulate (in)validity bits.
- ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2;
- ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2;
- ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2;
- ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2;
-
- timestamp += 3;
-
-
- switch(PC & 0xC)
- {
- case 0x0:
- timestamp++;
- ICI[0x00].TV &= ~0x2;
- ICI[0x00].Data = MDFN_de32lsb(&FMP[0x0]);
- case 0x4:
- timestamp++;
- ICI[0x01].TV &= ~0x2;
- ICI[0x01].Data = MDFN_de32lsb(&FMP[0x4]);
- case 0x8:
- timestamp++;
- ICI[0x02].TV &= ~0x2;
- ICI[0x02].Data = MDFN_de32lsb(&FMP[0x8]);
- case 0xC:
- timestamp++;
- ICI[0x03].TV &= ~0x2;
- ICI[0x03].Data = MDFN_de32lsb(&FMP[0xC]);
- break;
- }
- instr = ICache[(PC & 0xFFC) >> 2].Data;
- }
- }
-
- //printf("PC=%08x, SP=%08x - op=0x%02x - funct=0x%02x - instr=0x%08x\n", PC, GPR[29], instr >> 26, instr & 0x3F, instr);
- //for(int i = 0; i < 32; i++)
- // printf("%02x : %08x\n", i, GPR[i]);
- //printf("\n");
-
- opf = instr & 0x3F;
-
- if(instr & (0x3F << 26))
- opf = 0x40 | (instr >> 26);
-
- opf |= IPCache;
-
-#if 0
- {
- uint32_t tmp = (ReadAbsorb[ReadAbsorbWhich] + 0x7FFFFFFF) >> 31;
- ReadAbsorb[ReadAbsorbWhich] -= tmp;
- timestamp = timestamp + 1 - tmp;
- }
-#else
- if(ReadAbsorb[ReadAbsorbWhich])
- ReadAbsorb[ReadAbsorbWhich]--;
- //else if((uint8)WriteAbsorb)
- //{
- // WriteAbsorb--;
- // if(!WriteAbsorb)
- // {
- // WriteAbsorbCount--;
- // if(WriteAbsorbMonkey)
- // WriteAbsorbMonkey--;
- // WriteAbsorb >>= 8;
- // }
- //}
- else
- timestamp++;
-#endif
-
-#define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; }
-#define BEGIN_OPF(name, arg_op, arg_funct) { op_##name: /*assert( ((arg_op) ? (0x40 | (arg_op)) : (arg_funct)) == opf); */
-#define END_OPF goto OpDone; }
-
-#define DO_BRANCH(offset, mask) \
- { \
- if(ILHMode) \
- { \
- uint32_t old_PC = PC; \
- PC = (PC & new_PC_mask) + new_PC; \
- if(old_PC == ((PC & (mask)) + (offset))) \
- { \
- if(MDFN_densb(&FastMap[PC >> FAST_MAP_SHIFT][PC]) == 0) \
- { \
- if(next_event_ts > timestamp) /* Necessary since next_event_ts might be set to something like "0" to force a call to the event handler. */ \
- { \
- timestamp = next_event_ts; \
- } \
- } \
- } \
- } \
- else \
- PC = (PC & new_PC_mask) + new_PC; \
- new_PC = (offset); \
- new_PC_mask = (mask) & ~3; \
- /* Lower bits of new_PC_mask being clear signifies being in a branch delay slot. (overloaded behavior for performance) */ \
- \
- if(DebugMode && ADDBT) \
- { \
- ADDBT(PC, (PC & new_PC_mask) + new_PC, false); \
- } \
- goto SkipNPCStuff; \
- }
-
-#define ITYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = (int32)(int16)(instr & 0xFFFF); /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
-#define ITYPE_ZE uint32_t rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32_t rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32_t immediate = instr & 0xFFFF; /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
-#define JTYPE uint32_t target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/
-#define RTYPE uint32_t rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32_t rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32_t rd MDFN_NOWARN_UNUSED = (instr >> 11) & 0x1F; uint32_t shamt MDFN_NOWARN_UNUSED = (instr >> 6) & 0x1F; /*printf(" rs=%02x(%08x), rt=%02x(%08x), rd=%02x(%08x) ", rs, GPR[rs], rt, GPR[rt], rd, GPR[rd]);*/
-
- {
- if(g_ShockTraceCallback)
- {
- char tmp[100];
- shock_Util_DisassembleMIPS(PC, instr, tmp, 100);
- g_ShockTraceCallback(g_ShockTraceCallbackOpaque, PC, instr, tmp);
- }
- }
-
-#if 1
-#include "cpu_bigswitch.inc"
-#else
-#include "cpu_coputedgoto.inc"
-#endif
-
-OpDone: ;
-
- PC = (PC & new_PC_mask) + new_PC;
- new_PC_mask = ~0U;
- new_PC = 4;
-
-SkipNPCStuff: ;
-
- //printf("\n");
- }
- } while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
-
- if(gte_ts_done > 0)
- gte_ts_done -= timestamp;
-
- if(muldiv_ts_done > 0)
- muldiv_ts_done -= timestamp;
-
- ACTIVE_TO_BACKING;
-
- return(timestamp);
-}
-
-pscpu_timestamp_t PS_CPU::Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode)
-{
- if(CPUHook || ADDBT)
- return(RunReal(timestamp_in));
- else
- {
- if(ILHMode)
- return(RunReal(timestamp_in));
- else
- {
- if(BIOSPrintMode)
- return(RunReal(timestamp_in));
- else
- return(RunReal(timestamp_in));
- }
- }
-}
-
-
-void PS_CPU::SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception))
-{
- ADDBT = addbt;
- CPUHook = cpuh;
-}
-
-uint32_t PS_CPU::GetRegister(unsigned int which, char *special, const uint32_t special_len)
-{
- uint32_t ret = 0;
-
- if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
- return GPR[which];
-
- switch(which)
- {
- case GSREG_PC:
- ret = BACKED_PC;
- break;
-
- case GSREG_PC_NEXT:
- ret = BACKED_new_PC;
- break;
-
- case GSREG_IN_BD_SLOT:
- ret = !(BACKED_new_PC_mask & 3);
- break;
-
- case GSREG_LO:
- ret = LO;
- break;
-
- case GSREG_HI:
- ret = HI;
- break;
-
- case GSREG_SR:
- ret = CP0.SR;
- break;
-
- case GSREG_CAUSE:
- ret = CP0.CAUSE;
- break;
-
- case GSREG_EPC:
- ret = CP0.EPC;
- break;
-
- }
-
- return ret;
-}
-
-void PS_CPU::SetRegister(unsigned int which, uint32_t value)
-{
- if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
- {
- if(which != (GSREG_GPR + 0))
- GPR[which] = value;
- }
- else switch(which)
- {
- case GSREG_PC:
- BACKED_PC = value & ~0x3; // Remove masking if we ever add proper misaligned PC exception
- break;
-
- case GSREG_LO:
- LO = value;
- break;
-
- case GSREG_HI:
- HI = value;
- break;
-
- case GSREG_SR:
- CP0.SR = value; // TODO: mask
- break;
-
- case GSREG_CAUSE:
- CP0.CAUSE = value;
- break;
-
- case GSREG_EPC:
- CP0.EPC = value & ~0x3U;
- break;
- }
-}
-
-bool PS_CPU::PeekCheckICache(uint32_t PC, uint32_t *iw)
-{
- if(ICache[(PC & 0xFFC) >> 2].TV == PC)
- {
- *iw = ICache[(PC & 0xFFC) >> 2].Data;
- return(true);
- }
-
- return(false);
-}
-
-
-uint8_t PS_CPU::PeekMem8(uint32_t A)
-{
- return PeekMemory(A);
-}
-
-uint16_t PS_CPU::PeekMem16(uint32_t A)
-{
- return PeekMemory(A);
-}
-
-uint32_t PS_CPU::PeekMem32(uint32_t A)
-{
- return PeekMemory(A);
-}
-
-
-#undef BEGIN_OPF
-#undef END_OPF
-#undef MK_OPF
-
-#define MK_OPF(op, funct) ((op) ? (0x40 | (op)) : (funct))
-#define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
-#define END_OPF } break;
-
-// FIXME: should we breakpoint on an illegal address? And with LWC2/SWC2 if CP2 isn't enabled?
-void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr)
-{
- uint32_t opf;
-
- opf = instr & 0x3F;
-
- if(instr & (0x3F << 26))
- opf = 0x40 | (instr >> 26);
-
-
- switch(opf)
- {
- default:
- break;
-
- //
- // LB - Load Byte
- //
- BEGIN_OPF(0x20, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 1);
- END_OPF;
-
- //
- // LBU - Load Byte Unsigned
- //
- BEGIN_OPF(0x24, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 1);
- END_OPF;
-
- //
- // LH - Load Halfword
- //
- BEGIN_OPF(0x21, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 2);
- END_OPF;
-
- //
- // LHU - Load Halfword Unsigned
- //
- BEGIN_OPF(0x25, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 2);
- END_OPF;
-
-
- //
- // LW - Load Word
- //
- BEGIN_OPF(0x23, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 4);
- END_OPF;
-
- //
- // SB - Store Byte
- //
- BEGIN_OPF(0x28, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(true, address, 1);
- END_OPF;
-
- //
- // SH - Store Halfword
- //
- BEGIN_OPF(0x29, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(true, address, 2);
- END_OPF;
-
- //
- // SW - Store Word
- //
- BEGIN_OPF(0x2B, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(true, address, 4);
- END_OPF;
-
- //
- // LWL - Load Word Left
- //
- BEGIN_OPF(0x22, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- do
- {
- callback(false, address, 1);
- } while((address--) & 0x3);
-
- END_OPF;
-
- //
- // SWL - Store Word Left
- //
- BEGIN_OPF(0x2A, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- do
- {
- callback(true, address, 1);
- } while((address--) & 0x3);
-
- END_OPF;
-
- //
- // LWR - Load Word Right
- //
- BEGIN_OPF(0x26, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- do
- {
- callback(false, address, 1);
- } while((++address) & 0x3);
-
- END_OPF;
-
- //
- // SWR - Store Word Right
- //
- BEGIN_OPF(0x2E, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- do
- {
- callback(true, address, 1);
- } while((++address) & 0x3);
-
- END_OPF;
-
- //
- // LWC2
- //
- BEGIN_OPF(0x32, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(false, address, 4);
- END_OPF;
-
- //
- // SWC2
- //
- BEGIN_OPF(0x3A, 0);
- ITYPE;
- uint32_t address = GPR[rs] + immediate;
-
- callback(true, address, 4);
- END_OPF;
-
- }
-}
-
-
-
-SYNCFUNC(PS_CPU)
-{
- NSS(GPR);
- NSS(LO);
- NSS(HI);
- NSS(BACKED_PC);
- NSS(BACKED_new_PC);
- NSS(BACKED_new_PC_mask);
-
- NSS(IPCache);
- NSS(Halted);
-
- NSS(BACKED_LDWhich);
- NSS(BACKED_LDValue);
- NSS(LDAbsorb);
-
- NSS(next_event_ts);
- NSS(gte_ts_done);
- NSS(muldiv_ts_done);
-
- NSS(BIU);
- NSS(ICache_Bulk);
-
- NSS(CP0.Regs);
-
- NSS(ReadAbsorb);
- NSS(ReadAbsorbDummy);
- NSS(ReadAbsorbWhich);
- NSS(ReadFudge);
-
- NSS(ScratchRAM.data8);
-
-} //SYNCFUNC(CPU)
-
-} //namespace MDFN_IEN_PSX
+/* Mednafen - Multi-system Emulator
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include
+#include "psx.h"
+#include "cpu.h"
+#include "math_ops.h"
+
+//not very organized, is it
+void* g_ShockTraceCallbackOpaque = NULL;
+ShockCallback_Trace g_ShockTraceCallback = NULL;
+
+/* TODO
+ Make sure load delays are correct.
+
+ Consider preventing IRQs being taken while in a branch delay slot, to prevent potential problems with games that like to be too clever and perform
+ un-restartable sequences of instructions.
+*/
+
+#define BIU_ENABLE_ICACHE_S1 0x00000800 // Enable I-cache, set 1
+#define BIU_ENABLE_DCACHE 0x00000080 // Enable D-cache
+#define BIU_TAG_TEST_MODE 0x00000004 // Enable TAG test mode(IsC must be set to 1 as well presumably?)
+#define BIU_INVALIDATE_MODE 0x00000002 // Enable Invalidate mode(IsC must be set to 1 as well presumably?)
+#define BIU_LOCK 0x00000001 // Enable Lock mode(IsC must be set to 1 as well presumably?)
+ // Does lock mode prevent the actual data payload from being modified, while allowing tags to be modified/updated???
+
+namespace MDFN_IEN_PSX
+{
+
+
+PS_CPU::PS_CPU()
+{
+ Halted = false;
+
+ memset(FastMap, 0, sizeof(FastMap));
+ memset(DummyPage, 0xFF, sizeof(DummyPage)); // 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging.
+
+ for(uint64 a = 0x00000000; a < (1ULL << 32); a += FAST_MAP_PSIZE)
+ SetFastMap(DummyPage, a, FAST_MAP_PSIZE);
+
+ CPUHook = NULL;
+ ADDBT = NULL;
+
+ GTE_Init();
+
+ for(unsigned i = 0; i < 24; i++)
+ {
+ uint8 v = 7;
+
+ if(i < 12)
+ v += 4;
+
+ if(i < 21)
+ v += 3;
+
+ MULT_Tab24[i] = v;
+ }
+}
+
+PS_CPU::~PS_CPU()
+{
+
+
+}
+
+void PS_CPU::SetFastMap(void *region_mem, uint32 region_address, uint32 region_size)
+{
+ // FAST_MAP_SHIFT
+ // FAST_MAP_PSIZE
+
+ for(uint64 A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
+ {
+ FastMap[A >> FAST_MAP_SHIFT] = ((uint8 *)region_mem - region_address);
+ }
+}
+
+INLINE void PS_CPU::RecalcIPCache(void)
+{
+ IPCache = 0;
+
+ if((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1))
+ IPCache = 0x80;
+
+ if(Halted)
+ IPCache = 0x80;
+}
+
+void PS_CPU::SetHalt(bool status)
+{
+ Halted = status;
+ RecalcIPCache();
+}
+
+void PS_CPU::Power(void)
+{
+ assert(sizeof(ICache) == sizeof(ICache_Bulk));
+
+ memset(GPR, 0, sizeof(GPR));
+ memset(&CP0, 0, sizeof(CP0));
+ LO = 0;
+ HI = 0;
+
+ gte_ts_done = 0;
+ muldiv_ts_done = 0;
+
+ BACKED_PC = 0xBFC00000;
+ BACKED_new_PC = 4;
+ BACKED_new_PC_mask = ~0U;
+
+ BACKED_LDWhich = 0x20;
+ BACKED_LDValue = 0;
+ LDAbsorb = 0;
+ memset(ReadAbsorb, 0, sizeof(ReadAbsorb));
+ ReadAbsorbWhich = 0;
+ ReadFudge = 0;
+
+ //WriteAbsorb = 0;
+ //WriteAbsorbCount = 0;
+ //WriteAbsorbMonkey = 0;
+
+ CP0.SR |= (1 << 22); // BEV
+ CP0.SR |= (1 << 21); // TS
+
+ CP0.PRID = 0x2;
+
+ RecalcIPCache();
+
+
+ BIU = 0;
+
+ memset(ScratchRAM.data8, 0, 1024);
+
+ // Not quite sure about these poweron/reset values:
+ for(unsigned i = 0; i < 1024; i++)
+ {
+ ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1);
+ ICache[i].Data = 0;
+ }
+
+ GTE_Power();
+}
+
+void PS_CPU::AssertIRQ(unsigned which, bool asserted)
+{
+ assert(which <= 5);
+
+ CP0.CAUSE &= ~(1 << (10 + which));
+
+ if(asserted)
+ CP0.CAUSE |= 1 << (10 + which);
+
+ RecalcIPCache();
+}
+
+void PS_CPU::SetBIU(uint32 val)
+{
+ const uint32 old_BIU = BIU;
+
+ BIU = val & ~(0x440);
+
+ if((BIU ^ old_BIU) & 0x800)
+ {
+ if(BIU & 0x800) // ICache enabled
+ {
+ for(unsigned i = 0; i < 1024; i++)
+ ICache[i].TV &= ~0x1;
+ }
+ else // ICache disabled
+ {
+ for(unsigned i = 0; i < 1024; i++)
+ ICache[i].TV |= 0x1;
+ }
+ }
+
+ PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU);
+}
+
+uint32 PS_CPU::GetBIU(void)
+{
+ return BIU;
+}
+
+static const uint32 addr_mask[8] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x7FFFFFFF, 0x1FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+
+template
+INLINE T PS_CPU::PeekMemory(uint32 address)
+{
+ T ret;
+ address &= addr_mask[address >> 29];
+
+ if(address >= 0x1F800000 && address <= 0x1F8003FF)
+ return ScratchRAM.Read(address & 0x3FF);
+
+ //assert(!(CP0.SR & 0x10000));
+
+ if(sizeof(T) == 1)
+ ret = PSX_MemPeek8(address);
+ else if(sizeof(T) == 2)
+ ret = PSX_MemPeek16(address);
+ else
+ ret = PSX_MemPeek32(address);
+
+ return(ret);
+}
+
+template
+INLINE T PS_CPU::ReadMemory(pscpu_timestamp_t ×tamp, uint32 address, bool DS24, bool LWC_timing)
+{
+ T ret;
+
+ //WriteAbsorb >>= WriteAbsorbMonkey * 8;
+ //WriteAbsorbCount -= WriteAbsorbMonkey;
+ //WriteAbsorbMonkey = WriteAbsorbCount;
+
+ ReadAbsorb[ReadAbsorbWhich] = 0;
+ ReadAbsorbWhich = 0;
+
+ address &= addr_mask[address >> 29];
+
+ if(address >= 0x1F800000 && address <= 0x1F8003FF)
+ {
+ LDAbsorb = 0;
+
+ if(DS24)
+ return ScratchRAM.ReadU24(address & 0x3FF);
+ else
+ return ScratchRAM.Read(address & 0x3FF);
+ }
+
+ timestamp += (ReadFudge >> 4) & 2;
+
+ //assert(!(CP0.SR & 0x10000));
+
+ pscpu_timestamp_t lts = timestamp;
+
+ if(sizeof(T) == 1)
+ ret = PSX_MemRead8(lts, address);
+ else if(sizeof(T) == 2)
+ ret = PSX_MemRead16(lts, address);
+ else
+ {
+ if(DS24)
+ ret = PSX_MemRead24(lts, address) & 0xFFFFFF;
+ else
+ ret = PSX_MemRead32(lts, address);
+ }
+
+ if(LWC_timing)
+ lts += 1;
+ else
+ lts += 2;
+
+ LDAbsorb = (lts - timestamp);
+ timestamp = lts;
+
+ return(ret);
+}
+
+template
+INLINE void PS_CPU::WriteMemory(pscpu_timestamp_t ×tamp, uint32 address, uint32 value, bool DS24)
+{
+ if(MDFN_LIKELY(!(CP0.SR & 0x10000)))
+ {
+ address &= addr_mask[address >> 29];
+
+ if(address >= 0x1F800000 && address <= 0x1F8003FF)
+ {
+ if(DS24)
+ ScratchRAM.WriteU24(address & 0x3FF, value);
+ else
+ ScratchRAM.Write(address & 0x3FF, value);
+
+ return;
+ }
+
+ //if(WriteAbsorbCount == 4)
+ //{
+ // WriteAbsorb >>= 8;
+ // WriteAbsorbCount--;
+ //
+ // if(WriteAbsorbMonkey)
+ // WriteAbsorbMonkey--;
+ //}
+ //timestamp += 3;
+ //WriteAbsorb |= (3U << (WriteAbsorbCount * 8));
+ //WriteAbsorbCount++;
+
+ if(sizeof(T) == 1)
+ PSX_MemWrite8(timestamp, address, value);
+ else if(sizeof(T) == 2)
+ PSX_MemWrite16(timestamp, address, value);
+ else
+ {
+ if(DS24)
+ PSX_MemWrite24(timestamp, address, value);
+ else
+ PSX_MemWrite32(timestamp, address, value);
+ }
+ }
+ else
+ {
+ if(BIU & 0x800) // Instruction cache is enabled/active
+ {
+ if(BIU & 0x4) // TAG test mode.
+ {
+ // TODO: Respect written value.
+ __ICache *ICI = &ICache[((address & 0xFF0) >> 2)];
+ const uint8 valid_bits = 0x00;
+
+ ICI[0].TV = ((valid_bits & 0x01) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
+ ICI[1].TV = ((valid_bits & 0x02) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
+ ICI[2].TV = ((valid_bits & 0x04) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
+ ICI[3].TV = ((valid_bits & 0x08) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
+ }
+ else if(!(BIU & 0x1))
+ {
+ ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8);
+ }
+ }
+
+ if((BIU & 0x081) == 0x080) // Writes to the scratchpad(TODO test)
+ {
+ if(DS24)
+ ScratchRAM.WriteU24(address & 0x3FF, value);
+ else
+ ScratchRAM.Write(address & 0x3FF, value);
+ }
+ //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR);
+ }
+}
+
+uint32 PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NPM)
+{
+ const bool InBDSlot = !(NPM & 0x3);
+ uint32 handler = 0x80000080;
+
+ assert(code < 16);
+
+ if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
+ {
+ PSX_DBG(PSX_DBG_WARNING, "Exception: %08x @ PC=0x%08x(IBDS=%d) -- IPCache=0x%02x -- IPEND=0x%02x -- SR=0x%08x ; IRQC_Status=0x%04x -- IRQC_Mask=0x%04x\n", code, PC, InBDSlot, IPCache, (CP0.CAUSE >> 8) & 0xFF, CP0.SR,
+ IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0));
+ }
+
+ if(CP0.SR & (1 << 22)) // BEV
+ handler = 0xBFC00180;
+
+ CP0.EPC = PC;
+ if(InBDSlot)
+ CP0.EPC -= 4;
+
+ if(ADDBT)
+ ADDBT(PC, handler, true);
+
+ // "Push" IEc and KUc(so that the new IEc and KUc are 0)
+ CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F);
+
+ // Setup cause register
+ CP0.CAUSE &= 0x0000FF00;
+ CP0.CAUSE |= code << 2;
+
+ // If EPC was adjusted -= 4 because we were in a branch delay slot, set the bit.
+ if(InBDSlot)
+ CP0.CAUSE |= 0x80000000;
+
+ RecalcIPCache();
+
+ return(handler);
+}
+
+#define BACKING_TO_ACTIVE \
+ PC = BACKED_PC; \
+ new_PC = BACKED_new_PC; \
+ new_PC_mask = BACKED_new_PC_mask; \
+ LDWhich = BACKED_LDWhich; \
+ LDValue = BACKED_LDValue;
+
+#define ACTIVE_TO_BACKING \
+ BACKED_PC = PC; \
+ BACKED_new_PC = new_PC; \
+ BACKED_new_PC_mask = new_PC_mask; \
+ BACKED_LDWhich = LDWhich; \
+ BACKED_LDValue = LDValue;
+
+#define GPR_DEPRES_BEGIN { uint8 back = ReadAbsorb[0];
+#define GPR_DEP(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
+#define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
+#define GPR_DEPRES_END ReadAbsorb[0] = back; }
+
+template
+pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
+{
+ register pscpu_timestamp_t timestamp = timestamp_in;
+
+ register uint32 PC;
+ register uint32 new_PC;
+ register uint32 new_PC_mask;
+ register uint32 LDWhich;
+ register uint32 LDValue;
+
+ //printf("%d %d\n", gte_ts_done, muldiv_ts_done);
+
+ gte_ts_done += timestamp;
+ muldiv_ts_done += timestamp;
+
+ BACKING_TO_ACTIVE;
+
+ do
+ {
+ //printf("Running: %d %d\n", timestamp, next_event_ts);
+ while(MDFN_LIKELY(timestamp < next_event_ts))
+ {
+ uint32 instr;
+ uint32 opf;
+
+ // Zero must be zero...until the Master Plan is enacted.
+ GPR[0] = 0;
+
+ if(DebugMode && CPUHook)
+ {
+ ACTIVE_TO_BACKING;
+
+ // For save states in step mode.
+ gte_ts_done -= timestamp;
+ muldiv_ts_done -= timestamp;
+
+ CPUHook(timestamp, PC);
+
+ // For save states in step mode.
+ gte_ts_done += timestamp;
+ muldiv_ts_done += timestamp;
+
+ BACKING_TO_ACTIVE;
+ }
+
+ if(BIOSPrintMode)
+ {
+ if(PC == 0xB0)
+ {
+ if(MDFN_UNLIKELY(GPR[9] == 0x3D))
+ {
+ PSX_DBG_BIOS_PUTC(GPR[4]);
+ }
+ }
+ }
+
+ // We can't fold this into the ICache[] != PC handling, since the lower 2 bits of TV
+ // are already used for cache management purposes and it assumes that the lower 2 bits of PC will be 0.
+ if(MDFN_UNLIKELY(PC & 0x3))
+ {
+ // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working
+ // than super-duper-accurate pipeline emulation, it shouldn't be a problem.
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ goto OpDone;
+ }
+
+ instr = ICache[(PC & 0xFFC) >> 2].Data;
+
+ if(ICache[(PC & 0xFFC) >> 2].TV != PC)
+ {
+ //WriteAbsorb = 0;
+ //WriteAbsorbCount = 0;
+ //WriteAbsorbMonkey = 0;
+ ReadAbsorb[ReadAbsorbWhich] = 0;
+ ReadAbsorbWhich = 0;
+
+ // FIXME: Handle executing out of scratchpad.
+ if(PC >= 0xA0000000 || !(BIU & 0x800))
+ {
+ instr = MDFN_de32lsb(&FastMap[PC >> FAST_MAP_SHIFT][PC]);
+ timestamp += 4; // Approximate best-case cache-disabled time, per PS1 tests(executing out of 0xA0000000+); it can be 5 in *some* sequences of code(like a lot of sequential "nop"s, probably other simple instructions too).
+ }
+ else
+ {
+ __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)];
+ const uint8 *FMP = &FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF];
+
+ // | 0x2 to simulate (in)validity bits.
+ ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2;
+ ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2;
+ ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2;
+ ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2;
+
+ timestamp += 3;
+
+ switch(PC & 0xC)
+ {
+ case 0x0:
+ timestamp++;
+ ICI[0x00].TV &= ~0x2;
+ ICI[0x00].Data = MDFN_de32lsb(&FMP[0x0]);
+ case 0x4:
+ timestamp++;
+ ICI[0x01].TV &= ~0x2;
+ ICI[0x01].Data = MDFN_de32lsb(&FMP[0x4]);
+ case 0x8:
+ timestamp++;
+ ICI[0x02].TV &= ~0x2;
+ ICI[0x02].Data = MDFN_de32lsb(&FMP[0x8]);
+ case 0xC:
+ timestamp++;
+ ICI[0x03].TV &= ~0x2;
+ ICI[0x03].Data = MDFN_de32lsb(&FMP[0xC]);
+ break;
+ }
+ instr = ICache[(PC & 0xFFC) >> 2].Data;
+ }
+ }
+
+ //printf("PC=%08x, SP=%08x - op=0x%02x - funct=0x%02x - instr=0x%08x\n", PC, GPR[29], instr >> 26, instr & 0x3F, instr);
+ //for(int i = 0; i < 32; i++)
+ // printf("%02x : %08x\n", i, GPR[i]);
+ //printf("\n");
+
+ opf = instr & 0x3F;
+
+ if(instr & (0x3F << 26))
+ opf = 0x40 | (instr >> 26);
+
+ opf |= IPCache;
+
+#if 0
+ {
+ uint32 tmp = (ReadAbsorb[ReadAbsorbWhich] + 0x7FFFFFFF) >> 31;
+ ReadAbsorb[ReadAbsorbWhich] -= tmp;
+ timestamp = timestamp + 1 - tmp;
+ }
+#else
+ if(ReadAbsorb[ReadAbsorbWhich])
+ ReadAbsorb[ReadAbsorbWhich]--;
+ //else if((uint8)WriteAbsorb)
+ //{
+ // WriteAbsorb--;
+ // if(!WriteAbsorb)
+ // {
+ // WriteAbsorbCount--;
+ // if(WriteAbsorbMonkey)
+ // WriteAbsorbMonkey--;
+ // WriteAbsorb >>= 8;
+ // }
+ //}
+ else
+ timestamp++;
+#endif
+
+ #define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; }
+ #define BEGIN_OPF(name, arg_op, arg_funct) { op_##name: /*assert( ((arg_op) ? (0x40 | (arg_op)) : (arg_funct)) == opf); */
+ #define END_OPF goto OpDone; }
+
+ #define DO_BRANCH(offset, mask) \
+ { \
+ if(ILHMode) \
+ { \
+ uint32 old_PC = PC; \
+ PC = (PC & new_PC_mask) + new_PC; \
+ if(old_PC == ((PC & (mask)) + (offset))) \
+ { \
+ if(MDFN_densb(&FastMap[PC >> FAST_MAP_SHIFT][PC]) == 0) \
+ { \
+ if(next_event_ts > timestamp) /* Necessary since next_event_ts might be set to something like "0" to force a call to the event handler. */ \
+ { \
+ timestamp = next_event_ts; \
+ } \
+ } \
+ } \
+ } \
+ else \
+ PC = (PC & new_PC_mask) + new_PC; \
+ new_PC = (offset); \
+ new_PC_mask = (mask) & ~3; \
+ /* Lower bits of new_PC_mask being clear signifies being in a branch delay slot. (overloaded behavior for performance) */ \
+ \
+ if(DebugMode && ADDBT) \
+ { \
+ ADDBT(PC, (PC & new_PC_mask) + new_PC, false); \
+ } \
+ goto SkipNPCStuff; \
+ }
+
+ #define ITYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = (int32)(int16)(instr & 0xFFFF); /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
+ #define ITYPE_ZE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = instr & 0xFFFF; /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
+ #define JTYPE uint32 target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/
+ #define RTYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 rd MDFN_NOWARN_UNUSED = (instr >> 11) & 0x1F; uint32 shamt MDFN_NOWARN_UNUSED = (instr >> 6) & 0x1F; /*printf(" rs=%02x(%08x), rt=%02x(%08x), rd=%02x(%08x) ", rs, GPR[rs], rt, GPR[rt], rd, GPR[rd]);*/
+
+#if HAVE_COMPUTED_GOTO
+ #define CGBEGIN static const void *const op_goto_table[256] = {
+ #define CGE(l) &&l,
+ #define CGEND }; goto *op_goto_table[opf];
+#else
+ /* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more
+ expensive than computed goto which needs no masking nor bounds checking.
+ */
+ #define CGBEGIN { enum { CGESB = 1 + __COUNTER__ }; switch((uint8)opf) {
+ #define CGE(l) case __COUNTER__ - CGESB: goto l;
+ #define CGEND } }
+#endif
+
+ CGBEGIN
+ CGE(op_SLL) CGE(op_ILL) CGE(op_SRL) CGE(op_SRA) CGE(op_SLLV) CGE(op_ILL) CGE(op_SRLV) CGE(op_SRAV)
+ CGE(op_JR) CGE(op_JALR) CGE(op_ILL) CGE(op_ILL) CGE(op_SYSCALL) CGE(op_BREAK) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_MFHI) CGE(op_MTHI) CGE(op_MFLO) CGE(op_MTLO) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_MULT) CGE(op_MULTU) CGE(op_DIV) CGE(op_DIVU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_ADD) CGE(op_ADDU) CGE(op_SUB) CGE(op_SUBU) CGE(op_AND) CGE(op_OR) CGE(op_XOR) CGE(op_NOR)
+ CGE(op_ILL) CGE(op_ILL) CGE(op_SLT) CGE(op_SLTU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+
+ CGE(op_ILL) CGE(op_BCOND) CGE(op_J) CGE(op_JAL) CGE(op_BEQ) CGE(op_BNE) CGE(op_BLEZ) CGE(op_BGTZ)
+ CGE(op_ADDI) CGE(op_ADDIU) CGE(op_SLTI) CGE(op_SLTIU) CGE(op_ANDI) CGE(op_ORI) CGE(op_XORI) CGE(op_LUI)
+ CGE(op_COP0) CGE(op_COP1) CGE(op_COP2) CGE(op_COP3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_LB) CGE(op_LH) CGE(op_LWL) CGE(op_LW) CGE(op_LBU) CGE(op_LHU) CGE(op_LWR) CGE(op_ILL)
+ CGE(op_SB) CGE(op_SH) CGE(op_SWL) CGE(op_SW) CGE(op_ILL) CGE(op_ILL) CGE(op_SWR) CGE(op_ILL)
+ CGE(op_LWC0) CGE(op_LWC1) CGE(op_LWC2) CGE(op_LWC3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+ CGE(op_SWC0) CGE(op_SWC1) CGE(op_SWC2) CGE(op_SWC3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
+
+ // Interrupt portion of this table is constructed so that an interrupt won't be taken when the PC is pointing to a GTE instruction,
+ // to avoid problems caused by pipeline vs coprocessor nuances that aren't emulated.
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+
+ CGE(op_ILL) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_COP2) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
+ CGEND
+
+ {
+ BEGIN_OPF(ILL, 0, 0);
+ PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F));
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // ADD - Add Word
+ //
+ BEGIN_OPF(ADD, 0, 0x20);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] + GPR[rt];
+ bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(ep))
+ {
+ new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // ADDI - Add Immediate Word
+ //
+ BEGIN_OPF(ADDI, 0x08, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] + immediate;
+ bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(ep))
+ {
+ new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ GPR[rt] = result;
+
+ END_OPF;
+
+ //
+ // ADDIU - Add Immediate Unsigned Word
+ //
+ BEGIN_OPF(ADDIU, 0x09, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ GPR[rt] = result;
+
+ END_OPF;
+
+ //
+ // ADDU - Add Unsigned Word
+ //
+ BEGIN_OPF(ADDU, 0, 0x21);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] + GPR[rt];
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // AND - And
+ //
+ BEGIN_OPF(AND, 0, 0x24);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] & GPR[rt];
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // ANDI - And Immediate
+ //
+ BEGIN_OPF(ANDI, 0x0C, 0);
+ ITYPE_ZE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] & immediate;
+
+ DO_LDS();
+
+ GPR[rt] = result;
+
+ END_OPF;
+
+ //
+ // BEQ - Branch on Equal
+ //
+ BEGIN_OPF(BEQ, 0x04, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ bool result = (GPR[rs] == GPR[rt]);
+
+ DO_LDS();
+
+ if(result)
+ {
+ DO_BRANCH((immediate << 2), ~0U);
+ }
+ END_OPF;
+
+ // Bah, why does MIPS encoding have to be funky like this. :(
+ // Handles BGEZ, BGEZAL, BLTZ, BLTZAL
+ BEGIN_OPF(BCOND, 0x01, 0);
+ const uint32 tv = GPR[(instr >> 21) & 0x1F];
+ uint32 riv = (instr >> 16) & 0x1F;
+ uint32 immediate = (int32)(int16)(instr & 0xFFFF);
+ bool result = (int32)(tv ^ (riv << 31)) < 0;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP((instr >> 21) & 0x1F);
+
+ if(riv & 0x10)
+ GPR_RES(31);
+
+ GPR_DEPRES_END
+
+
+ DO_LDS();
+
+ if(riv & 0x10) // Unconditional link reg setting.
+ GPR[31] = PC + 8;
+
+ if(result)
+ {
+ DO_BRANCH((immediate << 2), ~0U);
+ }
+
+ END_OPF;
+
+
+ //
+ // BGTZ - Branch on Greater than Zero
+ //
+ BEGIN_OPF(BGTZ, 0x07, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ bool result = (int32)GPR[rs] > 0;
+
+ DO_LDS();
+
+ if(result)
+ {
+ DO_BRANCH((immediate << 2), ~0U);
+ }
+ END_OPF;
+
+ //
+ // BLEZ - Branch on Less Than or Equal to Zero
+ //
+ BEGIN_OPF(BLEZ, 0x06, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ bool result = (int32)GPR[rs] <= 0;
+
+ DO_LDS();
+
+ if(result)
+ {
+ DO_BRANCH((immediate << 2), ~0U);
+ }
+
+ END_OPF;
+
+ //
+ // BNE - Branch on Not Equal
+ //
+ BEGIN_OPF(BNE, 0x05, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ bool result = GPR[rs] != GPR[rt];
+
+ DO_LDS();
+
+ if(result)
+ {
+ DO_BRANCH((immediate << 2), ~0U);
+ }
+
+ END_OPF;
+
+ //
+ // BREAK - Breakpoint
+ //
+ BEGIN_OPF(BREAK, 0, 0x0D);
+ PSX_WARNING("[CPU] BREAK BREAK BREAK BREAK DAAANCE -- PC=0x%08x", PC);
+
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_BP, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ // Cop "instructions": CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0)
+ //
+ // COP0 instructions
+ BEGIN_OPF(COP0, 0x10, 0);
+ uint32 sub_op = (instr >> 21) & 0x1F;
+
+ if(sub_op & 0x10)
+ sub_op = 0x10 + (instr & 0x3F);
+
+ //printf("COP0 thing: %02x\n", sub_op);
+ switch(sub_op)
+ {
+ default:
+ DO_LDS();
+ break;
+
+ case 0x00: // MFC0 - Move from Coprocessor
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+
+ //printf("MFC0: rt=%d <- rd=%d(%08x)\n", rt, rd, CP0.Regs[rd]);
+ DO_LDS();
+
+ LDAbsorb = 0;
+ LDWhich = rt;
+ LDValue = CP0.Regs[rd];
+ }
+ break;
+
+ case 0x04: // MTC0 - Move to Coprocessor
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+ uint32 val = GPR[rt];
+
+ if(rd != CP0REG_PRID && rd != CP0REG_CAUSE && rd != CP0REG_SR && val)
+ {
+ PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd);
+ }
+
+ switch(rd)
+ {
+ case CP0REG_BPC:
+ CP0.BPC = val;
+ break;
+
+ case CP0REG_BDA:
+ CP0.BDA = val;
+ break;
+
+ case CP0REG_TAR:
+ CP0.TAR = val;
+ break;
+
+ case CP0REG_DCIC:
+ CP0.DCIC = val & 0xFF80003F;
+ break;
+
+ case CP0REG_BDAM:
+ CP0.BDAM = val;
+ break;
+
+ case CP0REG_BPCM:
+ CP0.BPCM = val;
+ break;
+
+ case CP0REG_CAUSE:
+ CP0.CAUSE &= ~(0x3 << 8);
+ CP0.CAUSE |= val & (0x3 << 8);
+ RecalcIPCache();
+ break;
+
+ case CP0REG_SR:
+ if((CP0.SR ^ val) & 0x10000)
+ PSX_DBG(PSX_DBG_SPARSE, "[CPU] IsC %u->%u\n", (bool)(CP0.SR & (1U << 16)), (bool)(val & (1U << 16)));
+
+ CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
+ RecalcIPCache();
+ break;
+ }
+ }
+ DO_LDS();
+ break;
+
+ case (0x10 + 0x10): // RFE
+ // "Pop"
+ DO_LDS();
+ CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F);
+ RecalcIPCache();
+ break;
+ }
+ END_OPF;
+
+ //
+ // COP1
+ //
+ BEGIN_OPF(COP1, 0x11, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // COP2
+ //
+ BEGIN_OPF(COP2, 0x12, 0);
+ uint32 sub_op = (instr >> 21) & 0x1F;
+
+ switch(sub_op)
+ {
+ default:
+ DO_LDS();
+ break;
+
+ case 0x00: // MFC2 - Move from Coprocessor
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+
+ DO_LDS();
+
+ if(timestamp < gte_ts_done)
+ {
+ LDAbsorb = gte_ts_done - timestamp;
+ timestamp = gte_ts_done;
+ }
+ else
+ LDAbsorb = 0;
+
+ LDWhich = rt;
+ LDValue = GTE_ReadDR(rd);
+ }
+ break;
+
+ case 0x04: // MTC2 - Move to Coprocessor
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+ uint32 val = GPR[rt];
+
+ if(timestamp < gte_ts_done)
+ timestamp = gte_ts_done;
+
+ //printf("GTE WriteDR: %d %d\n", rd, val);
+ GTE_WriteDR(rd, val);
+ DO_LDS();
+ }
+ break;
+
+ case 0x02: // CFC2
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+
+ DO_LDS();
+
+ if(timestamp < gte_ts_done)
+ {
+ LDAbsorb = gte_ts_done - timestamp;
+ timestamp = gte_ts_done;
+ }
+ else
+ LDAbsorb = 0;
+
+ LDWhich = rt;
+ LDValue = GTE_ReadCR(rd);
+
+ //printf("GTE ReadCR: %d %d\n", rd, GPR[rt]);
+ }
+ break;
+
+ case 0x06: // CTC2
+ {
+ uint32 rt = (instr >> 16) & 0x1F;
+ uint32 rd = (instr >> 11) & 0x1F;
+ uint32 val = GPR[rt];
+
+ //printf("GTE WriteCR: %d %d\n", rd, val);
+
+ if(timestamp < gte_ts_done)
+ timestamp = gte_ts_done;
+
+ GTE_WriteCR(rd, val);
+ DO_LDS();
+ }
+ break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
+ //printf("%08x\n", PC);
+ if(timestamp < gte_ts_done)
+ timestamp = gte_ts_done;
+ gte_ts_done = timestamp + GTE_Instruction(instr);
+ DO_LDS();
+ break;
+ }
+ END_OPF;
+
+ //
+ // COP3
+ //
+ BEGIN_OPF(COP3, 0x13, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // LWC0
+ //
+ BEGIN_OPF(LWC0, 0x30, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // LWC1
+ //
+ BEGIN_OPF(LWC1, 0x31, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // LWC2
+ //
+ BEGIN_OPF(LWC2, 0x32, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(address & 3))
+ {
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ {
+ if(timestamp < gte_ts_done)
+ timestamp = gte_ts_done;
+
+ GTE_WriteDR(rt, ReadMemory(timestamp, address, false, true));
+ }
+ // GTE stuff here
+ END_OPF;
+
+ //
+ // LWC3
+ //
+ BEGIN_OPF(LWC3, 0x33, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+
+ //
+ // SWC0
+ //
+ BEGIN_OPF(SWC0, 0x38, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // SWC1
+ //
+ BEGIN_OPF(SWC1, 0x39, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+ //
+ // SWC2
+ //
+ BEGIN_OPF(SWC2, 0x3A, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ if(MDFN_UNLIKELY(address & 0x3))
+ {
+ new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ {
+ if(timestamp < gte_ts_done)
+ timestamp = gte_ts_done;
+
+ WriteMemory(timestamp, address, GTE_ReadDR(rt));
+ }
+ DO_LDS();
+ END_OPF;
+
+ //
+ // SWC3
+ ///
+ BEGIN_OPF(SWC3, 0x3B, 0);
+ DO_LDS();
+ new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+
+ //
+ // DIV - Divide Word
+ //
+ BEGIN_OPF(DIV, 0, 0x1A);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ if(!GPR[rt])
+ {
+ if(GPR[rs] & 0x80000000)
+ LO = 1;
+ else
+ LO = 0xFFFFFFFF;
+
+ HI = GPR[rs];
+ }
+ else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF)
+ {
+ LO = 0x80000000;
+ HI = 0;
+ }
+ else
+ {
+ LO = (int32)GPR[rs] / (int32)GPR[rt];
+ HI = (int32)GPR[rs] % (int32)GPR[rt];
+ }
+ muldiv_ts_done = timestamp + 37;
+
+ DO_LDS();
+
+ END_OPF;
+
+
+ //
+ // DIVU - Divide Unsigned Word
+ //
+ BEGIN_OPF(DIVU, 0, 0x1B);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ if(!GPR[rt])
+ {
+ LO = 0xFFFFFFFF;
+ HI = GPR[rs];
+ }
+ else
+ {
+ LO = GPR[rs] / GPR[rt];
+ HI = GPR[rs] % GPR[rt];
+ }
+ muldiv_ts_done = timestamp + 37;
+
+ DO_LDS();
+ END_OPF;
+
+ //
+ // J - Jump
+ //
+ BEGIN_OPF(J, 0x02, 0);
+ JTYPE;
+
+ DO_LDS();
+
+ DO_BRANCH(target << 2, 0xF0000000);
+ END_OPF;
+
+ //
+ // JAL - Jump and Link
+ //
+ BEGIN_OPF(JAL, 0x03, 0);
+ JTYPE;
+
+ //GPR_DEPRES_BEGIN
+ GPR_RES(31);
+ //GPR_DEPRES_END
+
+ DO_LDS();
+
+ GPR[31] = PC + 8;
+
+ DO_BRANCH(target << 2, 0xF0000000);
+ END_OPF;
+
+ //
+ // JALR - Jump and Link Register
+ //
+ BEGIN_OPF(JALR, 0, 0x09);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 tmp = GPR[rs];
+
+ DO_LDS();
+
+ GPR[rd] = PC + 8;
+
+ DO_BRANCH(tmp, 0);
+
+ END_OPF;
+
+ //
+ // JR - Jump Register
+ //
+ BEGIN_OPF(JR, 0, 0x08);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 bt = GPR[rs];
+
+ DO_LDS();
+
+ DO_BRANCH(bt, 0);
+
+ END_OPF;
+
+ //
+ // LUI - Load Upper Immediate
+ //
+ BEGIN_OPF(LUI, 0x0F, 0);
+ ITYPE_ZE; // Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b
+
+ GPR_DEPRES_BEGIN
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ DO_LDS();
+
+ GPR[rt] = immediate << 16;
+
+ END_OPF;
+
+ //
+ // MFHI - Move from HI
+ //
+ BEGIN_OPF(MFHI, 0, 0x10);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ DO_LDS();
+
+ if(timestamp < muldiv_ts_done)
+ {
+ if(timestamp == muldiv_ts_done - 1)
+ muldiv_ts_done--;
+ else
+ {
+ do
+ {
+ if(ReadAbsorb[ReadAbsorbWhich])
+ ReadAbsorb[ReadAbsorbWhich]--;
+ timestamp++;
+ } while(timestamp < muldiv_ts_done);
+ }
+ }
+
+ GPR[rd] = HI;
+
+ END_OPF;
+
+
+ //
+ // MFLO - Move from LO
+ //
+ BEGIN_OPF(MFLO, 0, 0x12);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ DO_LDS();
+
+ if(timestamp < muldiv_ts_done)
+ {
+ if(timestamp == muldiv_ts_done - 1)
+ muldiv_ts_done--;
+ else
+ {
+ do
+ {
+ if(ReadAbsorb[ReadAbsorbWhich])
+ ReadAbsorb[ReadAbsorbWhich]--;
+ timestamp++;
+ } while(timestamp < muldiv_ts_done);
+ }
+ }
+
+ GPR[rd] = LO;
+
+ END_OPF;
+
+
+ //
+ // MTHI - Move to HI
+ //
+ BEGIN_OPF(MTHI, 0, 0x11);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ HI = GPR[rs];
+
+ DO_LDS();
+
+ END_OPF;
+
+ //
+ // MTLO - Move to LO
+ //
+ BEGIN_OPF(MTLO, 0, 0x13);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ LO = GPR[rs];
+
+ DO_LDS();
+
+ END_OPF;
+
+
+ //
+ // MULT - Multiply Word
+ //
+ BEGIN_OPF(MULT, 0, 0x18);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint64 result;
+
+ result = (int64)(int32)GPR[rs] * (int32)GPR[rt];
+ muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32((GPR[rs] ^ ((int32)GPR[rs] >> 31)) | 0x400)];
+ DO_LDS();
+
+ LO = result;
+ HI = result >> 32;
+
+ END_OPF;
+
+ //
+ // MULTU - Multiply Unsigned Word
+ //
+ BEGIN_OPF(MULTU, 0, 0x19);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint64 result;
+
+ result = (uint64)GPR[rs] * GPR[rt];
+ muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32(GPR[rs] | 0x400)];
+ DO_LDS();
+
+ LO = result;
+ HI = result >> 32;
+
+ END_OPF;
+
+
+ //
+ // NOR - NOR
+ //
+ BEGIN_OPF(NOR, 0, 0x27);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = ~(GPR[rs] | GPR[rt]);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // OR - OR
+ //
+ BEGIN_OPF(OR, 0, 0x25);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] | GPR[rt];
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // ORI - OR Immediate
+ //
+ BEGIN_OPF(ORI, 0x0D, 0);
+ ITYPE_ZE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] | immediate;
+
+ DO_LDS();
+
+ GPR[rt] = result;
+
+ END_OPF;
+
+
+ //
+ // SLL - Shift Word Left Logical
+ //
+ BEGIN_OPF(SLL, 0, 0x00); // SLL
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rt] << shamt;
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SLLV - Shift Word Left Logical Variable
+ //
+ BEGIN_OPF(SLLV, 0, 0x04);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rt] << (GPR[rs] & 0x1F);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // SLT - Set on Less Than
+ //
+ BEGIN_OPF(SLT, 0, 0x2A);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = (bool)((int32)GPR[rs] < (int32)GPR[rt]);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SLTI - Set on Less Than Immediate
+ //
+ BEGIN_OPF(SLTI, 0x0A, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = (bool)((int32)GPR[rs] < (int32)immediate);
+
+ DO_LDS();
+
+ GPR[rt] = result;
+
+ END_OPF;
+
+
+ //
+ // SLTIU - Set on Less Than Immediate, Unsigned
+ //
+ BEGIN_OPF(SLTIU, 0x0B, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = (bool)(GPR[rs] < (uint32)immediate);
+
+ DO_LDS();
+
+ GPR[rt] = result;
+
+ END_OPF;
+
+
+ //
+ // SLTU - Set on Less Than, Unsigned
+ //
+ BEGIN_OPF(SLTU, 0, 0x2B);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = (bool)(GPR[rs] < GPR[rt]);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SRA - Shift Word Right Arithmetic
+ //
+ BEGIN_OPF(SRA, 0, 0x03);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = ((int32)GPR[rt]) >> shamt;
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SRAV - Shift Word Right Arithmetic Variable
+ //
+ BEGIN_OPF(SRAV, 0, 0x07);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SRL - Shift Word Right Logical
+ //
+ BEGIN_OPF(SRL, 0, 0x02);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rt] >> shamt;
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // SRLV - Shift Word Right Logical Variable
+ //
+ BEGIN_OPF(SRLV, 0, 0x06);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rt] >> (GPR[rs] & 0x1F);
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SUB - Subtract Word
+ //
+ BEGIN_OPF(SUB, 0, 0x22);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] - GPR[rt];
+ bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(ep))
+ {
+ new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SUBU - Subtract Unsigned Word
+ //
+ BEGIN_OPF(SUBU, 0, 0x23); // SUBU
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] - GPR[rt];
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+
+ //
+ // SYSCALL
+ //
+ BEGIN_OPF(SYSCALL, 0, 0x0C);
+ DO_LDS();
+
+ new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ END_OPF;
+
+
+ //
+ // XOR
+ //
+ BEGIN_OPF(XOR, 0, 0x26);
+ RTYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_RES(rd);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] ^ GPR[rt];
+
+ DO_LDS();
+
+ GPR[rd] = result;
+
+ END_OPF;
+
+ //
+ // XORI - Exclusive OR Immediate
+ //
+ BEGIN_OPF(XORI, 0x0E, 0);
+ ITYPE_ZE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_RES(rt);
+ GPR_DEPRES_END
+
+ uint32 result = GPR[rs] ^ immediate;
+
+ DO_LDS();
+
+ GPR[rt] = result;
+ END_OPF;
+
+ //
+ // Memory access instructions(besides the coprocessor ones) follow:
+ //
+
+ //
+ // LB - Load Byte
+ //
+ BEGIN_OPF(LB, 0x20, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ LDWhich = rt;
+ LDValue = (int32)ReadMemory(timestamp, address);
+ END_OPF;
+
+ //
+ // LBU - Load Byte Unsigned
+ //
+ BEGIN_OPF(LBU, 0x24, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ LDWhich = rt;
+ LDValue = ReadMemory(timestamp, address);
+ END_OPF;
+
+ //
+ // LH - Load Halfword
+ //
+ BEGIN_OPF(LH, 0x21, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(address & 1))
+ {
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ {
+ LDWhich = rt;
+ LDValue = (int32)ReadMemory(timestamp, address);
+ }
+ END_OPF;
+
+ //
+ // LHU - Load Halfword Unsigned
+ //
+ BEGIN_OPF(LHU, 0x25, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(address & 1))
+ {
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ {
+ LDWhich = rt;
+ LDValue = ReadMemory(timestamp, address);
+ }
+ END_OPF;
+
+
+ //
+ // LW - Load Word
+ //
+ BEGIN_OPF(LW, 0x23, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ DO_LDS();
+
+ if(MDFN_UNLIKELY(address & 3))
+ {
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ {
+ LDWhich = rt;
+ LDValue = ReadMemory(timestamp, address);
+ }
+ END_OPF;
+
+ //
+ // SB - Store Byte
+ //
+ BEGIN_OPF(SB, 0x28, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ WriteMemory(timestamp, address, GPR[rt]);
+
+ DO_LDS();
+ END_OPF;
+
+ //
+ // SH - Store Halfword
+ //
+ BEGIN_OPF(SH, 0x29, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ if(MDFN_UNLIKELY(address & 0x1))
+ {
+ new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ WriteMemory(timestamp, address, GPR[rt]);
+
+ DO_LDS();
+ END_OPF;
+
+ //
+ // SW - Store Word
+ //
+ BEGIN_OPF(SW, 0x2B, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ if(MDFN_UNLIKELY(address & 0x3))
+ {
+ new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ else
+ WriteMemory(timestamp, address, GPR[rt]);
+
+ DO_LDS();
+ END_OPF;
+
+ // LWL and LWR load delay slot tomfoolery appears to apply even to MFC0! (and probably MFCn and CFCn as well, though they weren't explicitly tested)
+
+ //
+ // LWL - Load Word Left
+ //
+ BEGIN_OPF(LWL, 0x22, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ //GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+ uint32 v = GPR[rt];
+
+ if(LDWhich == rt)
+ {
+ v = LDValue;
+ ReadFudge = 0;
+ }
+ else
+ {
+ DO_LDS();
+ }
+
+ LDWhich = rt;
+ switch(address & 0x3)
+ {
+ case 0: LDValue = (v & ~(0xFF << 24)) | (ReadMemory(timestamp, address & ~3) << 24);
+ break;
+
+ case 1: LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory(timestamp, address & ~3) << 16);
+ break;
+
+ case 2: LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory(timestamp, address & ~3, true) << 8);
+ break;
+
+ case 3: LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory(timestamp, address & ~3) << 0);
+ break;
+ }
+ END_OPF;
+
+ //
+ // SWL - Store Word Left
+ //
+ BEGIN_OPF(SWL, 0x2A, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ switch(address & 0x3)
+ {
+ case 0: WriteMemory(timestamp, address & ~3, GPR[rt] >> 24);
+ break;
+
+ case 1: WriteMemory(timestamp, address & ~3, GPR[rt] >> 16);
+ break;
+
+ case 2: WriteMemory(timestamp, address & ~3, GPR[rt] >> 8, true);
+ break;
+
+ case 3: WriteMemory(timestamp, address & ~3, GPR[rt] >> 0);
+ break;
+ }
+ DO_LDS();
+
+ END_OPF;
+
+ //
+ // LWR - Load Word Right
+ //
+ BEGIN_OPF(LWR, 0x26, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ //GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+ uint32 v = GPR[rt];
+
+ if(LDWhich == rt)
+ {
+ v = LDValue;
+ ReadFudge = 0;
+ }
+ else
+ {
+ DO_LDS();
+ }
+
+ LDWhich = rt;
+ switch(address & 0x3)
+ {
+ case 0: LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory(timestamp, address);
+ break;
+
+ case 1: LDValue = (v & ~(0xFFFFFF)) | ReadMemory(timestamp, address, true);
+ break;
+
+ case 2: LDValue = (v & ~(0xFFFF)) | ReadMemory(timestamp, address);
+ break;
+
+ case 3: LDValue = (v & ~(0xFF)) | ReadMemory(timestamp, address);
+ break;
+ }
+ END_OPF;
+
+ //
+ // SWR - Store Word Right
+ //
+ BEGIN_OPF(SWR, 0x2E, 0);
+ ITYPE;
+
+ GPR_DEPRES_BEGIN
+ GPR_DEP(rs);
+ GPR_DEP(rt);
+ GPR_DEPRES_END
+
+ uint32 address = GPR[rs] + immediate;
+
+ switch(address & 0x3)
+ {
+ case 0: WriteMemory(timestamp, address, GPR[rt]);
+ break;
+
+ case 1: WriteMemory(timestamp, address, GPR[rt], true);
+ break;
+
+ case 2: WriteMemory(timestamp, address, GPR[rt]);
+ break;
+
+ case 3: WriteMemory(timestamp, address, GPR[rt]);
+ break;
+ }
+
+ DO_LDS();
+
+ END_OPF;
+
+ //
+ // Mednafen special instruction
+ //
+ BEGIN_OPF(INTERRUPT, 0x3F, 0);
+ if(Halted)
+ {
+ goto SkipNPCStuff;
+ }
+ else
+ {
+ DO_LDS();
+
+ new_PC = Exception(EXCEPTION_INT, PC, new_PC_mask);
+ new_PC_mask = 0;
+ }
+ END_OPF;
+ }
+
+ OpDone: ;
+
+ PC = (PC & new_PC_mask) + new_PC;
+ new_PC_mask = ~0U;
+ new_PC = 4;
+
+ SkipNPCStuff: ;
+
+ //printf("\n");
+ }
+ } while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
+
+ if(gte_ts_done > 0)
+ gte_ts_done -= timestamp;
+
+ if(muldiv_ts_done > 0)
+ muldiv_ts_done -= timestamp;
+
+ ACTIVE_TO_BACKING;
+
+ return(timestamp);
+}
+
+pscpu_timestamp_t PS_CPU::Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode)
+{
+ if(CPUHook || ADDBT)
+ return(RunReal(timestamp_in));
+ else
+ {
+ if(ILHMode)
+ return(RunReal(timestamp_in));
+ else
+ {
+ if(BIOSPrintMode)
+ return(RunReal(timestamp_in));
+ else
+ return(RunReal(timestamp_in));
+ }
+ }
+}
+
+void PS_CPU::SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception))
+{
+ ADDBT = addbt;
+ CPUHook = cpuh;
+}
+
+uint32 PS_CPU::GetRegister(unsigned int which, char *special, const uint32 special_len)
+{
+ uint32 ret = 0;
+
+ if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
+ ret = GPR[which];
+ else switch(which)
+ {
+ case GSREG_PC:
+ ret = BACKED_PC;
+ break;
+
+ case GSREG_PC_NEXT:
+ ret = BACKED_new_PC;
+ break;
+
+ case GSREG_IN_BD_SLOT:
+ ret = !(BACKED_new_PC_mask & 3);
+ break;
+
+ case GSREG_LO:
+ ret = LO;
+ break;
+
+ case GSREG_HI:
+ ret = HI;
+ break;
+
+ case GSREG_SR:
+ ret = CP0.SR;
+ break;
+
+ case GSREG_CAUSE:
+ ret = CP0.CAUSE;
+ break;
+
+ case GSREG_EPC:
+ ret = CP0.EPC;
+ break;
+
+ }
+
+ return(ret);
+}
+
+void PS_CPU::SetRegister(unsigned int which, uint32 value)
+{
+ if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
+ {
+ if(which != (GSREG_GPR + 0))
+ GPR[which] = value;
+ }
+ else switch(which)
+ {
+ case GSREG_PC:
+ BACKED_PC = value & ~0x3; // Remove masking if we ever add proper misaligned PC exception
+ break;
+
+ case GSREG_LO:
+ LO = value;
+ break;
+
+ case GSREG_HI:
+ HI = value;
+ break;
+
+ case GSREG_SR:
+ CP0.SR = value; // TODO: mask
+ break;
+
+ case GSREG_CAUSE:
+ CP0.CAUSE = value;
+ break;
+
+ case GSREG_EPC:
+ CP0.EPC = value & ~0x3U;
+ break;
+
+
+ }
+}
+
+bool PS_CPU::PeekCheckICache(uint32 PC, uint32 *iw)
+{
+ if(ICache[(PC & 0xFFC) >> 2].TV == PC)
+ {
+ *iw = ICache[(PC & 0xFFC) >> 2].Data;
+ return(true);
+ }
+
+ return(false);
+}
+
+
+uint8 PS_CPU::PeekMem8(uint32 A)
+{
+ return PeekMemory(A);
+}
+
+uint16 PS_CPU::PeekMem16(uint32 A)
+{
+ return PeekMemory(A);
+}
+
+uint32 PS_CPU::PeekMem32(uint32 A)
+{
+ return PeekMemory(A);
+}
+
+
+#undef BEGIN_OPF
+#undef END_OPF
+#undef MK_OPF
+
+#define MK_OPF(op, funct) ((op) ? (0x40 | (op)) : (funct))
+#define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
+#define END_OPF } break;
+
+// FIXME: should we breakpoint on an illegal address? And with LWC2/SWC2 if CP2 isn't enabled?
+void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr)
+{
+ uint32 opf;
+
+ opf = instr & 0x3F;
+
+ if(instr & (0x3F << 26))
+ opf = 0x40 | (instr >> 26);
+
+
+ switch(opf)
+ {
+ default:
+ break;
+
+ //
+ // LB - Load Byte
+ //
+ BEGIN_OPF(0x20, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 1);
+ END_OPF;
+
+ //
+ // LBU - Load Byte Unsigned
+ //
+ BEGIN_OPF(0x24, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 1);
+ END_OPF;
+
+ //
+ // LH - Load Halfword
+ //
+ BEGIN_OPF(0x21, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 2);
+ END_OPF;
+
+ //
+ // LHU - Load Halfword Unsigned
+ //
+ BEGIN_OPF(0x25, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 2);
+ END_OPF;
+
+
+ //
+ // LW - Load Word
+ //
+ BEGIN_OPF(0x23, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 4);
+ END_OPF;
+
+ //
+ // SB - Store Byte
+ //
+ BEGIN_OPF(0x28, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(true, address, 1);
+ END_OPF;
+
+ //
+ // SH - Store Halfword
+ //
+ BEGIN_OPF(0x29, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(true, address, 2);
+ END_OPF;
+
+ //
+ // SW - Store Word
+ //
+ BEGIN_OPF(0x2B, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(true, address, 4);
+ END_OPF;
+
+ //
+ // LWL - Load Word Left
+ //
+ BEGIN_OPF(0x22, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ do
+ {
+ callback(false, address, 1);
+ } while((address--) & 0x3);
+
+ END_OPF;
+
+ //
+ // SWL - Store Word Left
+ //
+ BEGIN_OPF(0x2A, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ do
+ {
+ callback(true, address, 1);
+ } while((address--) & 0x3);
+
+ END_OPF;
+
+ //
+ // LWR - Load Word Right
+ //
+ BEGIN_OPF(0x26, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ do
+ {
+ callback(false, address, 1);
+ } while((++address) & 0x3);
+
+ END_OPF;
+
+ //
+ // SWR - Store Word Right
+ //
+ BEGIN_OPF(0x2E, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ do
+ {
+ callback(true, address, 1);
+ } while((++address) & 0x3);
+
+ END_OPF;
+
+ //
+ // LWC2
+ //
+ BEGIN_OPF(0x32, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(false, address, 4);
+ END_OPF;
+
+ //
+ // SWC2
+ //
+ BEGIN_OPF(0x3A, 0);
+ ITYPE;
+ uint32 address = GPR[rs] + immediate;
+
+ callback(true, address, 4);
+ END_OPF;
+
+ }
+}
+
+
+
+SYNCFUNC(PS_CPU)
+{
+ NSS(GPR);
+ NSS(LO);
+ NSS(HI);
+ NSS(BACKED_PC);
+ NSS(BACKED_new_PC);
+ NSS(BACKED_new_PC_mask);
+
+ NSS(IPCache);
+ NSS(Halted);
+
+ NSS(BACKED_LDWhich);
+ NSS(BACKED_LDValue);
+ NSS(LDAbsorb);
+
+ NSS(next_event_ts);
+ NSS(gte_ts_done);
+ NSS(muldiv_ts_done);
+
+ NSS(BIU);
+ NSS(ICache_Bulk);
+
+ NSS(CP0.Regs);
+
+ NSS(ReadAbsorb);
+ NSS(ReadAbsorbWhich);
+ NSS(ReadFudge);
+
+ NSS(ScratchRAM.data8);
+
+} //SYNCFUNC(CPU)
+
+} //namespace MDFN_IEN_PSX
diff --git a/psx/octoshock/psx/cpu.h b/psx/octoshock/psx/cpu.h
index 51d79aa01d..7de9ed3532 100644
--- a/psx/octoshock/psx/cpu.h
+++ b/psx/octoshock/psx/cpu.h
@@ -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;
-
- templatevoid 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 pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
-
- template T PeekMemory(uint32_t address) MDFN_COLD;
- template T ReadMemory(pscpu_timestamp_t ×tamp, uint32_t address, bool DS24 = false, bool LWC_timing = false);
- template 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;
+
+ templatevoid 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 pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE;
+
+ template T PeekMemory(uint32 address) MDFN_COLD;
+ template T ReadMemory(pscpu_timestamp_t ×tamp, uint32 address, bool DS24 = false, bool LWC_timing = false);
+ template 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
diff --git a/psx/octoshock/psx/dma.cpp b/psx/octoshock/psx/dma.cpp
index 0d73a94492..145f2d711c 100644
--- a/psx/octoshock/psx/dma.cpp
+++ b/psx/octoshock/psx/dma.cpp
@@ -20,10 +20,6 @@
#include "cdc.h"
#include "spu.h"
-//#include