1 /*  Copyright 2003-2006 Guillaume Duhamel
2     Copyright 2005-2006 Theo Berkau
3     Copyright 2015 Shinya Miyamoto(devmiyax)
4 
5     This file is part of Yabause.
6 
7     Yabause is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     Yabause is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Yabause; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20 */
21 
22 /*! \file scu.c
23     \brief SCU emulation functions.
24 */
25 
26 #include <stdlib.h>
27 #include "scu.h"
28 #include "debug.h"
29 #include "memory.h"
30 #include "sh2core.h"
31 #include "yabause.h"
32 #include "cs0.h"
33 #include "cs1.h"
34 #include "cs2.h"
35 #include "scsp.h"
36 #include "vdp1.h"
37 #include "vdp2.h"
38 #include "ygr.h"
39 #include "assert.h"
40 #include <stdarg.h>
41 #include "scu_dsp_jit.h"
42 
43 #ifdef OPTIMIZED_DMA
44 # include "cs2.h"
45 # include "scsp.h"
46 # include "vdp1.h"
47 # include "vdp2.h"
48 #endif
49 
50 Scu * ScuRegs;
51 scudspregs_struct * ScuDsp;
52 scubp_struct * ScuBP;
53 static int incFlg[4] = { 0 };
54 static void ScuTestInterruptMask(void);
55 struct ScuDspInterface scu_dsp_inf;
56 void scu_dsp_init();
57 //////////////////////////////////////////////////////////////////////////////
58 
ScuInit(void)59 int ScuInit(void) {
60    int i;
61 
62    if ((ScuRegs = (Scu *) calloc(1, sizeof(Scu))) == NULL)
63       return -1;
64 
65    if ((ScuDsp = (scudspregs_struct *) calloc(1, sizeof(scudspregs_struct))) == NULL)
66       return -1;
67 
68    if ((ScuBP = (scubp_struct *) calloc(1, sizeof(scubp_struct))) == NULL)
69       return -1;
70 
71    ScuDsp->jmpaddr = 0xFFFFFFFF;
72 
73    for (i = 0; i < MAX_BREAKPOINTS; i++)
74       ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF;
75    ScuBP->numcodebreakpoints = 0;
76    ScuBP->BreakpointCallBack=NULL;
77    ScuBP->inbreakpoint=0;
78 
79 #ifdef HAVE_PLAY_JIT
80    if (yabsys.use_scu_dsp_jit)
81       scu_dsp_jit_init();
82    else
83       scu_dsp_init();
84 #else
85    scu_dsp_init();
86 #endif
87 
88    return 0;
89 }
90 
91 //////////////////////////////////////////////////////////////////////////////
92 
ScuDeInit(void)93 void ScuDeInit(void) {
94    if (ScuRegs)
95       free(ScuRegs);
96    ScuRegs = NULL;
97 
98    if (ScuDsp)
99       free(ScuDsp);
100    ScuDsp = NULL;
101 
102    if (ScuBP)
103       free(ScuBP);
104    ScuBP = NULL;
105 }
106 
107 //////////////////////////////////////////////////////////////////////////////
108 
ScuReset(void)109 void ScuReset(void) {
110    ScuRegs->D0AD = ScuRegs->D1AD = ScuRegs->D2AD = 0x101;
111    ScuRegs->D0EN = ScuRegs->D1EN = ScuRegs->D2EN = 0x0;
112    ScuRegs->D0MD = ScuRegs->D1MD = ScuRegs->D2MD = 0x7;
113    ScuRegs->DSTP = 0x0;
114    ScuRegs->DSTA = 0x0;
115 
116    ScuDsp->ProgControlPort.all = 0;
117    ScuRegs->PDA = 0x0;
118 
119    ScuRegs->T1MD = 0x0;
120 
121    ScuRegs->IMS = 0xBFFF;
122    ScuRegs->IST = 0x0;
123 
124    ScuRegs->AIACK = 0x0;
125    ScuRegs->ASR0 = ScuRegs->ASR1 = 0x0;
126    ScuRegs->AREF = 0x0;
127 
128    ScuRegs->RSEL = 0x0;
129    ScuRegs->VER = 0x04; // Looks like all consumer saturn's used at least version 4
130 
131    ScuRegs->timer0 = 0;
132    ScuRegs->timer1 = 0;
133 
134    memset((void *)ScuRegs->interrupts, 0, sizeof(scuinterrupt_struct) * 30);
135    ScuRegs->NumberOfInterrupts = 0;
136 }
137 
138 //////////////////////////////////////////////////////////////////////////////
139 
140 #ifdef OPTIMIZED_DMA
141 
142 // Table of memory types for DMA optimization, in 512k (1<<19 byte) units:
143 //    0x00 = no special handling
144 //    0x12 = VDP1/2 RAM (8-bit organized, 16-bit copy unit)
145 //    0x22 = M68K RAM (16-bit organized, 16-bit copy unit)
146 //    0x23 = VDP2 color RAM (16-bit organized, 16-bit copy unit)
147 //    0x24 = SH-2 RAM (16-bit organized, 32-bit copy unit)
148 static const u8 DMAMemoryType[0x20000000>>19] = {
149    [0x00200000>>19] = 0x24,
150    [0x00280000>>19] = 0x24,
151    [0x05A00000>>19] = 0x22,
152    [0x05A80000>>19] = 0x22,
153    [0x05C00000>>19] = 0x12,
154    [0x05C00000>>19] = 0x12,
155    [0x05E00000>>19] = 0x12,
156    [0x05E80000>>19] = 0x12,
157    [0x05F00000>>19] = 0x23,
158    [0x06000000>>19] = 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
159                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
160                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
161                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
162                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
163                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
164                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
165                       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
166 };
167 
168 // Function to return the native pointer for an optimized address
169 #ifdef __GNUC__
170 __attribute__((always_inline))  // Force it inline for better performance
171 #endif
DMAMemoryPointer(u32 address)172 static INLINE void *DMAMemoryPointer(u32 address) {
173    u32 page = (address & 0x1FF80000) >> 19;
174    switch (DMAMemoryType[page]) {
175       case 0x12:
176          switch (page) {
177             case 0x05C00000>>19: return &Vdp1Ram[address & 0x7FFFF];
178             case 0x05E00000>>19: // fall through
179             case 0x05E80000>>19: return &Vdp2Ram[address & 0x7FFFF];
180             default: return NULL;
181          }
182       case 0x22:
183          return &SoundRam[address & 0x7FFFF];
184       case 0x23:
185          return &Vdp2ColorRam[address & 0xFFF];
186       case 0x24:
187          if (page == 0x00200000>>19) {
188             return &LowWram[address & 0xFFFFF];
189          } else {
190             return &HighWram[address & 0xFFFFF];
191          }
192       default:
193          return NULL;
194    }
195 }
196 
197 #endif  // OPTIMIZED_DMA
198 
DoDMA(u32 ReadAddress,unsigned int ReadAdd,u32 WriteAddress,unsigned int WriteAdd,u32 TransferSize)199 static void DoDMA(u32 ReadAddress, unsigned int ReadAdd,
200                   u32 WriteAddress, unsigned int WriteAdd,
201                   u32 TransferSize)
202 {
203 	LOG("DoDMA src=%08X,dst=%08X,size=%d\n", ReadAddress, WriteAddress, TransferSize);
204    if (ReadAdd == 0) {
205       // DMA fill
206 
207 #ifdef OPTIMIZED_DMA
208       if (ReadAddress == 0x25818000 && WriteAdd == 4) {
209          // Reading from the CD buffer, so optimize if possible.
210          if ((WriteAddress & 0x1E000000) == 0x06000000) {
211             Cs2RapidCopyT2(&HighWram[WriteAddress & 0xFFFFF], TransferSize/4);
212             SH2WriteNotify(WriteAddress, TransferSize);
213             return;
214          }
215          else if ((WriteAddress & 0x1FF00000) == 0x00200000) {
216             Cs2RapidCopyT2(&LowWram[WriteAddress & 0xFFFFF], TransferSize/4);
217             SH2WriteNotify(WriteAddress, TransferSize);
218             return;
219          }
220       }
221 #endif
222 
223       // Is it a constant source or a register whose value can change from
224       // read to read?
225       int constant_source = ((ReadAddress & 0x1FF00000) == 0x00200000)
226                          || ((ReadAddress & 0x1E000000) == 0x06000000)
227                          || ((ReadAddress & 0x1FF00000) == 0x05A00000)
228                          || ((ReadAddress & 0x1DF00000) == 0x05C00000);
229 
230       if ((WriteAddress & 0x1FFFFFFF) >= 0x5A00000
231             && (WriteAddress & 0x1FFFFFFF) < 0x5FF0000) {
232          // Fill a 32-bit value in 16-bit units.  We have to be careful to
233          // avoid misaligned 32-bit accesses, because some hardware (e.g.
234          // PSP) crashes on such accesses.
235          if (constant_source) {
236             u32 counter = 0;
237             u32 val;
238             if (ReadAddress & 2) {  // Avoid misaligned access
239                val = MappedMemoryReadWordNocache(MSH2, ReadAddress) << 16
240                    | MappedMemoryReadWordNocache(MSH2, ReadAddress+2);
241             } else {
242                val = MappedMemoryReadLongNocache(MSH2, ReadAddress);
243             }
244             while (counter < TransferSize) {
245                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(val >> 16));
246                WriteAddress += WriteAdd;
247                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)val);
248                WriteAddress += WriteAdd;
249                counter += 4;
250             }
251          } else {
252             u32 counter = 0;
253             while (counter < TransferSize) {
254                u32 tmp = MappedMemoryReadLongNocache(MSH2, ReadAddress);
255                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(tmp >> 16));
256                WriteAddress += WriteAdd;
257                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)tmp);
258                WriteAddress += WriteAdd;
259                ReadAddress += ReadAdd;
260                counter += 4;
261             }
262          }
263       }
264       else {
265          // Fill in 32-bit units (always aligned).
266          u32 start = WriteAddress;
267          if (constant_source) {
268             u32 val = MappedMemoryReadLongNocache(MSH2, ReadAddress);
269             u32 counter = 0;
270             while (counter < TransferSize) {
271                MappedMemoryWriteLongNocache(MSH2, WriteAddress, val);
272                ReadAddress += ReadAdd;
273                WriteAddress += WriteAdd;
274                counter += 4;
275             }
276          } else {
277             u32 counter = 0;
278             while (counter < TransferSize) {
279                MappedMemoryWriteLongNocache(MSH2, WriteAddress,
280                                      MappedMemoryReadLongNocache(MSH2, ReadAddress));
281                ReadAddress += ReadAdd;
282                WriteAddress += WriteAdd;
283                counter += 4;
284             }
285          }
286          // Inform the SH-2 core in case it was a write to main RAM.
287          SH2WriteNotify(start, WriteAddress - start);
288       }
289 
290    }
291 
292    else {
293       // DMA copy
294 
295 #ifdef OPTIMIZED_DMA
296       int source_type = DMAMemoryType[(ReadAddress  & 0x1FF80000) >> 19];
297       int dest_type   = DMAMemoryType[(WriteAddress & 0x1FF80000) >> 19];
298       if (WriteAdd == ((dest_type & 0x2) ? 2 : 4)) {
299          // Writes don't skip any bytes, so use an optimized copy algorithm
300          // if possible.
301          const u8 *source_ptr = DMAMemoryPointer(ReadAddress);
302          u8 *dest_ptr = DMAMemoryPointer(WriteAddress);
303 # ifdef WORDS_BIGENDIAN
304          if ((source_type & 0x30) && (dest_type & 0x30)) {
305             // Source and destination are both directly accessible.
306             memcpy(dest_ptr, source_ptr, TransferSize);
307             if (dest_type == 0x24) {
308                SH2WriteNotify(WriteAddress, TransferSize);
309             } else if (dest_type == 0x22) {
310                M68KWriteNotify(WriteAddress & 0x7FFFF, TransferSize);
311             }
312             return;
313          }
314 # else  // !WORDS_BIGENDIAN
315          if (source_type & dest_type & 0x10) {
316             // Source and destination are both 8-bit organized.
317             memcpy(dest_ptr, source_ptr, TransferSize);
318             return;
319          }
320          else if (source_type & dest_type & 0x20) {
321             // Source and destination are both 16-bit organized.
322             memcpy(dest_ptr, source_ptr, TransferSize);
323             if (dest_type == 0x24) {
324                SH2WriteNotify(WriteAddress, TransferSize);
325             } else if (dest_type == 0x22) {
326                M68KWriteNotify(WriteAddress & 0x7FFFF, TransferSize);
327             }
328             return;
329          }
330          else if ((source_type | dest_type) >> 4 == 0x3) {
331             // Need to convert between 8-bit and 16-bit organization.
332             if ((ReadAddress | WriteAddress) & 2) {  // Avoid misaligned access
333                const u16 *source_16 = (u16 *)source_ptr;
334                u16 *dest_16 = (u16 *)dest_ptr;
335                u32 counter;
336                for (counter = 0; counter < TransferSize-6;
337                      counter += 8, source_16 += 4, dest_16 += 4) {
338                   // Use "unsigned int" rather than "u16" because some
339                   // compilers try too hard to keep the high bits zero,
340                   // thus wasting cycles on every iteration.
341                   unsigned int val0 = BSWAP16(source_16[0]);
342                   unsigned int val1 = BSWAP16(source_16[1]);
343                   unsigned int val2 = BSWAP16(source_16[2]);
344                   unsigned int val3 = BSWAP16(source_16[3]);
345                   dest_16[0] = val0;
346                   dest_16[1] = val1;
347                   dest_16[2] = val2;
348                   dest_16[3] = val3;
349                }
350                for (; counter < TransferSize;
351                      counter += 2, source_16++, dest_16++) {
352                   *dest_16 = BSWAP16(*source_16);
353                }
354             }
355             else {  // 32-bit aligned accesses possible
356                const u32 *source_32 = (u32 *)source_ptr;
357                u32 *dest_32 = (u32 *)dest_ptr;
358                u32 counter;
359                for (counter = 0; counter < TransferSize-12;
360                      counter += 16, source_32 += 4, dest_32 += 4) {
361                   u32 val0 = BSWAP16(source_32[0]);
362                   u32 val1 = BSWAP16(source_32[1]);
363                   u32 val2 = BSWAP16(source_32[2]);
364                   u32 val3 = BSWAP16(source_32[3]);
365                   dest_32[0] = val0;
366                   dest_32[1] = val1;
367                   dest_32[2] = val2;
368                   dest_32[3] = val3;
369                }
370                for (; counter < TransferSize;
371                      counter += 4, source_32++, dest_32++) {
372                   *dest_32 = BSWAP16(*source_32);
373                }
374             }
375             return;
376          }
377 # endif  // WORDS_BIGENDIAN
378       }
379 #endif  // OPTIMIZED_DMA
380 
381       if ((WriteAddress & 0x1FFFFFFF) >= 0x5A00000
382           && (WriteAddress & 0x1FFFFFFF) < 0x5FF0000) {
383          // Copy in 16-bit units, avoiding misaligned accesses.
384          u32 counter = 0;
385          if (ReadAddress & 2) {  // Avoid misaligned access
386             u16 tmp = MappedMemoryReadWordNocache(MSH2, ReadAddress);
387             MappedMemoryWriteWordNocache(MSH2, WriteAddress, tmp);
388             WriteAddress += WriteAdd;
389             ReadAddress += 2;
390             counter += 2;
391          }
392          if (TransferSize >= 3)
393          {
394             while (counter < TransferSize-2) {
395                u32 tmp = MappedMemoryReadLongNocache(MSH2, ReadAddress);
396                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(tmp >> 16));
397                WriteAddress += WriteAdd;
398                MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)tmp);
399                WriteAddress += WriteAdd;
400                ReadAddress += 4;
401                counter += 4;
402             }
403          }
404          if (counter < TransferSize) {
405             u16 tmp = MappedMemoryReadWordNocache(MSH2, ReadAddress);
406             MappedMemoryWriteWordNocache(MSH2, WriteAddress, tmp);
407             WriteAddress += WriteAdd;
408             ReadAddress += 2;
409             counter += 2;
410          }
411       }
412       else {
413          u32 counter = 0;
414          u32 start = WriteAddress;
415          while (counter < TransferSize) {
416             MappedMemoryWriteLongNocache(MSH2, WriteAddress, MappedMemoryReadLongNocache(MSH2, ReadAddress));
417             ReadAddress += 4;
418             WriteAddress += WriteAdd;
419             counter += 4;
420          }
421          /* Inform the SH-2 core in case it was a write to main RAM */
422          SH2WriteNotify(start, WriteAddress - start);
423       }
424 
425    }  // Fill / copy
426 }
427 
428 //////////////////////////////////////
429 
430 #define DMA_FINISHED 0
431 #define DMA_WAITING_FACTOR 1
432 #define DMA_QUEUED 2
433 #define DMA_ACTIVE 3
434 
435 #define DMA_TRANSFER_A_TO_B 1
436 #define DMA_TRANSFER_CPU_TO_B 2
437 #define DMA_TRANSFER_A_TO_CPU 3
438 #define DMA_TRANSFER_B_TO_CPU 4
439 #define DMA_TRANSFER_CPU_TO_A 5
440 #define DMA_TRANSFER_B_TO_A 6
441 
442 #define DSP_CPU_BUS 1
443 #define DSP_B_BUS 2
444 #define DSP_A_BUS 3
445 
446 void scu_sort_dma();
447 
448 struct QueuedDma
449 {
450    u32 read_address;
451    u32 write_address;
452    u32 count;
453    u32 original_count;
454    int count_mod_4;
455    int status;
456    int second_word;
457    u32 buffer;
458    u32 read_add;
459    int add_setting;
460    u32 write_add;
461    int bus_type;
462    int is_indirect;
463    int read_addr_update;
464    int write_addr_update;
465    int starting_factor;
466    int level;
467    u32 indirect_address;
468    int is_last_indirect;
469    int is_dsp;
470    int dsp_dma_type;
471    int dsp_bank;
472    int dsp_add;
473    u32 dsp_address;
474    u8 program_ram_counter;
475    u8 dsp_add_setting;
476    u32 dsp_orig_count;
477    u8 ct;
478    int num_written;
479    int dsp_bus;
480 }scu_dma_queue[16] = { 0 };
481 
get_write_add_value(u32 reg_val)482 int get_write_add_value(u32 reg_val)
483 {
484    switch (reg_val & 0x7)
485    {
486    case 0:
487       return 0;
488    case 1:
489       return 2;
490    case 2:
491       return 4;
492    case 3:
493       return 8;
494    case 4:
495       return 16;
496    case 5:
497       return 32;
498    case 6:
499       return 64;
500    case 7:
501       return 128;
502    }
503 
504    return 0;
505 }
506 
scu_active_dma_exists()507 int scu_active_dma_exists()
508 {
509    int i = 0;
510    for (i = 0; i < 16; i++)
511    {
512       if (scu_dma_queue[i].status == DMA_ACTIVE)
513          return 1;
514    }
515 
516    return 0;
517 }
518 
dma_finish(struct QueuedDma * dma)519 void dma_finish(struct QueuedDma * dma)
520 {
521    memset(dma, 0, sizeof(struct QueuedDma));
522 
523    dma->status = DMA_FINISHED;
524 
525    scu_sort_dma();
526 
527    if (!scu_active_dma_exists())
528    {
529       if (scu_dma_queue[0].status == DMA_QUEUED)
530          scu_dma_queue[0].status = DMA_ACTIVE;
531    }
532 }
533 
dma_finished(struct QueuedDma * dma)534 void dma_finished(struct QueuedDma * dma)
535 {
536    if (dma->bus_type == DMA_TRANSFER_A_TO_B)
537       ScuRegs->DSTA &= ~0x300000;
538 
539    //complete
540    switch (dma->level)
541    {
542    case 0:
543       ScuRegs->DSTA &= ~(1 << 4);//clear dma operation flag
544       ScuSendLevel0DMAEnd();
545       break;
546    case 1:
547       ScuRegs->DSTA &= ~(1 << 8);
548       ScuSendLevel1DMAEnd();
549       break;
550    case 2:
551       ScuRegs->DSTA &= ~(1 << 12);
552       ScuSendLevel2DMAEnd();
553       break;
554    }
555 
556    dma_finish(dma);
557 }
558 
dma_read_indirect(struct QueuedDma * dma)559 void dma_read_indirect(struct QueuedDma * dma)
560 {
561    u32 address = MappedMemoryReadLongNocache(MSH2, dma->indirect_address + 8);
562    dma->original_count = dma->count = MappedMemoryReadLongNocache(MSH2, dma->indirect_address);
563    dma->write_address = MappedMemoryReadLongNocache(MSH2, dma->indirect_address + 4);
564    dma->read_address = address & (~0x80000000);
565    dma->second_word = 0;
566 
567    if (address & 0x80000000)
568       dma->is_last_indirect = 1;
569 }
570 
571 int get_bus_type(u32 src, u32 dst);
572 
check_dma_finished(struct QueuedDma * dma)573 void check_dma_finished(struct QueuedDma *dma)
574 {
575    if (dma->count == 0)
576    {
577       if (dma->is_indirect)
578       {
579          if (dma->is_last_indirect)
580          {
581             dma->status = DMA_FINISHED;
582             dma_finished(dma);
583          }
584          else
585          {
586             dma_read_indirect(dma);
587             dma->bus_type = get_bus_type(dma->read_address, dma->write_address);
588             dma->indirect_address += 0xC;
589          }
590       }
591       else
592       {
593          dma_finished(dma);
594       }
595    }
596 }
597 
get_write_add_b(struct QueuedDma * dma)598 void get_write_add_b(struct QueuedDma * dma)
599 {
600    switch (dma->add_setting)
601    {
602    case 0:
603       break;
604    case 1:
605          dma->write_address += 2;
606       break;
607    case 2:
608          dma->write_address += 4;
609       break;
610    case 3:
611          dma->write_address += 8;
612       break;
613    case 4:
614          dma->write_address += 16;
615       break;
616    case 5:
617          dma->write_address += 32;
618       break;
619    case 6:
620          dma->write_address += 64;
621       break;
622    case 7:
623          dma->write_address += 128;
624       break;
625    }
626 }
627 
get_write_add_a_to_cpu(struct QueuedDma * dma)628 void get_write_add_a_to_cpu(struct QueuedDma * dma)
629 {
630    switch (dma->add_setting)
631    {
632    case 0:
633       break;
634    case 1:
635       if ((dma->num_written % 8) == 0)
636          dma->write_address += 4;
637       break;
638    case 2:
639       dma->write_address += 4;
640       break;
641    case 3:
642       dma->write_address += 8;
643       break;
644    case 4:
645       dma->write_address += 16;
646       break;
647    case 5:
648       dma->write_address += 32;
649       break;
650    case 6:
651       dma->write_address += 64;
652       break;
653    case 7:
654       dma->write_address += 128;
655       break;
656    }
657 }
658 
659 int sh2_check_wait(SH2_struct * sh, u32 addr, int size);
660 void get_add(struct QueuedDma * dma);
661 
do_writes_b(struct QueuedDma * dma)662 void do_writes_b(struct QueuedDma* dma)
663 {
664    if (!dma->second_word)
665    {
666       dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address);
667       MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16);
668       dma->second_word = 1;
669       dma->count -= 2;
670       dma->num_written += 2;
671       get_write_add_b(dma);
672    }
673    else
674    {
675       MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer & 0xffff);
676       dma->read_address += dma->read_add;
677       dma->count -= 2;
678       dma->num_written += 2;
679       dma->second_word = 0;
680       get_write_add_b(dma);
681    }
682 }
683 
scu_dma_tick_to_b(struct QueuedDma * dma)684 void scu_dma_tick_to_b(struct QueuedDma *dma)
685 {
686    if (sh2_check_wait(NULL, dma->read_address, 2))
687       return;
688 
689    if (dma->count_mod_4 == 0)
690    {
691       do_writes_b(dma);
692    }
693    else if (dma->count_mod_4 == 1)
694    {
695       //this mode will write 0x90 at the end of a dma for some reason
696       if ((dma->original_count >= 0x5 )
697          && (dma->add_setting >= 2 ) && dma->count == 1)
698       {
699          MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xff);
700          MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, 0x90);
701          dma->count = 0;
702       }
703       else if (dma->count == 1 && dma->original_count > 1 && dma->add_setting == 0)
704       {
705          u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address);
706          MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, 0x90);
707          dma->count = 0;
708       }
709       else if (dma->count == 1)
710       {
711          u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address);
712          MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte);
713          dma->count = 0;
714       }
715       else
716       {
717          do_writes_b(dma);
718       }
719    }
720    else if (dma->count_mod_4 == 2)
721    {
722       if (dma->count == 2)
723       {
724          u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address);
725          MappedMemoryWriteWordNocache(MSH2, dma->write_address, word);
726          dma->count = 0;
727       }
728       else
729          do_writes_b(dma);
730    }
731    else if (dma->count_mod_4 == 3)
732    {
733       if (dma->count == 3 && dma->original_count > 3)
734       {
735          dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address);
736          MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16);
737 
738          get_write_add_b(dma);
739 
740          MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xFF);
741          dma->count = 0;
742       }
743       else if (dma->count == 3)
744       {
745          dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address);
746          MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16);
747 
748          get_write_add_b(dma);
749 
750          MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xFF);
751          dma->count = 0;
752       }
753       else
754       {
755          do_writes_b(dma);
756       }
757    }
758 
759    check_dma_finished(dma);
760 }
761 
do_writes_a_to_cpu(struct QueuedDma * dma)762 void do_writes_a_to_cpu(struct QueuedDma * dma)
763 {
764    if (!dma->second_word)
765    {
766       dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16;
767       dma->second_word = 1;
768       dma->count -= 2;
769       dma->num_written += 2;
770    }
771    else
772    {
773       dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2);
774       MappedMemoryWriteLongNocache(MSH2, dma->write_address, dma->buffer);
775       dma->read_address += dma->read_add;
776       dma->count -= 2;
777       dma->num_written += 2;
778       dma->second_word = 0;
779       get_write_add_a_to_cpu(dma);
780    }
781 }
782 
scu_dma_tick_a_to_cpu(struct QueuedDma * dma)783 void scu_dma_tick_a_to_cpu(struct QueuedDma *dma)
784 {
785    if (sh2_check_wait(NULL, dma->read_address, 2))
786       return;
787 
788    if (dma->count_mod_4 == 0)
789    {
790       do_writes_a_to_cpu(dma);
791    }
792    else if (dma->count_mod_4 == 1)
793    {
794       if (dma->count == 1)
795       {
796          u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address);
797          MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte);
798          dma->count = 0;
799       }
800       else
801       {
802          do_writes_a_to_cpu(dma);
803       }
804    }
805    else if (dma->count_mod_4 == 2)
806    {
807       if (dma->count == 2)
808       {
809          u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address);
810          MappedMemoryWriteWordNocache(MSH2, dma->write_address, word);
811          dma->count = 0;
812       }
813       else  do_writes_a_to_cpu(dma);
814    }
815    else if (dma->count_mod_4 == 3)
816    {
817       if (dma->count == 3)
818       {
819          dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16;
820          MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16);
821          dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2);
822 
823          MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, (dma->buffer >> 8) & 0xFF);
824          dma->count = 0;
825       }
826       else
827       {
828          do_writes_a_to_cpu(dma);
829       }
830    }
831 
832    check_dma_finished(dma);
833 }
834 
swap_dma_queue(int i,int j)835 void swap_dma_queue(int i, int j)
836 {
837    struct QueuedDma temp = scu_dma_queue[i];
838    scu_dma_queue[i] = scu_dma_queue[j];
839    scu_dma_queue[j] = temp;
840 }
841 
scu_sort_dma()842 void scu_sort_dma()
843 {
844    int i = 0;
845 
846    //sort active, queued, starting factor, finished
847    //statuses are defined in numerical order
848    for (i = 0; i < 16; i++)
849    {
850       int j = 0;
851       for (j = 0; j < 16; j++)
852       {
853          if (scu_dma_queue[i].status > scu_dma_queue[j].status)
854          {
855             swap_dma_queue(i, j);
856          }
857       }
858    }
859 }
860 
scu_dma_tick_32(struct QueuedDma * dma)861 void scu_dma_tick_32(struct QueuedDma * dma)
862 {
863    u32 src_val = 0;
864 
865    if (sh2_check_wait(NULL, dma->read_address, 2))
866       return;
867 
868    src_val = MappedMemoryReadLongNocache(MSH2, dma->read_address);
869    MappedMemoryWriteLongNocache(MSH2, dma->write_address, src_val);
870 
871    dma->read_address += dma->read_add;
872    dma->write_address += dma->write_add;
873    dma->count-=4;
874 
875    check_dma_finished(dma);
876 }
877 
is_a_bus(u32 addr)878 int is_a_bus(u32 addr)
879 {
880    addr &= 0xFFFFFFF;
881 
882    if (addr >= 0x2000000 && addr <= 0x58FFFFF)
883       return 1;
884 
885    return 0;
886 }
887 
is_b_bus(u32 addr)888 int is_b_bus(u32 addr)
889 {
890    addr &= 0xFFFFFFF;
891 
892    if (addr >= 0x5A00000 && addr <= 0x5F8011F)
893       return 1;
894 
895    return 0;
896 }
897 
is_cpu_bus(u32 addr)898 int is_cpu_bus(u32 addr)
899 {
900    addr &= 0xFFFFFFF;
901 
902    if (is_a_bus(addr))
903       return 0;
904    if (is_b_bus(addr))
905       return 0;
906 
907    return 1;
908 }
909 
get_bus_type(u32 src,u32 dst)910 int get_bus_type(u32 src, u32 dst)
911 {
912    u8 src_type_a = is_a_bus(src);
913    u8 src_type_b = is_b_bus(src);
914    u8 src_type_cpu = (src_type_a == 0) && (src_type_b == 0);
915 
916    u8 dst_type_a = is_a_bus(dst);
917    u8 dst_type_b = is_b_bus(dst);
918    u8 dst_type_cpu = (dst_type_a == 0) && (dst_type_b == 0);
919 
920    if (src_type_a && dst_type_b)
921       return DMA_TRANSFER_A_TO_B;
922 
923    if (src_type_cpu && dst_type_b)
924       return DMA_TRANSFER_CPU_TO_B;
925 
926    if (src_type_a && dst_type_cpu)
927       return DMA_TRANSFER_A_TO_CPU;
928 
929    if (src_type_b && dst_type_cpu)
930       return DMA_TRANSFER_B_TO_CPU;
931 
932    if (src_type_cpu && dst_type_a)
933       return DMA_TRANSFER_CPU_TO_A;
934 
935    if (src_type_b && dst_type_a)
936       return DMA_TRANSFER_B_TO_A;
937 
938    return 0;
939 }
940 
scu_dma_sort_activate(struct QueuedDma * dma)941 void scu_dma_sort_activate(struct QueuedDma *dma)
942 {
943    scu_sort_dma();
944 
945    if (!scu_active_dma_exists())
946    {
947       if (scu_dma_queue[0].status == DMA_QUEUED)
948       {
949          scu_dma_queue[0].status = DMA_ACTIVE;
950 
951          if (scu_dma_queue[0].level == 0)
952             ScuRegs->DSTA |= (1 << 4);//set dma operation flag
953          else if (scu_dma_queue[0].level == 1)
954             ScuRegs->DSTA |= (1 << 8);
955          else if (scu_dma_queue[0].level == 2)
956             ScuRegs->DSTA |= (1 << 12);
957 
958          if (dma->bus_type == DMA_TRANSFER_A_TO_B)
959             ScuRegs->DSTA |= 0x300000;
960       }
961    }
962 }
963 
964 
scu_enqueue_dma(struct QueuedDma * dma,u32 read_reg,u32 write_reg,u32 count_reg,u32 add_reg,u32 mode_reg,int level)965 void scu_enqueue_dma(struct QueuedDma *dma,
966    u32 read_reg, u32 write_reg, u32 count_reg, u32 add_reg, u32 mode_reg, int level)
967 {
968    memset(dma, 0, sizeof(struct QueuedDma));
969 
970    dma->read_address = read_reg;
971    dma->indirect_address = dma->write_address = write_reg;
972    dma->add_setting = add_reg & 0x7;
973    dma->write_add = get_write_add_value(add_reg & 0x7);
974    dma->is_indirect = (mode_reg >> 24) & 1;
975    dma->read_addr_update = (mode_reg >> 16) & 1;
976    dma->write_addr_update = (mode_reg >> 8) & 1;
977    dma->starting_factor = mode_reg & 7;
978    dma->original_count = dma->count = count_reg;
979    dma->level = level;
980 
981    if (dma->is_indirect)
982       dma_read_indirect(dma);
983 
984    dma->count_mod_4 = dma->count % 4;
985 
986    if (dma->starting_factor != 7)
987       dma->status = DMA_WAITING_FACTOR;//wait for an event
988    else
989       dma->status = DMA_QUEUED;
990 
991    if ((add_reg >> 8) & 1)
992       dma->read_add = 4;
993 
994    dma->bus_type = get_bus_type(dma->read_address, dma->write_address);
995 
996    if (!dma->is_indirect)
997    {
998       if (dma->level > 0) {
999          dma->count &= 0xFFF;
1000 
1001          if (dma->count == 0)
1002             dma->count = 0x1000;
1003       }
1004       else {
1005          if (dma->count == 0)
1006             dma->count = 0x100000;
1007       }
1008    }
1009 
1010    //sort dmas, if there are queued dmas but none are active
1011    //then activate one
1012 
1013    scu_dma_sort_activate(dma);
1014 }
1015 
scu_insert_dma(u32 read_reg,u32 write_reg,u32 count_reg,u32 add_reg,u32 mode_reg,int level)1016 void scu_insert_dma(u32 read_reg, u32 write_reg, u32 count_reg, u32 add_reg, u32 mode_reg, int level)
1017 {
1018    int i = 0;
1019    for (i = 0; i < 16; i++)
1020    {
1021       if (scu_dma_queue[i].status == DMA_FINISHED)
1022       {
1023          scu_enqueue_dma(&scu_dma_queue[i], read_reg, write_reg, count_reg, add_reg, mode_reg, level);
1024          break;
1025       }
1026    }
1027 
1028    scu_sort_dma();
1029 }
1030 
adjust_ra0_wa0(struct QueuedDma * dma)1031 void adjust_ra0_wa0(struct QueuedDma * dma)
1032 {
1033    scudspregs_struct * sc = ScuDsp;
1034 
1035    int is_a_bus = ((dma->dsp_address & 0x0F000000) >= 0x02000000 &&
1036       (dma->dsp_address & 0x0FF00000) <= 0x05800000);
1037 
1038    int is_c_bus = (dma->dsp_address & 0x0F000000) == 0x06000000;
1039 
1040    if (dma->dsp_dma_type == 1 || dma->dsp_dma_type == 3)
1041    {
1042       switch (dma->dsp_add_setting)
1043       {
1044       case 0:
1045       case 1:
1046       case 4:
1047       case 5:
1048          sc->RA0 += 1;
1049          break;
1050       case 2:
1051       case 3:
1052       case 6:
1053       case 7:
1054          sc->RA0 += dma->dsp_orig_count;
1055       default:
1056          break;
1057       }
1058    }
1059    else if (dma->dsp_dma_type == 2 || dma->dsp_dma_type == 4)
1060    {
1061       if (is_c_bus || is_a_bus)
1062       {
1063          switch (dma->dsp_add_setting)
1064          {
1065          case 0:
1066             sc->WA0 += 1;
1067             break;
1068          case 1:
1069             if (dma->dsp_orig_count == 1 || dma->dsp_orig_count == 2)
1070                sc->WA0 += 1;
1071             else
1072                sc->WA0 += (dma->dsp_orig_count >> 1) + 1;
1073             break;
1074          case 2:
1075             sc->WA0 += dma->dsp_orig_count;
1076             break;
1077          case 3:
1078             sc->WA0 += (dma->dsp_orig_count * 2) - 1;
1079             break;
1080          case 4:
1081             sc->WA0 += (dma->dsp_orig_count * 4) - 3;
1082             break;
1083          case 5:
1084             sc->WA0 += (dma->dsp_orig_count * 8) - 7;
1085             break;
1086          case 6:
1087             sc->WA0 += (dma->dsp_orig_count * 16) - 15;
1088             break;
1089          case 7:
1090             sc->WA0 += (dma->dsp_orig_count * 32) - 31;
1091             break;
1092          default:
1093             break;
1094          }
1095       }
1096       else
1097       {
1098          //b-bus
1099 
1100          switch (dma->dsp_add_setting)
1101          {
1102          case 0:
1103             sc->WA0 += 1;
1104             break;
1105          case 1:
1106             sc->WA0 += dma->dsp_orig_count;
1107             break;
1108          case 2:
1109             sc->WA0 += (dma->dsp_orig_count * 2) - 1;
1110             break;
1111          case 3:
1112             sc->WA0 += (dma->dsp_orig_count * 4) - 3;
1113             break;
1114          case 4:
1115             sc->WA0 += (dma->dsp_orig_count * 8) - 7;
1116             break;
1117          case 5:
1118             sc->WA0 += (dma->dsp_orig_count * 16) - 15;
1119             break;
1120          case 6:
1121             sc->WA0 += (dma->dsp_orig_count * 32) - 31;
1122             break;
1123          case 7:
1124             sc->WA0 += (dma->dsp_orig_count * 64) - 63;
1125             break;
1126          default:
1127             break;
1128          }
1129       }
1130    }
1131 }
1132 
scu_dma_tick_dsp(struct QueuedDma * dma)1133 void scu_dma_tick_dsp(struct QueuedDma * dma)
1134 {
1135    scudspregs_struct * sc = ScuDsp;
1136 
1137    if (dma->dsp_dma_type == 1)
1138    {
1139       if (sh2_check_wait(NULL, dma->dsp_address, 2))
1140          return;
1141 
1142       sc->MD[dma->dsp_bank][dma->ct] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address);
1143       dma->ct++;
1144       dma->ct &= 0x3F;
1145 
1146       if (dma->dsp_bus == DSP_CPU_BUS || dma->dsp_bus == DSP_A_BUS)
1147       {
1148          switch (dma->dsp_add_setting)
1149          {
1150          case 0:
1151          case 1:
1152          case 4:
1153          case 5:
1154             break;
1155          case 2:
1156          case 3:
1157          case 6:
1158          case 7:
1159             dma->dsp_address += 4;
1160             break;
1161          default:
1162             break;
1163          }
1164       }
1165       else
1166          dma->dsp_address += 4;
1167 
1168       dma->count--;
1169    }
1170    else if (dma->dsp_dma_type == 2 || dma->dsp_dma_type == 4)
1171    {
1172       if (dma->dsp_bus == DSP_A_BUS || dma->dsp_bus == DSP_CPU_BUS)
1173       {
1174          u32 Val = sc->MD[dma->dsp_bank][dma->ct];
1175          MappedMemoryWriteLongNocache(MSH2, dma->dsp_address, Val);
1176 
1177          switch (dma->dsp_add_setting)
1178          {
1179          case 0:
1180             break;
1181          case 1:
1182             if (dma->num_written & 1)
1183                dma->dsp_address += 4;
1184 
1185             dma->num_written++;
1186             break;
1187          case 2:
1188             dma->dsp_address += 4;
1189             break;
1190          case 3:
1191             dma->dsp_address += 8;
1192             break;
1193          case 4:
1194             dma->dsp_address += 16;
1195             break;
1196          case 5:
1197             dma->dsp_address += 32;
1198             break;
1199          case 6:
1200             dma->dsp_address += 64;
1201             break;
1202          case 7:
1203             dma->dsp_address += 128;
1204             break;
1205          default:
1206             break;
1207          }
1208       }
1209       else
1210       {
1211          u32 Val = sc->MD[dma->dsp_bank][dma->ct];
1212          MappedMemoryWriteWordNocache(MSH2, dma->dsp_address, Val >> 16);
1213          dma->dsp_address += dma->dsp_add << 1;
1214          MappedMemoryWriteWordNocache(MSH2, dma->dsp_address, Val & 0xffff);
1215          dma->dsp_address += dma->dsp_add << 1;
1216       }
1217 
1218       dma->ct++;
1219       dma->ct &= 0x3F;
1220       dma->count--;
1221    }
1222    else if (dma->dsp_dma_type == 3)
1223    {
1224       if (dma->dsp_bank > 3)
1225       {
1226          sc->ProgramRam[dma->program_ram_counter++] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address);
1227          dma->dsp_address += dma->dsp_add << 1;
1228          dma->count--;
1229       }
1230       else
1231       {
1232          if (sh2_check_wait(NULL, dma->dsp_address, 2))
1233             return;
1234 
1235          sc->MD[dma->dsp_bank][dma->ct] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address);
1236          dma->ct++;
1237          dma->ct &= 0x3F;
1238 
1239          if (dma->dsp_bus == DSP_CPU_BUS || dma->dsp_bus == DSP_A_BUS)
1240          {
1241             switch (dma->dsp_add_setting)
1242             {
1243             case 0:
1244             case 1:
1245             case 4:
1246             case 5:
1247                break;
1248             case 2:
1249             case 3:
1250             case 6:
1251             case 7:
1252                dma->dsp_address += 4;
1253                break;
1254             default:
1255                break;
1256             }
1257          }
1258          else
1259             dma->dsp_address += dma->dsp_add;
1260 
1261          dma->count--;
1262       }
1263    }
1264 
1265    if (dma->count == 0)
1266    {
1267       ScuRegs->DSTA &= ~1;
1268 
1269       ScuRegs->DSTA &= ~0x700000;
1270 
1271       sc->ProgControlPort.part.T0 = 0;
1272 
1273       dma_finish(dma);
1274    }
1275 }
1276 
get_write_add_from_b(struct QueuedDma * dma)1277 void get_write_add_from_b(struct QueuedDma * dma)
1278 {
1279    switch (dma->add_setting)
1280    {
1281    case 0:
1282       break;
1283    case 1:
1284       if ((dma->num_written % 8) == 0)
1285          dma->write_address += 4;
1286       break;
1287    case 2:
1288       if ((dma->num_written % 4) == 0)
1289          dma->write_address += 4;
1290       break;
1291    case 3:
1292       if ((dma->num_written % 4) == 0)
1293          dma->write_address += 8;
1294       break;
1295    case 4:
1296       if ((dma->num_written % 4) == 0)
1297          dma->write_address += 16;
1298       break;
1299    case 5:
1300       if ((dma->num_written % 4) == 0)
1301          dma->write_address += 32;
1302       break;
1303    case 6:
1304       if ((dma->num_written % 4) == 0)
1305          dma->write_address += 64;
1306       break;
1307    case 7:
1308       if ((dma->num_written % 4) == 0)
1309          dma->write_address += 128;
1310       break;
1311    }
1312 }
1313 
do_write_from_b(struct QueuedDma * dma)1314 void do_write_from_b(struct QueuedDma * dma)
1315 {
1316    if (!dma->second_word)
1317    {
1318       dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16;
1319       dma->second_word = 1;
1320       dma->count -= 2;
1321       dma->num_written += 2;
1322    }
1323    else
1324    {
1325       dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2);
1326       MappedMemoryWriteLongNocache(MSH2, dma->write_address, dma->buffer);
1327       dma->read_address += 4;
1328       dma->count -= 2;
1329       dma->num_written += 2;
1330       dma->second_word = 0;
1331 
1332       get_write_add_a_to_cpu(dma);
1333    }
1334 }
1335 
scu_dma_tick_from_b(struct QueuedDma * dma)1336 void scu_dma_tick_from_b(struct QueuedDma * dma)
1337 {
1338    if (sh2_check_wait(NULL, dma->read_address, 1))
1339       return;
1340 
1341    if(dma->count_mod_4 == 0)
1342    {
1343       do_write_from_b(dma);
1344    }
1345    else if (dma->count_mod_4 == 1)
1346    {
1347       if (dma->count == 1)
1348       {
1349          u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address);
1350          MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte);
1351          dma->count = 0;
1352       }
1353       else
1354       {
1355          do_write_from_b(dma);
1356       }
1357    }
1358    else if (dma->count_mod_4 == 2)
1359    {
1360       if (dma->count == 2)
1361       {
1362          u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address);
1363          MappedMemoryWriteWordNocache(MSH2, dma->write_address, word);
1364          dma->count = 0;
1365       }
1366       else
1367          do_write_from_b(dma);
1368    }
1369    else if (dma->count_mod_4 == 3)
1370    {
1371       if (dma->count == 3)
1372       {
1373          u8 byte;
1374          u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address);
1375          MappedMemoryWriteWordNocache(MSH2, dma->write_address, word);
1376 
1377          byte = MappedMemoryReadByteNocache(MSH2, dma->read_address + 2);
1378          MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, byte);
1379          dma->count = 0;
1380       }
1381       else
1382       {
1383          do_write_from_b(dma);
1384       }
1385    }
1386 
1387    check_dma_finished(dma);
1388 }
1389 
scu_dma_tick(struct QueuedDma * dma)1390 void scu_dma_tick(struct QueuedDma * dma)
1391 {
1392    if (dma->is_dsp)
1393       scu_dma_tick_dsp(dma);
1394 
1395    //destination is b-bus
1396    else if (dma->bus_type == DMA_TRANSFER_CPU_TO_B || dma->bus_type == DMA_TRANSFER_A_TO_B)
1397       scu_dma_tick_to_b(dma);
1398 
1399    //a -> c , c -> a
1400    else if (dma->bus_type == DMA_TRANSFER_A_TO_CPU || dma->bus_type == DMA_TRANSFER_CPU_TO_A)
1401       scu_dma_tick_a_to_cpu(dma);
1402 
1403    //from b-bus
1404    else if (dma->bus_type == DMA_TRANSFER_B_TO_CPU || dma->bus_type == DMA_TRANSFER_B_TO_A)
1405       scu_dma_tick_from_b(dma);
1406    else
1407       //should not happen
1408       scu_dma_tick_32(dma);
1409 }
1410 
scu_dma_tick_all(u32 cycles)1411 void scu_dma_tick_all(u32 cycles)
1412 {
1413    int i = 0;
1414 
1415    for (i = 0; i < cycles; i++)
1416    {
1417       if (scu_dma_queue[0].status == DMA_ACTIVE)
1418          scu_dma_tick(&scu_dma_queue[0]);
1419    }
1420 }
1421 
ScuDMA(scudmainfo_struct * dmainfo)1422 static void FASTCALL ScuDMA(scudmainfo_struct *dmainfo) {
1423    u8 ReadAdd, WriteAdd;
1424 
1425    if (dmainfo->AddValue & 0x100)
1426       ReadAdd = 4;
1427    else
1428       ReadAdd = 0;
1429 
1430    switch(dmainfo->AddValue & 0x7) {
1431       case 0x0:
1432          WriteAdd = 0;
1433          break;
1434       case 0x1:
1435          WriteAdd = 2;
1436          break;
1437       case 0x2:
1438          WriteAdd = 4;
1439          break;
1440       case 0x3:
1441          WriteAdd = 8;
1442          break;
1443       case 0x4:
1444          WriteAdd = 16;
1445          break;
1446       case 0x5:
1447          WriteAdd = 32;
1448          break;
1449       case 0x6:
1450          WriteAdd = 64;
1451          break;
1452       case 0x7:
1453          WriteAdd = 128;
1454          break;
1455       default:
1456          WriteAdd = 0;
1457          break;
1458    }
1459 
1460    if (dmainfo->ModeAddressUpdate & 0x1000000) {
1461       // Indirect DMA
1462 
1463       for (;;) {
1464          u32 ThisTransferSize = MappedMemoryReadLongNocache(MSH2,dmainfo->WriteAddress);
1465          u32 ThisWriteAddress = MappedMemoryReadLongNocache(MSH2, dmainfo->WriteAddress + 4);
1466          u32 ThisReadAddress  = MappedMemoryReadLongNocache(MSH2, dmainfo->WriteAddress + 8);
1467 
1468          //LOG("SCU Indirect DMA: src %08x, dst %08x, size = %08x\n", ThisReadAddress, ThisWriteAddress, ThisTransferSize);
1469          DoDMA(ThisReadAddress & 0x7FFFFFFF, ReadAdd, ThisWriteAddress,
1470                WriteAdd, ThisTransferSize);
1471 
1472          if (ThisReadAddress & 0x80000000)
1473             break;
1474 
1475          dmainfo->WriteAddress+= 0xC;
1476       }
1477 
1478       switch(dmainfo->mode) {
1479          case 0:
1480             ScuSendLevel0DMAEnd();
1481             break;
1482          case 1:
1483             ScuSendLevel1DMAEnd();
1484             break;
1485          case 2:
1486             ScuSendLevel2DMAEnd();
1487             break;
1488       }
1489    }
1490    else {
1491       // Direct DMA
1492 
1493       if (dmainfo->mode > 0) {
1494          dmainfo->TransferNumber &= 0xFFF;
1495 
1496          if (dmainfo->TransferNumber == 0)
1497             dmainfo->TransferNumber = 0x1000;
1498       }
1499       else {
1500          if (dmainfo->TransferNumber == 0)
1501             dmainfo->TransferNumber = 0x100000;
1502       }
1503 
1504       DoDMA(dmainfo->ReadAddress, ReadAdd, dmainfo->WriteAddress, WriteAdd,
1505             dmainfo->TransferNumber);
1506 
1507       switch(dmainfo->mode) {
1508          case 0:
1509             ScuSendLevel0DMAEnd();
1510             break;
1511          case 1:
1512             ScuSendLevel1DMAEnd();
1513             break;
1514          case 2:
1515             ScuSendLevel2DMAEnd();
1516             break;
1517       }
1518    }
1519 }
1520 
1521 //////////////////////////////////////////////////////////////////////////////
1522 
readgensrc(u8 num)1523 static u32 readgensrc(u8 num)
1524 {
1525    u32 val;
1526 
1527    if( num <= 7  ){
1528 	   incFlg[(num & 0x3)] |= ((num >> 2) & 0x01);
1529 	   return ScuDsp->MD[(num & 0x3)][ScuDsp->CT[(num & 0x3)]];
1530    }else{
1531 	  if( num == 0x9)  // ALL
1532 		  return (u32)ScuDsp->ALU.part.L;
1533 	  else if( num == 0xA ) // ALH
1534 		  return (u32)((ScuDsp->ALU.all & (u64)(0x0000ffffffff0000))  >> 16);
1535    }
1536 #if 0
1537    switch(num) {
1538       case 0x0: // M0
1539          return ScuDsp->MD[0][ScuDsp->CT[0]];
1540       case 0x1: // M1
1541          return ScuDsp->MD[1][ScuDsp->CT[1]];
1542       case 0x2: // M2
1543          return ScuDsp->MD[2][ScuDsp->CT[2]];
1544       case 0x3: // M3
1545          return ScuDsp->MD[3][ScuDsp->CT[3]];
1546       case 0x4: // MC0
1547          val = ScuDsp->MD[0][ScuDsp->CT[0]];
1548          incFlg[0] = 1;
1549          return val;
1550       case 0x5: // MC1
1551          val = ScuDsp->MD[1][ScuDsp->CT[1]];
1552          incFlg[1] = 1;
1553          return val;
1554       case 0x6: // MC2
1555          val = ScuDsp->MD[2][ScuDsp->CT[2]];
1556          incFlg[2] = 1;
1557          return val;
1558       case 0x7: // MC3
1559          val = ScuDsp->MD[3][ScuDsp->CT[3]];
1560          incFlg[3] = 1;
1561          return val;
1562       case 0x9: // ALL
1563          return (u32)ScuDsp->ALU.part.L;
1564       case 0xA: // ALH
1565          return (u32)((ScuDsp->ALU.all & (u64)(0x0000ffffffff0000))  >> 16);
1566       default: break;
1567    }
1568 #endif
1569    return 0;
1570 }
1571 
1572 //////////////////////////////////////////////////////////////////////////////
1573 
writed1busdest(u8 num,u32 val)1574 static void writed1busdest(u8 num, u32 val)
1575 {
1576    switch(num) {
1577       case 0x0:
1578           ScuDsp->MD[0][ScuDsp->CT[0]] = val;
1579           ScuDsp->CT[0]++;
1580           ScuDsp->CT[0] &= 0x3f;
1581           return;
1582       case 0x1:
1583           ScuDsp->MD[1][ScuDsp->CT[1]] = val;
1584           ScuDsp->CT[1]++;
1585           ScuDsp->CT[1] &= 0x3f;
1586           return;
1587       case 0x2:
1588           ScuDsp->MD[2][ScuDsp->CT[2]] = val;
1589           ScuDsp->CT[2]++;
1590           ScuDsp->CT[2] &= 0x3f;
1591           return;
1592       case 0x3:
1593           ScuDsp->MD[3][ScuDsp->CT[3]] = val;
1594           ScuDsp->CT[3]++;
1595           ScuDsp->CT[3] &= 0x3f;
1596           return;
1597       case 0x4:
1598           ScuDsp->RX = val;
1599           return;
1600       case 0x5:
1601           ScuDsp->P.all = (signed)val;
1602           return;
1603       case 0x6:
1604           ScuDsp->RA0 = val;
1605           return;
1606       case 0x7:
1607           ScuDsp->WA0 = val;
1608           return;
1609       case 0xA:
1610           ScuDsp->LOP = (u16)val;
1611           return;
1612       case 0xB:
1613           ScuDsp->TOP = (u8)val;
1614           return;
1615       case 0xC:
1616           ScuDsp->CT[0] = (u8)val;
1617           return;
1618       case 0xD:
1619           ScuDsp->CT[1] = (u8)val;
1620           return;
1621       case 0xE:
1622           ScuDsp->CT[2] = (u8)val;
1623           return;
1624       case 0xF:
1625           ScuDsp->CT[3] = (u8)val;
1626           return;
1627       default: break;
1628    }
1629 }
1630 
1631 //////////////////////////////////////////////////////////////////////////////
1632 
writeloadimdest(u8 num,u32 val)1633 static void writeloadimdest(u8 num, u32 val)
1634 {
1635    switch(num) {
1636       case 0x0: // MC0
1637           ScuDsp->MD[0][ScuDsp->CT[0]] = val;
1638           ScuDsp->CT[0]++;
1639           ScuDsp->CT[0] &= 0x3f;
1640           return;
1641       case 0x1: // MC1
1642           ScuDsp->MD[1][ScuDsp->CT[1]] = val;
1643           ScuDsp->CT[1]++;
1644           ScuDsp->CT[1] &= 0x3f;
1645           return;
1646       case 0x2: // MC2
1647           ScuDsp->MD[2][ScuDsp->CT[2]] = val;
1648           ScuDsp->CT[2]++;
1649           ScuDsp->CT[2] &= 0x3f;
1650           return;
1651       case 0x3: // MC3
1652           ScuDsp->MD[3][ScuDsp->CT[3]] = val;
1653           ScuDsp->CT[3]++;
1654           ScuDsp->CT[3] &= 0x3f;
1655           return;
1656       case 0x4: // RX
1657           ScuDsp->RX = val;
1658           return;
1659       case 0x5: // PL
1660           ScuDsp->P.all = (s64)val;
1661           return;
1662       case 0x6: // RA0
1663           val = (val & 0x1FFFFFF);
1664           ScuDsp->RA0 = val;
1665           return;
1666       case 0x7: // WA0
1667           val = (val & 0x1FFFFFF);
1668           ScuDsp->WA0 = val;
1669           return;
1670       case 0xA: // LOP
1671           ScuDsp->LOP = (u16)val;
1672           return;
1673       case 0xC: // PC->TOP, PC
1674           ScuDsp->TOP = ScuDsp->PC+1;
1675           ScuDsp->jmpaddr = val;
1676           ScuDsp->delayed = 0;
1677           return;
1678       default: break;
1679    }
1680 }
1681 
1682 //////////////////////////////////////////////////////////////////////////////
1683 
readdmasrc(u8 num,u8 add)1684 static u32 readdmasrc(u8 num, u8 add)
1685 {
1686    u32 val;
1687 
1688    switch(num) {
1689       case 0x0: // M0
1690          val = ScuDsp->MD[0][ScuDsp->CT[0]];
1691          ScuDsp->CT[0]+=add;
1692          return val;
1693       case 0x1: // M1
1694          val = ScuDsp->MD[1][ScuDsp->CT[1]];
1695          ScuDsp->CT[1]+=add;
1696          return val;
1697       case 0x2: // M2
1698          val = ScuDsp->MD[2][ScuDsp->CT[2]];
1699          ScuDsp->CT[2]+=add;
1700          return val;
1701       case 0x3: // M3
1702          val = ScuDsp->MD[3][ScuDsp->CT[3]];
1703          ScuDsp->CT[3]+=add;
1704          return val;
1705       default: break;
1706    }
1707 
1708    return 0;
1709 }
1710 
dsp_get_bus(u32 addr)1711 int dsp_get_bus(u32 addr)
1712 {
1713    if (is_a_bus(addr))
1714       return DSP_A_BUS;
1715 
1716    if (is_b_bus(addr))
1717       return DSP_B_BUS;
1718 
1719    return DSP_CPU_BUS;
1720 }
1721 
1722 
scu_insert_dsp_dma(struct QueuedDma * dma)1723 void scu_insert_dsp_dma(struct QueuedDma *dma)
1724 {
1725    int i = 0;
1726    if (dma->count == 0)
1727       dma->count = dma->dsp_orig_count = 256;
1728 
1729    dma->dsp_bus = dsp_get_bus(dma->dsp_address);
1730 
1731    ScuRegs->DSTA |= 1;
1732 
1733    dma->ct = ScuDsp->CT[dma->dsp_bank];
1734 
1735    //count is added instantly for both reads and writes
1736    ScuDsp->CT[dma->dsp_bank] += dma->count;
1737    ScuDsp->CT[dma->dsp_bank] &= 0x3f;
1738 
1739    for (i = 0; i < 16; i++)
1740    {
1741       if (scu_dma_queue[i].status == DMA_FINISHED)
1742       {
1743          scu_dma_queue[i] = *dma;
1744          break;
1745       }
1746    }
1747 
1748    scu_dma_sort_activate(dma);
1749 }
1750 
set_dsta(u32 addr)1751 void set_dsta(u32 addr)
1752 {
1753    if (is_a_bus(addr))
1754       ScuRegs->DSTA |= 0x500000;
1755    else if (is_b_bus(addr))
1756       ScuRegs->DSTA |= 0x600000;
1757 }
1758 
1759 
dsp_dma01(scudspregs_struct * sc,u32 inst)1760 void dsp_dma01(scudspregs_struct *sc, u32 inst)
1761 {
1762     u32 imm = ((inst & 0xFF));
1763     u8  sel = ((inst >> 8) & 0x03);
1764     u8  add;
1765     u8  addr = sc->CT[sel];
1766     u32 i;
1767 	u32 abus_check;
1768 
1769     switch (((inst >> 15) & 0x07))
1770     {
1771     case 0: add = 0; break;
1772     case 1: add = 1; break;
1773     case 2: add = 2; break;
1774     case 3: add = 4; break;
1775     case 4: add = 8; break;
1776     case 5: add = 16; break;
1777     case 6: add = 32; break;
1778     case 7: add = 64; break;
1779     }
1780 
1781     if (yabsys.use_scu_dma_timing)
1782     {
1783        struct QueuedDma my_dma = { 0 };
1784        struct QueuedDma * dma = &my_dma;
1785 
1786        dma->is_dsp = 1;
1787        dma->dsp_dma_type = 1;
1788        dma->dsp_add = add;
1789        dma->dsp_add_setting = (inst >> 15) & 0x07;
1790        dma->dsp_bank = sel;
1791        dma->count = dma->dsp_orig_count = imm;
1792        dma->dsp_address = sc->RA0 << 2;
1793        dma->status = DMA_QUEUED;
1794        dma->level = 3;
1795 
1796        set_dsta(sc->RA0 << 2);
1797 
1798        if (((inst >> 11) & 0x0F) != 0x08)
1799           adjust_ra0_wa0(dma);
1800 
1801        scu_insert_dsp_dma(&my_dma);
1802        sc->ProgControlPort.part.T0 = 1;
1803        return;
1804     }
1805 
1806 	//LOG("DSP DMA01 addr=%08X cnt= %d add = %d\n", (sc->RA0 << 2), imm, add );
1807 
1808 	// is A-Bus?
1809 	abus_check = ((sc->RA0 << 2) & 0x0FF00000);
1810 	if (abus_check >= 0x02000000 && abus_check < 0x05900000){
1811 		if (add > 1){
1812 			add = 1;
1813 		}
1814 
1815 		for (i = 0; i < imm; i++)
1816 		{
1817             sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2, (sc->RA0 << 2));
1818 			sc->CT[sel]++;
1819 			sc->CT[sel] &= 0x3F;
1820 			sc->RA0 += add;
1821 
1822 		}
1823 	}
1824 	else{
1825 		for (i = 0; i < imm ; i++)
1826 		{
1827             sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2, (sc->RA0 << 2));
1828 			sc->CT[sel]++;
1829 			sc->CT[sel] &= 0x3F;
1830 			sc->RA0 += (add>>1);
1831 		}
1832 	}
1833 
1834     sc->ProgControlPort.part.T0 = 0;
1835 }
1836 
dsp_dma02(scudspregs_struct * sc,u32 inst)1837 void dsp_dma02(scudspregs_struct *sc, u32 inst)
1838 {
1839     u32 imm = ((inst & 0xFF));
1840     u8  sel = ((inst >> 8) & 0x03);
1841     u8  addr = sc->CT[sel];
1842     u8  add;
1843     u32 i;
1844 
1845     switch (((inst >> 15) & 0x07))
1846     {
1847     case 0: add = 0; break;
1848     case 1: add = 1; break;
1849     case 2: add = 2; break;
1850     case 3: add = 4; break;
1851     case 4: add = 8; break;
1852     case 5: add = 16; break;
1853     case 6: add = 32; break;
1854     case 7: add = 64; break;
1855     }
1856 
1857     if (yabsys.use_scu_dma_timing)
1858     {
1859        struct QueuedDma dma = { 0 };
1860 
1861        dma.is_dsp = 1;
1862        dma.dsp_dma_type = 2;
1863        dma.dsp_add = add;
1864        dma.dsp_bank = sel;
1865        dma.dsp_add_setting = (inst >> 15) & 0x07;
1866        dma.count = dma.dsp_orig_count = imm;
1867        dma.dsp_address = sc->WA0 << 2;
1868        dma.status = DMA_QUEUED;
1869        dma.level = 3;
1870 
1871        if (((inst >> 10) & 0x1F) != 0x14)
1872           adjust_ra0_wa0(&dma);
1873 
1874        set_dsta(sc->WA0 << 2);
1875 
1876        scu_insert_dsp_dma(&dma);
1877        sc->ProgControlPort.part.T0 = 1;
1878        return;
1879     }
1880 
1881     if (add != 1)
1882     {
1883        for (i = 0; i < imm; i++)
1884        {
1885           u32 Val = sc->MD[sel][sc->CT[sel]];
1886           u32 Adr = (sc->WA0 << 2);
1887           //LOG("SCU DSP DMA02 D:%08x V:%08x", Adr, Val);
1888           MappedMemoryWriteLongNocache(MSH2, Adr, Val);
1889           sc->CT[sel]++;
1890           sc->WA0 += add >> 1;
1891           sc->CT[sel] &= 0x3F;
1892        }
1893     }
1894     else {
1895 
1896        for (i = 0; i < imm; i++)
1897        {
1898           u32 Val = sc->MD[sel][sc->CT[sel]];
1899           u32 Adr = (sc->WA0 << 2);
1900 
1901           MappedMemoryWriteLongNocache(MSH2, Adr, Val);
1902           sc->CT[sel]++;
1903           sc->CT[sel] &= 0x3F;
1904           sc->WA0 += 1;
1905        }
1906 
1907     }
1908     sc->ProgControlPort.part.T0 = 0;
1909 }
1910 
determine_a_bus_add(struct QueuedDma * dma,u32 inst)1911 void determine_a_bus_add(struct QueuedDma* dma, u32 inst)
1912 {
1913    if ((is_a_bus(dma->dsp_address)))
1914    {
1915       if (((inst >> 15) & 0x01) == 0)
1916          dma->dsp_add = 0;
1917    }
1918 }
1919 
dsp_dma03(scudspregs_struct * sc,u32 inst)1920 void dsp_dma03(scudspregs_struct *sc, u32 inst)
1921 {
1922    u32 Counter = 0;
1923    u32 i;
1924 	int add;
1925 	int sel;
1926 	u32 abus_check;
1927 
1928    switch ((inst & 0x7))
1929    {
1930    case 0x00: Counter = sc->MD[0][sc->CT[0]]; break;
1931    case 0x01: Counter = sc->MD[1][sc->CT[1]]; break;
1932    case 0x02: Counter = sc->MD[2][sc->CT[2]]; break;
1933    case 0x03: Counter = sc->MD[3][sc->CT[3]]; break;
1934    case 0x04: Counter = sc->MD[0][sc->CT[0]]; ScuDsp->CT[0]++; break;
1935    case 0x05: Counter = sc->MD[1][sc->CT[1]]; ScuDsp->CT[1]++; break;
1936    case 0x06: Counter = sc->MD[2][sc->CT[2]]; ScuDsp->CT[2]++; break;
1937    case 0x07: Counter = sc->MD[3][sc->CT[3]]; ScuDsp->CT[3]++; break;
1938    }
1939 
1940 	switch (((inst >> 15) & 0x07))
1941 	{
1942 	case 0: add = 0; break;
1943 	case 1: add = 1; break;
1944 	case 2: add = 2; break;
1945 	case 3: add = 4; break;
1946 	case 4: add = 8; break;
1947 	case 5: add = 16; break;
1948 	case 6: add = 32; break;
1949 	case 7: add = 64; break;
1950 	}
1951 
1952 	sel = (inst >> 8) & 0x3;
1953 
1954 	//LOG("DSP DMA03 addr=%08X cnt= %d add = %d\n", (sc->RA0 << 2), Counter, add);
1955 
1956 	abus_check = ((sc->RA0 << 2) & 0x0FF00000);
1957 	if (abus_check >= 0x02000000 && abus_check < 0x05900000){
1958 		if (add > 1){
1959 			add = 1;
1960 		}
1961 		for (i = 0; i < Counter; i++)
1962 		{
1963 			sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2,(sc->RA0 << 2));
1964 			sc->CT[sel]++;
1965 			sc->CT[sel] &= 0x3F;
1966 			sc->RA0 += add;
1967 		}
1968 	}
1969 	else{
1970 		for (i = 0; i < Counter; i++)
1971 		{
1972 			sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2, (sc->RA0 << 2));
1973 			sc->CT[sel]++;
1974 			sc->CT[sel] &= 0x3F;
1975 			sc->RA0 += (add>>1);
1976 		}
1977 	}
1978 
1979 
1980 #if 0
1981    DestinationId = (inst >> 8) & 0x7;
1982 
1983    if (yabsys.use_scu_dma_timing)
1984    {
1985       struct QueuedDma dma = { 0 };
1986       dma.is_dsp = 1;
1987       dma.dsp_dma_type = 3;
1988       dma.dsp_add = 4;
1989       dma.dsp_add_setting = (inst >> 15) & 0x7;
1990       dma.dsp_bank = DestinationId;
1991       dma.count = dma.dsp_orig_count = Counter;
1992       dma.dsp_address = sc->RA0 << 2;
1993 
1994       determine_a_bus_add(&dma, inst);
1995 
1996       dma.status = DMA_QUEUED;
1997       dma.level = 3;
1998 
1999       set_dsta(sc->RA0 << 2);
2000 
2001       if (((inst >> 11) & 0x0F) != 0x0C)
2002          adjust_ra0_wa0(&dma);
2003 
2004       scu_insert_dsp_dma(&dma);
2005       sc->ProgControlPort.part.T0 = 1;
2006       return;
2007    }
2008 
2009     if (DestinationId > 3)
2010     {
2011         int incl = 1; //((sc->inst >> 15) & 0x01);
2012         for (i = 0; i < Counter; i++)
2013         {
2014             u32 Adr = (sc->RA0 << 2);
2015             sc->ProgramRam[i] = MappedMemoryReadLongNocache(MSH2, Adr);
2016             sc->RA0 += incl;
2017         }
2018     }
2019     else{
2020 
2021         int incl = 1; //((sc->inst >> 15) & 0x01);
2022         for (i = 0; i < Counter; i++)
2023         {
2024             u32 Adr = (sc->RA0 << 2);
2025 
2026             sc->MD[DestinationId][sc->CT[DestinationId]] = MappedMemoryReadLongNocache(MSH2, Adr);
2027             sc->CT[DestinationId]++;
2028             sc->CT[DestinationId] &= 0x3F;
2029             sc->RA0 += incl;
2030         }
2031     }
2032 #endif
2033     sc->ProgControlPort.part.T0 = 0;
2034 }
2035 
dsp_dma04(scudspregs_struct * sc,u32 inst)2036 void dsp_dma04(scudspregs_struct *sc, u32 inst)
2037 {
2038     u32 Counter = 0;
2039     u32 add = 0;
2040     u32 sel = ((inst >> 8) & 0x03);
2041     u32 i;
2042 
2043     switch ((inst & 0x7))
2044     {
2045     case 0x00: Counter = sc->MD[0][sc->CT[0]]; break;
2046     case 0x01: Counter = sc->MD[1][sc->CT[1]]; break;
2047     case 0x02: Counter = sc->MD[2][sc->CT[2]]; break;
2048     case 0x03: Counter = sc->MD[3][sc->CT[3]]; break;
2049     case 0x04: Counter = sc->MD[0][sc->CT[0]]; ScuDsp->CT[0]++; break;
2050     case 0x05: Counter = sc->MD[1][sc->CT[1]]; ScuDsp->CT[1]++; break;
2051     case 0x06: Counter = sc->MD[2][sc->CT[2]]; ScuDsp->CT[2]++; break;
2052     case 0x07: Counter = sc->MD[3][sc->CT[3]]; ScuDsp->CT[3]++; break;
2053     }
2054 
2055     switch (((inst >> 15) & 0x07))
2056     {
2057     case 0: add = 0; break;
2058     case 1: add = 1; break;
2059     case 2: add = 2; break;
2060     case 3: add = 4; break;
2061     case 4: add = 8; break;
2062     case 5: add = 16; break;
2063     case 6: add = 32; break;
2064     case 7: add = 64; break;
2065     }
2066 
2067     if (yabsys.use_scu_dma_timing)
2068     {
2069        struct QueuedDma dma = { 0 };
2070        dma.is_dsp = 1;
2071        dma.dsp_dma_type = 4;
2072        dma.dsp_add = add;
2073        dma.dsp_bank = sel;
2074        dma.dsp_add_setting = (inst >> 15) & 0x07;
2075        dma.count = dma.dsp_orig_count = Counter;
2076        dma.dsp_address = sc->WA0 << 2;
2077        dma.status = DMA_QUEUED;
2078        dma.level = 3;
2079 
2080        determine_a_bus_add(&dma, inst);
2081 
2082        if (((inst >> 10) & 0x1F) != 0x1C)
2083           adjust_ra0_wa0(&dma);
2084 
2085        set_dsta(sc->WA0 << 2);
2086 
2087        scu_insert_dsp_dma(&dma);
2088        sc->ProgControlPort.part.T0 = 1;
2089        return;
2090     }
2091 
2092     for (i = 0; i < Counter; i++)
2093     {
2094         u32 Val = sc->MD[sel][sc->CT[sel]];
2095         u32 Adr = (sc->WA0 << 2);
2096         MappedMemoryWriteLongNocache(MSH2, Adr, Val);
2097         sc->CT[sel]++;
2098         sc->CT[sel] &= 0x3F;
2099 		sc->WA0 += add;
2100 
2101     }
2102     sc->ProgControlPort.part.T0 = 0;
2103 }
2104 
dsp_dma05(scudspregs_struct * sc,u32 inst)2105 void dsp_dma05(scudspregs_struct *sc, u32 inst)
2106 {
2107     u32 saveRa0 = sc->RA0;
2108     dsp_dma01(sc, inst);
2109     sc->RA0 = saveRa0;
2110 }
2111 
dsp_dma06(scudspregs_struct * sc,u32 inst)2112 void dsp_dma06(scudspregs_struct *sc, u32 inst)
2113 {
2114     u32 saveWa0 = sc->WA0;
2115     dsp_dma02(sc, inst);
2116     sc->WA0 = saveWa0;
2117 }
2118 
dsp_dma07(scudspregs_struct * sc,u32 inst)2119 void dsp_dma07(scudspregs_struct *sc, u32 inst)
2120 {
2121     u32 saveRa0 = sc->RA0;
2122     dsp_dma03(sc, inst);
2123     sc->RA0 = saveRa0;
2124 
2125 }
2126 
dsp_dma08(scudspregs_struct * sc,u32 inst)2127 void dsp_dma08(scudspregs_struct *sc, u32 inst)
2128 {
2129     u32 saveWa0 = sc->WA0;
2130     dsp_dma04(sc, inst);
2131     sc->WA0 = saveWa0;
2132 }
2133 
2134 //////////////////////////////////////////////////////////////////////////////
2135 
writedmadest(u8 num,u32 val,u8 add)2136 static void writedmadest(u8 num, u32 val, u8 add)
2137 {
2138    switch(num) {
2139       case 0x0: // M0
2140           ScuDsp->MD[0][ScuDsp->CT[0]] = val;
2141           ScuDsp->CT[0]+=add;
2142           return;
2143       case 0x1: // M1
2144           ScuDsp->MD[1][ScuDsp->CT[1]] = val;
2145           ScuDsp->CT[1]+=add;
2146           return;
2147       case 0x2: // M2
2148           ScuDsp->MD[2][ScuDsp->CT[2]] = val;
2149           ScuDsp->CT[2]+=add;
2150           return;
2151       case 0x3: // M3
2152           ScuDsp->MD[3][ScuDsp->CT[3]] = val;
2153           ScuDsp->CT[3]+=add;
2154           return;
2155       case 0x4: // Program Ram
2156           //LOG("scu\t: DMA Program writes not implemented\n");
2157 //          ScuDsp->ProgramRam[?] = val;
2158 //          ?? += add;
2159           return;
2160       default: break;
2161    }
2162 }
2163 
2164 //////////////////////////////////////////////////////////////////////////////
2165 
2166 
ScuExec(u32 cycles)2167 void ScuExec(u32 cycles) {
2168    int i;
2169    u32 timing = cycles / 2;
2170    int scu_dma_cycles = cycles;
2171    int real_timing = 1;
2172 
2173 #ifdef HAVE_PLAY_JIT
2174    if (yabsys.use_scu_dsp_jit)
2175    {
2176       scu_dsp_jit_exec(cycles);
2177       return;
2178    }
2179 #endif
2180 
2181    // is dsp executing?
2182    if (ScuDsp->ProgControlPort.part.EX) {
2183       while (timing > 0) {
2184          u32 instruction;
2185 
2186          // Make sure it isn't one of our breakpoints
2187          for (i=0; i < ScuBP->numcodebreakpoints; i++) {
2188             if ((ScuDsp->PC == ScuBP->codebreakpoint[i].addr) && ScuBP->inbreakpoint == 0) {
2189                ScuBP->inbreakpoint = 1;
2190                if (ScuBP->BreakpointCallBack) ScuBP->BreakpointCallBack(ScuBP->codebreakpoint[i].addr);
2191                  ScuBP->inbreakpoint = 0;
2192             }
2193          }
2194 
2195          instruction = ScuDsp->ProgramRam[ScuDsp->PC];
2196 
2197          if (real_timing && (scu_dma_queue[0].status == DMA_ACTIVE))
2198          {
2199             scu_dma_tick(&scu_dma_queue[0]);
2200             scu_dma_cycles-=2;
2201          }
2202 
2203          incFlg[0] = 0;
2204          incFlg[1] = 0;
2205          incFlg[2] = 0;
2206          incFlg[3] = 0;
2207 
2208          // ALU commands
2209          switch (instruction >> 26)
2210          {
2211             case 0x0: // NOP
2212                //AC is moved as-is to the ALU
2213                ScuDsp->ALU.all = ScuDsp->AC.part.L;
2214                break;
2215             case 0x1: // AND
2216                //the upper 16 bits of AC are not modified for and, or, add, sub, rr and rl8
2217                ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L & ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000);
2218 
2219                if (ScuDsp->ALU.part.L == 0)
2220                   ScuDsp->ProgControlPort.part.Z = 1;
2221                else
2222                   ScuDsp->ProgControlPort.part.Z = 0;
2223 
2224                if ((s64)ScuDsp->ALU.part.L < 0)
2225                   ScuDsp->ProgControlPort.part.S = 1;
2226                else
2227                   ScuDsp->ProgControlPort.part.S = 0;
2228 
2229                ScuDsp->ProgControlPort.part.C = 0;
2230                break;
2231             case 0x2: // OR
2232                ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L | ((u32)ScuDsp->P.part.L)) | (ScuDsp->AC.part.L & 0xffff00000000);
2233 
2234                if (ScuDsp->ALU.part.L == 0)
2235                   ScuDsp->ProgControlPort.part.Z = 1;
2236                else
2237                   ScuDsp->ProgControlPort.part.Z = 0;
2238 
2239                if ((s64)ScuDsp->ALU.part.L < 0)
2240                   ScuDsp->ProgControlPort.part.S = 1;
2241                else
2242                   ScuDsp->ProgControlPort.part.S = 0;
2243 
2244                ScuDsp->ProgControlPort.part.C = 0;
2245                break;
2246             case 0x3: // XOR
2247                ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L ^ (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000);
2248 
2249                if (ScuDsp->ALU.part.L == 0)
2250                   ScuDsp->ProgControlPort.part.Z = 1;
2251                else
2252                   ScuDsp->ProgControlPort.part.Z = 0;
2253 
2254                if ((s64)ScuDsp->ALU.part.L < 0)
2255                   ScuDsp->ProgControlPort.part.S = 1;
2256                else
2257                   ScuDsp->ProgControlPort.part.S = 0;
2258 
2259                ScuDsp->ProgControlPort.part.C = 0;
2260                break;
2261             case 0x4: // ADD
2262                ScuDsp->ALU.all = (u64)((u32)ScuDsp->AC.part.L + (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000);
2263 
2264                if (ScuDsp->ALU.part.L == 0)
2265                   ScuDsp->ProgControlPort.part.Z = 1;
2266                else
2267                   ScuDsp->ProgControlPort.part.Z = 0;
2268 
2269                if ((s64)ScuDsp->ALU.part.L < 0)
2270                   ScuDsp->ProgControlPort.part.S = 1;
2271                else
2272                   ScuDsp->ProgControlPort.part.S = 0;
2273 
2274                //0x00000001 + 0xFFFFFFFF will set the carry bit, needs to be unsigned math
2275                if (((u64)(u32)ScuDsp->P.part.L + (u64)(u32)ScuDsp->AC.part.L) & 0x100000000)
2276                   ScuDsp->ProgControlPort.part.C = 1;
2277                else
2278                   ScuDsp->ProgControlPort.part.C = 0;
2279 
2280                //if (ScuDsp->ALU.part.L ??) // set overflow flag
2281                //    ScuDsp->ProgControlPort.part.V = 1;
2282                //else
2283                //   ScuDsp->ProgControlPort.part.V = 0;
2284                break;
2285             case 0x5: // SUB
2286                ScuDsp->ALU.all = (s64)((s32)ScuDsp->AC.part.L - (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000);
2287 
2288                if (ScuDsp->ALU.part.L == 0)
2289                   ScuDsp->ProgControlPort.part.Z = 1;
2290                else
2291                   ScuDsp->ProgControlPort.part.Z = 0;
2292 
2293                if ((s64)ScuDsp->ALU.part.L < 0)
2294                   ScuDsp->ProgControlPort.part.S = 1;
2295                else
2296                   ScuDsp->ProgControlPort.part.S = 0;
2297 
2298                //0x00000001 - 0xFFFFFFFF will set the carry bit, needs to be unsigned math
2299                if ((((u64)(u32)ScuDsp->AC.part.L - (u64)(u32)ScuDsp->P.part.L)) & 0x100000000)
2300                   ScuDsp->ProgControlPort.part.C = 1;
2301                else
2302                   ScuDsp->ProgControlPort.part.C = 0;
2303 
2304 //               if (ScuDsp->ALU.part.L ??) // set overflow flag
2305 //                  ScuDsp->ProgControlPort.part.V = 1;
2306 //               else
2307 //                  ScuDsp->ProgControlPort.part.V = 0;
2308                break;
2309             case 0x6: // AD2
2310                ScuDsp->ALU.all = (s64)ScuDsp->AC.all + (s64)ScuDsp->P.all;
2311 
2312                if (ScuDsp->ALU.all == 0)
2313                   ScuDsp->ProgControlPort.part.Z = 1;
2314                else
2315                   ScuDsp->ProgControlPort.part.Z = 0;
2316 
2317                //0x500000000000 + 0xd00000000000 will set the sign bit
2318                if (ScuDsp->ALU.all & 0x800000000000)
2319                   ScuDsp->ProgControlPort.part.S = 1;
2320                else
2321                   ScuDsp->ProgControlPort.part.S = 0;
2322 
2323                //AC.all and P.all are sign-extended so we need to mask it off and check for a carry
2324                if (((ScuDsp->AC.all & 0xffffffffffff) + (ScuDsp->P.all & 0xffffffffffff)) & (0x1000000000000))
2325                   ScuDsp->ProgControlPort.part.C = 1;
2326                else
2327                   ScuDsp->ProgControlPort.part.C = 0;
2328 
2329 //               if (ScuDsp->ALU.part.unused != 0)
2330 //                  ScuDsp->ProgControlPort.part.V = 1;
2331 //               else
2332 //                  ScuDsp->ProgControlPort.part.V = 0;
2333 
2334                break;
2335             case 0x8: // SR
2336                ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L & 0x1;
2337 
2338                ScuDsp->ALU.all = (s64)((ScuDsp->AC.part.L & 0x80000000) | (ScuDsp->AC.part.L >> 1)) | (ScuDsp->AC.part.L & 0xffff00000000);
2339 
2340                if (ScuDsp->ALU.all == 0)
2341                   ScuDsp->ProgControlPort.part.Z = 1;
2342                else
2343                   ScuDsp->ProgControlPort.part.Z = 0;
2344 
2345                if ((s64)ScuDsp->ALU.part.L < 0)
2346                   ScuDsp->ProgControlPort.part.S = 1;
2347                else
2348                   ScuDsp->ProgControlPort.part.S = 0;
2349 
2350                //0x00000001 >> 1 will set the carry bit
2351                //ScuDsp->ProgControlPort.part.C = ScuDsp->ALU.part.L >> 31; would not handle this case
2352 
2353                break;
2354             case 0x9: // RR
2355                ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L & 0x1;
2356 
2357                ScuDsp->ALU.all = (s64)((ScuDsp->ProgControlPort.part.C << 31) | ((u32)ScuDsp->AC.part.L >> 1) | (ScuDsp->AC.part.L & 0xffff00000000));
2358 
2359                if (ScuDsp->ALU.all == 0)
2360                   ScuDsp->ProgControlPort.part.Z = 1;
2361                else
2362                   ScuDsp->ProgControlPort.part.Z = 0;
2363 
2364                //rotating 0x00000001 right will produce 0x80000000 and set
2365                //the sign bit.
2366                if (ScuDsp->ALU.part.L < 0)
2367                   ScuDsp->ProgControlPort.part.S = 1;
2368                else
2369                   ScuDsp->ProgControlPort.part.S = 0;
2370 
2371                break;
2372             case 0xA: // SL
2373                ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L >> 31;
2374 
2375                ScuDsp->ALU.all = (s64)((u32)(ScuDsp->AC.part.L << 1)) | (ScuDsp->AC.part.L & 0xffff00000000);
2376 
2377                if (ScuDsp->ALU.part.L == 0)
2378                   ScuDsp->ProgControlPort.part.Z = 1;
2379                else
2380                   ScuDsp->ProgControlPort.part.Z = 0;
2381 
2382                if ((s64)ScuDsp->ALU.part.L < 0)
2383                   ScuDsp->ProgControlPort.part.S = 1;
2384                else
2385                   ScuDsp->ProgControlPort.part.S = 0;
2386 
2387                break;
2388             case 0xB: // RL
2389 
2390                ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L >> 31;
2391 
2392                ScuDsp->ALU.all = (s64)(((u32)ScuDsp->AC.part.L << 1) | ScuDsp->ProgControlPort.part.C) | (ScuDsp->AC.part.L & 0xffff00000000);
2393 
2394                if (ScuDsp->ALU.all == 0)
2395                   ScuDsp->ProgControlPort.part.Z = 1;
2396                else
2397                   ScuDsp->ProgControlPort.part.Z = 0;
2398 
2399                if ((s64)ScuDsp->ALU.part.L < 0)
2400                   ScuDsp->ProgControlPort.part.S = 1;
2401                else
2402                   ScuDsp->ProgControlPort.part.S = 0;
2403 
2404                break;
2405             case 0xF: // RL8
2406 
2407                ScuDsp->ALU.all = (s64)((u32)(ScuDsp->AC.part.L << 8) | ((ScuDsp->AC.part.L >> 24) & 0xFF)) | (ScuDsp->AC.part.L & 0xffff00000000);
2408 
2409                if (ScuDsp->ALU.all == 0)
2410                   ScuDsp->ProgControlPort.part.Z = 1;
2411                else
2412                   ScuDsp->ProgControlPort.part.Z = 0;
2413 
2414                //rotating 0x00ffffff left 8 will produce 0xffffff00 and
2415                //set the sign bit
2416                if ((s64)ScuDsp->ALU.part.L < 0)
2417                   ScuDsp->ProgControlPort.part.S = 1;
2418                else
2419                   ScuDsp->ProgControlPort.part.S = 0;
2420 
2421                //rotating 0xff000000 left 8 will produce 0x000000ff and set the
2422                //carry bit
2423                ScuDsp->ProgControlPort.part.C = (ScuDsp->AC.part.L >> 24) & 1;
2424                break;
2425             default: break;
2426          }
2427 
2428          switch (instruction >> 30) {
2429             case 0x00: // Operation Commands
2430 
2431                // X-bus
2432                if ((instruction >> 23) & 0x4)
2433                {
2434                   // MOV [s], X
2435                   ScuDsp->RX = readgensrc((instruction >> 20) & 0x7);
2436                }
2437                switch ((instruction >> 23) & 0x3)
2438                {
2439                   case 2: // MOV MUL, P
2440                      ScuDsp->P.all = ScuDsp->MUL.all;
2441                      break;
2442                   case 3: // MOV [s], P
2443                      //s32 cast to sign extend
2444                      ScuDsp->P.all = (s64)(s32)readgensrc((instruction >> 20) & 0x7);
2445                      break;
2446                   default: break;
2447                }
2448 
2449 
2450                // Y-bus
2451                if ((instruction >> 17) & 0x4)
2452                {
2453                   // MOV [s], Y
2454                   ScuDsp->RY = readgensrc((instruction >> 14) & 0x7);
2455                }
2456                switch ((instruction >> 17) & 0x3)
2457                {
2458                   case 1: // CLR A
2459                      ScuDsp->AC.all = 0;
2460                      break;
2461                   case 2: // MOV ALU,A
2462                      ScuDsp->AC.all = ScuDsp->ALU.all;
2463                      break;
2464                   case 3: // MOV [s],A
2465                      //s32 cast to sign extend
2466                      ScuDsp->AC.all = (s64)(s32)readgensrc((instruction >> 14) & 0x7);
2467                      break;
2468                   default: break;
2469                }
2470 
2471                if (incFlg[0] != 0){ ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; incFlg[0] = 0; };
2472                if (incFlg[1] != 0){ ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; incFlg[1] = 0; };
2473                if (incFlg[2] != 0){ ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; incFlg[2] = 0; };
2474                if (incFlg[3] != 0){ ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; incFlg[3] = 0; };
2475 
2476 
2477                // D1-bus
2478                switch ((instruction >> 12) & 0x3)
2479                {
2480                   case 1: // MOV SImm,[d]
2481                      writed1busdest((instruction >> 8) & 0xF, (u32)(signed char)(instruction & 0xFF));
2482                      break;
2483                   case 3: // MOV [s],[d]
2484                      writed1busdest((instruction >> 8) & 0xF, readgensrc(instruction & 0xF));
2485                      if (incFlg[0] != 0){ ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; incFlg[0] = 0; };
2486                      if (incFlg[1] != 0){ ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; incFlg[1] = 0; };
2487                      if (incFlg[2] != 0){ ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; incFlg[2] = 0; };
2488                      if (incFlg[3] != 0){ ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; incFlg[3] = 0; };
2489                      break;
2490                   default: break;
2491                }
2492 
2493                break;
2494             case 0x02: // Load Immediate Commands
2495                if ((instruction >> 25) & 1)
2496                {
2497                   switch ((instruction >> 19) & 0x3F) {
2498                      case 0x01: // MVI Imm,[d]NZ
2499                         if (!ScuDsp->ProgControlPort.part.Z)
2500                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2501                         break;
2502                      case 0x02: // MVI Imm,[d]NS
2503                         if (!ScuDsp->ProgControlPort.part.S)
2504                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2505                         break;
2506                      case 0x03: // MVI Imm,[d]NZS
2507                         if (!ScuDsp->ProgControlPort.part.Z || !ScuDsp->ProgControlPort.part.S)
2508                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2509                         break;
2510                      case 0x04: // MVI Imm,[d]NC
2511                         if (!ScuDsp->ProgControlPort.part.C)
2512                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2513                         break;
2514                      case 0x08: // MVI Imm,[d]NT0
2515                         if (!ScuDsp->ProgControlPort.part.T0)
2516                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2517                         break;
2518                      case 0x21: // MVI Imm,[d]Z
2519                         if (ScuDsp->ProgControlPort.part.Z)
2520                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2521                         break;
2522                      case 0x22: // MVI Imm,[d]S
2523                         if (ScuDsp->ProgControlPort.part.S)
2524                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2525                         break;
2526                      case 0x23: // MVI Imm,[d]ZS
2527                         if (ScuDsp->ProgControlPort.part.Z || ScuDsp->ProgControlPort.part.S)
2528                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2529                         break;
2530                      case 0x24: // MVI Imm,[d]C
2531                         if (ScuDsp->ProgControlPort.part.C)
2532                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2533                         break;
2534                      case 0x28: // MVI Imm,[d]T0
2535                         if (ScuDsp->ProgControlPort.part.T0)
2536                            writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000));
2537                         break;
2538                      default: break;
2539                   }
2540                }
2541                else
2542                {
2543                   // MVI Imm,[d]
2544                   int value = (instruction & 0x1FFFFFF);
2545                   if (value & 0x1000000) value |= 0xfe000000;
2546                   writeloadimdest((instruction >> 26) & 0xF, value);
2547                 }
2548 
2549                break;
2550             case 0x03: // Other
2551             {
2552                switch((instruction >> 28) & 0xF) {
2553                  case 0x0C: // DMA Commands
2554                  {
2555                    if (((instruction >> 10) & 0x1F) == 0x00/*0x08*/)
2556                    {
2557                        dsp_dma01(ScuDsp, instruction);
2558                    }
2559                    else if (((instruction >> 10) & 0x1F) == 0x04)
2560                    {
2561                        dsp_dma02(ScuDsp, instruction);
2562                    }
2563                    else if (((instruction >> 11) & 0x0F) == 0x04)
2564                    {
2565                        dsp_dma03(ScuDsp, instruction);
2566                    }
2567                    else if (((instruction >> 10) & 0x1F) == 0x0C)
2568                    {
2569                        dsp_dma04(ScuDsp, instruction);
2570                    }
2571                    else if (((instruction >> 11) & 0x0F) == 0x08)
2572                    {
2573                        dsp_dma05(ScuDsp, instruction);
2574                    }
2575                    else if (((instruction >> 10) & 0x1F) == 0x14)
2576                    {
2577                        dsp_dma06(ScuDsp, instruction);
2578                    }
2579                    else if (((instruction >> 11) & 0x0F) == 0x0C)
2580                    {
2581                        dsp_dma07(ScuDsp, instruction);
2582                    }
2583                    else if (((instruction >> 10) & 0x1F) == 0x1C)
2584                    {
2585                        dsp_dma08(ScuDsp, instruction);
2586                    }
2587                      break;
2588                   }
2589                   case 0x0D: // Jump Commands
2590                      switch ((instruction >> 19) & 0x7F) {
2591                         case 0x00: // JMP Imm
2592                            ScuDsp->jmpaddr = instruction & 0xFF;
2593                            ScuDsp->delayed = 0;
2594                            break;
2595                         case 0x41: // JMP NZ, Imm
2596                            if (!ScuDsp->ProgControlPort.part.Z)
2597                            {
2598                               ScuDsp->jmpaddr = instruction & 0xFF;
2599                               ScuDsp->delayed = 0;
2600                            }
2601                            break;
2602                         case 0x42: // JMP NS, Imm
2603                            if (!ScuDsp->ProgControlPort.part.S)
2604                            {
2605                               ScuDsp->jmpaddr = instruction & 0xFF;
2606                               ScuDsp->delayed = 0;
2607                            }
2608 
2609                            LOG("scu\t: JMP NS: S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr);
2610                            break;
2611                         case 0x43: // JMP NZS, Imm
2612                            if (!ScuDsp->ProgControlPort.part.Z || !ScuDsp->ProgControlPort.part.S)
2613                            {
2614                               ScuDsp->jmpaddr = instruction & 0xFF;
2615                               ScuDsp->delayed = 0;
2616                            }
2617 
2618                            LOG("scu\t: JMP NZS: Z = %d, S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.Z, (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr);
2619                            break;
2620                         case 0x44: // JMP NC, Imm
2621                            if (!ScuDsp->ProgControlPort.part.C)
2622                            {
2623                               ScuDsp->jmpaddr = instruction & 0xFF;
2624                               ScuDsp->delayed = 0;
2625                            }
2626                            break;
2627                         case 0x48: // JMP NT0, Imm
2628                            if (!ScuDsp->ProgControlPort.part.T0)
2629                            {
2630                               ScuDsp->jmpaddr = instruction & 0xFF;
2631                               ScuDsp->delayed = 0;
2632                            }
2633 
2634                            LOG("scu\t: JMP NT0: T0 = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.T0, (unsigned int)ScuDsp->jmpaddr);
2635                            break;
2636                         case 0x61: // JMP Z,Imm
2637                            if (ScuDsp->ProgControlPort.part.Z)
2638                            {
2639                               ScuDsp->jmpaddr = instruction & 0xFF;
2640                               ScuDsp->delayed = 0;
2641                            }
2642                            break;
2643                         case 0x62: // JMP S, Imm
2644                            if (ScuDsp->ProgControlPort.part.S)
2645                            {
2646                               ScuDsp->jmpaddr = instruction & 0xFF;
2647                               ScuDsp->delayed = 0;
2648                            }
2649 
2650                            LOG("scu\t: JMP S: S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr);
2651                            break;
2652                         case 0x63: // JMP ZS, Imm
2653                            if (ScuDsp->ProgControlPort.part.Z || ScuDsp->ProgControlPort.part.S)
2654                            {
2655                               ScuDsp->jmpaddr = instruction & 0xFF;
2656                               ScuDsp->delayed = 0;
2657                            }
2658 
2659                            LOG("scu\t: JMP ZS: Z = %d, S = %d, jmpaddr = %08X\n", ScuDsp->ProgControlPort.part.Z, (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr);
2660                            break;
2661                         case 0x64: // JMP C, Imm
2662                            if (ScuDsp->ProgControlPort.part.C)
2663                            {
2664                               ScuDsp->jmpaddr = instruction & 0xFF;
2665                               ScuDsp->delayed = 0;
2666                            }
2667                            break;
2668                         case 0x68: // JMP T0,Imm
2669                            if (ScuDsp->ProgControlPort.part.T0)
2670                            {
2671                               ScuDsp->jmpaddr = instruction & 0xFF;
2672                               ScuDsp->delayed = 0;
2673                            }
2674                            break;
2675                         default:
2676                            LOG("scu\t: Unknown JMP instruction not implemented\n");
2677                            break;
2678                      }
2679                      break;
2680                   case 0x0E: // Loop bottom Commands
2681                      if (instruction & 0x8000000)
2682                      {
2683                         // LPS
2684                         if (ScuDsp->LOP != 0)
2685                         {
2686                            ScuDsp->jmpaddr = ScuDsp->PC;
2687                            ScuDsp->delayed = 0;
2688                            ScuDsp->LOP--;
2689                         }
2690                      }
2691                      else
2692                      {
2693                         // BTM
2694                         if (ScuDsp->LOP != 0)
2695                         {
2696                            ScuDsp->jmpaddr = ScuDsp->TOP;
2697                            ScuDsp->delayed = 0;
2698                            ScuDsp->LOP--;
2699                         }
2700                      }
2701 
2702                      break;
2703                   case 0x0F: // End Commands
2704                      ScuDsp->ProgControlPort.part.EX = 0;
2705 
2706                      if (instruction & 0x8000000) {
2707                         // End with Interrupt
2708                         ScuDsp->ProgControlPort.part.E = 1;
2709                         ScuSendDSPEnd();
2710                      }
2711 
2712                      LOG("dsp has ended\n");
2713                      //dsp_trace_log("END\n");
2714                      ScuDsp->ProgControlPort.part.P = ScuDsp->PC+1;
2715                      timing = 1;
2716                      break;
2717                   default: break;
2718                }
2719                break;
2720             }
2721             default:
2722                LOG("scu\t: Invalid DSP opcode %08X at offset %02X\n", instruction, ScuDsp->PC);
2723                break;
2724          }
2725 
2726          ScuDsp->MUL.all = (s64)ScuDsp->RX * (s64)ScuDsp->RY;
2727 
2728 
2729 		 //LOG("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all);
2730 		 //LOG("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all);
2731         //dsp_trace_log("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all);
2732 
2733 
2734          ScuDsp->PC++;
2735 
2736          // Handle delayed jumps
2737          if (ScuDsp->jmpaddr != 0xFFFFFFFF)
2738          {
2739             if (ScuDsp->delayed)
2740             {
2741                ScuDsp->PC = (unsigned char)ScuDsp->jmpaddr;
2742                ScuDsp->jmpaddr = 0xFFFFFFFF;
2743             }
2744             else
2745                ScuDsp->delayed = 1;
2746          }
2747 
2748          timing--;
2749       }
2750    }
2751 
2752    if (scu_dma_cycles > 0)
2753    {
2754       scu_dma_tick_all(scu_dma_cycles);
2755    }
2756 }
2757 
2758 //////////////////////////////////////////////////////////////////////////////
2759 
disd1bussrc(u8 num)2760 static char *disd1bussrc(u8 num)
2761 {
2762    switch(num) {
2763       case 0x0:
2764          return "M0";
2765       case 0x1:
2766          return "M1";
2767       case 0x2:
2768          return "M2";
2769       case 0x3:
2770          return "M3";
2771       case 0x4:
2772          return "MC0";
2773       case 0x5:
2774          return "MC1";
2775       case 0x6:
2776          return "MC2";
2777       case 0x7:
2778          return "MC3";
2779       case 0x9:
2780          return "ALL";
2781       case 0xA:
2782          return "ALH";
2783       default: break;
2784    }
2785 
2786    return "??";
2787 }
2788 
2789 //////////////////////////////////////////////////////////////////////////////
2790 
disd1busdest(u8 num)2791 static char *disd1busdest(u8 num)
2792 {
2793    switch(num) {
2794       case 0x0:
2795          return "MC0";
2796       case 0x1:
2797          return "MC1";
2798       case 0x2:
2799          return "MC2";
2800       case 0x3:
2801          return "MC3";
2802       case 0x4:
2803          return "RX";
2804       case 0x5:
2805          return "PL";
2806       case 0x6:
2807          return "RA0";
2808       case 0x7:
2809          return "WA0";
2810       case 0xA:
2811          return "LOP";
2812       case 0xB:
2813          return "TOP";
2814       case 0xC:
2815          return "CT0";
2816       case 0xD:
2817          return "CT1";
2818       case 0xE:
2819          return "CT2";
2820       case 0xF:
2821          return "CT3";
2822       default: break;
2823    }
2824 
2825    return "??";
2826 }
2827 
2828 //////////////////////////////////////////////////////////////////////////////
2829 
disloadimdest(u8 num)2830 static char *disloadimdest(u8 num)
2831 {
2832    switch(num) {
2833       case 0x0:
2834          return "MC0";
2835       case 0x1:
2836          return "MC1";
2837       case 0x2:
2838          return "MC2";
2839       case 0x3:
2840          return "MC3";
2841       case 0x4:
2842          return "RX";
2843       case 0x5:
2844          return "PL";
2845       case 0x6:
2846          return "RA0";
2847       case 0x7:
2848          return "WA0";
2849       case 0xA:
2850          return "LOP";
2851       case 0xC:
2852          return "PC";
2853       default: break;
2854    }
2855 
2856    return "??";
2857 }
2858 
2859 //////////////////////////////////////////////////////////////////////////////
2860 
disdmaram(u8 num)2861 static char *disdmaram(u8 num)
2862 {
2863    switch(num)
2864    {
2865       case 0x0: // MC0
2866          return "MC0";
2867       case 0x1: // MC1
2868          return "MC1";
2869       case 0x2: // MC2
2870          return "MC2";
2871       case 0x3: // MC3
2872          return "MC3";
2873       case 0x4: // Program Ram
2874          return "PRG";
2875       default: break;
2876    }
2877 
2878    return "??";
2879 }
2880 
2881 //////////////////////////////////////////////////////////////////////////////
2882 
ScuDspDisasm(u8 addr,char * outstring)2883 void ScuDspDisasm(u8 addr, char *outstring) {
2884    u32 instruction;
2885    u8 counter=0;
2886    u8 filllength=0;
2887 
2888    instruction = ScuDsp->ProgramRam[addr];
2889 
2890    sprintf(outstring, "%02X: ", addr);
2891    outstring+=strlen(outstring);
2892 
2893    if (instruction == 0)
2894    {
2895       sprintf(outstring, "NOP");
2896       return;
2897    }
2898 
2899    // Handle ALU commands
2900    switch (instruction >> 26)
2901    {
2902       case 0x0: // NOP
2903          break;
2904       case 0x1: // AND
2905          sprintf(outstring, "AND");
2906          counter = (u8)strlen(outstring);
2907          outstring+=(u8)strlen(outstring);
2908          break;
2909       case 0x2: // OR
2910          sprintf(outstring, "OR");
2911          counter = (u8)strlen(outstring);
2912          outstring+=(u8)strlen(outstring);
2913          break;
2914       case 0x3: // XOR
2915          sprintf(outstring, "XOR");
2916          counter = (u8)strlen(outstring);
2917          outstring+=(u8)strlen(outstring);
2918          break;
2919       case 0x4: // ADD
2920          sprintf(outstring, "ADD");
2921          counter = (u8)strlen(outstring);
2922          outstring+=(u8)strlen(outstring);
2923          break;
2924       case 0x5: // SUB
2925          sprintf(outstring, "SUB");
2926          counter = (u8)strlen(outstring);
2927          outstring+=(u8)strlen(outstring);
2928          break;
2929       case 0x6: // AD2
2930          sprintf(outstring, "AD2");
2931          counter = (u8)strlen(outstring);
2932          outstring+=(u8)strlen(outstring);
2933          break;
2934       case 0x8: // SR
2935          sprintf(outstring, "SR");
2936          counter = (u8)strlen(outstring);
2937          outstring+=(u8)strlen(outstring);
2938          break;
2939       case 0x9: // RR
2940          sprintf(outstring, "RR");
2941          counter = (u8)strlen(outstring);
2942          outstring+=(u8)strlen(outstring);
2943          break;
2944       case 0xA: // SL
2945          sprintf(outstring, "SL");
2946          counter = (u8)strlen(outstring);
2947          outstring+=(u8)strlen(outstring);
2948          break;
2949       case 0xB: // RL
2950          sprintf(outstring, "RL");
2951          counter = (u8)strlen(outstring);
2952          outstring+=(u8)strlen(outstring);
2953          break;
2954       case 0xF: // RL8
2955          sprintf(outstring, "RL8");
2956          counter = (u8)strlen(outstring);
2957          outstring+=(u8)strlen(outstring);
2958          break;
2959       default: break;
2960    }
2961 
2962    switch (instruction >> 30) {
2963       case 0x00: // Operation Commands
2964          filllength = 5 - counter;
2965          memset((void  *)outstring, 0x20, filllength);
2966          counter += filllength;
2967          outstring += filllength;
2968 
2969          if ((instruction >> 23) & 0x4)
2970          {
2971             sprintf(outstring, "MOV %s, X", disd1bussrc((instruction >> 20) & 0x7));
2972             counter+=(u8)strlen(outstring);
2973             outstring+=(u8)strlen(outstring);
2974          }
2975 
2976          filllength = 16 - counter;
2977          memset((void  *)outstring, 0x20, filllength);
2978          counter += filllength;
2979          outstring += filllength;
2980 
2981          switch ((instruction >> 23) & 0x3)
2982          {
2983             case 2:
2984                sprintf(outstring, "MOV MUL, P");
2985                counter+=(u8)strlen(outstring);
2986                outstring+=(u8)strlen(outstring);
2987                break;
2988             case 3:
2989                sprintf(outstring, "MOV %s, P", disd1bussrc((instruction >> 20) & 0x7));
2990                counter+=(u8)strlen(outstring);
2991                outstring+=(u8)strlen(outstring);
2992                break;
2993             default: break;
2994          }
2995 
2996          filllength = 27 - counter;
2997          memset((void  *)outstring, 0x20, filllength);
2998          counter += filllength;
2999          outstring += filllength;
3000 
3001          // Y-bus
3002          if ((instruction >> 17) & 0x4)
3003          {
3004             sprintf(outstring, "MOV %s, Y", disd1bussrc((instruction >> 14) & 0x7));
3005             counter+=(u8)strlen(outstring);
3006             outstring+=(u8)strlen(outstring);
3007          }
3008 
3009          filllength = 38 - counter;
3010          memset((void  *)outstring, 0x20, filllength);
3011          counter += filllength;
3012          outstring += filllength;
3013 
3014          switch ((instruction >> 17) & 0x3)
3015          {
3016             case 1:
3017                sprintf(outstring, "CLR A");
3018                counter+=(u8)strlen(outstring);
3019                outstring+=(u8)strlen(outstring);
3020                break;
3021             case 2:
3022                sprintf(outstring, "MOV ALU, A");
3023                counter+=(u8)strlen(outstring);
3024                outstring+=(u8)strlen(outstring);
3025                break;
3026             case 3:
3027                sprintf(outstring, "MOV %s, A", disd1bussrc((instruction >> 14) & 0x7));
3028                counter+=(u8)strlen(outstring);
3029                outstring+=(u8)strlen(outstring);
3030                break;
3031             default: break;
3032          }
3033 
3034          filllength = 50 - counter;
3035          memset((void  *)outstring, 0x20, filllength);
3036          counter += filllength;
3037          outstring += filllength;
3038 
3039          // D1-bus
3040          switch ((instruction >> 12) & 0x3)
3041          {
3042             case 1:
3043                sprintf(outstring, "MOV #$%02X, %s", (unsigned int)instruction & 0xFF, disd1busdest((instruction >> 8) & 0xF));
3044                outstring+=(u8)strlen(outstring);
3045                break;
3046             case 3:
3047                sprintf(outstring, "MOV %s, %s", disd1bussrc(instruction & 0xF), disd1busdest((instruction >> 8) & 0xF));
3048                outstring+=(u8)strlen(outstring);
3049                break;
3050             default:
3051                outstring[0] = 0x00;
3052                break;
3053          }
3054 
3055          break;
3056       case 0x02: // Load Immediate Commands
3057          if ((instruction >> 25) & 1)
3058          {
3059             switch ((instruction >> 19) & 0x3F) {
3060                case 0x01:
3061                   sprintf(outstring, "MVI #$%05X,%s,NZ", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3062                   break;
3063                case 0x02:
3064                   sprintf(outstring, "MVI #$%05X,%s,NS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3065                   break;
3066                case 0x03:
3067                   sprintf(outstring, "MVI #$%05X,%s,NZS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3068                   break;
3069                case 0x04:
3070                   sprintf(outstring, "MVI #$%05X,%s,NC", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3071                   break;
3072                case 0x08:
3073                   sprintf(outstring, "MVI #$%05X,%s,NT0", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3074                   break;
3075                case 0x21:
3076                   sprintf(outstring, "MVI #$%05X,%s,Z", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3077                   break;
3078                case 0x22:
3079                   sprintf(outstring, "MVI #$%05X,%s,S", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3080                   break;
3081                case 0x23:
3082                   sprintf(outstring, "MVI #$%05X,%s,ZS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3083                   break;
3084                case 0x24:
3085                   sprintf(outstring, "MVI #$%05X,%s,C", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3086                   break;
3087                case 0x28:
3088                   sprintf(outstring, "MVI #$%05X,%s,T0", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF));
3089                   break;
3090                default: break;
3091             }
3092          }
3093          else
3094          {
3095            //sprintf(outstring, "MVI #$%08X,%s", (instruction & 0xFFFFFF) | ((instruction & 0x1000000) ? 0xFF000000 : 0x00000000), disloadimdest((instruction >> 26) & 0xF));
3096            sprintf(outstring, "MVI #$%08X,%s", (instruction & 0x1FFFFFF) << 2,disloadimdest((instruction >> 26) & 0xF));
3097          }
3098 
3099          break;
3100       case 0x03: // Other
3101          switch((instruction >> 28) & 0x3) {
3102             case 0x00: // DMA Commands
3103             {
3104                int addressAdd;
3105 
3106                if (instruction & 0x1000)
3107                   addressAdd = (instruction >> 15) & 0x7;
3108                else
3109                   addressAdd = (instruction >> 15) & 0x1;
3110 
3111                switch(addressAdd)
3112                {
3113                   case 0: // Add 0
3114                      addressAdd = 0;
3115                      break;
3116                   case 1: // Add 1
3117                      addressAdd = 1;
3118                      break;
3119                   case 2: // Add 2
3120                      addressAdd = 2;
3121                      break;
3122                   case 3: // Add 4
3123                      addressAdd = 4;
3124                      break;
3125                   case 4: // Add 8
3126                      addressAdd = 8;
3127                      break;
3128                   case 5: // Add 16
3129                      addressAdd = 16;
3130                      break;
3131                   case 6: // Add 32
3132                      addressAdd = 32;
3133                      break;
3134                   case 7: // Add 64
3135                      addressAdd = 64;
3136                      break;
3137                   default:
3138                      addressAdd = 0;
3139                      break;
3140                }
3141 
3142                LOG("DMA Add = %X, addressAdd = %d", (instruction >> 15) & 0x7, addressAdd);
3143 
3144                // Write Command name
3145                sprintf(outstring, "DMA");
3146                outstring+=(u8)strlen(outstring);
3147 
3148                // Is h bit set?
3149                if (instruction & 0x4000)
3150                {
3151                   outstring[0] = 'H';
3152                   outstring++;
3153                }
3154 
3155                sprintf(outstring, "%d ", addressAdd);
3156                outstring+=(u8)strlen(outstring);
3157 
3158                if (instruction & 0x2000)
3159                {
3160                   // Command Format 2
3161                   if (instruction & 0x1000)
3162                      sprintf(outstring, "%s, D0, %s", disdmaram((instruction >> 8) & 0x7), disd1bussrc(instruction & 0x7));
3163                   else
3164                      sprintf(outstring, "D0, %s, %s", disdmaram((instruction >> 8) & 0x7), disd1bussrc(instruction & 0x7));
3165                }
3166                else
3167                {
3168                   // Command Format 1
3169                   if (instruction & 0x1000)
3170                      sprintf(outstring, "%s, D0, #$%02X", disdmaram((instruction >> 8) & 0x7), (int)(instruction & 0xFF));
3171                   else
3172                      sprintf(outstring, "D0, %s, #$%02X", disdmaram((instruction >> 8) & 0x7), (int)(instruction & 0xFF));
3173                }
3174 
3175                break;
3176             }
3177             case 0x01: // Jump Commands
3178                switch ((instruction >> 19) & 0x7F) {
3179                   case 0x00:
3180                      sprintf(outstring, "JMP $%02X", (unsigned int)instruction & 0xFF);
3181                      break;
3182                   case 0x41:
3183                      sprintf(outstring, "JMP NZ,$%02X", (unsigned int)instruction & 0xFF);
3184                      break;
3185                   case 0x42:
3186                      sprintf(outstring, "JMP NS,$%02X", (unsigned int)instruction & 0xFF);
3187                      break;
3188                   case 0x43:
3189                      sprintf(outstring, "JMP NZS,$%02X", (unsigned int)instruction & 0xFF);
3190                      break;
3191                   case 0x44:
3192                      sprintf(outstring, "JMP NC,$%02X", (unsigned int)instruction & 0xFF);
3193                      break;
3194                   case 0x48:
3195                      sprintf(outstring, "JMP NT0,$%02X", (unsigned int)instruction & 0xFF);
3196                      break;
3197                   case 0x61:
3198                      sprintf(outstring, "JMP Z,$%02X", (unsigned int)instruction & 0xFF);
3199                      break;
3200                   case 0x62:
3201                      sprintf(outstring, "JMP S,$%02X", (unsigned int)instruction & 0xFF);
3202                      break;
3203                   case 0x63:
3204                      sprintf(outstring, "JMP ZS,$%02X", (unsigned int)instruction & 0xFF);
3205                      break;
3206                   case 0x64:
3207                      sprintf(outstring, "JMP C,$%02X", (unsigned int)instruction & 0xFF);
3208                      break;
3209                   case 0x68:
3210                      sprintf(outstring, "JMP T0,$%02X", (unsigned int)instruction & 0xFF);
3211                      break;
3212                   default:
3213                      sprintf(outstring, "Unknown JMP");
3214                      break;
3215                }
3216                break;
3217             case 0x02: // Loop bottom Commands
3218                if (instruction & 0x8000000)
3219                   sprintf(outstring, "LPS");
3220                else
3221                   sprintf(outstring, "BTM");
3222 
3223                break;
3224             case 0x03: // End Commands
3225                if (instruction & 0x8000000)
3226                   sprintf(outstring, "ENDI");
3227                else
3228                   sprintf(outstring, "END");
3229 
3230                break;
3231             default: break;
3232          }
3233          break;
3234       default:
3235          sprintf(outstring, "Invalid opcode");
3236          break;
3237    }
3238 }
3239 
3240 //////////////////////////////////////////////////////////////////////////////
3241 
ScuDspStep(void)3242 void ScuDspStep(void) {
3243    if (ScuDsp)
3244       ScuExec(1);
3245 }
3246 
3247 //////////////////////////////////////////////////////////////////////////////
3248 
ScuDspSaveProgram(const char * filename)3249 int ScuDspSaveProgram(const char *filename) {
3250    FILE *fp;
3251    u32 i;
3252    u8 *buffer;
3253 
3254    if (!filename)
3255       return -1;
3256 
3257    if ((fp = fopen(filename, "wb")) == NULL)
3258       return -1;
3259 
3260    if ((buffer = (u8 *)malloc(sizeof(ScuDsp->ProgramRam))) == NULL)
3261    {
3262       fclose(fp);
3263       return -2;
3264    }
3265 
3266    for (i = 0; i < 256; i++)
3267    {
3268       buffer[i * 4] = (u8)(ScuDsp->ProgramRam[i] >> 24);
3269       buffer[(i * 4)+1] = (u8)(ScuDsp->ProgramRam[i] >> 16);
3270       buffer[(i * 4)+2] = (u8)(ScuDsp->ProgramRam[i] >> 8);
3271       buffer[(i * 4)+3] = (u8)ScuDsp->ProgramRam[i];
3272    }
3273 
3274    fwrite((void *)buffer, 1, sizeof(ScuDsp->ProgramRam), fp);
3275    fclose(fp);
3276    free(buffer);
3277 
3278    return 0;
3279 }
3280 
3281 //////////////////////////////////////////////////////////////////////////////
3282 
ScuDspSaveMD(const char * filename,int num)3283 int ScuDspSaveMD(const char *filename, int num) {
3284    FILE *fp;
3285    u32 i;
3286    u8 *buffer;
3287 
3288    if (!filename)
3289       return -1;
3290 
3291    if ((fp = fopen(filename, "wb")) == NULL)
3292       return -1;
3293 
3294    if ((buffer = (u8 *)malloc(sizeof(ScuDsp->MD[num]))) == NULL)
3295    {
3296       fclose(fp);
3297       return -2;
3298    }
3299 
3300    for (i = 0; i < 64; i++)
3301    {
3302       buffer[i * 4] = (u8)(ScuDsp->MD[num][i] >> 24);
3303       buffer[(i * 4)+1] = (u8)(ScuDsp->MD[num][i] >> 16);
3304       buffer[(i * 4)+2] = (u8)(ScuDsp->MD[num][i] >> 8);
3305       buffer[(i * 4)+3] = (u8)ScuDsp->MD[num][i];
3306    }
3307 
3308    fwrite((void *)buffer, 1, sizeof(ScuDsp->MD[num]), fp);
3309    fclose(fp);
3310    free(buffer);
3311 
3312    return 0;
3313 }
3314 
3315 //////////////////////////////////////////////////////////////////////////////
3316 
ScuDspGetRegisters(scudspregs_struct * regs)3317 void ScuDspGetRegisters(scudspregs_struct *regs) {
3318    if (regs != NULL) {
3319       memcpy(regs->ProgramRam, ScuDsp->ProgramRam, sizeof(u32) * 256);
3320       memcpy(regs->MD, ScuDsp->MD, sizeof(u32) * 64 * 4);
3321 
3322       regs->ProgControlPort.all = ScuDsp->ProgControlPort.all;
3323       regs->ProgControlPort.part.P = regs->PC = ScuDsp->PC;
3324       regs->TOP = ScuDsp->TOP;
3325       regs->LOP = ScuDsp->LOP;
3326       regs->jmpaddr = ScuDsp->jmpaddr;
3327       regs->delayed = ScuDsp->delayed;
3328       regs->DataRamPage = ScuDsp->DataRamPage;
3329       regs->DataRamReadAddress = ScuDsp->DataRamReadAddress;
3330       memcpy(regs->CT, ScuDsp->CT, sizeof(u8) * 4);
3331       regs->RX = ScuDsp->RX;
3332       regs->RY = ScuDsp->RY;
3333       regs->RA0 = ScuDsp->RA0;
3334       regs->WA0 = ScuDsp->WA0;
3335 
3336       regs->AC.all = ScuDsp->AC.all;
3337       regs->P.all = ScuDsp->P.all;
3338       regs->ALU.all = ScuDsp->ALU.all;
3339       regs->MUL.all = ScuDsp->MUL.all;
3340    }
3341 }
3342 
3343 //////////////////////////////////////////////////////////////////////////////
3344 
ScuDspSetRegisters(scudspregs_struct * regs)3345 void ScuDspSetRegisters(scudspregs_struct *regs) {
3346    if (regs != NULL) {
3347       memcpy(ScuDsp->ProgramRam, regs->ProgramRam, sizeof(u32) * 256);
3348       memcpy(ScuDsp->MD, regs->MD, sizeof(u32) * 64 * 4);
3349 
3350       ScuDsp->ProgControlPort.all = regs->ProgControlPort.all;
3351       ScuDsp->PC = regs->ProgControlPort.part.P;
3352       ScuDsp->TOP = regs->TOP;
3353       ScuDsp->LOP = regs->LOP;
3354       ScuDsp->jmpaddr = regs->jmpaddr;
3355       ScuDsp->delayed = regs->delayed;
3356       ScuDsp->DataRamPage = regs->DataRamPage;
3357       ScuDsp->DataRamReadAddress = regs->DataRamReadAddress;
3358       memcpy(ScuDsp->CT, regs->CT, sizeof(u8) * 4);
3359       ScuDsp->RX = regs->RX;
3360       ScuDsp->RY = regs->RY;
3361       ScuDsp->RA0 = regs->RA0;
3362       ScuDsp->WA0 = regs->WA0;
3363 
3364       ScuDsp->AC.all = regs->AC.all;
3365       ScuDsp->P.all = regs->P.all;
3366       ScuDsp->ALU.all = regs->ALU.all;
3367       ScuDsp->MUL.all = regs->MUL.all;
3368    }
3369 }
3370 
3371 //////////////////////////////////////////////////////////////////////////////
3372 
ScuDspSetBreakpointCallBack(void (* func)(u32))3373 void ScuDspSetBreakpointCallBack(void (*func)(u32)) {
3374    ScuBP->BreakpointCallBack = func;
3375 }
3376 
3377 //////////////////////////////////////////////////////////////////////////////
3378 
ScuDspAddCodeBreakpoint(u32 addr)3379 int ScuDspAddCodeBreakpoint(u32 addr) {
3380    int i;
3381 
3382    if (ScuBP->numcodebreakpoints < MAX_BREAKPOINTS) {
3383       // Make sure it isn't already on the list
3384       for (i = 0; i < ScuBP->numcodebreakpoints; i++)
3385       {
3386          if (addr == ScuBP->codebreakpoint[i].addr)
3387             return -1;
3388       }
3389 
3390       ScuBP->codebreakpoint[ScuBP->numcodebreakpoints].addr = addr;
3391       ScuBP->numcodebreakpoints++;
3392 
3393       return 0;
3394    }
3395 
3396    return -1;
3397 }
3398 
3399 //////////////////////////////////////////////////////////////////////////////
3400 
ScuDspSortCodeBreakpoints(void)3401 static void ScuDspSortCodeBreakpoints(void) {
3402    int i, i2;
3403    u32 tmp;
3404 
3405    for (i = 0; i < (MAX_BREAKPOINTS-1); i++)
3406    {
3407       for (i2 = i+1; i2 < MAX_BREAKPOINTS; i2++)
3408       {
3409          if (ScuBP->codebreakpoint[i].addr == 0xFFFFFFFF &&
3410             ScuBP->codebreakpoint[i2].addr != 0xFFFFFFFF)
3411          {
3412             tmp = ScuBP->codebreakpoint[i].addr;
3413             ScuBP->codebreakpoint[i].addr = ScuBP->codebreakpoint[i2].addr;
3414             ScuBP->codebreakpoint[i2].addr = tmp;
3415          }
3416       }
3417    }
3418 }
3419 
3420 //////////////////////////////////////////////////////////////////////////////
3421 
ScuDspDelCodeBreakpoint(u32 addr)3422 int ScuDspDelCodeBreakpoint(u32 addr) {
3423    int i;
3424 
3425    if (ScuBP->numcodebreakpoints > 0) {
3426       for (i = 0; i < ScuBP->numcodebreakpoints; i++) {
3427          if (ScuBP->codebreakpoint[i].addr == addr)
3428          {
3429             ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF;
3430             ScuDspSortCodeBreakpoints();
3431             ScuBP->numcodebreakpoints--;
3432             return 0;
3433          }
3434       }
3435    }
3436 
3437    return -1;
3438 }
3439 
3440 //////////////////////////////////////////////////////////////////////////////
3441 
ScuDspGetBreakpointList(void)3442 scucodebreakpoint_struct *ScuDspGetBreakpointList(void) {
3443    return ScuBP->codebreakpoint;
3444 }
3445 
3446 //////////////////////////////////////////////////////////////////////////////
3447 
ScuDspClearCodeBreakpoints(void)3448 void ScuDspClearCodeBreakpoints(void) {
3449    int i;
3450    for (i = 0; i < MAX_BREAKPOINTS; i++)
3451       ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF;
3452 
3453    ScuBP->numcodebreakpoints = 0;
3454 }
3455 
3456 //////////////////////////////////////////////////////////////////////////////
3457 
ScuReadByte(u32 addr)3458 u8 FASTCALL ScuReadByte(u32 addr) {
3459    addr &= 0xFF;
3460 
3461    switch(addr) {
3462       case 0xA7:
3463          return (ScuRegs->IST & 0xFF);
3464       default:
3465          LOG("Unhandled SCU Register byte read %08X\n", addr);
3466          return 0;
3467    }
3468 
3469    return 0;
3470 }
3471 
3472 //////////////////////////////////////////////////////////////////////////////
3473 
ScuReadWord(u32 addr)3474 u16 FASTCALL ScuReadWord(u32 addr) {
3475    addr &= 0xFF;
3476    LOG("Unhandled SCU Register word read %08X\n", addr);
3477 
3478    return 0;
3479 }
3480 
3481 //////////////////////////////////////////////////////////////////////////////
3482 
scu_dsp_int_set_program(u32 val)3483 void scu_dsp_int_set_program(u32 val)
3484 {
3485    ScuDsp->ProgramRam[ScuDsp->PC] = val;
3486    ScuDsp->PC++;
3487    ScuDsp->ProgControlPort.part.P = ScuDsp->PC;
3488 }
3489 
scu_dsp_int_set_data_address(u32 val)3490 void scu_dsp_int_set_data_address(u32 val)
3491 {
3492    ScuDsp->DataRamPage = (val >> 6) & 3;
3493    ScuDsp->DataRamReadAddress = val & 0x3F;
3494 }
3495 
scu_dsp_int_set_data_ram_data(u32 val)3496 void scu_dsp_int_set_data_ram_data(u32 val)
3497 {
3498    if (!ScuDsp->ProgControlPort.part.EX) {
3499       ScuDsp->MD[ScuDsp->DataRamPage][ScuDsp->DataRamReadAddress] = val;
3500       ScuDsp->DataRamReadAddress++;
3501    }
3502 }
3503 
scu_dsp_int_set_program_control(u32 val)3504 void scu_dsp_int_set_program_control(u32 val)
3505 {
3506    ScuDsp->ProgControlPort.all = (ScuDsp->ProgControlPort.all & 0x00FC0000) | (val & 0x060380FF);
3507 
3508    if (ScuDsp->ProgControlPort.part.LE) {
3509       // set pc
3510       ScuDsp->PC = (u8)ScuDsp->ProgControlPort.part.P;
3511       LOG("scu\t: DSP set pc = %02X\n", ScuDsp->PC);
3512    }
3513 }
scu_dsp_int_get_program_control()3514 u32 scu_dsp_int_get_program_control()
3515 {
3516    return (ScuDsp->ProgControlPort.all & 0x00FD00FF);
3517 }
3518 
scu_dsp_int_get_data_ram()3519 u32 scu_dsp_int_get_data_ram()
3520 {
3521    if (!ScuDsp->ProgControlPort.part.EX)
3522       return ScuDsp->MD[ScuDsp->DataRamPage][ScuDsp->DataRamReadAddress++];
3523 
3524    return 0;
3525 }
3526 
scu_dsp_init()3527 void scu_dsp_init()
3528 {
3529    scu_dsp_inf.get_data_ram = scu_dsp_int_get_data_ram;
3530    scu_dsp_inf.get_program_control = scu_dsp_int_get_program_control;
3531    scu_dsp_inf.set_data_address = scu_dsp_int_set_data_address;
3532    scu_dsp_inf.set_data_ram_data = scu_dsp_int_set_data_ram_data;
3533    scu_dsp_inf.set_program = scu_dsp_int_set_program;
3534    scu_dsp_inf.set_program_control = scu_dsp_int_set_program_control;
3535 }
3536 
ScuReadLong(u32 addr)3537 u32 FASTCALL ScuReadLong(u32 addr) {
3538    addr &= 0xFF;
3539    //LOG("Scu read %08X:%08X\n", addr);
3540    switch(addr) {
3541       case 0:
3542          return ScuRegs->D0R;
3543       case 4:
3544          return ScuRegs->D0W;
3545       case 8:
3546          return ScuRegs->D0C;
3547       case 0x20:
3548          return ScuRegs->D1R;
3549       case 0x24:
3550          return ScuRegs->D1W;
3551       case 0x28:
3552          return ScuRegs->D1C;
3553       case 0x40:
3554          return ScuRegs->D2R;
3555       case 0x44:
3556          return ScuRegs->D2W;
3557       case 0x48:
3558          return ScuRegs->D2C;
3559       case 0x7C:
3560          return ScuRegs->DSTA;
3561       case 0x80: // DSP Program Control Port
3562          return scu_dsp_inf.get_program_control();
3563       case 0x8C: // DSP Data Ram Data Port
3564          return scu_dsp_inf.get_data_ram();
3565       case 0xA4:
3566          return ScuRegs->IST;
3567       case 0xA8:
3568          return ScuRegs->AIACK;
3569       case 0xC4:
3570          return ScuRegs->RSEL;
3571       case 0xC8:
3572          return ScuRegs->VER;
3573       default:
3574          LOG("Unhandled SCU Register long read %08X\n", addr);
3575          return 0;
3576    }
3577 }
3578 
3579 //////////////////////////////////////////////////////////////////////////////
3580 
ScuWriteByte(u32 addr,u8 val)3581 void FASTCALL ScuWriteByte(u32 addr, u8 val) {
3582    addr &= 0xFF;
3583    switch(addr) {
3584       case 0xA7:
3585          ScuRegs->IST &= (0xFFFFFF00 | val); // double check this
3586          return;
3587       default:
3588          LOG("Unhandled SCU Register byte write %08X\n", addr);
3589          return;
3590    }
3591 }
3592 
3593 //////////////////////////////////////////////////////////////////////////////
3594 
ScuWriteWord(u32 addr,UNUSED u16 val)3595 void FASTCALL ScuWriteWord(u32 addr, UNUSED u16 val) {
3596    addr &= 0xFF;
3597    LOG("Unhandled SCU Register word write %08X\n", addr);
3598 }
3599 
3600 //////////////////////////////////////////////////////////////////////////////
3601 
ScuWriteLong(u32 addr,u32 val)3602 void FASTCALL ScuWriteLong(u32 addr, u32 val) {
3603    addr &= 0xFF;
3604 	//LOG("Scu write %08X:%08X\n", addr, val);
3605    switch(addr) {
3606       case 0:
3607          ScuRegs->D0R = val;
3608          break;
3609       case 4:
3610          ScuRegs->D0W = val;
3611          break;
3612       case 8:
3613          ScuRegs->D0C = val;
3614          break;
3615       case 0xC:
3616          ScuRegs->D0AD = val;
3617          break;
3618       case 0x10:
3619 		  if ((val & 0x1) && ((ScuRegs->D0MD&0x7)==0x7) )
3620          {
3621             if (yabsys.use_scu_dma_timing)
3622                scu_insert_dma(ScuRegs->D0R, ScuRegs->D0W, ScuRegs->D0C, ScuRegs->D0AD, ScuRegs->D0MD, 0);
3623             else
3624             {
3625                scudmainfo_struct dmainfo;
3626 
3627                dmainfo.mode = 0;
3628                dmainfo.ReadAddress = ScuRegs->D0R;
3629                dmainfo.WriteAddress = ScuRegs->D0W;
3630                dmainfo.TransferNumber = ScuRegs->D0C;
3631                dmainfo.AddValue = ScuRegs->D0AD;
3632                dmainfo.ModeAddressUpdate = ScuRegs->D0MD;
3633 
3634                ScuDMA(&dmainfo);
3635             }
3636          }
3637          ScuRegs->D0EN = val;
3638          break;
3639       case 0x14:
3640          ScuRegs->D0MD = val;
3641          break;
3642       case 0x20:
3643          ScuRegs->D1R = val;
3644          break;
3645       case 0x24:
3646          ScuRegs->D1W = val;
3647          break;
3648       case 0x28:
3649          ScuRegs->D1C = val;
3650          break;
3651       case 0x2C:
3652          ScuRegs->D1AD = val;
3653          break;
3654       case 0x30:
3655 		  if ((val & 0x1) && ((ScuRegs->D1MD&0x07) == 0x7))
3656          {
3657             if (yabsys.use_scu_dma_timing)
3658                scu_insert_dma(ScuRegs->D1R, ScuRegs->D1W, ScuRegs->D1C, ScuRegs->D1AD, ScuRegs->D1MD, 1);
3659             else
3660             {
3661                scudmainfo_struct dmainfo;
3662 
3663                dmainfo.mode = 1;
3664                dmainfo.ReadAddress = ScuRegs->D1R;
3665                dmainfo.WriteAddress = ScuRegs->D1W;
3666                dmainfo.TransferNumber = ScuRegs->D1C;
3667                dmainfo.AddValue = ScuRegs->D1AD;
3668                dmainfo.ModeAddressUpdate = ScuRegs->D1MD;
3669 
3670                ScuDMA(&dmainfo);
3671             }
3672          }
3673          ScuRegs->D1EN = val;
3674          break;
3675       case 0x34:
3676          ScuRegs->D1MD = val;
3677          break;
3678       case 0x40:
3679          ScuRegs->D2R = val;
3680          break;
3681       case 0x44:
3682          ScuRegs->D2W = val;
3683          break;
3684       case 0x48:
3685          ScuRegs->D2C = val;
3686          break;
3687       case 0x4C:
3688          ScuRegs->D2AD = val;
3689          break;
3690       case 0x50:
3691 		  if ((val & 0x1) && ((ScuRegs->D2MD & 0x7) == 0x7))
3692          {
3693             if (yabsys.use_scu_dma_timing)
3694                scu_insert_dma(ScuRegs->D2R, ScuRegs->D2W, ScuRegs->D2C, ScuRegs->D2AD, ScuRegs->D2MD, 2);
3695             else
3696             {
3697                scudmainfo_struct dmainfo;
3698 
3699                dmainfo.mode = 2;
3700                dmainfo.ReadAddress = ScuRegs->D2R;
3701                dmainfo.WriteAddress = ScuRegs->D2W;
3702                dmainfo.TransferNumber = ScuRegs->D2C;
3703                dmainfo.AddValue = ScuRegs->D2AD;
3704                dmainfo.ModeAddressUpdate = ScuRegs->D2MD;
3705 
3706                ScuDMA(&dmainfo);
3707             }
3708          }
3709          ScuRegs->D2EN = val;
3710          break;
3711       case 0x54:
3712          ScuRegs->D2MD = val;
3713          break;
3714       case 0x60:
3715          ScuRegs->DSTP = val;
3716          break;
3717       case 0x80: // DSP Program Control Port
3718          LOG("scu\t: wrote %08X to DSP Program Control Port\n", val);
3719          scu_dsp_inf.set_program_control(val);
3720 #if DEBUG
3721          if (ScuDsp->ProgControlPort.part.EX)
3722             LOG("scu\t: DSP executing: PC = %02X\n", ScuDsp->PC);
3723 #endif
3724          break;
3725       case 0x84: // DSP Program Ram Data Port
3726 //         LOG("scu\t: wrote %08X to DSP Program ram offset %02X\n", val, ScuDsp->PC);
3727          scu_dsp_inf.set_program(val);
3728          break;
3729       case 0x88: // DSP Data Ram Address Port
3730          scu_dsp_inf.set_data_address(val);
3731          break;
3732       case 0x8C: // DSP Data Ram Data Port
3733 //         LOG("scu\t: wrote %08X to DSP Data Ram Data Port Page %d offset %02X\n", val, ScuDsp->DataRamPage, ScuDsp->DataRamReadAddress);
3734          scu_dsp_inf.set_data_ram_data(val);
3735          break;
3736       case 0x90:
3737          ScuRegs->T0C = val;
3738          break;
3739       case 0x94:
3740          ScuRegs->T1S = val;
3741          break;
3742       case 0x98:
3743          ScuRegs->T1MD = val;
3744          break;
3745       case 0xA0:
3746          ScuRegs->IMS = val;
3747 		 //LOG("scu\t: IMS = %02X\n", val);
3748          ScuTestInterruptMask();
3749          break;
3750       case 0xA4:
3751          ScuRegs->IST &= val;
3752          break;
3753       case 0xA8:
3754          ScuRegs->AIACK = val;
3755          break;
3756       case 0xB0:
3757          ScuRegs->ASR0 = val;
3758          break;
3759       case 0xB4:
3760          ScuRegs->ASR1 = val;
3761          break;
3762       case 0xB8:
3763          ScuRegs->AREF = val;
3764          break;
3765       case 0xC4:
3766          ScuRegs->RSEL = val;
3767          break;
3768       default:
3769          LOG("Unhandled SCU Register long write %08X\n", addr);
3770          break;
3771    }
3772 }
3773 
3774 
Sh2ScuReadByte(SH2_struct * sh,u32 addr)3775 u8 FASTCALL Sh2ScuReadByte(SH2_struct *sh, u32 addr) {
3776    return ScuReadByte(addr);
3777 }
3778 
3779 //////////////////////////////////////////////////////////////////////////////
3780 
Sh2ScuReadWord(SH2_struct * sh,u32 addr)3781 u16 FASTCALL Sh2ScuReadWord(SH2_struct *sh, u32 addr) {
3782    return ScuReadWord(addr);
3783 }
3784 
3785 //////////////////////////////////////////////////////////////////////////////
3786 
Sh2ScuReadLong(SH2_struct * sh,u32 addr)3787 u32 FASTCALL Sh2ScuReadLong(SH2_struct *sh, u32 addr) {
3788    return ScuReadLong(addr);
3789 }
3790 
3791 //////////////////////////////////////////////////////////////////////////////
3792 
Sh2ScuWriteByte(SH2_struct * sh,u32 addr,u8 val)3793 void FASTCALL Sh2ScuWriteByte(SH2_struct *sh, u32 addr, u8 val) {
3794    ScuWriteByte(addr, val);
3795 }
3796 
3797 //////////////////////////////////////////////////////////////////////////////
3798 
Sh2ScuWriteWord(SH2_struct * sh,u32 addr,UNUSED u16 val)3799 void FASTCALL Sh2ScuWriteWord(SH2_struct *sh, u32 addr, UNUSED u16 val) {
3800    ScuWriteWord(addr, val);
3801 }
3802 
3803 //////////////////////////////////////////////////////////////////////////////
3804 
Sh2ScuWriteLong(SH2_struct * sh,u32 addr,u32 val)3805 void FASTCALL Sh2ScuWriteLong(SH2_struct *sh, u32 addr, u32 val) {
3806    ScuWriteLong(addr, val);
3807 }
3808 
3809 //////////////////////////////////////////////////////////////////////////////
3810 
ScuTestInterruptMask()3811 void ScuTestInterruptMask()
3812 {
3813    unsigned int i, i2;
3814 
3815    // Handle SCU interrupts
3816    for (i = 0; i < ScuRegs->NumberOfInterrupts; i++)
3817    {
3818       if (!(ScuRegs->IMS & ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].mask))
3819       {
3820          SH2SendInterrupt(MSH2, ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].vector, ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].level);
3821          ScuRegs->IST &= ~ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].statusbit;
3822 
3823          // Shorten list
3824          for (i2 = ScuRegs->NumberOfInterrupts-1-i; i2 < (ScuRegs->NumberOfInterrupts-1); i2++)
3825             memcpy(&ScuRegs->interrupts[i2], &ScuRegs->interrupts[i2+1], sizeof(scuinterrupt_struct));
3826 
3827          ScuRegs->NumberOfInterrupts--;
3828          break;
3829       }
3830    }
3831 }
3832 
3833 //////////////////////////////////////////////////////////////////////////////
3834 
ScuQueueInterrupt(u8 vector,u8 level,u16 mask,u32 statusbit)3835 static void ScuQueueInterrupt(u8 vector, u8 level, u16 mask, u32 statusbit)
3836 {
3837    u32 i, i2;
3838    scuinterrupt_struct tmp;
3839 
3840    // Make sure interrupt doesn't already exist
3841    for (i = 0; i < ScuRegs->NumberOfInterrupts; i++)
3842    {
3843       if (ScuRegs->interrupts[i].vector == vector)
3844          return;
3845    }
3846 
3847    ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].vector = vector;
3848    ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].level = level;
3849    ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].mask = mask;
3850    ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].statusbit = statusbit;
3851    ScuRegs->NumberOfInterrupts++;
3852 
3853    // Sort interrupts
3854    for (i = 0; i < (ScuRegs->NumberOfInterrupts-1); i++)
3855    {
3856       for (i2 = i+1; i2 < ScuRegs->NumberOfInterrupts; i2++)
3857       {
3858          if (ScuRegs->interrupts[i].level > ScuRegs->interrupts[i2].level)
3859          {
3860             memcpy(&tmp, &ScuRegs->interrupts[i], sizeof(scuinterrupt_struct));
3861             memcpy(&ScuRegs->interrupts[i], &ScuRegs->interrupts[i2], sizeof(scuinterrupt_struct));
3862             memcpy(&ScuRegs->interrupts[i2], &tmp, sizeof(scuinterrupt_struct));
3863          }
3864       }
3865    }
3866 }
3867 
3868 //////////////////////////////////////////////////////////////////////////////
3869 
SendInterrupt(u8 vector,u8 level,u16 mask,u32 statusbit)3870 static INLINE void SendInterrupt(u8 vector, u8 level, u16 mask, u32 statusbit) {
3871 
3872 	if (!(ScuRegs->IMS & mask)){
3873 		//if (vector != 0x41) LOG("INT %d", vector);
3874 		SH2SendInterrupt(MSH2, vector, level);
3875 	}
3876 	else
3877    {
3878       ScuQueueInterrupt(vector, level, mask, statusbit);
3879       ScuRegs->IST |= statusbit;
3880    }
3881 }
3882 
3883 // 3.2 DMA control register
ScuChekIntrruptDMA(int id)3884 static INLINE void ScuChekIntrruptDMA(int id){
3885 
3886 	if ((ScuRegs->D0EN & 0x100) && (ScuRegs->D0MD & 0x07) == id){
3887 		scudmainfo_struct dmainfo;
3888 		dmainfo.mode = 0;
3889 		dmainfo.ReadAddress = ScuRegs->D0R;
3890 		dmainfo.WriteAddress = ScuRegs->D0W;
3891 		dmainfo.TransferNumber = ScuRegs->D0C;
3892 		dmainfo.AddValue = ScuRegs->D0AD;
3893 		dmainfo.ModeAddressUpdate = ScuRegs->D0MD;
3894 		ScuDMA(&dmainfo);
3895 		ScuRegs->D0EN = 0;
3896 	}
3897 	if ((ScuRegs->D1EN & 0x100) && (ScuRegs->D1MD & 0x07) == id){
3898 		scudmainfo_struct dmainfo;
3899 		dmainfo.mode = 1;
3900 		dmainfo.ReadAddress = ScuRegs->D1R;
3901 		dmainfo.WriteAddress = ScuRegs->D1W;
3902 		dmainfo.TransferNumber = ScuRegs->D1C;
3903 		dmainfo.AddValue = ScuRegs->D1AD;
3904 		dmainfo.ModeAddressUpdate = ScuRegs->D1MD;
3905 		ScuDMA(&dmainfo);
3906 		ScuRegs->D1EN = 0;
3907 	}
3908 	if ((ScuRegs->D2EN & 0x100) && (ScuRegs->D2MD & 0x07) == id){
3909 		scudmainfo_struct dmainfo;
3910 		dmainfo.mode = 2;
3911 		dmainfo.ReadAddress = ScuRegs->D2R;
3912 		dmainfo.WriteAddress = ScuRegs->D2W;
3913 		dmainfo.TransferNumber = ScuRegs->D2C;
3914 		dmainfo.AddValue = ScuRegs->D0AD;
3915 		dmainfo.ModeAddressUpdate = ScuRegs->D2MD;
3916 		ScuDMA(&dmainfo);
3917 		ScuRegs->D2EN = 0;
3918 	}
3919 }
3920 
3921 //////////////////////////////////////////////////////////////////////////////
3922 
ScuSendVBlankIN(void)3923 void ScuSendVBlankIN(void) {
3924    SendInterrupt(0x40, 0xF, 0x0001, 0x0001);
3925    ScuChekIntrruptDMA(0);
3926 }
3927 
3928 
3929 //////////////////////////////////////////////////////////////////////////////
3930 
ScuSendVBlankOUT(void)3931 void ScuSendVBlankOUT(void) {
3932    SendInterrupt(0x41, 0xE, 0x0002, 0x0002);
3933    ScuRegs->timer0 = 0;
3934    if (ScuRegs->T1MD & 0x1)
3935    {
3936       if (ScuRegs->timer0 == ScuRegs->T0C)
3937          ScuSendTimer0();
3938    }
3939    ScuChekIntrruptDMA(1);
3940 }
3941 
3942 //////////////////////////////////////////////////////////////////////////////
3943 
ScuSendHBlankIN(void)3944 void ScuSendHBlankIN(void) {
3945    SendInterrupt(0x42, 0xD, 0x0004, 0x0004);
3946 
3947    ScuRegs->timer0++;
3948    if (ScuRegs->T1MD & 0x1)
3949    {
3950       // if timer0 equals timer 0 compare register, do an interrupt
3951       if (ScuRegs->timer0 == ScuRegs->T0C)
3952          ScuSendTimer0();
3953 
3954       // FIX ME - Should handle timer 1 as well
3955    }
3956    ScuChekIntrruptDMA(2);
3957 }
3958 
3959 //////////////////////////////////////////////////////////////////////////////
3960 
ScuSendTimer0(void)3961 void ScuSendTimer0(void) {
3962    SendInterrupt(0x43, 0xC, 0x0008, 0x00000008);
3963    ScuChekIntrruptDMA(3);
3964 }
3965 
3966 //////////////////////////////////////////////////////////////////////////////
3967 
ScuSendTimer1(void)3968 void ScuSendTimer1(void) {
3969    SendInterrupt(0x44, 0xB, 0x0010, 0x00000010);
3970    ScuChekIntrruptDMA(4);
3971 }
3972 
3973 //////////////////////////////////////////////////////////////////////////////
3974 
ScuSendDSPEnd(void)3975 void ScuSendDSPEnd(void) {
3976    SendInterrupt(0x45, 0xA, 0x0020, 0x00000020);
3977 }
3978 
3979 //////////////////////////////////////////////////////////////////////////////
3980 
ScuSendSoundRequest(void)3981 void ScuSendSoundRequest(void) {
3982    SendInterrupt(0x46, 0x9, 0x0040, 0x00000040);
3983    ScuChekIntrruptDMA(5);
3984 }
3985 
3986 //////////////////////////////////////////////////////////////////////////////
3987 
ScuSendSystemManager(void)3988 void ScuSendSystemManager(void) {
3989    SendInterrupt(0x47, 0x8, 0x0080, 0x00000080);
3990 }
3991 
3992 //////////////////////////////////////////////////////////////////////////////
3993 
ScuSendPadInterrupt(void)3994 void ScuSendPadInterrupt(void) {
3995    SendInterrupt(0x48, 0x8, 0x0100, 0x00000100);
3996 }
3997 
3998 //////////////////////////////////////////////////////////////////////////////
3999 
ScuSendLevel2DMAEnd(void)4000 void ScuSendLevel2DMAEnd(void) {
4001    SendInterrupt(0x49, 0x6, 0x0200, 0x00000200);
4002 }
4003 
4004 //////////////////////////////////////////////////////////////////////////////
4005 
ScuSendLevel1DMAEnd(void)4006 void ScuSendLevel1DMAEnd(void) {
4007    SendInterrupt(0x4A, 0x6, 0x0400, 0x00000400);
4008 }
4009 
4010 //////////////////////////////////////////////////////////////////////////////
4011 
ScuSendLevel0DMAEnd(void)4012 void ScuSendLevel0DMAEnd(void) {
4013    SendInterrupt(0x4B, 0x5, 0x0800, 0x00000800);
4014 }
4015 
4016 //////////////////////////////////////////////////////////////////////////////
4017 
ScuSendDMAIllegal(void)4018 void ScuSendDMAIllegal(void) {
4019    SendInterrupt(0x4C, 0x3, 0x1000, 0x00001000);
4020 }
4021 
4022 //////////////////////////////////////////////////////////////////////////////
4023 
ScuSendDrawEnd(void)4024 void ScuSendDrawEnd(void) {
4025    SendInterrupt(0x4D, 0x2, 0x2000, 0x00002000);
4026    ScuChekIntrruptDMA(6);
4027 }
4028 
4029 //////////////////////////////////////////////////////////////////////////////
4030 
ScuSendExternalInterrupt00(void)4031 void ScuSendExternalInterrupt00(void) {
4032    SendInterrupt(0x50, 0x7, 0x8000, 0x00010000);
4033 }
4034 
4035 //////////////////////////////////////////////////////////////////////////////
4036 
ScuSendExternalInterrupt01(void)4037 void ScuSendExternalInterrupt01(void) {
4038    SendInterrupt(0x51, 0x7, 0x8000, 0x00020000);
4039 }
4040 
4041 //////////////////////////////////////////////////////////////////////////////
4042 
ScuSendExternalInterrupt02(void)4043 void ScuSendExternalInterrupt02(void) {
4044    SendInterrupt(0x52, 0x7, 0x8000, 0x00040000);
4045 }
4046 
4047 //////////////////////////////////////////////////////////////////////////////
4048 
ScuSendExternalInterrupt03(void)4049 void ScuSendExternalInterrupt03(void) {
4050    SendInterrupt(0x53, 0x7, 0x8000, 0x00080000);
4051 }
4052 
4053 //////////////////////////////////////////////////////////////////////////////
4054 
ScuSendExternalInterrupt04(void)4055 void ScuSendExternalInterrupt04(void) {
4056    SendInterrupt(0x54, 0x4, 0x8000, 0x00100000);
4057 }
4058 
4059 //////////////////////////////////////////////////////////////////////////////
4060 
ScuSendExternalInterrupt05(void)4061 void ScuSendExternalInterrupt05(void) {
4062    SendInterrupt(0x55, 0x4, 0x8000, 0x00200000);
4063 }
4064 
4065 //////////////////////////////////////////////////////////////////////////////
4066 
ScuSendExternalInterrupt06(void)4067 void ScuSendExternalInterrupt06(void) {
4068    SendInterrupt(0x56, 0x4, 0x8000, 0x00400000);
4069 }
4070 
4071 //////////////////////////////////////////////////////////////////////////////
4072 
ScuSendExternalInterrupt07(void)4073 void ScuSendExternalInterrupt07(void) {
4074    SendInterrupt(0x57, 0x4, 0x8000, 0x00800000);
4075 }
4076 
4077 //////////////////////////////////////////////////////////////////////////////
4078 
ScuSendExternalInterrupt08(void)4079 void ScuSendExternalInterrupt08(void) {
4080    SendInterrupt(0x58, 0x1, 0x8000, 0x01000000);
4081 }
4082 
4083 //////////////////////////////////////////////////////////////////////////////
4084 
ScuSendExternalInterrupt09(void)4085 void ScuSendExternalInterrupt09(void) {
4086    SendInterrupt(0x59, 0x1, 0x8000, 0x02000000);
4087 }
4088 
4089 //////////////////////////////////////////////////////////////////////////////
4090 
ScuSendExternalInterrupt10(void)4091 void ScuSendExternalInterrupt10(void) {
4092    SendInterrupt(0x5A, 0x1, 0x8000, 0x04000000);
4093 }
4094 
4095 //////////////////////////////////////////////////////////////////////////////
4096 
ScuSendExternalInterrupt11(void)4097 void ScuSendExternalInterrupt11(void) {
4098    SendInterrupt(0x5B, 0x1, 0x8000, 0x08000000);
4099 }
4100 
4101 //////////////////////////////////////////////////////////////////////////////
4102 
ScuSendExternalInterrupt12(void)4103 void ScuSendExternalInterrupt12(void) {
4104    SendInterrupt(0x5C, 0x1, 0x8000, 0x10000000);
4105 }
4106 
4107 //////////////////////////////////////////////////////////////////////////////
4108 
ScuSendExternalInterrupt13(void)4109 void ScuSendExternalInterrupt13(void) {
4110    SendInterrupt(0x5D, 0x1, 0x8000, 0x20000000);
4111 }
4112 
4113 //////////////////////////////////////////////////////////////////////////////
4114 
ScuSendExternalInterrupt14(void)4115 void ScuSendExternalInterrupt14(void) {
4116    SendInterrupt(0x5E, 0x1, 0x8000, 0x40000000);
4117 }
4118 
4119 //////////////////////////////////////////////////////////////////////////////
4120 
ScuSendExternalInterrupt15(void)4121 void ScuSendExternalInterrupt15(void) {
4122    SendInterrupt(0x5F, 0x1, 0x8000, 0x80000000);
4123 }
4124 
4125 //////////////////////////////////////////////////////////////////////////////
4126 
ScuSaveState(FILE * fp)4127 int ScuSaveState(FILE *fp)
4128 {
4129    int offset;
4130    IOCheck_struct check = { 0, 0 };
4131 
4132    offset = StateWriteHeader(fp, "SCU ", 1);
4133 
4134    // Write registers and internal variables
4135    ywrite(&check, (void *)ScuRegs, sizeof(Scu), 1, fp);
4136 
4137    // Write DSP area
4138    ywrite(&check, (void *)ScuDsp, sizeof(scudspregs_struct), 1, fp);
4139 
4140    return StateFinishHeader(fp, offset);
4141 }
4142 
4143 //////////////////////////////////////////////////////////////////////////////
4144 
ScuLoadState(FILE * fp,UNUSED int version,int size)4145 int ScuLoadState(FILE *fp, UNUSED int version, int size)
4146 {
4147    IOCheck_struct check = { 0, 0 };
4148 
4149    // Read registers and internal variables
4150    yread(&check, (void *)ScuRegs, sizeof(Scu), 1, fp);
4151 
4152    // Read DSP area
4153    yread(&check, (void *)ScuDsp, sizeof(scudspregs_struct), 1, fp);
4154 
4155    return size;
4156 }
4157 
4158 //////////////////////////////////////////////////////////////////////////////
4159