diff options
Diffstat (limited to 'src/devices/cpu/dsp16/dsp16ops.inc')
-rw-r--r-- | src/devices/cpu/dsp16/dsp16ops.inc | 937 |
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; + } +} |