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