DSP16 improvements. [Andrew Gardner]

- Fixed R=M disassembly
 - Added flag formatting
 - Shadow register is hooked up
 - Opcode & flag fixes
This commit is contained in:
Andrew Gardner 2013-06-26 15:47:18 +00:00
parent 61ffaec76e
commit 6c9a29c27f
4 changed files with 460 additions and 118 deletions

View File

@ -14,7 +14,11 @@
// TODO:
// * Store the cache in 15 unique memory locations as it is on-chip.
// * Modify cycle counts when running from within the cache
//
// * A write to PI resets the pseudoramdom sequence generator) (page 2-4)
// * Handle virtual shift addressing using RB & RE (when RE is enabled) (page 2-6)
// * The ALU sign-extends 32-bit operands from y or p to 36 bits and produces a 36-bit output
// * Interrupt lines (page 2-15)
//
//**************************************************************************
// DEVICE INTERFACE
@ -104,15 +108,15 @@ void dsp16_device::device_start()
state_add(DSP16_P, "P", m_p);
state_add(DSP16_A0, "A0", m_a0).mask(U64(0xfffffffff));
state_add(DSP16_A1, "A1", m_a1).mask(U64(0xfffffffff));
state_add(DSP16_AUC, "AUC", m_auc); //.formatstr("%6s");
state_add(DSP16_PSW, "PSW", m_psw); //.formatstr("%16s");
state_add(DSP16_AUC, "AUC", m_auc).formatstr("%8s");
state_add(DSP16_PSW, "PSW", m_psw).formatstr("%16s");
state_add(DSP16_C0, "C0", m_c0);
state_add(DSP16_C1, "C1", m_c1);
state_add(DSP16_C2, "C2", m_c2);
state_add(DSP16_SIOC, "SIOC", m_sioc).formatstr("%16s");
state_add(DSP16_SIOC, "SIOC", m_sioc).formatstr("%10s");
state_add(DSP16_SRTA, "SRTA", m_srta);
state_add(DSP16_SDX, "SDX", m_sdx);
state_add(DSP16_PIOC, "PIOC", m_pioc);
state_add(DSP16_PIOC, "PIOC", m_pioc).formatstr("%16s");
state_add(DSP16_PDX0, "PDX0", m_pdx0);
state_add(DSP16_PDX1, "PDX1", m_pdx1);
@ -170,12 +174,15 @@ void dsp16_device::device_reset()
{
// Page 7-5
m_pc = 0x0000;
m_sioc = 0x0000;
m_pi = 0x0000;
m_sioc = 0x0000; // (page 5-4)
// SRTA is unaltered by reset
m_pioc = 0x0008;
m_rb = 0x0000;
m_re = 0x0000;
// AUC is not affected by reset
// AUC is not affected by reset
m_ppc = m_pc;
// Hacky cache emulation.
@ -195,8 +202,8 @@ void dsp16_device::device_reset()
const address_space_config *dsp16_device::memory_space_config(address_spacenum spacenum) const
{
return (spacenum == AS_PROGRAM) ? &m_program_config :
(spacenum == AS_DATA) ? &m_data_config :
NULL;
(spacenum == AS_DATA) ? &m_data_config :
NULL;
}
@ -213,10 +220,101 @@ void dsp16_device::state_string_export(const device_state_entry &entry, astring
string.printf("(below)");
break;
case DSP16_AUC:
{
astring alignString;
const UINT8 align = m_auc & 0x03;
switch (align)
{
case 0x00: alignString.printf("xy"); break;
case 0x01: alignString.printf("/4"); break;
case 0x02: alignString.printf("x4"); break;
case 0x03: alignString.printf(",,"); break;
}
string.printf("%c%c%c%c%c%s",
m_auc & 0x40 ? 'Y':'.',
m_auc & 0x20 ? '1':'.',
m_auc & 0x10 ? '0':'.',
m_auc & 0x08 ? '1':'.',
m_auc & 0x04 ? '0':'.',
alignString.cstr());
break;
}
case DSP16_PSW:
string.printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
m_psw & 0x8000 ? 'M':'.',
m_psw & 0x4000 ? 'E':'.',
m_psw & 0x2000 ? 'L':'.',
m_psw & 0x1000 ? 'V':'.',
m_psw & 0x0800 ? ',':',',
m_psw & 0x0400 ? ',':',',
m_psw & 0x0200 ? 'O':'.',
m_psw & 0x0100 ? '1':'.',
m_psw & 0x0080 ? '1':'.',
m_psw & 0x0040 ? '1':'.',
m_psw & 0x0020 ? '1':'.',
m_psw & 0x0010 ? 'O':'.',
m_psw & 0x0008 ? '1':'.',
m_psw & 0x0004 ? '1':'.',
m_psw & 0x0002 ? '1':'.',
m_psw & 0x0001 ? '1':'.');
break;
case DSP16_PIOC:
{
astring strobeString;
const UINT8 strobe = (m_pioc & 0x6000) >> 13;
switch (strobe)
{
case 0x00: strobeString.printf("1T"); break;
case 0x01: strobeString.printf("2T"); break;
case 0x02: strobeString.printf("3T"); break;
case 0x03: strobeString.printf("4T"); break;
}
string.printf("%c%s%c%c%c%c%c%c%c%c%c%c%c%c%c",
m_pioc & 0x8000 ? 'I':'.',
strobeString.cstr(),
m_pioc & 0x1000 ? 'O':'I',
m_pioc & 0x0800 ? 'O':'I',
m_pioc & 0x0400 ? 'S':'.',
m_pioc & 0x0200 ? 'I':'.',
m_pioc & 0x0100 ? 'O':'.',
m_pioc & 0x0080 ? 'P':'.',
m_pioc & 0x0040 ? 'P':'.',
m_pioc & 0x0020 ? 'I':'.',
m_pioc & 0x0010 ? 'I':'.',
m_pioc & 0x0008 ? 'O':'.',
m_pioc & 0x0004 ? 'P':'.',
m_pioc & 0x0002 ? 'P':'.',
m_pioc & 0x0001 ? 'I':'.');
break;
}
// Placeholder for a better view later (TODO)
case DSP16_SIOC:
string.printf("%04x", *(UINT16*)entry.dataptr());
break;
{
astring clkString;
const UINT8 clk = (m_sioc & 0x0180) >> 7;
switch (clk)
{
case 0x00: clkString.printf("/4"); break;
case 0x01: clkString.printf("12"); break;
case 0x02: clkString.printf("16"); break;
case 0x03: clkString.printf("20"); break;
}
string.printf("%c%s%c%c%c%c%c%c%c",
m_sioc & 0x0200 ? 'I':'O',
clkString.cstr(),
m_sioc & 0x0040 ? 'L':'M',
m_sioc & 0x0020 ? 'I':'O',
m_sioc & 0x0010 ? 'I':'O',
m_sioc & 0x0008 ? 'I':'O',
m_sioc & 0x0004 ? 'I':'O',
m_sioc & 0x0002 ? '2':'1',
m_sioc & 0x0001 ? '2':'1');
break;
}
}
}
@ -343,6 +441,10 @@ void dsp16_device::execute_run()
m_pc += pcAdvance;
m_icount -= cycles;
// The 16 bit PI "shadow" register gets set to PC on each instruction except
// when an interrupt service routine is active (TODO: Interrupt check) (page 2-4)
m_pi = m_pc;
} while (m_icount > 0);
}

View File

@ -54,22 +54,24 @@ protected:
const address_space_config m_data_config;
// CPU registers
// ROM Address Arithmetic Unit (XAAU)
// ROM Address Arithmetic Unit (XAAU) (page 2-4)
UINT16 m_i; // 12 bits
UINT16 m_pc;
UINT16 m_pt;
UINT16 m_pr;
UINT16 m_pi;
// RAM Address Arithmetic Unit (YAAU)
UINT16 m_j;
UINT16 m_k;
// RAM Address Arithmetic Unit (YAAU) (page 2-6)
UINT16 m_j; // Signed
UINT16 m_k; // Signed
UINT16 m_rb;
UINT16 m_re;
UINT16 m_r0;
UINT16 m_r1;
UINT16 m_r2;
UINT16 m_r3;
// Data Arithmetic Unit (DAU)
// Data Arithmetic Unit (DAU) (page 2-6)
UINT16 m_x;
UINT32 m_y;
UINT32 m_p;
@ -80,19 +82,20 @@ protected:
UINT8 m_c0;
UINT8 m_c1;
UINT8 m_c2;
// Serial and parallel interfaces
// Serial and parallel interfaces (TODO: More here (page 2-13))
UINT16 m_sioc;
UINT16 m_srta;
UINT16 m_sdx;
UINT16 m_pioc;
UINT16 m_pdx0; // pdx0 & pdx1 refer to the same physical register (page 6-1)
UINT16 m_pdx1; // but we keep them seperate for logic's sake.
UINT16 m_pdx1; // but we keep them seperate for logic's sake.
// internal stuff
UINT16 m_ppc;
// This core handles the cache as more of a loop than 15 seperate memory elements.
// It's a bit of a hack, but it's easier this way.
// This CPU core handles the cache as more of a loop than 15 seperate memory elements.
// It's a bit of a hack, but it's easier this way (for now).
UINT16 m_cacheStart;
UINT16 m_cacheEnd;
UINT16 m_cacheRedoNextPC;
@ -118,7 +121,7 @@ protected:
// table decoders
void* registerFromRImmediateField(const UINT8& R);
void* registerFromRTable(const UINT8& R);
void* registerFromYFieldUpper(const UINT8& Y);
UINT16* registerFromYFieldUpper(const UINT8& Y);
// execution
void executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S);
@ -130,6 +133,12 @@ protected:
void* addressYL();
void writeRegister(void* reg, const UINT16& value);
bool conditionTest(const UINT8& CON);
// flags
bool lmi();
bool leq();
bool llv();
bool lmv();
};

View File

@ -535,10 +535,10 @@ CPU_DISASSEMBLE( dsp16a )
case 0x02: case 0x03:
{
// R = M
const UINT8 M = (op & 0x00ff);
const UINT8 R = (op & 0x0e00) >> 9;
const UINT16 M = (op & 0x01ff);
const UINT8 R = (op & 0x0e00) >> 9;
astring rString = disasmRImmediateField(R);
sprintf(buffer, "%s = 0x%02x", rString.cstr(), M);
sprintf(buffer, "%s = 0x%04x", rString.cstr(), M);
break;
}

View File

@ -1,5 +1,23 @@
#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()
@ -8,6 +26,28 @@ void* dsp16_device::addressYL()
}
// 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.
@ -22,6 +62,15 @@ void dsp16_device::writeRegister(void* reg, const UINT16 &value)
// 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
@ -29,12 +78,13 @@ void dsp16_device::writeRegister(void* reg, const UINT16 &value)
}
else if (reg == &m_y)
{
// Y register [[TODO - check a flag to see if clearing yl is necessary]]
// 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
// Yl register (Writes to yl do not change the data in the high half of y)
m_y = value | (m_y & 0xffff0000);
}
else
@ -49,26 +99,29 @@ bool dsp16_device::conditionTest(const UINT8& CON)
{
switch (CON)
{
case 0x00: return (m_psw & 0x8000); // mi (negative result)
case 0x01: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // pl (positive result)
case 0x02: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // eq (result == 0)
case 0x03: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // ne (result != 0)
case 0x04: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // lvs (logical overflow set)
case 0x05: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // lvc (logical overflow clear)
case 0x06: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // mvs (math. overflow set)
case 0x07: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // mvc (math. overflow clear)
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: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // true (always)
case 0x0f: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // false (never)
case 0x10: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // gt (result > 0
case 0x11: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // le (result <= 0)
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;
}
@ -120,7 +173,7 @@ void* dsp16_device::registerFromRTable(const UINT8 &R)
case 0x18: return (void*)&m_sioc;
case 0x19: return (void*)&m_srta;
case 0x1a: return (void*)&m_sdx;
//case 0x1b: return (void*)&m_tdms;
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;
@ -133,47 +186,194 @@ void* dsp16_device::registerFromRTable(const UINT8 &R)
void dsp16_device::executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S)
{
// Where is the first operation being written?
//UINT64* destinationReg = NULL;
//switch (D)
//{
// case 0x00: destinationReg = &m_a0;
// case 0x01: destinationReg = &m_a1;
// default: break;
//}
// 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;
// case 0x01: sourceReg = &m_a1;
// default: break;
//}
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: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x01: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x02: m_p = (INT32)((INT16)m_x * (INT16)((m_y & 0xffff0000) >> 16)); break;
case 0x03: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x04: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x05: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x06: /* nop */ break;
case 0x07: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x08: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x09: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0a: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0b: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0c: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0d: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0e: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
case 0x0f: printf("UNIMPLEMENTED F1 operation @ PC 0x%04x\n", m_pc); break;
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);
}
void* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
UINT16* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
{
UINT16* destinationReg = NULL;
const UINT8 N = (Y & 0x0c) >> 2;
@ -191,16 +391,7 @@ void* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
void dsp16_device::executeYFieldPost(const UINT8& Y)
{
UINT16* opReg = NULL;
const UINT8 N = (Y & 0x0c) >> 2;
switch (N)
{
case 0x00: opReg = &m_r0; break;
case 0x01: opReg = &m_r1; break;
case 0x02: opReg = &m_r2; break;
case 0x03: opReg = &m_r3; break;
default: break;
}
UINT16* opReg = registerFromYFieldUpper(Y);
const UINT8 lower = Y & 0x03;
switch (lower)
@ -208,7 +399,7 @@ void dsp16_device::executeYFieldPost(const UINT8& Y)
case 0x00: /* nop */ break;
case 0x01: (*opReg)++; break;
case 0x02: (*opReg)--; break;
case 0x03: (*opReg) += m_j; break;
case 0x03: (*opReg) += m_j; break; // TODO: J is signed
}
}
@ -221,7 +412,7 @@ void dsp16_device::executeZFieldPartOne(const UINT8& Z, UINT16* rN)
case 0x00: /* nop */ break;
case 0x01: (*rN)++; break;
case 0x02: (*rN)--; break;
case 0x03: (*rN) += m_j; break;
case 0x03: (*rN) += m_j; break; // TODO: J is signed
}
}
@ -234,7 +425,7 @@ void dsp16_device::executeZFieldPartTwo(const UINT8& Z, UINT16* rN)
case 0x00: (*rN)++; break;
case 0x01: /* nop */ break;
case 0x02: (*rN) += 2; break;
case 0x03: (*rN) += m_k; break;
case 0x03: (*rN) += m_k; break; // TODO: K is signed
}
}
@ -244,12 +435,15 @@ 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;
@ -263,21 +457,23 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
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 X = (op & 0x0010) >> 4;
const UINT8 S = (op & 0x0200) >> 9;
const UINT8 D = (op & 0x0400) >> 10;
const UINT8 F1 = (op & 0x01e0) >> 5;
UINT16* destinationReg = (UINT16*)registerFromYFieldUpper(Y);
UINT16* destinationReg = registerFromYFieldUpper(Y);
// (page 3-18)
UINT16 aRegValue = 0x0000;
if (op & 0xc000)
{
aRegValue = (X) ? (m_a0 & 0x0ffff0000) >> 16 : m_a0 & 0x00000ffff;
aRegValue = (m_a0 & U64(0x0ffff0000)) >> 16;
}
else
{
aRegValue = (X) ? (m_a1 & 0x0ffff0000) >> 16 : m_a1 & 0x00000ffff;
aRegValue = (m_a1 & U64(0x0ffff0000)) >> 16;
}
data_write(*destinationReg, aRegValue);
executeYFieldPost(Y);
@ -288,13 +484,14 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
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 = (UINT16*)registerFromYFieldUpper(Y);
UINT16* sourceReg = registerFromYFieldUpper(Y);
writeRegister(&m_x, data_read(*sourceReg));
executeYFieldPost(Y);
cycles = 1;
@ -303,6 +500,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x17:
{
DSP_LINE("3-44")
// F1, y[l] = Y : (page 3-44)
const UINT8 Y = (op & 0x000f);
const UINT8 X = (op & 0x0010) >> 4;
@ -310,7 +508,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
const UINT8 D = (op & 0x0400) >> 10;
const UINT8 F1 = (op & 0x01e0) >> 5;
executeF1Field(F1, D, S);
UINT16* sourceReg = (UINT16*)registerFromYFieldUpper(Y);
UINT16* sourceReg = registerFromYFieldUpper(Y);
UINT16 sourceValue = data_read(*sourceReg);
switch (X)
{
@ -325,6 +523,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
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;
@ -332,7 +531,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
const UINT8 D = (op & 0x0400) >> 10;
const UINT8 F1 = (op & 0x01e0) >> 5;
executeF1Field(F1, D, S);
UINT16* sourceRegR = (UINT16*)registerFromYFieldUpper(Y);
UINT16* sourceRegR = registerFromYFieldUpper(Y);
writeRegister(&m_y, data_read(*sourceRegR));
executeYFieldPost(Y);
writeRegister(&m_x, data_read(m_pt));
@ -347,6 +546,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
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;
@ -369,14 +569,15 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x14:
{
// F1, Y = y[1] : (page 3-53)
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 = (UINT16*)registerFromYFieldUpper(Y);
UINT16* destinationReg = registerFromYFieldUpper(Y);
UINT16 yRegValue = 0x0000;
switch (X)
{
@ -394,7 +595,9 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// 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;
@ -407,7 +610,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
case 1: destinationReg = &m_a0; break;
default: break;
}
UINT16 sourceAddress = *((UINT16*)registerFromYFieldUpper(Y));
UINT16 sourceAddress = *(registerFromYFieldUpper(Y));
INT64 sourceValueSigned = (INT16)data_read(sourceAddress);
*destinationReg = sourceValueSigned & U64(0xffffffffff);
executeYFieldPost(Y);
@ -419,7 +622,8 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 2: Multiply/ALU Read/Write Group
case 0x15:
{
// F1, Z : y[1] : (page 3-54)
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;
@ -427,7 +631,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
const UINT8 F1 = (op & 0x01e0) >> 5;
executeF1Field(F1, D, S);
UINT16 temp = 0x0000;
UINT16* rN = (UINT16*)registerFromYFieldUpper(Z);
UINT16* rN = registerFromYFieldUpper(Z);
switch (X)
{
case 0x00:
@ -453,6 +657,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x1d:
{
DSP_LINE("?")
// F1, Z : y, x=*pt++[i]
//const UINT8 Z = (op & 0x000f);
//const UINT8 X = (op & 0x0010) >> 4;
@ -465,6 +670,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// 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;
@ -478,7 +684,8 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
case 0x12:
case 0x13:
{
// if|ifc CON F2
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;
@ -486,7 +693,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
bool conditionFulfilled = conditionTest(CON);
if (conditionFulfilled)
{
printf("Fulfilled condition not yet implemented @ PC=0x%04x", m_pc);
printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
}
cycles = 1;
pcAdvance = 1;
@ -496,7 +703,8 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 4: Branch Direct Group
case 0x00: case 0x01:
{
// goto JA : (page 3-20)
DSP_LINE("3-20")
// goto JA : (page 3-20) (DONE)
const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
m_pc = JA;
cycles = 2;
@ -506,6 +714,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
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;
@ -518,6 +727,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 5: Branch Indirect Group
case 0x18:
{
DSP_LINE("3-21")
// goto B : (page 3-21)
const UINT8 B = (op & 0x0700) >> 8;
switch (B)
@ -536,6 +746,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// 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);
@ -551,8 +762,9 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 7: Data Move Group
case 0x09: case 0x0b:
{
// TODO: Fix register pdxX (pc=338)
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);
@ -565,6 +777,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x08:
{
DSP_LINE("3-30")
// aT = R : (page 3-30)
const UINT8 R = (op & 0x03f0) >> 4;
const UINT8 aT = (op & 0x0400) >> 10;
@ -587,10 +800,11 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x0f:
{
DSP_LINE("3-32")
// R = Y : (page 3-32)
const UINT8 Y = (op & 0x000f);
const UINT8 R = (op & 0x03f0) >> 4;
UINT16* sourceReg = (UINT16*)registerFromYFieldUpper(Y);
UINT16* sourceReg = registerFromYFieldUpper(Y);
void* destinationReg = registerFromRTable(R);
writeRegister(destinationReg, data_read(*sourceReg));
executeYFieldPost(Y);
@ -600,12 +814,14 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
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 = (UINT16*)registerFromYFieldUpper(Y);
UINT16* sourceReg = (UINT16*)registerFromRTable(R);
data_write(*destinationReg, *sourceReg);
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;
@ -613,6 +829,7 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
}
case 0x0d:
{
DSP_LINE("?")
// Z : R
//const UINT8 Z = (op & 0x000f);
//const UINT8 R = (op & 0x03f0) >> 4;
@ -622,11 +839,14 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 8: Data Move (immediate operand - 2 words)
case 0x0a:
{
// R = N : (page 3-28)
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* reg = registerFromRTable(R);
writeRegister(reg, iVal);
void* destinationReg = registerFromRTable(R);
writeRegister(destinationReg, iVal);
cycles = 2;
pcAdvance = 2;
break;
@ -635,11 +855,19 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// Format 9: Short Immediate Group
case 0x02: case 0x03:
{
DSP_LINE("3-27")
// R = M : (page 3-27)
const INT8 M = (op & 0x00ff);
const UINT8 R = (op & 0x0e00) >> 9;
void* reg = registerFromRImmediateField(R);
writeRegister(reg, (INT16)M); // Sign extend 8 bit int
// 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;
@ -648,14 +876,16 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// 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 + NI + 1;
m_cacheEnd = m_pc + 1 + NI;
m_cacheIterations = K-1; // -1 because we check the counter @ the end
cycles = 1;
pcAdvance = 1;
@ -666,9 +896,8 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
m_cacheIterations = K-1; // -1 because we check the counter @ the end
m_cacheRedoNextPC = m_pc + 1;
m_pc = m_cacheStart;
pcAdvance = 0;
cycles = 2;
pcAdvance = 1;
pcAdvance = 0;
}
break;
}
@ -676,12 +905,14 @@ void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance
// RESERVED
case 0x1e:
{
DSP_LINE("XXX")
break;
}
// UNKNOWN
default:
{
DSP_LINE("XXX")
break;
}
}