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