summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2026-03-08 05:49:08 +1100
committer Vas Crabb <vas@vastheman.com>2026-03-08 05:49:08 +1100
commitb401ac85b4d37aa82f9b42f484f0c2f9d59513aa (patch)
tree1c0bf5d6d7cb4d54b4fffdcb82c2dd0a0c0a308b /src/devices/cpu
parent6498190508d4297fd8a76d9f2695328320414937 (diff)
cpu/sharc: Fixed several interpreter issues:
* Fixed carry flag calculation for subtract with carry. * Implemented Rn = Rx + CI and Rn = Rx + CI - 1. * Rn = Rx + 1, Rn = Rx - 1 and Rn = -Rx should saturate the result.
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/sharc/compute.hxx93
-rw-r--r--src/devices/cpu/sharc/sharc.h2
-rw-r--r--src/devices/cpu/sharc/sharcdrc.cpp10
-rw-r--r--src/devices/cpu/sharc/sharcops.hxx2
4 files changed, 82 insertions, 25 deletions
diff --git a/src/devices/cpu/sharc/compute.hxx b/src/devices/cpu/sharc/compute.hxx
index 7048460a373..b0e515fca77 100644
--- a/src/devices/cpu/sharc/compute.hxx
+++ b/src/devices/cpu/sharc/compute.hxx
@@ -11,7 +11,7 @@
#define SET_FLAG_AN(r) do { m_core->astat |= (((r) & 0x80000000) ? AN : 0); } while (false)
#define SET_FLAG_AC_ADD(r,a,b) do { m_core->astat |= ((uint32_t(r) < uint32_t(a)) ? AC : 0); } while (false)
#define SET_FLAG_AV_ADD(r,a,b) do { m_core->astat |= (((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); } while (false)
-#define SET_FLAG_AC_SUB(r,a,b) do { m_core->astat |= (!(uint32_t(a) < uint32_t(b)) ? AC : 0); } while (false)
+#define SET_FLAG_AC_SUB(r,a,b) do { m_core->astat |= ((uint32_t(r) <= uint32_t(a)) ? AC : 0); } while (false)
#define SET_FLAG_AV_SUB(r,a,b) do { m_core->astat |= (((((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); } while (false)
#define CLEAR_MULTIPLIER_FLAGS() do { m_core->astat &= ~(MN|MV|MU|MI); } while (false)
@@ -153,13 +153,13 @@ void adsp21062_device::compute_sub(int rn, int rx, int ry)
/* Rn = Rx + Ry + CI */
void adsp21062_device::compute_add_ci(int rn, int rx, int ry)
{
- int c = (m_core->astat & AC) ? 1 : 0;
+ int const c = (m_core->astat & AC) ? 1 : 0;
uint32_t r = REG(rx) + REG(ry) + c;
CLEAR_ALU_FLAGS();
SET_FLAG_AV_ADD(r, REG(rx), REG(ry));
SET_FLAG_AC_ADD(r, REG(rx), REG(ry));
- if (c == 1 && REG(ry) == 0xffffffff)
+ if ((c == 1) && (REG(ry) == 0xffffffff))
m_core->astat |= AC;
if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
@@ -176,14 +176,13 @@ void adsp21062_device::compute_add_ci(int rn, int rx, int ry)
/* Rn = Rx - Ry + CI - 1 */
void adsp21062_device::compute_sub_ci(int rn, int rx, int ry)
{
- int c = (m_core->astat & AC) ? 1 : 0;
+ int const c = (m_core->astat & AC) ? 1 : 0;
uint32_t r = REG(rx) - REG(ry) + c - 1;
CLEAR_ALU_FLAGS();
SET_FLAG_AV_SUB(r, REG(rx), REG(ry));
- SET_FLAG_AC_SUB(r, REG(rx), REG(ry));
- if (c == 0 && REG(ry) == 0xffffffff)
- m_core->astat |= AC;
+ if ((c != 0) || (REG(ry) != 0xffffffff))
+ SET_FLAG_AC_SUB(r, REG(rx), REG(ry));
if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
SATURATE(r);
@@ -199,7 +198,7 @@ void adsp21062_device::compute_sub_ci(int rn, int rx, int ry)
/* Rn = Rx AND Ry */
void adsp21062_device::compute_and(int rn, int rx, int ry)
{
- uint32_t r = REG(rx) & REG(ry);
+ uint32_t const r = REG(rx) & REG(ry);
CLEAR_ALU_FLAGS();
SET_FLAG_AN(r);
@@ -247,7 +246,7 @@ void adsp21062_device::compute_pass(int rn, int rx)
/* Rn = Rx XOR Ry */
void adsp21062_device::compute_xor(int rn, int rx, int ry)
{
- uint32_t r = REG(rx) ^ REG(ry);
+ uint32_t const r = REG(rx) ^ REG(ry);
CLEAR_ALU_FLAGS();
SET_FLAG_AN(r);
SET_FLAG_AZ(r);
@@ -259,10 +258,52 @@ void adsp21062_device::compute_xor(int rn, int rx, int ry)
/* Rn = Rx OR Ry */
void adsp21062_device::compute_or(int rn, int rx, int ry)
{
- uint32_t r = REG(rx) | REG(ry);
+ uint32_t const r = REG(rx) | REG(ry);
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+ REG(rn) = r;
+
+ m_core->astat &= ~AF;
+}
+
+/* Rn = Rx + CI */
+void adsp21062_device::compute_add_ci(int rn, int rx)
+{
+ int const c = (m_core->astat & AC) ? 1 : 0;
+ uint32_t r = REG(rx) + c;
+
+ CLEAR_ALU_FLAGS();
+ SET_FLAG_AV_ADD(r, REG(rx), 0);
+ SET_FLAG_AC_ADD(r, REG(rx), 0);
+
+ if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
+ SATURATE(r);
+
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
+ REG(rn) = r;
+
+ m_core->astat &= ~AF;
+}
+
+/* Rn = Rx + CI - 1 */
+void adsp21062_device::compute_sub_ci(int rn, int rx)
+{
+ int const c = (m_core->astat & AC) ? 1 : 0;
+ uint32_t r = REG(rx) + c - 1;
+
CLEAR_ALU_FLAGS();
+ SET_FLAG_AV_SUB(r, REG(rx), 0);
+ SET_FLAG_AC_SUB(r, REG(rx), 0);
+
+ if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
+ SATURATE(r);
+
SET_FLAG_AN(r);
SET_FLAG_AZ(r);
+
REG(rn) = r;
m_core->astat &= ~AF;
@@ -274,11 +315,15 @@ void adsp21062_device::compute_inc(int rn, int rx)
uint32_t r = REG(rx) + 1;
CLEAR_ALU_FLAGS();
- SET_FLAG_AN(r);
- SET_FLAG_AZ(r);
SET_FLAG_AV_ADD(r, REG(rx), 1);
SET_FLAG_AC_ADD(r, REG(rx), 1);
+ if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
+ SATURATE(r);
+
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
REG(rn) = r;
m_core->astat &= ~AF;
@@ -290,11 +335,15 @@ void adsp21062_device::compute_dec(int rn, int rx)
uint32_t r = REG(rx) - 1;
CLEAR_ALU_FLAGS();
- SET_FLAG_AN(r);
- SET_FLAG_AZ(r);
SET_FLAG_AV_SUB(r, REG(rx), 1);
SET_FLAG_AC_SUB(r, REG(rx), 1);
+ if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
+ SATURATE(r);
+
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
REG(rn) = r;
m_core->astat &= ~AF;
@@ -303,7 +352,7 @@ void adsp21062_device::compute_dec(int rn, int rx)
/* Rn = MIN(Rx, Ry) */
void adsp21062_device::compute_min(int rn, int rx, int ry)
{
- uint32_t r = std::min((int32_t)REG(rx), (int32_t)REG(ry));
+ uint32_t const r = std::min(int32_t(REG(rx)), int32_t(REG(ry)));
CLEAR_ALU_FLAGS();
SET_FLAG_AN(r);
@@ -317,7 +366,7 @@ void adsp21062_device::compute_min(int rn, int rx, int ry)
/* Rn = MAX(Rx, Ry) */
void adsp21062_device::compute_max(int rn, int rx, int ry)
{
- uint32_t r = std::max((int32_t)REG(rx), (int32_t)REG(ry));
+ uint32_t const r = std::max(int32_t(REG(rx)), int32_t(REG(ry)));
CLEAR_ALU_FLAGS();
SET_FLAG_AN(r);
@@ -346,14 +395,18 @@ void adsp21062_device::compute_clip(int rn, int rx, int ry)
/* Rn = -Rx */
void adsp21062_device::compute_neg(int rn, int rx)
{
- uint32_t r = -(int32_t)(REG(rx));
+ uint32_t r = -int32_t(REG(rx));
CLEAR_ALU_FLAGS();
- SET_FLAG_AN(r);
- SET_FLAG_AZ(r);
SET_FLAG_AV_SUB(r, 0, REG(rx));
SET_FLAG_AC_SUB(r, 0, REG(rx));
+ if ((m_core->mode1 & MODE1_ALUSAT) && (m_core->astat & AV))
+ SATURATE(r);
+
+ SET_FLAG_AN(r);
+ SET_FLAG_AZ(r);
+
REG(rn) = r;
m_core->astat &= ~AF;
@@ -362,7 +415,7 @@ void adsp21062_device::compute_neg(int rn, int rx)
/* Rn = NOT Rx */
void adsp21062_device::compute_not(int rn, int rx)
{
- uint32_t r = ~REG(rx);
+ uint32_t const r = ~REG(rx);
CLEAR_ALU_FLAGS();
SET_FLAG_AN(r);
diff --git a/src/devices/cpu/sharc/sharc.h b/src/devices/cpu/sharc/sharc.h
index 33df1541875..fd41dd9d7b2 100644
--- a/src/devices/cpu/sharc/sharc.h
+++ b/src/devices/cpu/sharc/sharc.h
@@ -397,6 +397,8 @@ private:
inline void compute_pass(int rn, int rx);
inline void compute_xor(int rn, int rx, int ry);
inline void compute_or(int rn, int rx, int ry);
+ inline void compute_add_ci(int rn, int rx);
+ inline void compute_sub_ci(int rn, int rx);
inline void compute_inc(int rn, int rx);
inline void compute_dec(int rn, int rx);
inline void compute_min(int rn, int rx, int ry);
diff --git a/src/devices/cpu/sharc/sharcdrc.cpp b/src/devices/cpu/sharc/sharcdrc.cpp
index a857b74cb3b..1a5e5355292 100644
--- a/src/devices/cpu/sharc/sharcdrc.cpp
+++ b/src/devices/cpu/sharc/sharcdrc.cpp
@@ -4443,11 +4443,6 @@ void adsp21062_device::generate_compute(drcuml_block &block, compiler_state &com
update_az_av_an_ac_fixed(block, desc, true);
return;
- case 0x29: // Rn = Rx + 1
- UML_ADD(block, REG(rn), REG(rx), 1);
- update_az_av_an_ac_fixed(block, desc, false);
- return;
-
case 0x25: // Rn = Rx + CI
UML_ADD(block, REG(rn), REG(rx), ASTAT_AC);
update_az_av_an_ac_fixed(block, desc, false);
@@ -4459,6 +4454,11 @@ void adsp21062_device::generate_compute(drcuml_block &block, compiler_state &com
update_az_av_an_ac_fixed(block, desc, true);
return;
+ case 0x29: // Rn = Rx + 1
+ UML_ADD(block, REG(rn), REG(rx), 1);
+ update_az_av_an_ac_fixed(block, desc, false);
+ return;
+
case 0x2a: // Rn = Rx - 1
UML_SUB(block, REG(rn), REG(rx), 1);
update_az_av_an_ac_fixed(block, desc, true);
diff --git a/src/devices/cpu/sharc/sharcops.hxx b/src/devices/cpu/sharc/sharcops.hxx
index 9c4956a5a2f..d78f05a27c6 100644
--- a/src/devices/cpu/sharc/sharcops.hxx
+++ b/src/devices/cpu/sharc/sharcops.hxx
@@ -843,6 +843,8 @@ void adsp21062_device::COMPUTE(uint32_t opcode)
case 0x0a: compute_comp(rx, ry); break;
case 0x21: compute_pass(rn, rx); break;
case 0x22: compute_neg(rn, rx); break;
+ case 0x25: compute_add_ci(rn, rx); break;
+ case 0x26: compute_sub_ci(rn, rx); break;
case 0x29: compute_inc(rn, rx); break;
case 0x2a: compute_dec(rn, rx); break;
case 0x40: compute_and(rn, rx, ry); break;