diff options
| author | 2026-03-08 05:49:08 +1100 | |
|---|---|---|
| committer | 2026-03-08 05:49:08 +1100 | |
| commit | b401ac85b4d37aa82f9b42f484f0c2f9d59513aa (patch) | |
| tree | 1c0bf5d6d7cb4d54b4fffdcb82c2dd0a0c0a308b /src/devices/cpu | |
| parent | 6498190508d4297fd8a76d9f2695328320414937 (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.hxx | 93 | ||||
| -rw-r--r-- | src/devices/cpu/sharc/sharc.h | 2 | ||||
| -rw-r--r-- | src/devices/cpu/sharc/sharcdrc.cpp | 10 | ||||
| -rw-r--r-- | src/devices/cpu/sharc/sharcops.hxx | 2 |
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; |
