summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/dsp16/dsp16ops.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/dsp16/dsp16ops.hxx')
-rw-r--r--src/devices/cpu/dsp16/dsp16ops.hxx937
1 files changed, 0 insertions, 937 deletions
diff --git a/src/devices/cpu/dsp16/dsp16ops.hxx b/src/devices/cpu/dsp16/dsp16ops.hxx
deleted file mode 100644
index ab54a577fef..00000000000
--- a/src/devices/cpu/dsp16/dsp16ops.hxx
+++ /dev/null
@@ -1,937 +0,0 @@
-// 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_t*)&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_t &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_t*)reg = value & 0x00ff;
- }
- else if (reg == &m_psw)
- {
- // Writes to the a0 & a1 guard bits too
- m_a0 &= 0x0ffffffffU;
- m_a0 |= u64(m_psw & 0x000fU) << 32;
- m_a1 &= 0x0ffffffffU;
- m_a1 |= u64(m_psw & 0x01e0U) << 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_t*)reg = value;
- }
-}
-
-
-bool dsp16_device::conditionTest(const uint8_t& 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_t& 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 nullptr;
- }
- return nullptr;
-}
-
-
-void* dsp16_device::registerFromRTable(const uint8_t &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 nullptr;
- }
- return nullptr;
-}
-
-
-void dsp16_device::executeF1Field(const uint8_t& F1, const uint8_t& D, const uint8_t& 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_t* destinationReg = nullptr;
- switch (D)
- {
- case 0x00: destinationReg = &m_a0; break;
- case 0x01: destinationReg = &m_a1; break;
- default: break;
- }
-
- // Which source is being used?
- uint64_t* sourceReg = nullptr;
- 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_t 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_t y = (m_y & 0xffff0000) >> 16;
- m_p = (int32_t)((int16_t)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_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- 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_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- 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_t aS = *sourceReg;
- if (aS & 0x800000000U)
- aS |= 0xfffffff000000000U;
-
- int64_t y = (m_y & 0xffff0000) >> 16;
- if (y & 0x8000)
- y |= 0xffffffffffff0000U;
-
- result = aS-y;
- break;
- }
- }
-
- // CPU Flags (page 3-4)
- // LMI (logical minus)
- if (result & 0x800000000U)
- m_psw |= 0x8000;
- else
- m_psw &= (~0x8000);
-
- // LEQ (logical equal)
- if (result == 0x000000000U)
- m_psw |= 0x4000;
- else
- m_psw &= (~0x4000);
-
- // LLV (logical overflow)
- // TODO
-
- // LMV (mathematical overflow)
- if ((result & 0xf00000000U) != 0xf00000000U &&
- (result & 0xf00000000U) != 0x000000000U)
- 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_t)result & 0x0000000fffffffffU;
-}
-
-
-uint16_t* dsp16_device::registerFromYFieldUpper(const uint8_t& Y)
-{
- uint16_t* destinationReg = nullptr;
- const uint8_t 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_t& Y)
-{
- uint16_t* opReg = registerFromYFieldUpper(Y);
-
- const uint8_t 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_t& Z, uint16_t* rN)
-{
- const uint8_t 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_t& Z, uint16_t* rN)
-{
- const uint8_t 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_t& op, uint8_t& cycles, uint8_t& pcAdvance)
-{
- cycles = 1;
- pcAdvance = 0;
-
-// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
-
- const uint8_t 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_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t 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_t Y = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- // (page 3-18)
- uint16_t aRegValue = 0x0000;
- if (op & 0xc000)
- {
- aRegValue = (m_a0 & 0x0ffff0000U) >> 16;
- }
- else
- {
- aRegValue = (m_a1 & 0x0ffff0000U) >> 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_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* 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_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* sourceReg = registerFromYFieldUpper(Y);
- uint16_t 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_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* 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_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t 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_t Y = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- uint16_t 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_t Y = (op & 0x000f);
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t aT = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, !aT, S);
- uint64_t* destinationReg = nullptr;
- switch(aT)
- {
- case 0: destinationReg = &m_a1; break;
- case 1: destinationReg = &m_a0; break;
- default: break;
- }
- uint16_t sourceAddress = *(registerFromYFieldUpper(Y));
- int64_t sourceValueSigned = (int16_t)data_read(sourceAddress);
- *destinationReg = sourceValueSigned & 0xffffffffffU;
- 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_t Z = (op & 0x000f);
- const uint8_t X = (op & 0x0010) >> 4;
- const uint8_t S = (op & 0x0200) >> 9;
- const uint8_t D = (op & 0x0400) >> 10;
- const uint8_t F1 = (op & 0x01e0) >> 5;
- executeF1Field(F1, D, S);
- uint16_t temp = 0x0000;
- uint16_t* 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_t Z = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t D = (op & 0x0400) >> 10;
- //const uint8_t F1 = (op & 0x01e0) >> 5;
- break;
- }
-
- // Format 2a: Multiply/ALU Read/Write Group
- case 0x05:
- {
- DSP_LINE("?")
- // F1, Z : aT[1]
- //const uint8_t Z = (op & 0x000f);
- //const uint8_t X = (op & 0x0010) >> 4;
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t aT = (op & 0x0400) >> 10;
- //const uint8_t 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_t CON = (op & 0x001f);
- //const uint8_t S = (op & 0x0200) >> 9;
- //const uint8_t D = (op & 0x0400) >> 10;
- //const uint8_t 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_t 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_t 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_t 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_t 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_t R = (op & 0x03f0) >> 4;
- const uint8_t S = (op & 0x1000) >> 12;
- void* destinationReg = registerFromRTable(R);
- uint64_t* sourceReg = (S) ? &m_a1 : &m_a0;
- uint16_t sourceValue = (*sourceReg & 0x0ffff0000U) >> 16;
- writeRegister(destinationReg, sourceValue);
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x08:
- {
- DSP_LINE("3-30")
- // aT = R : (page 3-30)
- const uint8_t R = (op & 0x03f0) >> 4;
- const uint8_t aT = (op & 0x0400) >> 10;
- uint64_t* destinationReg = nullptr;
- switch(aT)
- {
- case 0: destinationReg = &m_a1; break;
- case 1: destinationReg = &m_a0; break;
- default: break;
- }
- void* sourceReg = registerFromRTable(R);
- *destinationReg &= 0x00000ffffU;
- *destinationReg |= (*(uint16_t*)sourceReg) << 16; // TODO: Fix for all registers
- if (*(uint16_t*)sourceReg & 0x8000)
- *destinationReg |= 0xf00000000U;
- // TODO: Special function encoding
- cycles = 2;
- pcAdvance = 1;
- break;
- }
- case 0x0f:
- {
- DSP_LINE("3-32")
- // R = Y : (page 3-32)
- const uint8_t Y = (op & 0x000f);
- const uint8_t R = (op & 0x03f0) >> 4;
- uint16_t* 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_t Y = (op & 0x000f);
- const uint8_t R = (op & 0x03f0) >> 4;
- uint16_t* destinationReg = registerFromYFieldUpper(Y);
- uint16_t* sourceReg = (uint16_t*)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_t Z = (op & 0x000f);
- //const uint8_t 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_t R = (op & 0x03f0) >> 4;
- const uint16_t 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_t M = (op & 0x01ff);
- const uint8_t R = (op & 0x0e00) >> 9;
- void* destinationReg = registerFromRImmediateField(R);
- // Sign extend if the destination is j or k
- uint16_t 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_t K = (op & 0x007f);
- const uint8_t 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;
- }
-}