1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include "snes9x.h"
8#include "memmap.h"
9
10uint8 SA1OpenBus;
11
12static void S9xSA1SetBWRAMMemMap (uint8);
13static void S9xSetSA1MemMap (uint32, uint8);
14static void S9xSA1CharConv2 (void);
15static void S9xSA1DMA (void);
16static void S9xSA1ReadVariableLengthData (bool8, bool8);
17
18
19void S9xSA1Init (void)
20{
21 SA1.Cycles = 0;
22 SA1.PrevCycles = 0;
23 SA1.Flags = 0;
24 SA1.WaitingForInterrupt = FALSE;
25
26 memset(&Memory.FillRAM[0x2200], 0, 0x200);
27 Memory.FillRAM[0x2200] = 0x20;
28 Memory.FillRAM[0x2220] = 0x00;
29 Memory.FillRAM[0x2221] = 0x01;
30 Memory.FillRAM[0x2222] = 0x02;
31 Memory.FillRAM[0x2223] = 0x03;
32 Memory.FillRAM[0x2228] = 0x0f;
33
34 SA1.in_char_dma = FALSE;
35 SA1.TimerIRQLastState = FALSE;
36 SA1.HTimerIRQPos = 0;
37 SA1.VTimerIRQPos = 0;
38 SA1.HCounter = 0;
39 SA1.VCounter = 0;
40 SA1.PrevHCounter = 0;
41 SA1.arithmetic_op = 0;
42 SA1.op1 = 0;
43 SA1.op2 = 0;
44 SA1.sum = 0;
45 SA1.overflow = FALSE;
46 SA1.VirtualBitmapFormat = 4;
47 SA1.variable_bit_pos = 0;
48
49 SA1Registers.PBPC = 0;
50 SA1Registers.PB = 0;
51 SA1Registers.PCw = 0;
52 SA1Registers.D.W = 0;
53 SA1Registers.DB = 0;
54 SA1Registers.SH = 1;
55 SA1Registers.SL = 0xFF;
56 SA1Registers.XH = 0;
57 SA1Registers.YH = 0;
58 SA1Registers.P.W = 0;
59
60 SA1.ShiftedPB = 0;
61 SA1.ShiftedDB = 0;
62 SA1SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
63 SA1ClearFlags(Decimal);
64
65 SA1.MemSpeed = ONE_CYCLE;
66 SA1.MemSpeedx2 = ONE_CYCLE * 2;
67
68 SA1.S9xOpcodes = S9xSA1OpcodesM1X1;
69 SA1.S9xOpLengths = S9xOpLengthsM1X1;
70
71 S9xSA1SetPCBase(SA1Registers.PBPC);
72
73 S9xSA1UnpackStatus();
74 S9xSA1FixCycles();
75
76 SA1.BWRAM = Memory.SRAM;
77
78 CPU.IRQExternal = FALSE;
79}
80
81static void S9xSA1SetBWRAMMemMap (uint8 val)
82{
83 if (val & 0x80)
84 {
85 for (int c = 0; c < 0x400; c += 16)
86 {
87 SA1.Map[c + 6] = SA1.Map[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
88 SA1.Map[c + 7] = SA1.Map[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
89 SA1.WriteMap[c + 6] = SA1.WriteMap[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
90 SA1.WriteMap[c + 7] = SA1.WriteMap[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
91 }
92
93 SA1.BWRAM = Memory.SRAM + (val & 0x7f) * 0x2000 / 4;
94 }
95 else
96 {
97 for (int c = 0; c < 0x400; c += 16)
98 {
99 SA1.Map[c + 6] = SA1.Map[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM;
100 SA1.Map[c + 7] = SA1.Map[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM;
101 SA1.WriteMap[c + 6] = SA1.WriteMap[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM;
102 SA1.WriteMap[c + 7] = SA1.WriteMap[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM;
103 }
104
105 SA1.BWRAM = Memory.SRAM + (val & 0x1f) * 0x2000;
106 }
107}
108
109void S9xSA1PostLoadState (void)
110{
111 SA1.ShiftedPB = (uint32) SA1Registers.PB << 16;
112 SA1.ShiftedDB = (uint32) SA1Registers.DB << 16;
113
114 S9xSA1SetPCBase(SA1Registers.PBPC);
115 S9xSA1UnpackStatus();
116 S9xSA1FixCycles();
117 SA1.VirtualBitmapFormat = (Memory.FillRAM[0x223f] & 0x80) ? 2 : 4;
118 Memory.BWRAM = Memory.SRAM + (Memory.FillRAM[0x2224] & 0x1f) * 0x2000;
119 S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]);
120 S9xSetSA1(Memory.FillRAM[0x2220], 0x2220);
121 S9xSetSA1(Memory.FillRAM[0x2221], 0x2221);
122 S9xSetSA1(Memory.FillRAM[0x2222], 0x2222);
123 S9xSetSA1(Memory.FillRAM[0x2223], 0x2223);
124}
125
126static void S9xSetSA1MemMap (uint32 which1, uint8 map)
127{
128 int start = which1 * 0x100 + 0xc00;
129 int start2 = which1 * 0x200;
130
131 if (which1 >= 2)
132 start2 += 0x400;
133
134 for (int c = 0; c < 0x100; c += 16)
135 {
136 uint8 *block;
137 if (Multi.cartType != 5)
138 block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)];
139 else
140 {
141 if ((map & 7) < 4)
142 block = Memory.ROM + Multi.cartOffsetA + ((map & 7) * 0x100000 + (c << 12));
143 else
144 block = Memory.ROM + Multi.cartOffsetB + (((map & 7) - 4) * 0x100000 + (c << 12));
145 }
146 for (int i = c; i < c + 16; i++)
147 Memory.Map[start + i] = SA1.Map[start + i] = block;
148 }
149
150 for (int c = 0; c < 0x200; c += 16)
151 {
152 // conversion to int is needed here - map is promoted but which1 is not
153 int32 offset;
154 uint8 *block;
155 if (Multi.cartType != 5)
156 {
157 offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
158 block = &Memory.ROM[offset];
159 }
160 else
161 {
162 if ((map & 7) < 4)
163 {
164 offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
165 block = Memory.ROM + Multi.cartOffsetA + offset;
166 }
167 else
168 {
169 offset = (((map & 0x80) ? (map - 4) : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
170 block = Memory.ROM + Multi.cartOffsetB + offset;
171 }
172 }
173 for (int i = c + 8; i < c + 16; i++)
174 Memory.Map[start2 + i] = SA1.Map[start2 + i] = block;
175 }
176}
177
178uint8 S9xGetSA1 (uint32 address)
179{
180 switch (address)
181 {
182 case 0x2300: // S-CPU flag
183 return ((Memory.FillRAM[0x2209] & 0x5f) | (Memory.FillRAM[0x2300] & 0xa0));
184
185 case 0x2301: // SA-1 flag
186 return ((Memory.FillRAM[0x2200] & 0x0f) | (Memory.FillRAM[0x2301] & 0xf0));
187
188 case 0x2302: // H counter (L)
189 SA1.HTimerIRQPos = SA1.HCounter / ONE_DOT_CYCLE;
190 SA1.VTimerIRQPos = SA1.VCounter;
191 return ((uint8) SA1.HTimerIRQPos);
192
193 case 0x2303: // H counter (H)
194 return ((uint8) (SA1.HTimerIRQPos >> 8));
195
196 case 0x2304: // V counter (L)
197 return ((uint8) SA1.VTimerIRQPos);
198
199 case 0x2305: // V counter (H)
200 return ((uint8) (SA1.VTimerIRQPos >> 8));
201
202 case 0x2306: // arithmetic result (LLL)
203 return ((uint8) SA1.sum);
204
205 case 0x2307: // arithmetic result (LLH)
206 return ((uint8) (SA1.sum >> 8));
207
208 case 0x2308: // arithmetic result (LHL)
209 return ((uint8) (SA1.sum >> 16));
210
211 case 0x2309: // arithmetic result (LLH)
212 return ((uint8) (SA1.sum >> 24));
213
214 case 0x230a: // arithmetic result (HLL)
215 return ((uint8) (SA1.sum >> 32));
216
217 case 0x230b: // arithmetic overflow
218 return (SA1.overflow ? 0x80 : 0);
219
220 case 0x230c: // variable-length data read port (L)
221 return (Memory.FillRAM[0x230c]);
222
223 case 0x230d: // variable-length data read port (H)
224 {
225 uint8 byte = Memory.FillRAM[0x230d];
226
227 if (Memory.FillRAM[0x2258] & 0x80)
228 S9xSA1ReadVariableLengthData(TRUE, FALSE);
229
230 return (byte);
231 }
232
233 case 0x230e: // version code register
234 return (0x23);
235
236 default:
237 break;
238 }
239
240 return (Memory.FillRAM[address]);
241}
242
243void S9xSetSA1 (uint8 byte, uint32 address)
244{
245 switch (address)
246 {
247 case 0x2200: // SA-1 control
248 #ifdef DEBUGGER
249 if (byte & 0x60)
250 printf("SA-1 sleep\n");
251 #endif
252
253 // SA-1 reset
254 if (!(byte & 0x80) && (Memory.FillRAM[0x2200] & 0x20))
255 {
256 #ifdef DEBUGGER
257 printf("SA-1 reset\n");
258 #endif
259 SA1Registers.PBPC = 0;
260 SA1Registers.PB = 0;
261 SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8);
262 S9xSA1SetPCBase(SA1Registers.PBPC);
263 }
264
265 // SA-1 IRQ control
266 if (byte & 0x80)
267 {
268 Memory.FillRAM[0x2301] |= 0x80;
269 if (Memory.FillRAM[0x220a] & 0x80)
270 Memory.FillRAM[0x220b] &= ~0x80;
271 }
272
273 // SA-1 NMI control
274 if (byte & 0x10)
275 {
276 Memory.FillRAM[0x2301] |= 0x10;
277 if (Memory.FillRAM[0x220a] & 0x10)
278 Memory.FillRAM[0x220b] &= ~0x10;
279 }
280
281 break;
282
283 case 0x2201: // S-CPU interrupt enable
284 // S-CPU IRQ enable
285 if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80))
286 {
287 Memory.FillRAM[0x2202] &= ~0x80;
288 CPU.IRQExternal = TRUE;
289 }
290
291 // S-CPU CHDMA IRQ enable
292 if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20))
293 {
294 Memory.FillRAM[0x2202] &= ~0x20;
295 CPU.IRQExternal = TRUE;
296 }
297
298 break;
299
300 case 0x2202: // S-CPU interrupt clear
301 // S-CPU IRQ clear
302 if (byte & 0x80)
303 Memory.FillRAM[0x2300] &= ~0x80;
304
305 // S-CPU CHDMA IRQ clear
306 if (byte & 0x20)
307 Memory.FillRAM[0x2300] &= ~0x20;
308
309 if (!(Memory.FillRAM[0x2300] & 0xa0))
310 CPU.IRQExternal = FALSE;
311
312 break;
313
314 case 0x2203: // SA-1 reset vector (L)
315 case 0x2204: // SA-1 reset vector (H)
316 case 0x2205: // SA-1 NMI vector (L)
317 case 0x2206: // SA-1 NMI vector (H)
318 case 0x2207: // SA-1 IRQ vector (L)
319 case 0x2208: // SA-1 IRQ vector (H)
320 break;
321
322 case 0x2209: // S-CPU control
323 // 0x40: S-CPU IRQ overwrite
324 // 0x20: S-CPU NMI overwrite
325
326 // S-CPU IRQ control
327 if (byte & 0x80)
328 {
329 Memory.FillRAM[0x2300] |= 0x80;
330 if (Memory.FillRAM[0x2201] & 0x80)
331 {
332 Memory.FillRAM[0x2202] &= ~0x80;
333 CPU.IRQExternal = TRUE;
334 }
335 }
336
337 break;
338
339 case 0x220a: // SA-1 interrupt enable
340 // SA-1 IRQ enable
341 if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80))
342 Memory.FillRAM[0x220b] &= ~0x80;
343
344 // SA-1 timer IRQ enable
345 if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40))
346 Memory.FillRAM[0x220b] &= ~0x40;
347
348 // SA-1 DMA IRQ enable
349 if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20))
350 Memory.FillRAM[0x220b] &= ~0x20;
351
352 // SA-1 NMI enable
353 if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10))
354 Memory.FillRAM[0x220b] &= ~0x10;
355
356 break;
357
358 case 0x220b: // SA-1 interrupt clear
359 // SA-1 IRQ clear
360 if (byte & 0x80)
361 Memory.FillRAM[0x2301] &= ~0x80;
362
363 // SA-1 timer IRQ clear
364 if (byte & 0x40)
365 Memory.FillRAM[0x2301] &= ~0x40;
366
367 // SA-1 DMA IRQ clear
368 if (byte & 0x20)
369 Memory.FillRAM[0x2301] &= ~0x20;
370
371 // SA-1 NMI clear
372 if (byte & 0x10)
373 Memory.FillRAM[0x2301] &= ~0x10;
374
375 break;
376
377 case 0x220c: // S-CPU NMI vector (L)
378 case 0x220d: // S-CPU NMI vector (H)
379 case 0x220e: // S-CPU IRQ vector (L)
380 case 0x220f: // S-CPU IRQ vector (H)
381 break;
382
383 case 0x2210: // SA-1 timer control
384 // 0x80: mode (linear / HV)
385 // 0x02: V timer enable
386 // 0x01: H timer enable
387 #ifdef DEBUGGER
388 printf("SA-1 timer control write:%02x\n", byte);
389 #endif
390 break;
391
392 case 0x2211: // SA-1 timer reset
393 SA1.HCounter = 0;
394 SA1.VCounter = 0;
395 break;
396
397 case 0x2212: // SA-1 H-timer (L)
398 SA1.HTimerIRQPos = byte | (Memory.FillRAM[0x2213] << 8);
399 break;
400
401 case 0x2213: // SA-1 H-timer (H)
402 SA1.HTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2212];
403 break;
404
405 case 0x2214: // SA-1 V-timer (L)
406 SA1.VTimerIRQPos = byte | (Memory.FillRAM[0x2215] << 8);
407 break;
408
409 case 0x2215: // SA-1 V-timer (H)
410 SA1.VTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2214];
411 break;
412
413 case 0x2220: // MMC bank C
414 case 0x2221: // MMC bank D
415 case 0x2222: // MMC bank E
416 case 0x2223: // MMC bank F
417 S9xSetSA1MemMap(address - 0x2220, byte);
418 break;
419
420 case 0x2224: // S-CPU BW-RAM mapping
421 Memory.BWRAM = Memory.SRAM + (byte & 0x1f) * 0x2000;
422 break;
423
424 case 0x2225: // SA-1 BW-RAM mapping
425 if (byte != Memory.FillRAM[0x2225])
426 S9xSA1SetBWRAMMemMap(byte);
427
428 break;
429
430 case 0x2226: // S-CPU BW-RAM write enable
431 case 0x2227: // SA-1 BW-RAM write enable
432 case 0x2228: // BW-RAM write-protected area
433 case 0x2229: // S-CPU I-RAM write protection
434 case 0x222a: // SA-1 I-RAM write protection
435 break;
436
437 case 0x2230: // DMA control
438 // 0x80: enable
439 // 0x40: priority (DMA / SA-1)
440 // 0x20: character conversion / normal
441 // 0x10: BW-RAM -> I-RAM / SA-1 -> I-RAM
442 // 0x04: destinatin (BW-RAM / I-RAM)
443 // 0x03: source
444 break;
445
446 case 0x2231: // character conversion DMA parameters
447 // 0x80: CHDEND (complete / incomplete)
448 // 0x03: color mode
449 // (byte >> 2) & 7: virtual VRAM width
450 if (byte & 0x80)
451 SA1.in_char_dma = FALSE;
452
453 break;
454
455 case 0x2232: // DMA source start address (LL)
456 case 0x2233: // DMA source start address (LH)
457 case 0x2234: // DMA source start address (HL)
458 break;
459
460 case 0x2235: // DMA destination start address (LL)
461 break;
462
463 case 0x2236: // DMA destination start address (LH)
464 Memory.FillRAM[0x2236] = byte;
465
466 if ((Memory.FillRAM[0x2230] & 0xa4) == 0x80) // Normal DMA to I-RAM
467 S9xSA1DMA();
468 else
469 if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0) // CC1
470 {
471 SA1.in_char_dma = TRUE;
472
473 Memory.FillRAM[0x2300] |= 0x20;
474 if (Memory.FillRAM[0x2201] & 0x20)
475 {
476 Memory.FillRAM[0x2202] &= ~0x20;
477 CPU.IRQExternal = TRUE;
478 }
479 }
480
481 break;
482
483 case 0x2237: // DMA destination start address (HL)
484 Memory.FillRAM[0x2237] = byte;
485
486 if ((Memory.FillRAM[0x2230] & 0xa4) == 0x84) // Normal DMA to BW-RAM
487 S9xSA1DMA();
488
489 break;
490
491 case 0x2238: // DMA terminal counter (L)
492 case 0x2239: // DMA terminal counter (H)
493 break;
494
495 case 0x223f: // BW-RAM bitmap format
496 SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4;
497 break;
498
499 case 0x2240: // bitmap register 0
500 case 0x2241: // bitmap register 1
501 case 0x2242: // bitmap register 2
502 case 0x2243: // bitmap register 3
503 case 0x2244: // bitmap register 4
504 case 0x2245: // bitmap register 5
505 case 0x2246: // bitmap register 6
506 case 0x2247: // bitmap register 7
507 case 0x2248: // bitmap register 8
508 case 0x2249: // bitmap register 9
509 case 0x224a: // bitmap register A
510 case 0x224b: // bitmap register B
511 case 0x224c: // bitmap register C
512 case 0x224d: // bitmap register D
513 case 0x224e: // bitmap register E
514 break;
515
516 case 0x224f: // bitmap register F
517 Memory.FillRAM[0x224f] = byte;
518
519 if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // CC2
520 {
521 memmove(&Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, &Memory.FillRAM[0x2240], 16);
522 SA1.in_char_dma = (SA1.in_char_dma + 1) & 7;
523 if ((SA1.in_char_dma & 3) == 0)
524 S9xSA1CharConv2();
525 }
526
527 break;
528
529 case 0x2250: // arithmetic control
530 if (byte & 2)
531 SA1.sum = 0;
532 SA1.arithmetic_op = byte & 3;
533 break;
534
535 case 0x2251: // multiplicand / dividend (L)
536 SA1.op1 = (SA1.op1 & 0xff00) | byte;
537 break;
538
539 case 0x2252: // multiplicand / dividend (H)
540 SA1.op1 = (SA1.op1 & 0x00ff) | (byte << 8);
541 break;
542
543 case 0x2253: // multiplier / divisor (L)
544 SA1.op2 = (SA1.op2 & 0xff00) | byte;
545 break;
546
547 case 0x2254: // multiplier / divisor (H)
548 SA1.op2 = (SA1.op2 & 0x00ff) | (byte << 8);
549
550 switch (SA1.arithmetic_op)
551 {
552 case 0: // signed multiplication
553 SA1.sum = (int16) SA1.op1 * (int16) SA1.op2;
554 SA1.op2 = 0;
555 break;
556
557 case 1: // unsigned division
558 if (SA1.op2 == 0)
559 SA1.sum = 0;
560 else
561 {
562 int16 dividend = (int16) SA1.op1;
563 uint16 divisor = (uint16) SA1.op2;
564 uint16 remainder = (dividend >= 0) ? dividend % divisor : (dividend % divisor) + divisor;
565 uint16 quotient = (dividend - remainder) / divisor;
566 SA1.sum = (remainder << 16) | quotient;
567 }
568
569 SA1.op1 = 0;
570 SA1.op2 = 0;
571 break;
572
573 case 2: // cumulative sum
574 default:
575 SA1.sum += (int16) SA1.op1 * (int16) SA1.op2;
576 SA1.overflow = (SA1.sum >= (1ULL << 40));
577 SA1.sum &= (1ULL << 40) - 1;
578 SA1.op2 = 0;
579 break;
580 }
581
582 break;
583
584 case 0x2258: // variable bit-field length / auto inc / start
585 Memory.FillRAM[0x2258] = byte;
586 S9xSA1ReadVariableLengthData(TRUE, FALSE);
587 return;
588
589 case 0x2259: // variable bit-field start address (LL)
590 case 0x225a: // variable bit-field start address (LH)
591 case 0x225b: // variable bit-field start address (HL)
592 Memory.FillRAM[address] = byte;
593 // XXX: ???
594 SA1.variable_bit_pos = 0;
595 S9xSA1ReadVariableLengthData(FALSE, TRUE);
596 return;
597
598 default:
599 break;
600 }
601
602 if (address >= 0x2200 && address <= 0x22ff)
603 Memory.FillRAM[address] = byte;
604}
605
606static void S9xSA1CharConv2 (void)
607{
608 uint32 dest = Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8);
609 uint32 offset = (SA1.in_char_dma & 7) ? 0 : 1;
610 int depth = (Memory.FillRAM[0x2231] & 3) == 0 ? 8 : (Memory.FillRAM[0x2231] & 3) == 1 ? 4 : 2;
611 int bytes_per_char = 8 * depth;
612 uint8 *p = &Memory.FillRAM[0x3000] + (dest & 0x7ff) + offset * bytes_per_char;
613 uint8 *q = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + offset * 64;
614
615 switch (depth)
616 {
617 case 2:
618 for (int l = 0; l < 8; l++, q += 8)
619 {
620 for (int b = 0; b < 8; b++)
621 {
622 uint8 r = *(q + b);
623 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
624 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
625 }
626
627 p += 2;
628 }
629
630 break;
631
632 case 4:
633 for (int l = 0; l < 8; l++, q += 8)
634 {
635 for (int b = 0; b < 8; b++)
636 {
637 uint8 r = *(q + b);
638 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
639 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
640 *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
641 *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
642 }
643
644 p += 2;
645 }
646
647 break;
648
649 case 8:
650 for (int l = 0; l < 8; l++, q += 8)
651 {
652 for (int b = 0; b < 8; b++)
653 {
654 uint8 r = *(q + b);
655 *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
656 *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
657 *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
658 *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
659 *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
660 *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
661 *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
662 *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
663 }
664
665 p += 2;
666 }
667
668 break;
669 }
670}
671
672static void S9xSA1DMA (void)
673{
674 uint32 src = Memory.FillRAM[0x2232] | (Memory.FillRAM[0x2233] << 8) | (Memory.FillRAM[0x2234] << 16);
675 uint32 dst = Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8) | (Memory.FillRAM[0x2237] << 16);
676 uint32 len = Memory.FillRAM[0x2238] | (Memory.FillRAM[0x2239] << 8);
677 uint8 *s, *d;
678
679 switch (Memory.FillRAM[0x2230] & 3)
680 {
681 case 0: // ROM
682 s = SA1.Map[((src & 0xffffff) >> MEMMAP_SHIFT)];
683 if (s >= (uint8 *) CMemory::MAP_LAST)
684 s += (src & 0xffff);
685 else
686 s = Memory.ROM + (src & 0xffff);
687 break;
688
689 case 1: // BW-RAM
690 src &= Memory.SRAMMask;
691 len &= Memory.SRAMMask;
692 s = Memory.SRAM + src;
693 break;
694
695 default:
696 case 2:
697 src &= 0x3ff;
698 len &= 0x3ff;
699 s = &Memory.FillRAM[0x3000] + src;
700 break;
701 }
702
703 if (Memory.FillRAM[0x2230] & 4)
704 {
705 dst &= Memory.SRAMMask;
706 len &= Memory.SRAMMask;
707 d = Memory.SRAM + dst;
708 }
709 else
710 {
711 dst &= 0x3ff;
712 len &= 0x3ff;
713 d = &Memory.FillRAM[0x3000] + dst;
714 }
715
716 memmove(d, s, len);
717
718 // SA-1 DMA IRQ control
719 Memory.FillRAM[0x2301] |= 0x20;
720 if (Memory.FillRAM[0x220a] & 0x20)
721 Memory.FillRAM[0x220b] &= ~0x20;
722}
723
724static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift)
725{
726 uint32 addr = Memory.FillRAM[0x2259] | (Memory.FillRAM[0x225a] << 8) | (Memory.FillRAM[0x225b] << 16);
727 uint8 shift = Memory.FillRAM[0x2258] & 15;
728
729 if (no_shift)
730 shift = 0;
731 else
732 if (shift == 0)
733 shift = 16;
734
735 uint8 s = shift + SA1.variable_bit_pos;
736
737 if (s >= 16)
738 {
739 addr += (s >> 4) << 1;
740 s &= 15;
741 }
742
743 uint32 data = S9xSA1GetWord(addr) | (S9xSA1GetWord(addr + 2) << 16);
744
745 data >>= s;
746 Memory.FillRAM[0x230c] = (uint8) data;
747 Memory.FillRAM[0x230d] = (uint8) (data >> 8);
748
749 if (inc)
750 {
751 SA1.variable_bit_pos = (SA1.variable_bit_pos + shift) & 15;
752 Memory.FillRAM[0x2259] = (uint8) addr;
753 Memory.FillRAM[0x225a] = (uint8) (addr >> 8);
754 Memory.FillRAM[0x225b] = (uint8) (addr >> 16);
755 }
756}
757
758uint8 S9xSA1GetByte (uint32 address)
759{
760 uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT];
761
762 if (GetAddress >= (uint8 *)CMemory::MAP_LAST)
763 {
764 SA1.Cycles += SA1.MemSpeed;
765 return (*(GetAddress + (address & 0xffff)));
766 }
767
768 switch ((pint) GetAddress)
769 {
770 case CMemory::MAP_PPU:
771 SA1.Cycles += ONE_CYCLE;
772 return (S9xGetSA1(address & 0xffff));
773
774 case CMemory::MAP_LOROM_SRAM:
775 case CMemory::MAP_HIROM_SRAM:
776 case CMemory::MAP_SA1RAM:
777 SA1.Cycles += ONE_CYCLE * 2;
778 return (*(Memory.SRAM + (address & 0x3ffff)));
779
780 case CMemory::MAP_BWRAM:
781 SA1.Cycles += ONE_CYCLE * 2;
782 return (*(SA1.BWRAM + (address & 0x1fff)));
783
784 case CMemory::MAP_BWRAM_BITMAP:
785 SA1.Cycles += ONE_CYCLE * 2;
786
787 address -= 0x600000;
788 if (SA1.VirtualBitmapFormat == 2)
789 return ((Memory.SRAM[(address >> 2) & 0x3ffff] >> ((address & 3) << 1)) & 3);
790 else
791 return ((Memory.SRAM[(address >> 1) & 0x3ffff] >> ((address & 1) << 2)) & 15);
792
793 case CMemory::MAP_BWRAM_BITMAP2:
794 SA1.Cycles += ONE_CYCLE * 2;
795
796 address = (address & 0xffff) - 0x6000;
797 if (SA1.VirtualBitmapFormat == 2)
798 return ((SA1.BWRAM[(address >> 2) & 0x3ffff] >> ((address & 3) << 1)) & 3);
799 else
800 return ((SA1.BWRAM[(address >> 1) & 0x3ffff] >> ((address & 1) << 2)) & 15);
801
802 default:
803 SA1.Cycles += ONE_CYCLE;
804 return (SA1OpenBus);
805 }
806}
807
808uint16 S9xSA1GetWord (uint32 address, s9xwrap_t w)
809{
810 PC_t a;
811
812 SA1OpenBus = S9xSA1GetByte(address);
813
814 switch (w)
815 {
816 case WRAP_PAGE:
817 a.xPBPC = address;
818 a.B.xPCl++;
819 return (SA1OpenBus | (S9xSA1GetByte(a.xPBPC) << 8));
820
821 case WRAP_BANK:
822 a.xPBPC = address;
823 a.W.xPC++;
824 return (SA1OpenBus | (S9xSA1GetByte(a.xPBPC) << 8));
825
826 case WRAP_NONE:
827 default:
828 return (SA1OpenBus | (S9xSA1GetByte(address + 1) << 8));
829 }
830}
831
832void S9xSA1SetByte (uint8 byte, uint32 address)
833{
834 uint8 *SetAddress = SA1.WriteMap[(address & 0xffffff) >> MEMMAP_SHIFT];
835
836 if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
837 {
838 *(SetAddress + (address & 0xffff)) = byte;
839 return;
840 }
841
842 switch ((pint) SetAddress)
843 {
844 case CMemory::MAP_PPU:
845 S9xSetSA1(byte, address & 0xffff);
846 return;
847
848 case CMemory::MAP_LOROM_SRAM:
849 case CMemory::MAP_HIROM_SRAM:
850 case CMemory::MAP_SA1RAM:
851 *(Memory.SRAM + (address & 0x3ffff)) = byte;
852 return;
853
854 case CMemory::MAP_BWRAM:
855 *(SA1.BWRAM + (address & 0x1fff)) = byte;
856 return;
857
858 case CMemory::MAP_BWRAM_BITMAP:
859 address -= 0x600000;
860 if (SA1.VirtualBitmapFormat == 2)
861 {
862 uint8 *ptr = &Memory.SRAM[(address >> 2) & 0x3ffff];
863 *ptr &= ~(3 << ((address & 3) << 1));
864 *ptr |= (byte & 3) << ((address & 3) << 1);
865 }
866 else
867 {
868 uint8 *ptr = &Memory.SRAM[(address >> 1) & 0x3ffff];
869 *ptr &= ~(15 << ((address & 1) << 2));
870 *ptr |= (byte & 15) << ((address & 1) << 2);
871 }
872
873 return;
874
875 case CMemory::MAP_BWRAM_BITMAP2:
876 address = (address & 0xffff) - 0x6000;
877 if (SA1.VirtualBitmapFormat == 2)
878 {
879 uint8 *ptr = &SA1.BWRAM[(address >> 2) & 0x3ffff];
880 *ptr &= ~(3 << ((address & 3) << 1));
881 *ptr |= (byte & 3) << ((address & 3) << 1);
882 }
883 else
884 {
885 uint8 *ptr = &SA1.BWRAM[(address >> 1) & 0x3ffff];
886 *ptr &= ~(15 << ((address & 1) << 2));
887 *ptr |= (byte & 15) << ((address & 1) << 2);
888 }
889
890 return;
891
892 default:
893 return;
894 }
895}
896
897void S9xSA1SetWord (uint16 Word, uint32 address, enum s9xwrap_t w, enum s9xwriteorder_t o)
898{
899 PC_t a;
900
901 if (!o)
902 S9xSA1SetByte((uint8) Word, address);
903
904 switch (w)
905 {
906 case WRAP_PAGE:
907 a.xPBPC = address;
908 a.B.xPCl++;
909 S9xSA1SetByte(Word >> 8, a.xPBPC);
910 break;
911
912 case WRAP_BANK:
913 a.xPBPC = address;
914 a.W.xPC++;
915 S9xSA1SetByte(Word >> 8, a.xPBPC);
916 break;
917
918 case WRAP_NONE:
919 default:
920 S9xSA1SetByte(Word >> 8, address + 1);
921 break;
922 }
923
924 if (o)
925 S9xSA1SetByte((uint8) Word, address);
926}
927
928void S9xSA1SetPCBase (uint32 address)
929{
930 SA1Registers.PBPC = address & 0xffffff;
931 SA1.ShiftedPB = address & 0xff0000;
932
933 // FIXME
934 SA1.MemSpeed = ONE_CYCLE;
935 if ((address & 0xc00000) == 0x400000 || (address & 0x40e000) == 0x6000)
936 {
937 SA1.MemSpeed = TWO_CYCLES;
938 }
939
940 SA1.MemSpeedx2 = SA1.MemSpeed << 1;
941
942 uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT];
943
944 if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
945 {
946 SA1.PCBase = GetAddress;
947 return;
948 }
949
950 switch ((pint) GetAddress)
951 {
952 case CMemory::MAP_LOROM_SRAM:
953 if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
954 SA1.PCBase = NULL;
955 else
956 SA1.PCBase = (Memory.SRAM + ((((address & 0xff0000) >> 1) | (address & 0x7fff)) & Memory.SRAMMask)) - (address & 0xffff);
957 return;
958
959 case CMemory::MAP_HIROM_SRAM:
960 if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
961 SA1.PCBase = NULL;
962 else
963 SA1.PCBase = (Memory.SRAM + (((address & 0x7fff) - 0x6000 + ((address & 0xf0000) >> 3)) & Memory.SRAMMask)) - (address & 0xffff);
964 return;
965
966 case CMemory::MAP_BWRAM:
967 SA1.PCBase = SA1.BWRAM - 0x6000 - (address & 0x8000);
968 return;
969
970 case CMemory::MAP_SA1RAM:
971 SA1.PCBase = Memory.SRAM;
972 return;
973
974 default:
975 SA1.PCBase = NULL;
976 return;
977 }
978}
979