summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/dsp16/dsp16ops.inc
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/dsp16/dsp16ops.inc')
-rw-r--r--src/devices/cpu/dsp16/dsp16ops.inc937
1 files changed, 937 insertions, 0 deletions
diff --git a/src/devices/cpu/dsp16/dsp16ops.inc b/src/devices/cpu/dsp16/dsp16ops.inc
new file mode 100644
index 00000000000..d63fe9d3f99
--- /dev/null
+++ b/src/devices/cpu/dsp16/dsp16ops.inc
@@ -0,0 +1,937 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrew Gardner
+#include "dsp16.h"
+
+#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__);
+
+// TODO:
+// * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits
+// implement as a clean function (page 2-7)
+// * Implement saturation overflow (SAT on AUC) (page 2-8)
+// * Implement p alignment (ALIGN on AUC) (page 2-9)
+// * When a register is used as a memory pointer. its value is compared with re. If its value is
+// equal to the contents of re and the postincrement is +1, then the value in rb is copied into
+// the register after the memory access is complete. See Section 4.2.3.
+// * CPU flags go to the PSW & conditionTest() works on that (Page 3-4)
+// * Some instructions are not interruptible.
+//
+
+
+// NOTES:
+// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read
+// or write the high half (bits 16-31) of the y register (page 2-7)
+
+// The YL register is the lower half of the 32 bit Y register
+void* dsp16_device::addressYL()
+{
+ return (void*)(((UINT8*)&m_y) + 2);
+}
+
+
+// Flag getters
+bool dsp16_device::lmi()
+{
+ return m_psw & 0x8000;
+}
+
+bool dsp16_device::leq()
+{
+ return m_psw & 0x4000;
+}
+
+bool dsp16_device::llv()
+{
+ return m_psw & 0x2000;
+}
+
+bool dsp16_device::lmv()
+{
+ return m_psw & 0x1000;
+}
+
+
+void dsp16_device::writeRegister(void* reg, const UINT16 &value)
+{
+ // Make sure you're not attempting to write somewhere this function doesn't support.
+ if (reg == &m_p || reg == &m_a0 || reg == &m_a1)
+ {
+ logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc);
+ return;
+ }
+
+ if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2)
+ {
+ // 8 bit registers
+ *(UINT8*)reg = value & 0x00ff;
+ }
+ else if (reg == &m_psw)
+ {
+ // Writes to the a0 & a1 guard bits too
+ m_a0 &= U64(0x0ffffffff);
+ m_a0 |= U64(m_psw & 0x000f) << 32;
+ m_a1 &= U64(0x0ffffffff);
+ m_a1 |= U64(m_psw & 0x01e0) << 27;
+ m_psw = value;
+ }
+ else if (reg == &m_i)
+ {
+ // 12 bit register
+ m_i = value & 0x0fff;
+ }
+ else if (reg == &m_y)
+ {
+ // Y register
+ // TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register) (page 2-7)
+ m_y = (value << 16) | (m_y & 0x0000ffff);
+ }
+ else if (reg == addressYL())
+ {
+ // Yl register (Writes to yl do not change the data in the high half of y)
+ m_y = value | (m_y & 0xffff0000);
+ }
+ else
+ {
+ // Everything else
+ *(UINT16*)reg = value;
+ }
+}
+
+
+bool dsp16_device::conditionTest(const UINT8& CON)
+{
+ switch (CON)
+ {
+ case 0x00: return lmi(); // mi (negative result)
+ case 0x01: return !lmi(); // pl (positive result)
+ case 0x02: return leq(); // eq (result == 0)
+ case 0x03: return !leq(); // ne (result != 0)
+ case 0x04: return llv(); // lvs (logical overflow set)
+ case 0x05: return !llv(); // lvc (logical overflow clear)
+ case 0x06: return lmv(); // mvs (math. overflow set)
+ case 0x07: return !lmv(); // mvc (math. overflow clear)
+ case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // heads (random bit set)
+ case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // tails (random bit clear)
+ case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0ge (counter0 >= 0)*
+ case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0lt (counter0 < 0)*
+ case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1ge (counter1 >= 0)*
+ case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1lt (counter1 < 0)*
+ case 0x0e: return true; // true (always)
+ case 0x0f: return false; // false (never)
+ case 0x10: return (!lmi() && !leq()); // gt (result > 0)
+ case 0x11: return (lmi() || leq()); // le (result <= 0)
+ default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break;
+ }
+
+ // Testing each of these conditions (*) increments the respective counter being tested (page 3-5)
+
+ return false;
+}
+
+
+void* dsp16_device::registerFromRImmediateField(const UINT8& R)
+{
+ switch (R)
+ {
+ case 0x00: return (void*)&m_j;
+ case 0x01: return (void*)&m_k;
+ case 0x02: return (void*)&m_rb;
+ case 0x03: return (void*)&m_re;
+ case 0x04: return (void*)&m_r0;
+ case 0x05: return (void*)&m_r1;
+ case 0x06: return (void*)&m_r2;
+ case 0x07: return (void*)&m_r3;
+
+ default: return NULL;
+ }
+ return NULL;
+}
+
+
+void* dsp16_device::registerFromRTable(const UINT8 &R)
+{
+ switch (R)
+ {
+ case 0x00: return (void*)&m_r0;
+ case 0x01: return (void*)&m_r1;
+ case 0x02: return (void*)&m_r2;
+ case 0x03: return (void*)&m_r3;
+ case 0x04: return (void*)&m_j;
+ case 0x05: return (void*)&m_k;
+ case 0x06: return (void*)&m_rb;
+ case 0x07: return (void*)&m_re;
+ case 0x08: return (void*)&m_pt;
+ case 0x09: return (void*)&m_pr;
+ case 0x0a: return (void*)&m_pi;
+ case 0x0b: return (void*)&m_i;
+
+ case 0x10: return (void*)&m_x;
+ case 0x11: return (void*)&m_y;
+ case 0x12: return (void*)addressYL();
+ case 0x13: return (void*)&m_auc; // zero extended
+ case 0x14: return (void*)&m_psw;
+ case 0x15: return (void*)&m_c0; // sign extended
+ case 0x16: return (void*)&m_c1; // sign extended
+ case 0x17: return (void*)&m_c2; // sign extended
+ case 0x18: return (void*)&m_sioc;
+ case 0x19: return (void*)&m_srta;
+ case 0x1a: return (void*)&m_sdx;
+ case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break;
+ case 0x1c: return (void*)&m_pioc;
+ case 0x1d: return (void*)&m_pdx0;
+ case 0x1e: return (void*)&m_pdx1;
+
+ default: return NULL;
+ }
+ return NULL;
+}
+
+
+void dsp16_device::executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S)
+{
+ // TODO: I'm pretty sure we need to feed X into these as well - Double check
+
+ // Note these instructions read right-to-left, so act accordingly (page 3-6)
+ // y & p are sign extended (page 3-9)
+ // implementation details (page 3-9)
+
+ // Where is are the results going?
+ UINT64* destinationReg = NULL;
+ switch (D)
+ {
+ case 0x00: destinationReg = &m_a0; break;
+ case 0x01: destinationReg = &m_a1; break;
+ default: break;
+ }
+
+ // Which source is being used?
+ UINT64* sourceReg = NULL;
+ switch (S)
+ {
+ case 0x00: sourceReg = &m_a0; break;
+ case 0x01: sourceReg = &m_a1; break;
+ default: break;
+ }
+
+
+ // We must compute into an intermediate variable to compute flags on
+ UINT64 result = 0;
+ bool justATest = false;
+
+ switch (F1)
+ {
+ case 0x00:
+ {
+ // Ad = p p = x*y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x01:
+ {
+ // Ad = aS+p p = x*y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x02:
+ {
+ // p = x*y
+ // TODO: What happens to the flags in this operation?
+ const INT16 y = (m_y & 0xffff0000) >> 16;
+ m_p = (INT32)((INT16)m_x * y);
+ justATest = true;
+ break;
+ }
+ case 0x03:
+ {
+ // Ad = aS-p p = x*y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x04:
+ {
+ // Ad = p
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x05:
+ {
+ // Ad = aS+p
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x06:
+ {
+ // nop
+ justATest = true;
+ break;
+ }
+ case 0x07:
+ {
+ // Ad = aS-p
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x08:
+ {
+ // Ad = aS|y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x09:
+ {
+ // Ad = aS^y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x0a:
+ {
+ // aS&y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ justATest = true;
+ break;
+ }
+ case 0x0b:
+ {
+ // aS-y
+ INT64 aS = *sourceReg;
+ if (aS & U64(0x800000000))
+ aS |= U64(0xfffffff000000000);
+
+ INT64 y = (m_y & 0xffff0000) >> 16;
+ if (y & 0x8000)
+ y |= U64(0xffffffffffff0000);
+
+ result = aS-y;
+ justATest = true;
+ break;
+ }
+ case 0x0c:
+ {
+ // Ad = y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x0d:
+ {
+ // Ad = aS+y
+ INT64 aS = *sourceReg;
+ if (aS & U64(0x800000000))
+ aS |= U64(0xfffffff000000000);
+
+ INT64 y = (m_y & 0xffff0000) >> 16;
+ if (y & 0x8000)
+ y |= U64(0xffffffffffff0000);
+
+ result = aS+y;
+ break;
+ }
+ case 0x0e:
+ {
+ // Ad = aS&y
+ printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
+ break;
+ }
+ case 0x0f:
+ {
+ // Ad = aS-y
+ INT64 aS = *sourceReg;
+ if (aS & U64(0x800000000))
+ aS |= U64(0xfffffff000000000);
+
+ INT64 y = (m_y & 0xffff0000) >> 16;
+ if (y & 0x8000)
+ y |= U64(0xffffffffffff0000);
+
+ result = aS-y;
+ break;
+ }
+ }
+
+ // CPU Flags (page 3-4)
+ // LMI (logical minus)
+ if (result & U64(0x800000000))
+ m_psw |= 0x8000;
+ else
+ m_psw &= (~0x8000);
+
+ // LEQ (logical equal)
+ if (result == U64(0x000000000))
+ m_psw |= 0x4000;
+ else
+ m_psw &= (~0x4000);
+
+ // LLV (logical overflow)
+ // TODO
+
+ // LMV (mathematical overflow)
+ if ((result & U64(0xf00000000)) != U64(0xf00000000) &&
+ (result & U64(0xf00000000)) != U64(0x000000000))
+ m_psw |= 0x1000;
+ else
+ m_psw &= (~0x1000);
+
+ // If it was a real operation, make sure the data goes where it should
+ if (!justATest)
+ *destinationReg = (UINT64)result & U64(0x0000000fffffffff);
+}
+
+
+UINT16* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
+{
+ UINT16* destinationReg = NULL;
+ const UINT8 N = (Y & 0x0c) >> 2;
+ switch (N)
+ {
+ case 0x00: destinationReg = &m_r0; break;
+ case 0x01: destinationReg = &m_r1; break;
+ case 0x02: destinationReg = &m_r2; break;
+ case 0x03: destinationReg = &m_r3; break;
+ default: break;
+ }
+ return destinationReg;
+}
+
+
+void dsp16_device::executeYFieldPost(const UINT8& Y)
+{
+ UINT16* opReg = registerFromYFieldUpper(Y);
+
+ const UINT8 lower = Y & 0x03;
+ switch (lower)
+ {
+ case 0x00: /* nop */ break;
+ case 0x01: (*opReg)++; break;
+ case 0x02: (*opReg)--; break;
+ case 0x03: (*opReg) += m_j; break; // TODO: J is signed
+ }
+}
+
+
+void dsp16_device::executeZFieldPartOne(const UINT8& Z, UINT16* rN)
+{
+ const UINT8 lower = Z & 0x03;
+ switch (lower)
+ {
+ case 0x00: /* nop */ break;
+ case 0x01: (*rN)++; break;
+ case 0x02: (*rN)--; break;
+ case 0x03: (*rN) += m_j; break; // TODO: J is signed
+ }
+}
+
+
+void dsp16_device::executeZFieldPartTwo(const UINT8& Z, UINT16* rN)
+{
+ const UINT8 lower = Z & 0x03;
+ switch (lower)
+ {
+ case 0x00: (*rN)++; break;
+ case 0x01: /* nop */ break;
+ case 0x02: (*rN) += 2; break;
+ case 0x03: (*rN) += m_k; break; // TODO: K is signed
+ }
+}
+
+
+void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance)
+{
+ cycles = 1;
+ pcAdvance = 0;
+
+// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
+
+ const UINT8 opcode = (op >> 11) & 0x1f;
+ switch(opcode)
+ {
+ // Format 1: Multiply/ALU Read/Write Group
+ case 0x06:
+ {
+ DSP_LINE("3-38")
+ // F1, Y : (page 3-38)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ executeYFieldPost(Y);
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x04: case 0x1c:
+ {
+ DSP_LINE("3-40")
+ // F1 Y=a0[1] | F1 Y=a1[1] : (page 3-40)
+ const UINT8 Y = (op & 0x000f);
+ //const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ UINT16* destinationReg = registerFromYFieldUpper(Y);
+ // (page 3-18)
+ UINT16 aRegValue = 0x0000;
+ if (op & 0xc000)
+ {
+ aRegValue = (m_a0 & U64(0x0ffff0000)) >> 16;
+ }
+ else
+ {
+ aRegValue = (m_a1 & U64(0x0ffff0000)) >> 16;
+ }
+ data_write(*destinationReg, aRegValue);
+ executeYFieldPost(Y);
+ executeF1Field(F1, D, S);
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x16:
+ {
+ DSP_LINE("3-42")
+ // F1, x = Y : (page 3-42)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ UINT16* sourceReg = registerFromYFieldUpper(Y);
+ writeRegister(&m_x, data_read(*sourceReg));
+ executeYFieldPost(Y);
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x17:
+ {
+ DSP_LINE("3-44")
+ // F1, y[l] = Y : (page 3-44)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ UINT16* sourceReg = registerFromYFieldUpper(Y);
+ UINT16 sourceValue = data_read(*sourceReg);
+ switch (X)
+ {
+ case 0x00: writeRegister(addressYL(), sourceValue); break;
+ case 0x01: writeRegister(&m_y, sourceValue); break;
+ default: break;
+ }
+ executeYFieldPost(Y);
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x1f:
+ {
+ DSP_LINE("3-46")
+ // F1, y = Y, x = *pt++[i] : (page 3-46)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ UINT16* sourceRegR = registerFromYFieldUpper(Y);
+ writeRegister(&m_y, data_read(*sourceRegR));
+ executeYFieldPost(Y);
+ writeRegister(&m_x, data_read(m_pt));
+ switch (X)
+ {
+ case 0x00: m_pt++; break;
+ case 0x01: m_pt += m_i; break;
+ }
+ cycles = 2; // TODO: 1 if cached
+ pcAdvance = 1;
+ break;
+ }
+ case 0x19: case 0x1b:
+ {
+ DSP_LINE("3-48")
+ // F1, y = a0|1, x = *pt++[i] : (page 3-48)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ bool useA1 = (opcode == 0x1b);
+ if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc);
+ m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff); // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)?
+ executeF1Field(F1, D, S);
+ writeRegister(&m_x, data_read(m_pt)); // TODO: EXM Pin & internal/external ROM? Research.
+ switch (X)
+ {
+ case 0x00: m_pt++; break;
+ case 0x01: m_pt += m_i; break;
+ }
+ cycles = 2; // TODO: 1 if cached
+ pcAdvance = 1;
+ break;
+ }
+ case 0x14:
+ {
+ DSP_LINE("3-53")
+ // F1, Y = y[l] : (page 3-53)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ UINT16* destinationReg = registerFromYFieldUpper(Y);
+ UINT16 yRegValue = 0x0000;
+ switch (X)
+ {
+ case 0x00: yRegValue = (m_y & 0x0000ffff); break;
+ case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break;
+ default: break;
+ }
+ data_write(*destinationReg, yRegValue);
+ executeYFieldPost(Y);
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+
+ // Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51)
+ case 0x07:
+ {
+ DSP_LINE("3-50")
+ // F1, At[1] = Y : (page 3-50)
+ // TODO: What does the X field do here, exactly?
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 aT = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, !aT, S);
+ UINT64* destinationReg = NULL;
+ switch(aT)
+ {
+ case 0: destinationReg = &m_a1; break;
+ case 1: destinationReg = &m_a0; break;
+ default: break;
+ }
+ UINT16 sourceAddress = *(registerFromYFieldUpper(Y));
+ INT64 sourceValueSigned = (INT16)data_read(sourceAddress);
+ *destinationReg = sourceValueSigned & U64(0xffffffffff);
+ executeYFieldPost(Y);
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+
+ // Format 2: Multiply/ALU Read/Write Group
+ case 0x15:
+ {
+ DSP_LINE("3-54")
+ // F1, Z : y[l] : (page 3-54)
+ const UINT8 Z = (op & 0x000f);
+ const UINT8 X = (op & 0x0010) >> 4;
+ const UINT8 S = (op & 0x0200) >> 9;
+ const UINT8 D = (op & 0x0400) >> 10;
+ const UINT8 F1 = (op & 0x01e0) >> 5;
+ executeF1Field(F1, D, S);
+ UINT16 temp = 0x0000;
+ UINT16* rN = registerFromYFieldUpper(Z);
+ switch (X)
+ {
+ case 0x00:
+ temp = m_y & 0x0000ffff;
+ m_y &= 0xffff0000;
+ m_y |= data_read(*rN);
+ executeZFieldPartOne(Z, rN);
+ data_write(*rN, temp);
+ executeZFieldPartTwo(Z, rN);
+ break;
+ case 0x01:
+ temp = (m_y & 0xffff0000) >> 16;
+ m_y &= 0x0000ffff;
+ m_y |= (data_read(*rN) << 16);
+ executeZFieldPartOne(Z, rN);
+ data_write(*rN, temp);
+ executeZFieldPartTwo(Z, rN);
+ break;
+ }
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x1d:
+ {
+ DSP_LINE("?")
+ // F1, Z : y, x=*pt++[i]
+ //const UINT8 Z = (op & 0x000f);
+ //const UINT8 X = (op & 0x0010) >> 4;
+ //const UINT8 S = (op & 0x0200) >> 9;
+ //const UINT8 D = (op & 0x0400) >> 10;
+ //const UINT8 F1 = (op & 0x01e0) >> 5;
+ break;
+ }
+
+ // Format 2a: Multiply/ALU Read/Write Group
+ case 0x05:
+ {
+ DSP_LINE("?")
+ // F1, Z : aT[1]
+ //const UINT8 Z = (op & 0x000f);
+ //const UINT8 X = (op & 0x0010) >> 4;
+ //const UINT8 S = (op & 0x0200) >> 9;
+ //const UINT8 aT = (op & 0x0400) >> 10;
+ //const UINT8 F1 = (op & 0x01e0) >> 5;
+ break;
+ }
+
+ // Format 3: Special Functions
+ case 0x12:
+ case 0x13:
+ {
+ DSP_LINE("3-36")
+ // if|ifc CON F2 (page 3-36)
+ const UINT8 CON = (op & 0x001f);
+ //const UINT8 S = (op & 0x0200) >> 9;
+ //const UINT8 D = (op & 0x0400) >> 10;
+ //const UINT8 F2 = (op & 0x01e0) >> 5;
+ bool conditionFulfilled = conditionTest(CON);
+ if (conditionFulfilled)
+ {
+ printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
+ }
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+
+ // Format 4: Branch Direct Group
+ case 0x00: case 0x01:
+ {
+ DSP_LINE("3-20")
+ // goto JA : (page 3-20) (DONE)
+ const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
+ m_pc = JA;
+ cycles = 2;
+ pcAdvance = 0;
+ break;
+ }
+
+ case 0x10: case 0x11:
+ {
+ DSP_LINE("3-23")
+ // call JA : (page 3-23)
+ const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
+ m_pr = m_pc + 1;
+ m_pc = JA;
+ cycles = 2;
+ pcAdvance = 0;
+ break;
+ }
+
+ // Format 5: Branch Indirect Group
+ case 0x18:
+ {
+ DSP_LINE("3-21")
+ // goto B : (page 3-21)
+ const UINT8 B = (op & 0x0700) >> 8;
+ switch (B)
+ {
+ case 0x00: m_pc = m_pr; break;
+ case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
+ case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
+ case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
+ default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break;
+ }
+ cycles = 2;
+ pcAdvance = 0;
+ break;
+ }
+
+ // Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
+ case 0x1a:
+ {
+ DSP_LINE("3-22")
+ // if CON [goto/call/return] : (page 3-22)
+ const UINT8 CON = (op & 0x001f);
+ bool conditionFulfilled = conditionTest(CON);
+ cycles = 3; // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3?
+ pcAdvance = 1;
+ if (!conditionFulfilled)
+ {
+ pcAdvance = 2;
+ }
+ break;
+ }
+
+ // Format 7: Data Move Group
+ case 0x09: case 0x0b:
+ {
+ DSP_LINE("3-29")
+ // R = aS : (page 3-29)
+ // TODO: Fix register pdxX (pc=338)
+ const UINT8 R = (op & 0x03f0) >> 4;
+ const UINT8 S = (op & 0x1000) >> 12;
+ void* destinationReg = registerFromRTable(R);
+ UINT64* sourceReg = (S) ? &m_a1 : &m_a0;
+ UINT16 sourceValue = (*sourceReg & U64(0x0ffff0000)) >> 16;
+ writeRegister(destinationReg, sourceValue);
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x08:
+ {
+ DSP_LINE("3-30")
+ // aT = R : (page 3-30)
+ const UINT8 R = (op & 0x03f0) >> 4;
+ const UINT8 aT = (op & 0x0400) >> 10;
+ UINT64* destinationReg = NULL;
+ switch(aT)
+ {
+ case 0: destinationReg = &m_a1; break;
+ case 1: destinationReg = &m_a0; break;
+ default: break;
+ }
+ void* sourceReg = registerFromRTable(R);
+ *destinationReg &= U64(0x00000ffff);
+ *destinationReg |= (*(UINT16*)sourceReg) << 16; // TODO: Fix for all registers
+ if (*(UINT16*)sourceReg & 0x8000)
+ *destinationReg |= U64(0xf00000000);
+ // TODO: Special function encoding
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x0f:
+ {
+ DSP_LINE("3-32")
+ // R = Y : (page 3-32)
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 R = (op & 0x03f0) >> 4;
+ UINT16* sourceReg = registerFromYFieldUpper(Y);
+ void* destinationReg = registerFromRTable(R);
+ writeRegister(destinationReg, data_read(*sourceReg));
+ executeYFieldPost(Y);
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x0c:
+ {
+ DSP_LINE("3-33")
+ // Y = R : (page 3-33)
+ // TODO: Zero & Sign extend i, c0, c1, c2, and auc
+ const UINT8 Y = (op & 0x000f);
+ const UINT8 R = (op & 0x03f0) >> 4;
+ UINT16* destinationReg = registerFromYFieldUpper(Y);
+ UINT16* sourceReg = (UINT16*)registerFromRTable(R); // TODO: This won't work for certain registers!
+ data_write(*destinationReg, *sourceReg); // Fix in data_write() maybe?
+ executeYFieldPost(Y);
+ cycles = 2;
+ pcAdvance = 1;
+ break;
+ }
+ case 0x0d:
+ {
+ DSP_LINE("?")
+ // Z : R
+ //const UINT8 Z = (op & 0x000f);
+ //const UINT8 R = (op & 0x03f0) >> 4;
+ break;
+ }
+
+ // Format 8: Data Move (immediate operand - 2 words)
+ case 0x0a:
+ {
+ DSP_LINE("3-28")
+ // R = N : (page 3-28) (DONE)
+ // NOTE: The docs speak of register sources & sign extension, but this is a register
+ // destination, so, typo? If so, what does one do with the overflow bits?
+ const UINT8 R = (op & 0x03f0) >> 4;
+ const UINT16 iVal = opcode_read(1);
+ void* destinationReg = registerFromRTable(R);
+ writeRegister(destinationReg, iVal);
+ cycles = 2;
+ pcAdvance = 2;
+ break;
+ }
+
+ // Format 9: Short Immediate Group
+ case 0x02: case 0x03:
+ {
+ DSP_LINE("3-27")
+ // R = M : (page 3-27)
+ // TODO: Figure out notes about the DSP16A vs the DSP16. 9 bit is very DSP16...
+ const UINT16 M = (op & 0x01ff);
+ const UINT8 R = (op & 0x0e00) >> 9;
+ void* destinationReg = registerFromRImmediateField(R);
+ // Sign extend if the destination is j or k
+ UINT16 mValue = M;
+ if (destinationReg == &m_j || destinationReg == &m_k)
+ {
+ if (mValue & 0x0100) mValue |= 0xfe00;
+ }
+ writeRegister(destinationReg, mValue);
+ cycles = 1;
+ pcAdvance = 1;
+ break;
+ }
+
+ // Format 10: do - redo
+ case 0x0e:
+ {
+ DSP_LINE("3-25/3-26")
+ // do|redo K : (pages 3-25 & 3-26)
+ // TODO: The timings are intricate to say the least...
+ const UINT8 K = (op & 0x007f);
+ const UINT8 NI = (op & 0x0780) >> 7;
+ if (NI != 0)
+ {
+ // Do
+ m_cacheStart = m_pc + 1;
+ m_cacheEnd = m_pc + 1 + NI;
+ m_cacheIterations = K-1; // -1 because we check the counter @ the end
+ cycles = 1;
+ pcAdvance = 1;
+ }
+ else
+ {
+ // Redo
+ m_cacheIterations = K-1; // -1 because we check the counter @ the end
+ m_cacheRedoNextPC = m_pc + 1;
+ m_pc = m_cacheStart;
+ cycles = 2;
+ pcAdvance = 0;
+ }
+ break;
+ }
+
+ // RESERVED
+ case 0x1e:
+ {
+ DSP_LINE("XXX")
+ break;
+ }
+
+ // UNKNOWN
+ default:
+ {
+ DSP_LINE("XXX")
+ break;
+ }
+ }
+
+ // Handle end-of-cache conditions for do|redos
+ if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID)
+ {
+ // You've reached the end of a cache loop after a redo opcode.
+ m_pc = m_cacheRedoNextPC;
+ m_cacheRedoNextPC = CACHE_INVALID;
+ pcAdvance = 0;
+ }
+ if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd))
+ {
+ // A regular iteration on a cached loop.
+ m_cacheIterations--;
+ m_pc = m_cacheStart;
+ pcAdvance = 0;
+ }
+}