Previous 199869 Revisions Next

r28737 Wednesday 19th March, 2014 at 18:38:17 UTC by Oliver Stöneberg
and more *.c -> *.inc renaming
[src/emu/cpu/dsp16]dsp16.c dsp16ops.c dsp16ops.inc*

trunk/src/emu/cpu/dsp16/dsp16ops.c
r28736r28737
1#include "dsp16.h"
2
3#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__);
4
5// TODO:
6//   * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits
7//     implement as a clean function (page 2-7)
8//   * Implement saturation overflow (SAT on AUC) (page 2-8)
9//   * Implement p alignment (ALIGN on AUC) (page 2-9)
10//   * When a register is used as a memory pointer. its value is compared with re. If its value is
11//     equal to the contents of re and the postincrement is +1, then the value in rb is copied into
12//     the register after the memory access is complete. See Section 4.2.3.
13//   * CPU flags go to the PSW & conditionTest() works on that (Page 3-4)
14//   * Some instructions are not interruptible.
15//
16
17
18// NOTES:
19// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read
20// or write the high half (bits 16-31) of the y register  (page 2-7)
21
22// The YL register is the lower half of the 32 bit Y register
23void* dsp16_device::addressYL()
24{
25   return (void*)(((UINT8*)&m_y) + 2);
26}
27
28
29// Flag getters
30bool dsp16_device::lmi()
31{
32   return m_psw & 0x8000;
33}
34
35bool dsp16_device::leq()
36{
37   return m_psw & 0x4000;
38}
39
40bool dsp16_device::llv()
41{
42   return m_psw & 0x2000;
43}
44
45bool dsp16_device::lmv()
46{
47   return m_psw & 0x1000;
48}
49
50
51void dsp16_device::writeRegister(void* reg, const UINT16 &value)
52{
53   // Make sure you're not attempting to write somewhere this function doesn't support.
54   if (reg == &m_p || reg == &m_a0 || reg == &m_a1)
55   {
56      logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc);
57      return;
58   }
59
60   if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2)
61   {
62      // 8 bit registers
63      *(UINT8*)reg = value & 0x00ff;
64   }
65   else if (reg == &m_psw)
66   {
67      // Writes to the a0 & a1 guard bits too
68      m_a0 &= U64(0x0ffffffff);
69      m_a0 |= U64(m_psw & 0x000f) << 32;
70      m_a1 &= U64(0x0ffffffff);
71      m_a1 |= U64(m_psw & 0x01e0) << 27;
72      m_psw = value;
73   }
74   else if (reg == &m_i)
75   {
76      // 12 bit register
77      m_i = value & 0x0fff;
78   }
79   else if (reg == &m_y)
80   {
81      // Y register
82      // TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register)  (page 2-7)
83      m_y = (value << 16) | (m_y & 0x0000ffff);
84   }
85   else if (reg == addressYL())
86   {
87      // Yl register (Writes to yl do not change the data in the high half of y)
88      m_y = value | (m_y & 0xffff0000);
89   }
90   else
91   {
92      // Everything else
93      *(UINT16*)reg = value;
94   }
95}
96
97
98bool dsp16_device::conditionTest(const UINT8& CON)
99{
100   switch (CON)
101   {
102      case 0x00: return lmi();   // mi (negative result)
103      case 0x01: return !lmi();  // pl (positive result)
104      case 0x02: return leq();   // eq (result == 0)
105      case 0x03: return !leq();  // ne (result != 0)
106      case 0x04: return llv();   // lvs (logical overflow set)
107      case 0x05: return !llv();  // lvc (logical overflow clear)
108      case 0x06: return lmv();   // mvs (math. overflow set)
109      case 0x07: return !lmv();  // mvc (math. overflow clear)
110      case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // heads (random bit set)
111      case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // tails (random bit clear)
112      case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c0ge (counter0 >= 0)*
113      case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c0lt (counter0 < 0)*
114      case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c1ge (counter1 >= 0)*
115      case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c1lt (counter1 < 0)*
116      case 0x0e: return true;    // true (always)
117      case 0x0f: return false;   // false (never)
118      case 0x10: return (!lmi() && !leq());   // gt (result > 0)
119      case 0x11: return (lmi()  ||  leq());   // le (result <= 0)
120      default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break;
121   }
122
123   // Testing each of these conditions (*) increments the respective counter being tested  (page 3-5)
124
125   return false;
126}
127
128
129void* dsp16_device::registerFromRImmediateField(const UINT8& R)
130{
131   switch (R)
132   {
133      case 0x00: return (void*)&m_j;
134      case 0x01: return (void*)&m_k;
135      case 0x02: return (void*)&m_rb;
136      case 0x03: return (void*)&m_re;
137      case 0x04: return (void*)&m_r0;
138      case 0x05: return (void*)&m_r1;
139      case 0x06: return (void*)&m_r2;
140      case 0x07: return (void*)&m_r3;
141
142      default: return NULL;
143   }
144   return NULL;
145}
146
147
148void* dsp16_device::registerFromRTable(const UINT8 &R)
149{
150   switch (R)
151   {
152      case 0x00: return (void*)&m_r0;
153      case 0x01: return (void*)&m_r1;
154      case 0x02: return (void*)&m_r2;
155      case 0x03: return (void*)&m_r3;
156      case 0x04: return (void*)&m_j;
157      case 0x05: return (void*)&m_k;
158      case 0x06: return (void*)&m_rb;
159      case 0x07: return (void*)&m_re;
160      case 0x08: return (void*)&m_pt;
161      case 0x09: return (void*)&m_pr;
162      case 0x0a: return (void*)&m_pi;
163      case 0x0b: return (void*)&m_i;
164
165      case 0x10: return (void*)&m_x;
166      case 0x11: return (void*)&m_y;
167      case 0x12: return (void*)addressYL();
168      case 0x13: return (void*)&m_auc;    // zero extended
169      case 0x14: return (void*)&m_psw;
170      case 0x15: return (void*)&m_c0;     // sign extended
171      case 0x16: return (void*)&m_c1;     // sign extended
172      case 0x17: return (void*)&m_c2;     // sign extended
173      case 0x18: return (void*)&m_sioc;
174      case 0x19: return (void*)&m_srta;
175      case 0x1a: return (void*)&m_sdx;
176      case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break;
177      case 0x1c: return (void*)&m_pioc;
178      case 0x1d: return (void*)&m_pdx0;
179      case 0x1e: return (void*)&m_pdx1;
180
181      default: return NULL;
182   }
183   return NULL;
184}
185
186
187void dsp16_device::executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S)
188{
189   // TODO: I'm pretty sure we need to feed X into these as well - Double check
190
191   // Note these instructions read right-to-left, so act accordingly  (page 3-6)
192   // y & p are sign extended  (page 3-9)
193   // implementation details  (page 3-9)
194
195   // Where is are the results going?
196   UINT64* destinationReg = NULL;
197   switch (D)
198   {
199      case 0x00: destinationReg = &m_a0; break;
200      case 0x01: destinationReg = &m_a1; break;
201      default: break;
202   }
203
204   // Which source is being used?
205   UINT64* sourceReg = NULL;
206   switch (S)
207   {
208      case 0x00: sourceReg = &m_a0; break;
209      case 0x01: sourceReg = &m_a1; break;
210      default: break;
211   }
212
213
214   // We must compute into an intermediate variable to compute flags on
215   UINT64 result = 0;
216   bool justATest = false;
217
218   switch (F1)
219   {
220      case 0x00:
221      {
222         // Ad = p   p = x*y
223         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
224         break;
225      }
226      case 0x01:
227      {
228         // Ad = aS+p   p = x*y
229         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
230         break;
231      }
232      case 0x02:
233      {
234         // p = x*y
235         // TODO: What happens to the flags in this operation?
236         const INT16 y = (m_y & 0xffff0000) >> 16;
237         m_p = (INT32)((INT16)m_x * y);
238         justATest = true;
239         break;
240      }
241      case 0x03:
242      {
243         // Ad = aS-p   p = x*y
244         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
245         break;
246      }
247      case 0x04:
248      {
249         // Ad = p
250         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
251         break;
252      }
253      case 0x05:
254      {
255         // Ad = aS+p
256         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
257         break;
258      }
259      case 0x06:
260      {
261         // nop
262         justATest = true;
263         break;
264      }
265      case 0x07:
266      {
267         // Ad = aS-p
268         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
269         break;
270      }
271      case 0x08:
272      {
273         // Ad = aS|y
274         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
275         break;
276      }
277      case 0x09:
278      {
279         // Ad = aS^y
280         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
281         break;
282      }
283      case 0x0a:
284      {
285         // aS&y
286         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
287         justATest = true;
288         break;
289      }
290      case 0x0b:
291      {
292         // aS-y
293         INT64 aS = *sourceReg;
294         if (aS & U64(0x800000000))
295            aS |= U64(0xfffffff000000000);
296
297         INT64 y  = (m_y & 0xffff0000) >> 16;
298         if (y & 0x8000)
299            y |= U64(0xffffffffffff0000);
300
301         result = aS-y;
302         justATest = true;
303         break;
304      }
305      case 0x0c:
306      {
307         // Ad = y
308         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
309         break;
310      }
311      case 0x0d:
312      {
313         // Ad = aS+y
314         INT64 aS = *sourceReg;
315         if (aS & U64(0x800000000))
316            aS |= U64(0xfffffff000000000);
317
318         INT64 y  = (m_y & 0xffff0000) >> 16;
319         if (y & 0x8000)
320            y |= U64(0xffffffffffff0000);
321
322         result = aS+y;
323         break;
324      }
325      case 0x0e:
326      {
327         // Ad = aS&y
328         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
329         break;
330      }
331      case 0x0f:
332      {
333         // Ad = aS-y
334         INT64 aS = *sourceReg;
335         if (aS & U64(0x800000000))
336            aS |= U64(0xfffffff000000000);
337
338         INT64 y  = (m_y & 0xffff0000) >> 16;
339         if (y & 0x8000)
340            y |= U64(0xffffffffffff0000);
341
342         result = aS-y;
343         break;
344      }
345   }
346
347   // CPU Flags  (page 3-4)
348   // LMI (logical minus)
349   if (result & U64(0x800000000))
350      m_psw |= 0x8000;
351   else
352      m_psw &= (~0x8000);
353
354   // LEQ (logical equal)
355   if (result == U64(0x000000000))
356      m_psw |= 0x4000;
357   else
358      m_psw &= (~0x4000);
359
360   // LLV (logical overflow)
361   // TODO
362
363   // LMV (mathematical overflow)
364   if ((result | U64(0xf00000000)) != U64(0xf00000000) &&
365      (result | U64(0xf00000000)) != U64(0x000000000))
366      m_psw |= 0x1000;
367   else
368      m_psw &= (~0x1000);
369
370   // If it was a real operation, make sure the data goes where it should
371   if (!justATest)
372      *destinationReg = (UINT64)result & U64(0x0000000fffffffff);
373}
374
375
376UINT16* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
377{
378   UINT16* destinationReg = NULL;
379   const UINT8 N = (Y & 0x0c) >> 2;
380   switch (N)
381   {
382      case 0x00: destinationReg = &m_r0; break;
383      case 0x01: destinationReg = &m_r1; break;
384      case 0x02: destinationReg = &m_r2; break;
385      case 0x03: destinationReg = &m_r3; break;
386      default: break;
387   }
388   return destinationReg;
389}
390
391
392void dsp16_device::executeYFieldPost(const UINT8& Y)
393{
394   UINT16* opReg = registerFromYFieldUpper(Y);
395
396   const UINT8 lower = Y & 0x03;
397   switch (lower)
398   {
399      case 0x00: /* nop */ break;
400      case 0x01: (*opReg)++; break;
401      case 0x02: (*opReg)--; break;
402      case 0x03: (*opReg) += m_j; break;  // TODO: J is signed
403   }
404}
405
406
407void dsp16_device::executeZFieldPartOne(const UINT8& Z, UINT16* rN)
408{
409   const UINT8 lower = Z & 0x03;
410   switch (lower)
411   {
412      case 0x00: /* nop */ break;
413      case 0x01: (*rN)++; break;
414      case 0x02: (*rN)--; break;
415      case 0x03: (*rN) += m_j; break;  // TODO: J is signed
416   }
417}
418
419
420void dsp16_device::executeZFieldPartTwo(const UINT8& Z, UINT16* rN)
421{
422   const UINT8 lower = Z & 0x03;
423   switch (lower)
424   {
425      case 0x00: (*rN)++; break;
426      case 0x01: /* nop */   break;
427      case 0x02: (*rN) += 2; break;
428      case 0x03: (*rN) += m_k; break;  // TODO: K is signed
429   }
430}
431
432
433void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance)
434{
435   cycles = 1;
436   pcAdvance = 0;
437
438// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
439
440   const UINT8 opcode = (op >> 11) & 0x1f;
441   switch(opcode)
442   {
443      // Format 1: Multiply/ALU Read/Write Group
444      case 0x06:
445      {
446         DSP_LINE("3-38")
447         // F1, Y  :  (page 3-38)
448         const UINT8 Y = (op & 0x000f);
449         const UINT8 S = (op & 0x0200) >> 9;
450         const UINT8 D = (op & 0x0400) >> 10;
451         const UINT8 F1 = (op & 0x01e0) >> 5;
452         executeF1Field(F1, D, S);
453         executeYFieldPost(Y);
454         cycles = 1;
455         pcAdvance = 1;
456         break;
457      }
458      case 0x04: case 0x1c:
459      {
460         DSP_LINE("3-40")
461         // F1 Y=a0[1] | F1 Y=a1[1]  :  (page 3-40)
462         const UINT8 Y = (op & 0x000f);
463         //const UINT8 X = (op & 0x0010) >> 4;
464         const UINT8 S = (op & 0x0200) >> 9;
465         const UINT8 D = (op & 0x0400) >> 10;
466         const UINT8 F1 = (op & 0x01e0) >> 5;
467         UINT16* destinationReg = registerFromYFieldUpper(Y);
468         // (page 3-18)
469         UINT16 aRegValue = 0x0000;
470         if (op & 0xc000)
471         {
472            aRegValue = (m_a0 & U64(0x0ffff0000)) >> 16;
473         }
474         else
475         {
476            aRegValue = (m_a1 & U64(0x0ffff0000)) >> 16;
477         }
478         data_write(*destinationReg, aRegValue);
479         executeYFieldPost(Y);
480         executeF1Field(F1, D, S);
481         cycles = 2;
482         pcAdvance = 1;
483         break;
484      }
485      case 0x16:
486      {
487         DSP_LINE("3-42")
488         // F1, x = Y  :  (page 3-42)
489         const UINT8 Y = (op & 0x000f);
490         const UINT8 S = (op & 0x0200) >> 9;
491         const UINT8 D = (op & 0x0400) >> 10;
492         const UINT8 F1 = (op & 0x01e0) >> 5;
493         executeF1Field(F1, D, S);
494         UINT16* sourceReg = registerFromYFieldUpper(Y);
495         writeRegister(&m_x, data_read(*sourceReg));
496         executeYFieldPost(Y);
497         cycles = 1;
498         pcAdvance = 1;
499         break;
500      }
501      case 0x17:
502      {
503         DSP_LINE("3-44")
504         // F1, y[l] = Y  :  (page 3-44)
505         const UINT8 Y = (op & 0x000f);
506         const UINT8 X = (op & 0x0010) >> 4;
507         const UINT8 S = (op & 0x0200) >> 9;
508         const UINT8 D = (op & 0x0400) >> 10;
509         const UINT8 F1 = (op & 0x01e0) >> 5;
510         executeF1Field(F1, D, S);
511         UINT16* sourceReg = registerFromYFieldUpper(Y);
512         UINT16 sourceValue = data_read(*sourceReg);
513         switch (X)
514         {
515            case 0x00: writeRegister(addressYL(), sourceValue); break;
516            case 0x01: writeRegister(&m_y, sourceValue); break;
517            default: break;
518         }
519         executeYFieldPost(Y);
520         cycles = 1;
521         pcAdvance = 1;
522         break;
523      }
524      case 0x1f:
525      {
526         DSP_LINE("3-46")
527         // F1, y = Y, x = *pt++[i]  :  (page 3-46)
528         const UINT8 Y = (op & 0x000f);
529         const UINT8 X = (op & 0x0010) >> 4;
530         const UINT8 S = (op & 0x0200) >> 9;
531         const UINT8 D = (op & 0x0400) >> 10;
532         const UINT8 F1 = (op & 0x01e0) >> 5;
533         executeF1Field(F1, D, S);
534         UINT16* sourceRegR = registerFromYFieldUpper(Y);
535         writeRegister(&m_y, data_read(*sourceRegR));
536         executeYFieldPost(Y);
537         writeRegister(&m_x, data_read(m_pt));
538         switch (X)
539         {
540            case 0x00: m_pt++;      break;
541            case 0x01: m_pt += m_i; break;
542         }
543         cycles = 2;     // TODO: 1 if cached
544         pcAdvance = 1;
545         break;
546      }
547      case 0x19: case 0x1b:
548      {
549         DSP_LINE("3-48")
550         // F1, y = a0|1, x = *pt++[i]  :  (page 3-48)
551         const UINT8 Y = (op & 0x000f);
552         const UINT8 X = (op & 0x0010) >> 4;
553         const UINT8 S = (op & 0x0200) >> 9;
554         const UINT8 D = (op & 0x0400) >> 10;
555         const UINT8 F1 = (op & 0x01e0) >> 5;
556         bool useA1 = (opcode == 0x1b);
557         if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc);
558         m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff);      // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)?
559         executeF1Field(F1, D, S);
560         writeRegister(&m_x, data_read(m_pt));                           // TODO: EXM Pin & internal/external ROM?  Research.
561         switch (X)
562         {
563            case 0x00: m_pt++;      break;
564            case 0x01: m_pt += m_i; break;
565         }
566         cycles = 2;     // TODO: 1 if cached
567         pcAdvance = 1;
568         break;
569      }
570      case 0x14:
571      {
572         DSP_LINE("3-53")
573         // F1, Y = y[l]  :  (page 3-53)
574         const UINT8 Y = (op & 0x000f);
575         const UINT8 X = (op & 0x0010) >> 4;
576         const UINT8 S = (op & 0x0200) >> 9;
577         const UINT8 D = (op & 0x0400) >> 10;
578         const UINT8 F1 = (op & 0x01e0) >> 5;
579         executeF1Field(F1, D, S);
580         UINT16* destinationReg = registerFromYFieldUpper(Y);
581         UINT16 yRegValue = 0x0000;
582         switch (X)
583         {
584            case 0x00: yRegValue = (m_y & 0x0000ffff); break;
585            case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break;
586            default: break;
587         }
588         data_write(*destinationReg, yRegValue);
589         executeYFieldPost(Y);
590         cycles = 2;
591         pcAdvance = 1;
592         break;
593      }
594
595      // Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51)
596      case 0x07:
597      {
598         DSP_LINE("3-50")
599         // F1, At[1] = Y  :  (page 3-50)
600         // TODO: What does the X field do here, exactly?
601         const UINT8 Y = (op & 0x000f);
602         const UINT8 S = (op & 0x0200) >> 9;
603         const UINT8 aT = (op & 0x0400) >> 10;
604         const UINT8 F1 = (op & 0x01e0) >> 5;
605         executeF1Field(F1, !aT, S);
606         UINT64* destinationReg = NULL;
607         switch(aT)
608         {
609            case 0: destinationReg = &m_a1; break;
610            case 1: destinationReg = &m_a0; break;
611            default: break;
612         }
613         UINT16 sourceAddress = *(registerFromYFieldUpper(Y));
614         INT64 sourceValueSigned = (INT16)data_read(sourceAddress);
615         *destinationReg = sourceValueSigned & U64(0xffffffffff);
616         executeYFieldPost(Y);
617         cycles = 1;
618         pcAdvance = 1;
619         break;
620      }
621
622      // Format 2: Multiply/ALU Read/Write Group
623      case 0x15:
624      {
625         DSP_LINE("3-54")
626         // F1, Z : y[l]  :  (page 3-54)
627         const UINT8 Z = (op & 0x000f);
628         const UINT8 X = (op & 0x0010) >> 4;
629         const UINT8 S = (op & 0x0200) >> 9;
630         const UINT8 D = (op & 0x0400) >> 10;
631         const UINT8 F1 = (op & 0x01e0) >> 5;
632         executeF1Field(F1, D, S);
633         UINT16 temp = 0x0000;
634         UINT16* rN = registerFromYFieldUpper(Z);
635         switch (X)
636         {
637            case 0x00:
638               temp = m_y & 0x0000ffff;
639               m_y &= 0xffff0000;
640               m_y |= data_read(*rN);
641               executeZFieldPartOne(Z, rN);
642               data_write(*rN, temp);
643               executeZFieldPartTwo(Z, rN);
644               break;
645            case 0x01:
646               temp = (m_y & 0xffff0000) >> 16;
647               m_y &= 0x0000ffff;
648               m_y |= (data_read(*rN) << 16);
649               executeZFieldPartOne(Z, rN);
650               data_write(*rN, temp);
651               executeZFieldPartTwo(Z, rN);
652               break;
653         }
654         cycles = 2;
655         pcAdvance = 1;
656         break;
657      }
658      case 0x1d:
659      {
660         DSP_LINE("?")
661         // F1, Z : y, x=*pt++[i]
662         //const UINT8 Z = (op & 0x000f);
663         //const UINT8 X = (op & 0x0010) >> 4;
664         //const UINT8 S = (op & 0x0200) >> 9;
665         //const UINT8 D = (op & 0x0400) >> 10;
666         //const UINT8 F1 = (op & 0x01e0) >> 5;
667         break;
668      }
669
670      // Format 2a: Multiply/ALU Read/Write Group
671      case 0x05:
672      {
673         DSP_LINE("?")
674         // F1, Z : aT[1]
675         //const UINT8 Z = (op & 0x000f);
676         //const UINT8 X = (op & 0x0010) >> 4;
677         //const UINT8 S = (op & 0x0200) >> 9;
678         //const UINT8 aT = (op & 0x0400) >> 10;
679         //const UINT8 F1 = (op & 0x01e0) >> 5;
680         break;
681      }
682
683      // Format 3: Special Functions
684      case 0x12:
685      case 0x13:
686      {
687         DSP_LINE("3-36")
688         // if|ifc CON F2  (page 3-36)
689         const UINT8 CON = (op & 0x001f);
690         //const UINT8 S = (op & 0x0200) >> 9;
691         //const UINT8 D = (op & 0x0400) >> 10;
692         //const UINT8 F2 = (op & 0x01e0) >> 5;
693         bool conditionFulfilled = conditionTest(CON);
694         if (conditionFulfilled)
695         {
696            printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
697         }
698         cycles = 1;
699         pcAdvance = 1;
700         break;
701      }
702
703      // Format 4: Branch Direct Group
704      case 0x00: case 0x01:
705      {
706         DSP_LINE("3-20")
707         // goto JA  :  (page 3-20) (DONE)
708         const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
709         m_pc = JA;
710         cycles = 2;
711         pcAdvance = 0;
712         break;
713      }
714
715      case 0x10: case 0x11:
716      {
717         DSP_LINE("3-23")
718         // call JA  :  (page 3-23)
719         const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
720         m_pr = m_pc + 1;
721         m_pc = JA;
722         cycles = 2;
723         pcAdvance = 0;
724         break;
725      }
726
727      // Format 5: Branch Indirect Group
728      case 0x18:
729      {
730         DSP_LINE("3-21")
731         // goto B  :  (page 3-21)
732         const UINT8 B = (op & 0x0700) >> 8;
733         switch (B)
734         {
735            case 0x00: m_pc = m_pr; break;
736            case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
737            case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
738            case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
739            default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break;
740         }
741         cycles = 2;
742         pcAdvance = 0;
743         break;
744      }
745
746      // Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
747      case 0x1a:
748      {
749         DSP_LINE("3-22")
750         // if CON [goto/call/return]  :  (page 3-22)
751         const UINT8 CON = (op & 0x001f);
752         bool conditionFulfilled = conditionTest(CON);
753         cycles = 3;                 // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3?
754         pcAdvance = 1;
755         if (!conditionFulfilled)
756         {
757            pcAdvance = 2;
758         }
759         break;
760      }
761
762      // Format 7: Data Move Group
763      case 0x09: case 0x0b:
764      {
765         DSP_LINE("3-29")
766         // R = aS  :  (page 3-29)
767         // TODO: Fix register pdxX (pc=338)
768         const UINT8 R = (op & 0x03f0) >> 4;
769         const UINT8 S = (op & 0x1000) >> 12;
770         void* destinationReg = registerFromRTable(R);
771         UINT64* sourceReg = (S) ? &m_a1 : &m_a0;
772         UINT16 sourceValue = (*sourceReg & U64(0x0ffff0000)) >> 16;
773         writeRegister(destinationReg, sourceValue);
774         cycles = 2;
775         pcAdvance = 1;
776         break;
777      }
778      case 0x08:
779      {
780         DSP_LINE("3-30")
781         // aT = R  :  (page 3-30)
782         const UINT8 R  = (op & 0x03f0) >> 4;
783         const UINT8 aT = (op & 0x0400) >> 10;
784         UINT64* destinationReg = NULL;
785         switch(aT)
786         {
787            case 0: destinationReg = &m_a1; break;
788            case 1: destinationReg = &m_a0; break;
789            default: break;
790         }
791         void* sourceReg = registerFromRTable(R);
792         *destinationReg &= U64(0x00000ffff);
793         *destinationReg |= (*(UINT16*)sourceReg) << 16;     // TODO: Fix for all registers
794         if (*(UINT16*)sourceReg & 0x8000)
795            *destinationReg |= U64(0xf00000000);
796         // TODO: Special function encoding
797         cycles = 2;
798         pcAdvance = 1;
799         break;
800      }
801      case 0x0f:
802      {
803         DSP_LINE("3-32")
804         // R = Y  :  (page 3-32)
805         const UINT8 Y = (op & 0x000f);
806         const UINT8 R = (op & 0x03f0) >> 4;
807         UINT16* sourceReg = registerFromYFieldUpper(Y);
808         void* destinationReg = registerFromRTable(R);
809         writeRegister(destinationReg, data_read(*sourceReg));
810         executeYFieldPost(Y);
811         cycles = 2;
812         pcAdvance = 1;
813         break;
814      }
815      case 0x0c:
816      {
817         DSP_LINE("3-33")
818         // Y = R  :  (page 3-33)
819         // TODO: Zero & Sign extend i, c0, c1, c2, and auc
820         const UINT8 Y = (op & 0x000f);
821         const UINT8 R = (op & 0x03f0) >> 4;
822         UINT16* destinationReg = registerFromYFieldUpper(Y);
823         UINT16* sourceReg = (UINT16*)registerFromRTable(R);     // TODO: This won't work for certain registers!
824         data_write(*destinationReg, *sourceReg);                //       Fix in data_write() maybe?
825         executeYFieldPost(Y);
826         cycles = 2;
827         pcAdvance = 1;
828         break;
829      }
830      case 0x0d:
831      {
832         DSP_LINE("?")
833         // Z : R
834         //const UINT8 Z = (op & 0x000f);
835         //const UINT8 R = (op & 0x03f0) >> 4;
836         break;
837      }
838
839      // Format 8: Data Move (immediate operand - 2 words)
840      case 0x0a:
841      {
842         DSP_LINE("3-28")
843         // R = N  :  (page 3-28) (DONE)
844         // NOTE: The docs speak of register sources & sign extension, but this is a register
845         // destination, so, typo?  If so, what does one do with the overflow bits?
846         const UINT8 R = (op & 0x03f0) >> 4;
847         const UINT16 iVal = opcode_read(1);
848         void* destinationReg = registerFromRTable(R);
849         writeRegister(destinationReg, iVal);
850         cycles = 2;
851         pcAdvance = 2;
852         break;
853      }
854
855      // Format 9: Short Immediate Group
856      case 0x02: case 0x03:
857      {
858         DSP_LINE("3-27")
859         // R = M  :  (page 3-27)
860         // TODO: Figure out notes about the DSP16A vs the DSP16.  9 bit is very DSP16...
861         const UINT16 M = (op & 0x01ff);
862         const UINT8  R = (op & 0x0e00) >> 9;
863         void* destinationReg = registerFromRImmediateField(R);
864         // Sign extend if the destination is j or k
865         UINT16 mValue = M;
866         if (destinationReg == &m_j || destinationReg == &m_k)
867         {
868            if (mValue & 0x0100) mValue |= 0xfe00;
869         }
870         writeRegister(destinationReg, mValue);
871         cycles = 1;
872         pcAdvance = 1;
873         break;
874      }
875
876      // Format 10: do - redo
877      case 0x0e:
878      {
879         DSP_LINE("3-25/3-26")
880         // do|redo K  :  (pages 3-25 & 3-26)
881         // TODO: The timings are intricate to say the least...
882         const UINT8 K = (op & 0x007f);
883         const UINT8 NI = (op & 0x0780) >> 7;
884         if (NI != 0)
885         {
886            // Do
887            m_cacheStart = m_pc + 1;
888            m_cacheEnd   = m_pc + 1 + NI;
889            m_cacheIterations = K-1;    // -1 because we check the counter @ the end
890            cycles = 1;
891            pcAdvance = 1;
892         }
893         else
894         {
895            // Redo
896            m_cacheIterations = K-1;    // -1 because we check the counter @ the end
897            m_cacheRedoNextPC = m_pc + 1;
898            m_pc = m_cacheStart;
899            cycles = 2;
900            pcAdvance = 0;
901         }
902         break;
903      }
904
905      // RESERVED
906      case 0x1e:
907      {
908         DSP_LINE("XXX")
909         break;
910      }
911
912      // UNKNOWN
913      default:
914      {
915         DSP_LINE("XXX")
916         break;
917      }
918   }
919
920   // Handle end-of-cache conditions for do|redos
921   if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID)
922   {
923      // You've reached the end of a cache loop after a redo opcode.
924      m_pc = m_cacheRedoNextPC;
925      m_cacheRedoNextPC = CACHE_INVALID;
926      pcAdvance = 0;
927   }
928   if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd))
929   {
930      // A regular iteration on a cached loop.
931      m_cacheIterations--;
932      m_pc = m_cacheStart;
933      pcAdvance = 0;
934   }
935}
trunk/src/emu/cpu/dsp16/dsp16.c
r28736r28737
448448   } while (m_icount > 0);
449449}
450450
451#include "dsp16ops.c"
451#include "dsp16ops.inc"
trunk/src/emu/cpu/dsp16/dsp16ops.inc
r0r28737
1#include "dsp16.h"
2
3#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__);
4
5// TODO:
6//   * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits
7//     implement as a clean function (page 2-7)
8//   * Implement saturation overflow (SAT on AUC) (page 2-8)
9//   * Implement p alignment (ALIGN on AUC) (page 2-9)
10//   * When a register is used as a memory pointer. its value is compared with re. If its value is
11//     equal to the contents of re and the postincrement is +1, then the value in rb is copied into
12//     the register after the memory access is complete. See Section 4.2.3.
13//   * CPU flags go to the PSW & conditionTest() works on that (Page 3-4)
14//   * Some instructions are not interruptible.
15//
16
17
18// NOTES:
19// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read
20// or write the high half (bits 16-31) of the y register  (page 2-7)
21
22// The YL register is the lower half of the 32 bit Y register
23void* dsp16_device::addressYL()
24{
25   return (void*)(((UINT8*)&m_y) + 2);
26}
27
28
29// Flag getters
30bool dsp16_device::lmi()
31{
32   return m_psw & 0x8000;
33}
34
35bool dsp16_device::leq()
36{
37   return m_psw & 0x4000;
38}
39
40bool dsp16_device::llv()
41{
42   return m_psw & 0x2000;
43}
44
45bool dsp16_device::lmv()
46{
47   return m_psw & 0x1000;
48}
49
50
51void dsp16_device::writeRegister(void* reg, const UINT16 &value)
52{
53   // Make sure you're not attempting to write somewhere this function doesn't support.
54   if (reg == &m_p || reg == &m_a0 || reg == &m_a1)
55   {
56      logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc);
57      return;
58   }
59
60   if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2)
61   {
62      // 8 bit registers
63      *(UINT8*)reg = value & 0x00ff;
64   }
65   else if (reg == &m_psw)
66   {
67      // Writes to the a0 & a1 guard bits too
68      m_a0 &= U64(0x0ffffffff);
69      m_a0 |= U64(m_psw & 0x000f) << 32;
70      m_a1 &= U64(0x0ffffffff);
71      m_a1 |= U64(m_psw & 0x01e0) << 27;
72      m_psw = value;
73   }
74   else if (reg == &m_i)
75   {
76      // 12 bit register
77      m_i = value & 0x0fff;
78   }
79   else if (reg == &m_y)
80   {
81      // Y register
82      // TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register)  (page 2-7)
83      m_y = (value << 16) | (m_y & 0x0000ffff);
84   }
85   else if (reg == addressYL())
86   {
87      // Yl register (Writes to yl do not change the data in the high half of y)
88      m_y = value | (m_y & 0xffff0000);
89   }
90   else
91   {
92      // Everything else
93      *(UINT16*)reg = value;
94   }
95}
96
97
98bool dsp16_device::conditionTest(const UINT8& CON)
99{
100   switch (CON)
101   {
102      case 0x00: return lmi();   // mi (negative result)
103      case 0x01: return !lmi();  // pl (positive result)
104      case 0x02: return leq();   // eq (result == 0)
105      case 0x03: return !leq();  // ne (result != 0)
106      case 0x04: return llv();   // lvs (logical overflow set)
107      case 0x05: return !llv();  // lvc (logical overflow clear)
108      case 0x06: return lmv();   // mvs (math. overflow set)
109      case 0x07: return !lmv();  // mvc (math. overflow clear)
110      case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // heads (random bit set)
111      case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // tails (random bit clear)
112      case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c0ge (counter0 >= 0)*
113      case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c0lt (counter0 < 0)*
114      case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c1ge (counter1 >= 0)*
115      case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false;   // c1lt (counter1 < 0)*
116      case 0x0e: return true;    // true (always)
117      case 0x0f: return false;   // false (never)
118      case 0x10: return (!lmi() && !leq());   // gt (result > 0)
119      case 0x11: return (lmi()  ||  leq());   // le (result <= 0)
120      default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break;
121   }
122
123   // Testing each of these conditions (*) increments the respective counter being tested  (page 3-5)
124
125   return false;
126}
127
128
129void* dsp16_device::registerFromRImmediateField(const UINT8& R)
130{
131   switch (R)
132   {
133      case 0x00: return (void*)&m_j;
134      case 0x01: return (void*)&m_k;
135      case 0x02: return (void*)&m_rb;
136      case 0x03: return (void*)&m_re;
137      case 0x04: return (void*)&m_r0;
138      case 0x05: return (void*)&m_r1;
139      case 0x06: return (void*)&m_r2;
140      case 0x07: return (void*)&m_r3;
141
142      default: return NULL;
143   }
144   return NULL;
145}
146
147
148void* dsp16_device::registerFromRTable(const UINT8 &R)
149{
150   switch (R)
151   {
152      case 0x00: return (void*)&m_r0;
153      case 0x01: return (void*)&m_r1;
154      case 0x02: return (void*)&m_r2;
155      case 0x03: return (void*)&m_r3;
156      case 0x04: return (void*)&m_j;
157      case 0x05: return (void*)&m_k;
158      case 0x06: return (void*)&m_rb;
159      case 0x07: return (void*)&m_re;
160      case 0x08: return (void*)&m_pt;
161      case 0x09: return (void*)&m_pr;
162      case 0x0a: return (void*)&m_pi;
163      case 0x0b: return (void*)&m_i;
164
165      case 0x10: return (void*)&m_x;
166      case 0x11: return (void*)&m_y;
167      case 0x12: return (void*)addressYL();
168      case 0x13: return (void*)&m_auc;    // zero extended
169      case 0x14: return (void*)&m_psw;
170      case 0x15: return (void*)&m_c0;     // sign extended
171      case 0x16: return (void*)&m_c1;     // sign extended
172      case 0x17: return (void*)&m_c2;     // sign extended
173      case 0x18: return (void*)&m_sioc;
174      case 0x19: return (void*)&m_srta;
175      case 0x1a: return (void*)&m_sdx;
176      case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break;
177      case 0x1c: return (void*)&m_pioc;
178      case 0x1d: return (void*)&m_pdx0;
179      case 0x1e: return (void*)&m_pdx1;
180
181      default: return NULL;
182   }
183   return NULL;
184}
185
186
187void dsp16_device::executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S)
188{
189   // TODO: I'm pretty sure we need to feed X into these as well - Double check
190
191   // Note these instructions read right-to-left, so act accordingly  (page 3-6)
192   // y & p are sign extended  (page 3-9)
193   // implementation details  (page 3-9)
194
195   // Where is are the results going?
196   UINT64* destinationReg = NULL;
197   switch (D)
198   {
199      case 0x00: destinationReg = &m_a0; break;
200      case 0x01: destinationReg = &m_a1; break;
201      default: break;
202   }
203
204   // Which source is being used?
205   UINT64* sourceReg = NULL;
206   switch (S)
207   {
208      case 0x00: sourceReg = &m_a0; break;
209      case 0x01: sourceReg = &m_a1; break;
210      default: break;
211   }
212
213
214   // We must compute into an intermediate variable to compute flags on
215   UINT64 result = 0;
216   bool justATest = false;
217
218   switch (F1)
219   {
220      case 0x00:
221      {
222         // Ad = p   p = x*y
223         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
224         break;
225      }
226      case 0x01:
227      {
228         // Ad = aS+p   p = x*y
229         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
230         break;
231      }
232      case 0x02:
233      {
234         // p = x*y
235         // TODO: What happens to the flags in this operation?
236         const INT16 y = (m_y & 0xffff0000) >> 16;
237         m_p = (INT32)((INT16)m_x * y);
238         justATest = true;
239         break;
240      }
241      case 0x03:
242      {
243         // Ad = aS-p   p = x*y
244         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
245         break;
246      }
247      case 0x04:
248      {
249         // Ad = p
250         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
251         break;
252      }
253      case 0x05:
254      {
255         // Ad = aS+p
256         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
257         break;
258      }
259      case 0x06:
260      {
261         // nop
262         justATest = true;
263         break;
264      }
265      case 0x07:
266      {
267         // Ad = aS-p
268         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
269         break;
270      }
271      case 0x08:
272      {
273         // Ad = aS|y
274         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
275         break;
276      }
277      case 0x09:
278      {
279         // Ad = aS^y
280         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
281         break;
282      }
283      case 0x0a:
284      {
285         // aS&y
286         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
287         justATest = true;
288         break;
289      }
290      case 0x0b:
291      {
292         // aS-y
293         INT64 aS = *sourceReg;
294         if (aS & U64(0x800000000))
295            aS |= U64(0xfffffff000000000);
296
297         INT64 y  = (m_y & 0xffff0000) >> 16;
298         if (y & 0x8000)
299            y |= U64(0xffffffffffff0000);
300
301         result = aS-y;
302         justATest = true;
303         break;
304      }
305      case 0x0c:
306      {
307         // Ad = y
308         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
309         break;
310      }
311      case 0x0d:
312      {
313         // Ad = aS+y
314         INT64 aS = *sourceReg;
315         if (aS & U64(0x800000000))
316            aS |= U64(0xfffffff000000000);
317
318         INT64 y  = (m_y & 0xffff0000) >> 16;
319         if (y & 0x8000)
320            y |= U64(0xffffffffffff0000);
321
322         result = aS+y;
323         break;
324      }
325      case 0x0e:
326      {
327         // Ad = aS&y
328         printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__);
329         break;
330      }
331      case 0x0f:
332      {
333         // Ad = aS-y
334         INT64 aS = *sourceReg;
335         if (aS & U64(0x800000000))
336            aS |= U64(0xfffffff000000000);
337
338         INT64 y  = (m_y & 0xffff0000) >> 16;
339         if (y & 0x8000)
340            y |= U64(0xffffffffffff0000);
341
342         result = aS-y;
343         break;
344      }
345   }
346
347   // CPU Flags  (page 3-4)
348   // LMI (logical minus)
349   if (result & U64(0x800000000))
350      m_psw |= 0x8000;
351   else
352      m_psw &= (~0x8000);
353
354   // LEQ (logical equal)
355   if (result == U64(0x000000000))
356      m_psw |= 0x4000;
357   else
358      m_psw &= (~0x4000);
359
360   // LLV (logical overflow)
361   // TODO
362
363   // LMV (mathematical overflow)
364   if ((result | U64(0xf00000000)) != U64(0xf00000000) &&
365      (result | U64(0xf00000000)) != U64(0x000000000))
366      m_psw |= 0x1000;
367   else
368      m_psw &= (~0x1000);
369
370   // If it was a real operation, make sure the data goes where it should
371   if (!justATest)
372      *destinationReg = (UINT64)result & U64(0x0000000fffffffff);
373}
374
375
376UINT16* dsp16_device::registerFromYFieldUpper(const UINT8& Y)
377{
378   UINT16* destinationReg = NULL;
379   const UINT8 N = (Y & 0x0c) >> 2;
380   switch (N)
381   {
382      case 0x00: destinationReg = &m_r0; break;
383      case 0x01: destinationReg = &m_r1; break;
384      case 0x02: destinationReg = &m_r2; break;
385      case 0x03: destinationReg = &m_r3; break;
386      default: break;
387   }
388   return destinationReg;
389}
390
391
392void dsp16_device::executeYFieldPost(const UINT8& Y)
393{
394   UINT16* opReg = registerFromYFieldUpper(Y);
395
396   const UINT8 lower = Y & 0x03;
397   switch (lower)
398   {
399      case 0x00: /* nop */ break;
400      case 0x01: (*opReg)++; break;
401      case 0x02: (*opReg)--; break;
402      case 0x03: (*opReg) += m_j; break;  // TODO: J is signed
403   }
404}
405
406
407void dsp16_device::executeZFieldPartOne(const UINT8& Z, UINT16* rN)
408{
409   const UINT8 lower = Z & 0x03;
410   switch (lower)
411   {
412      case 0x00: /* nop */ break;
413      case 0x01: (*rN)++; break;
414      case 0x02: (*rN)--; break;
415      case 0x03: (*rN) += m_j; break;  // TODO: J is signed
416   }
417}
418
419
420void dsp16_device::executeZFieldPartTwo(const UINT8& Z, UINT16* rN)
421{
422   const UINT8 lower = Z & 0x03;
423   switch (lower)
424   {
425      case 0x00: (*rN)++; break;
426      case 0x01: /* nop */   break;
427      case 0x02: (*rN) += 2; break;
428      case 0x03: (*rN) += m_k; break;  // TODO: K is signed
429   }
430}
431
432
433void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance)
434{
435   cycles = 1;
436   pcAdvance = 0;
437
438// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up
439
440   const UINT8 opcode = (op >> 11) & 0x1f;
441   switch(opcode)
442   {
443      // Format 1: Multiply/ALU Read/Write Group
444      case 0x06:
445      {
446         DSP_LINE("3-38")
447         // F1, Y  :  (page 3-38)
448         const UINT8 Y = (op & 0x000f);
449         const UINT8 S = (op & 0x0200) >> 9;
450         const UINT8 D = (op & 0x0400) >> 10;
451         const UINT8 F1 = (op & 0x01e0) >> 5;
452         executeF1Field(F1, D, S);
453         executeYFieldPost(Y);
454         cycles = 1;
455         pcAdvance = 1;
456         break;
457      }
458      case 0x04: case 0x1c:
459      {
460         DSP_LINE("3-40")
461         // F1 Y=a0[1] | F1 Y=a1[1]  :  (page 3-40)
462         const UINT8 Y = (op & 0x000f);
463         //const UINT8 X = (op & 0x0010) >> 4;
464         const UINT8 S = (op & 0x0200) >> 9;
465         const UINT8 D = (op & 0x0400) >> 10;
466         const UINT8 F1 = (op & 0x01e0) >> 5;
467         UINT16* destinationReg = registerFromYFieldUpper(Y);
468         // (page 3-18)
469         UINT16 aRegValue = 0x0000;
470         if (op & 0xc000)
471         {
472            aRegValue = (m_a0 & U64(0x0ffff0000)) >> 16;
473         }
474         else
475         {
476            aRegValue = (m_a1 & U64(0x0ffff0000)) >> 16;
477         }
478         data_write(*destinationReg, aRegValue);
479         executeYFieldPost(Y);
480         executeF1Field(F1, D, S);
481         cycles = 2;
482         pcAdvance = 1;
483         break;
484      }
485      case 0x16:
486      {
487         DSP_LINE("3-42")
488         // F1, x = Y  :  (page 3-42)
489         const UINT8 Y = (op & 0x000f);
490         const UINT8 S = (op & 0x0200) >> 9;
491         const UINT8 D = (op & 0x0400) >> 10;
492         const UINT8 F1 = (op & 0x01e0) >> 5;
493         executeF1Field(F1, D, S);
494         UINT16* sourceReg = registerFromYFieldUpper(Y);
495         writeRegister(&m_x, data_read(*sourceReg));
496         executeYFieldPost(Y);
497         cycles = 1;
498         pcAdvance = 1;
499         break;
500      }
501      case 0x17:
502      {
503         DSP_LINE("3-44")
504         // F1, y[l] = Y  :  (page 3-44)
505         const UINT8 Y = (op & 0x000f);
506         const UINT8 X = (op & 0x0010) >> 4;
507         const UINT8 S = (op & 0x0200) >> 9;
508         const UINT8 D = (op & 0x0400) >> 10;
509         const UINT8 F1 = (op & 0x01e0) >> 5;
510         executeF1Field(F1, D, S);
511         UINT16* sourceReg = registerFromYFieldUpper(Y);
512         UINT16 sourceValue = data_read(*sourceReg);
513         switch (X)
514         {
515            case 0x00: writeRegister(addressYL(), sourceValue); break;
516            case 0x01: writeRegister(&m_y, sourceValue); break;
517            default: break;
518         }
519         executeYFieldPost(Y);
520         cycles = 1;
521         pcAdvance = 1;
522         break;
523      }
524      case 0x1f:
525      {
526         DSP_LINE("3-46")
527         // F1, y = Y, x = *pt++[i]  :  (page 3-46)
528         const UINT8 Y = (op & 0x000f);
529         const UINT8 X = (op & 0x0010) >> 4;
530         const UINT8 S = (op & 0x0200) >> 9;
531         const UINT8 D = (op & 0x0400) >> 10;
532         const UINT8 F1 = (op & 0x01e0) >> 5;
533         executeF1Field(F1, D, S);
534         UINT16* sourceRegR = registerFromYFieldUpper(Y);
535         writeRegister(&m_y, data_read(*sourceRegR));
536         executeYFieldPost(Y);
537         writeRegister(&m_x, data_read(m_pt));
538         switch (X)
539         {
540            case 0x00: m_pt++;      break;
541            case 0x01: m_pt += m_i; break;
542         }
543         cycles = 2;     // TODO: 1 if cached
544         pcAdvance = 1;
545         break;
546      }
547      case 0x19: case 0x1b:
548      {
549         DSP_LINE("3-48")
550         // F1, y = a0|1, x = *pt++[i]  :  (page 3-48)
551         const UINT8 Y = (op & 0x000f);
552         const UINT8 X = (op & 0x0010) >> 4;
553         const UINT8 S = (op & 0x0200) >> 9;
554         const UINT8 D = (op & 0x0400) >> 10;
555         const UINT8 F1 = (op & 0x01e0) >> 5;
556         bool useA1 = (opcode == 0x1b);
557         if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc);
558         m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff);      // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)?
559         executeF1Field(F1, D, S);
560         writeRegister(&m_x, data_read(m_pt));                           // TODO: EXM Pin & internal/external ROM?  Research.
561         switch (X)
562         {
563            case 0x00: m_pt++;      break;
564            case 0x01: m_pt += m_i; break;
565         }
566         cycles = 2;     // TODO: 1 if cached
567         pcAdvance = 1;
568         break;
569      }
570      case 0x14:
571      {
572         DSP_LINE("3-53")
573         // F1, Y = y[l]  :  (page 3-53)
574         const UINT8 Y = (op & 0x000f);
575         const UINT8 X = (op & 0x0010) >> 4;
576         const UINT8 S = (op & 0x0200) >> 9;
577         const UINT8 D = (op & 0x0400) >> 10;
578         const UINT8 F1 = (op & 0x01e0) >> 5;
579         executeF1Field(F1, D, S);
580         UINT16* destinationReg = registerFromYFieldUpper(Y);
581         UINT16 yRegValue = 0x0000;
582         switch (X)
583         {
584            case 0x00: yRegValue = (m_y & 0x0000ffff); break;
585            case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break;
586            default: break;
587         }
588         data_write(*destinationReg, yRegValue);
589         executeYFieldPost(Y);
590         cycles = 2;
591         pcAdvance = 1;
592         break;
593      }
594
595      // Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51)
596      case 0x07:
597      {
598         DSP_LINE("3-50")
599         // F1, At[1] = Y  :  (page 3-50)
600         // TODO: What does the X field do here, exactly?
601         const UINT8 Y = (op & 0x000f);
602         const UINT8 S = (op & 0x0200) >> 9;
603         const UINT8 aT = (op & 0x0400) >> 10;
604         const UINT8 F1 = (op & 0x01e0) >> 5;
605         executeF1Field(F1, !aT, S);
606         UINT64* destinationReg = NULL;
607         switch(aT)
608         {
609            case 0: destinationReg = &m_a1; break;
610            case 1: destinationReg = &m_a0; break;
611            default: break;
612         }
613         UINT16 sourceAddress = *(registerFromYFieldUpper(Y));
614         INT64 sourceValueSigned = (INT16)data_read(sourceAddress);
615         *destinationReg = sourceValueSigned & U64(0xffffffffff);
616         executeYFieldPost(Y);
617         cycles = 1;
618         pcAdvance = 1;
619         break;
620      }
621
622      // Format 2: Multiply/ALU Read/Write Group
623      case 0x15:
624      {
625         DSP_LINE("3-54")
626         // F1, Z : y[l]  :  (page 3-54)
627         const UINT8 Z = (op & 0x000f);
628         const UINT8 X = (op & 0x0010) >> 4;
629         const UINT8 S = (op & 0x0200) >> 9;
630         const UINT8 D = (op & 0x0400) >> 10;
631         const UINT8 F1 = (op & 0x01e0) >> 5;
632         executeF1Field(F1, D, S);
633         UINT16 temp = 0x0000;
634         UINT16* rN = registerFromYFieldUpper(Z);
635         switch (X)
636         {
637            case 0x00:
638               temp = m_y & 0x0000ffff;
639               m_y &= 0xffff0000;
640               m_y |= data_read(*rN);
641               executeZFieldPartOne(Z, rN);
642               data_write(*rN, temp);
643               executeZFieldPartTwo(Z, rN);
644               break;
645            case 0x01:
646               temp = (m_y & 0xffff0000) >> 16;
647               m_y &= 0x0000ffff;
648               m_y |= (data_read(*rN) << 16);
649               executeZFieldPartOne(Z, rN);
650               data_write(*rN, temp);
651               executeZFieldPartTwo(Z, rN);
652               break;
653         }
654         cycles = 2;
655         pcAdvance = 1;
656         break;
657      }
658      case 0x1d:
659      {
660         DSP_LINE("?")
661         // F1, Z : y, x=*pt++[i]
662         //const UINT8 Z = (op & 0x000f);
663         //const UINT8 X = (op & 0x0010) >> 4;
664         //const UINT8 S = (op & 0x0200) >> 9;
665         //const UINT8 D = (op & 0x0400) >> 10;
666         //const UINT8 F1 = (op & 0x01e0) >> 5;
667         break;
668      }
669
670      // Format 2a: Multiply/ALU Read/Write Group
671      case 0x05:
672      {
673         DSP_LINE("?")
674         // F1, Z : aT[1]
675         //const UINT8 Z = (op & 0x000f);
676         //const UINT8 X = (op & 0x0010) >> 4;
677         //const UINT8 S = (op & 0x0200) >> 9;
678         //const UINT8 aT = (op & 0x0400) >> 10;
679         //const UINT8 F1 = (op & 0x01e0) >> 5;
680         break;
681      }
682
683      // Format 3: Special Functions
684      case 0x12:
685      case 0x13:
686      {
687         DSP_LINE("3-36")
688         // if|ifc CON F2  (page 3-36)
689         const UINT8 CON = (op & 0x001f);
690         //const UINT8 S = (op & 0x0200) >> 9;
691         //const UINT8 D = (op & 0x0400) >> 10;
692         //const UINT8 F2 = (op & 0x01e0) >> 5;
693         bool conditionFulfilled = conditionTest(CON);
694         if (conditionFulfilled)
695         {
696            printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc);
697         }
698         cycles = 1;
699         pcAdvance = 1;
700         break;
701      }
702
703      // Format 4: Branch Direct Group
704      case 0x00: case 0x01:
705      {
706         DSP_LINE("3-20")
707         // goto JA  :  (page 3-20) (DONE)
708         const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
709         m_pc = JA;
710         cycles = 2;
711         pcAdvance = 0;
712         break;
713      }
714
715      case 0x10: case 0x11:
716      {
717         DSP_LINE("3-23")
718         // call JA  :  (page 3-23)
719         const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000);
720         m_pr = m_pc + 1;
721         m_pc = JA;
722         cycles = 2;
723         pcAdvance = 0;
724         break;
725      }
726
727      // Format 5: Branch Indirect Group
728      case 0x18:
729      {
730         DSP_LINE("3-21")
731         // goto B  :  (page 3-21)
732         const UINT8 B = (op & 0x0700) >> 8;
733         switch (B)
734         {
735            case 0x00: m_pc = m_pr; break;
736            case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
737            case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
738            case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break;
739            default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break;
740         }
741         cycles = 2;
742         pcAdvance = 0;
743         break;
744      }
745
746      // Format 6: Contitional Branch Qualifier/Software Interrupt (icall)
747      case 0x1a:
748      {
749         DSP_LINE("3-22")
750         // if CON [goto/call/return]  :  (page 3-22)
751         const UINT8 CON = (op & 0x001f);
752         bool conditionFulfilled = conditionTest(CON);
753         cycles = 3;                 // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3?
754         pcAdvance = 1;
755         if (!conditionFulfilled)
756         {
757            pcAdvance = 2;
758         }
759         break;
760      }
761
762      // Format 7: Data Move Group
763      case 0x09: case 0x0b:
764      {
765         DSP_LINE("3-29")
766         // R = aS  :  (page 3-29)
767         // TODO: Fix register pdxX (pc=338)
768         const UINT8 R = (op & 0x03f0) >> 4;
769         const UINT8 S = (op & 0x1000) >> 12;
770         void* destinationReg = registerFromRTable(R);
771         UINT64* sourceReg = (S) ? &m_a1 : &m_a0;
772         UINT16 sourceValue = (*sourceReg & U64(0x0ffff0000)) >> 16;
773         writeRegister(destinationReg, sourceValue);
774         cycles = 2;
775         pcAdvance = 1;
776         break;
777      }
778      case 0x08:
779      {
780         DSP_LINE("3-30")
781         // aT = R  :  (page 3-30)
782         const UINT8 R  = (op & 0x03f0) >> 4;
783         const UINT8 aT = (op & 0x0400) >> 10;
784         UINT64* destinationReg = NULL;
785         switch(aT)
786         {
787            case 0: destinationReg = &m_a1; break;
788            case 1: destinationReg = &m_a0; break;
789            default: break;
790         }
791         void* sourceReg = registerFromRTable(R);
792         *destinationReg &= U64(0x00000ffff);
793         *destinationReg |= (*(UINT16*)sourceReg) << 16;     // TODO: Fix for all registers
794         if (*(UINT16*)sourceReg & 0x8000)
795            *destinationReg |= U64(0xf00000000);
796         // TODO: Special function encoding
797         cycles = 2;
798         pcAdvance = 1;
799         break;
800      }
801      case 0x0f:
802      {
803         DSP_LINE("3-32")
804         // R = Y  :  (page 3-32)
805         const UINT8 Y = (op & 0x000f);
806         const UINT8 R = (op & 0x03f0) >> 4;
807         UINT16* sourceReg = registerFromYFieldUpper(Y);
808         void* destinationReg = registerFromRTable(R);
809         writeRegister(destinationReg, data_read(*sourceReg));
810         executeYFieldPost(Y);
811         cycles = 2;
812         pcAdvance = 1;
813         break;
814      }
815      case 0x0c:
816      {
817         DSP_LINE("3-33")
818         // Y = R  :  (page 3-33)
819         // TODO: Zero & Sign extend i, c0, c1, c2, and auc
820         const UINT8 Y = (op & 0x000f);
821         const UINT8 R = (op & 0x03f0) >> 4;
822         UINT16* destinationReg = registerFromYFieldUpper(Y);
823         UINT16* sourceReg = (UINT16*)registerFromRTable(R);     // TODO: This won't work for certain registers!
824         data_write(*destinationReg, *sourceReg);                //       Fix in data_write() maybe?
825         executeYFieldPost(Y);
826         cycles = 2;
827         pcAdvance = 1;
828         break;
829      }
830      case 0x0d:
831      {
832         DSP_LINE("?")
833         // Z : R
834         //const UINT8 Z = (op & 0x000f);
835         //const UINT8 R = (op & 0x03f0) >> 4;
836         break;
837      }
838
839      // Format 8: Data Move (immediate operand - 2 words)
840      case 0x0a:
841      {
842         DSP_LINE("3-28")
843         // R = N  :  (page 3-28) (DONE)
844         // NOTE: The docs speak of register sources & sign extension, but this is a register
845         // destination, so, typo?  If so, what does one do with the overflow bits?
846         const UINT8 R = (op & 0x03f0) >> 4;
847         const UINT16 iVal = opcode_read(1);
848         void* destinationReg = registerFromRTable(R);
849         writeRegister(destinationReg, iVal);
850         cycles = 2;
851         pcAdvance = 2;
852         break;
853      }
854
855      // Format 9: Short Immediate Group
856      case 0x02: case 0x03:
857      {
858         DSP_LINE("3-27")
859         // R = M  :  (page 3-27)
860         // TODO: Figure out notes about the DSP16A vs the DSP16.  9 bit is very DSP16...
861         const UINT16 M = (op & 0x01ff);
862         const UINT8  R = (op & 0x0e00) >> 9;
863         void* destinationReg = registerFromRImmediateField(R);
864         // Sign extend if the destination is j or k
865         UINT16 mValue = M;
866         if (destinationReg == &m_j || destinationReg == &m_k)
867         {
868            if (mValue & 0x0100) mValue |= 0xfe00;
869         }
870         writeRegister(destinationReg, mValue);
871         cycles = 1;
872         pcAdvance = 1;
873         break;
874      }
875
876      // Format 10: do - redo
877      case 0x0e:
878      {
879         DSP_LINE("3-25/3-26")
880         // do|redo K  :  (pages 3-25 & 3-26)
881         // TODO: The timings are intricate to say the least...
882         const UINT8 K = (op & 0x007f);
883         const UINT8 NI = (op & 0x0780) >> 7;
884         if (NI != 0)
885         {
886            // Do
887            m_cacheStart = m_pc + 1;
888            m_cacheEnd   = m_pc + 1 + NI;
889            m_cacheIterations = K-1;    // -1 because we check the counter @ the end
890            cycles = 1;
891            pcAdvance = 1;
892         }
893         else
894         {
895            // Redo
896            m_cacheIterations = K-1;    // -1 because we check the counter @ the end
897            m_cacheRedoNextPC = m_pc + 1;
898            m_pc = m_cacheStart;
899            cycles = 2;
900            pcAdvance = 0;
901         }
902         break;
903      }
904
905      // RESERVED
906      case 0x1e:
907      {
908         DSP_LINE("XXX")
909         break;
910      }
911
912      // UNKNOWN
913      default:
914      {
915         DSP_LINE("XXX")
916         break;
917      }
918   }
919
920   // Handle end-of-cache conditions for do|redos
921   if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID)
922   {
923      // You've reached the end of a cache loop after a redo opcode.
924      m_pc = m_cacheRedoNextPC;
925      m_cacheRedoNextPC = CACHE_INVALID;
926      pcAdvance = 0;
927   }
928   if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd))
929   {
930      // A regular iteration on a cached loop.
931      m_cacheIterations--;
932      m_pc = m_cacheStart;
933      pcAdvance = 0;
934   }
935}
Property changes on: trunk/src/emu/cpu/dsp16/dsp16ops.inc
Added: svn:eol-style
   + native
Added: svn:mime-type
   + text/plain

Previous 199869 Revisions Next


© 1997-2024 The MAME Team