disabling inline set/gets + enable sa-1 c cpu
[drnoksnes] / sa1.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41
42 #include "snes9x.h"
43
44 #ifdef USE_SA1
45
46 #include "ppu.h"
47 #include "cpuexec.h"
48
49 #include "sa1.h"
50
51 static void S9xSA1CharConv2 ();
52 static void S9xSA1DMA ();
53 static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift);
54
55 void S9xSA1Init ()
56 {
57     SA1.NMIActive = FALSE;
58     SA1.IRQActive = FALSE;
59     SA1.WaitingForInterrupt = FALSE;
60     SA1.Waiting = FALSE;
61     SA1.Flags = 0;
62     SA1.Executing = FALSE;
63     memset (&Memory.FillRAM [0x2200], 0, 0x200);
64     Memory.FillRAM [0x2200] = 0x20;
65     Memory.FillRAM [0x2220] = 0x00;
66     Memory.FillRAM [0x2221] = 0x01;
67     Memory.FillRAM [0x2222] = 0x02;
68     Memory.FillRAM [0x2223] = 0x03;
69     Memory.FillRAM [0x2228] = 0xff;
70     SA1.op1 = 0;
71     SA1.op2 = 0;
72     SA1.arithmetic_op = 0;
73     SA1.sum = 0;
74     SA1.overflow = FALSE;
75 }
76
77 void S9xSA1Reset ()
78 {
79     SA1Registers.PB = 0;
80     SA1Registers.PC = Memory.FillRAM [0x2203] |
81                       (Memory.FillRAM [0x2204] << 8);
82     SA1Registers.D.W = 0;
83     SA1Registers.DB = 0;
84     SA1Registers.SH = 1;
85     SA1Registers.SL = 0xFF;
86     SA1Registers.XH = 0;
87     SA1Registers.YH = 0;
88     SA1Registers.P.W = 0;
89
90     SA1.ShiftedPB = 0;
91     SA1.ShiftedDB = 0;
92     SA1SetFlags (MemoryFlag | IndexFlag | IRQ | Emulation);
93     SA1ClearFlags (Decimal);
94
95     SA1.WaitingForInterrupt = FALSE;
96     SA1.PC = NULL;
97     SA1.PCBase = NULL;
98     S9xSA1SetPCBase (SA1Registers.PC);
99     //SA1.S9xOpcodes = S9xSA1OpcodesM1X1; // unused
100
101     S9xSA1UnpackStatus();
102     //S9xSA1FixCycles (); // unused
103     SA1.Executing = TRUE;
104     SA1.BWRAM = Memory.SRAM;
105     Memory.FillRAM [0x2225] = 0;
106 }
107
108 void S9xSA1SetBWRAMMemMap (uint8 val)
109 {
110     int c;
111
112     if (val & 0x80)
113     {
114         for (c = 0; c < 0x400; c += 16)
115         {
116             SA1.Map [c + 6] = SA1.Map [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
117             SA1.Map [c + 7] = SA1.Map [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
118             SA1.WriteMap [c + 6] = SA1.WriteMap [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
119             SA1.WriteMap [c + 7] = SA1.WriteMap [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2;
120         }
121         SA1.BWRAM = Memory.SRAM + (val & 0x7f) * 0x2000 / 4;
122     }
123     else
124     {
125         for (c = 0; c < 0x400; c += 16)
126         {
127             SA1.Map [c + 6] = SA1.Map [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM;
128             SA1.Map [c + 7] = SA1.Map [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM;
129             SA1.WriteMap [c + 6] = SA1.WriteMap [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM;
130             SA1.WriteMap [c + 7] = SA1.WriteMap [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM;
131         }
132         SA1.BWRAM = Memory.SRAM + (val & 7) * 0x2000;
133     }
134 }
135
136 void S9xFixSA1AfterSnapshotLoad ()
137 {
138     SA1.ShiftedPB = (uint32) SA1Registers.PB << 16;
139     SA1.ShiftedDB = (uint32) SA1Registers.DB << 16;
140
141     S9xSA1SetPCBase (SA1.ShiftedPB + SA1Registers.PC);
142     S9xSA1UnpackStatus ();
143     //S9xSA1FixCycles (); // unused
144     SA1.VirtualBitmapFormat = (Memory.FillRAM [0x223f] & 0x80) ? 2 : 4;
145     Memory.BWRAM = Memory.SRAM + (Memory.FillRAM [0x2224] & 7) * 0x2000;
146     S9xSA1SetBWRAMMemMap (Memory.FillRAM [0x2225]);
147
148     SA1.Waiting = (Memory.FillRAM [0x2200] & 0x60) != 0;
149     SA1.Executing = !SA1.Waiting;
150 }
151
152 uint8 S9xSA1GetByte (uint32 address)
153 {
154     uint8 *GetAddress = SA1.Map [(address >> MEMMAP_SHIFT) & MEMMAP_MASK];
155     if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
156         return (*(GetAddress + (address & 0xffff)));
157
158     switch ((int) GetAddress)
159     {
160     case CMemory::MAP_PPU:
161         return (S9xGetSA1 (address & 0xffff));
162     case CMemory::MAP_LOROM_SRAM:
163     case CMemory::MAP_SA1RAM:
164         return (*(Memory.SRAM + (address & 0xffff)));
165     case CMemory::MAP_BWRAM:
166         return (*(SA1.BWRAM + ((address & 0x7fff) - 0x6000)));
167     case CMemory::MAP_BWRAM_BITMAP:
168         address -= 0x600000;
169         if (SA1.VirtualBitmapFormat == 2)
170             return ((Memory.SRAM [(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3);
171         else
172             return ((Memory.SRAM [(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15);
173     case CMemory::MAP_BWRAM_BITMAP2:
174         address = (address & 0xffff) - 0x6000;
175         if (SA1.VirtualBitmapFormat == 2)
176             return ((SA1.BWRAM [(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3);
177         else
178             return ((SA1.BWRAM [(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15);
179
180     case CMemory::MAP_DEBUG:
181     default:
182 #ifdef DEBUGGER
183 //      printf ("R(B) %06x\n", address);
184 #endif
185
186         return (0);
187     }
188 }
189
190 uint16 S9xSA1GetWord (uint32 address)
191 {
192     return (S9xSA1GetByte (address) | (S9xSA1GetByte (address + 1) << 8));
193 }
194
195 void S9xSA1SetByte (uint8 byte, uint32 address)
196 {
197     uint8 *Setaddress = SA1.WriteMap [(address >> MEMMAP_SHIFT) & MEMMAP_MASK];
198
199     if (Setaddress >= (uint8 *) CMemory::MAP_LAST)
200     {
201         *(Setaddress + (address & 0xffff)) = byte;
202         return;
203     }
204
205     switch ((int) Setaddress)
206     {
207     case CMemory::MAP_PPU:
208         S9xSetSA1 (byte, address & 0xffff);
209         return;
210     case CMemory::MAP_SA1RAM:
211     case CMemory::MAP_LOROM_SRAM:
212         *(Memory.SRAM + (address & 0xffff)) = byte;
213         return;
214     case CMemory::MAP_BWRAM:
215         *(SA1.BWRAM + ((address & 0x7fff) - 0x6000)) = byte;
216         return;
217     case CMemory::MAP_BWRAM_BITMAP:
218         address -= 0x600000;
219         if (SA1.VirtualBitmapFormat == 2)
220         {
221             uint8 *ptr = &Memory.SRAM [(address >> 2) & 0xffff];
222             *ptr &= ~(3 << ((address & 3) << 1));
223             *ptr |= (byte & 3) << ((address & 3) << 1);
224         }
225         else
226         {
227             uint8 *ptr = &Memory.SRAM [(address >> 1) & 0xffff];
228             *ptr &= ~(15 << ((address & 1) << 2));
229             *ptr |= (byte & 15) << ((address & 1) << 2);
230         }
231         break;
232     case CMemory::MAP_BWRAM_BITMAP2:
233         address = (address & 0xffff) - 0x6000;
234         if (SA1.VirtualBitmapFormat == 2)
235         {
236             uint8 *ptr = &SA1.BWRAM [(address >> 2) & 0xffff];
237             *ptr &= ~(3 << ((address & 3) << 1));
238             *ptr |= (byte & 3) << ((address & 3) << 1);
239         }
240         else
241         {
242             uint8 *ptr = &SA1.BWRAM [(address >> 1) & 0xffff];
243             *ptr &= ~(15 << ((address & 1) << 2));
244             *ptr |= (byte & 15) << ((address & 1) << 2);
245         }
246     default:
247         return;
248     }
249 }
250
251 void S9xSA1SetWord (uint16 Word, uint32 address)
252 {
253     S9xSA1SetByte ((uint8) Word, address);
254     S9xSA1SetByte ((uint8) (Word >> 8), address + 1);
255 }
256
257 void S9xSA1SetPCBase (uint32 address)
258 {
259     uint8 *GetAddress = SA1.Map [(address >> MEMMAP_SHIFT) & MEMMAP_MASK];
260     if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
261     {
262         SA1.PCBase = GetAddress;
263         SA1.PC = GetAddress + (address & 0xffff);
264         return;
265     }
266
267     switch ((int) GetAddress)
268     {
269     case CMemory::MAP_PPU:
270         SA1.PCBase = Memory.FillRAM - 0x2000;
271         SA1.PC = SA1.PCBase + (address & 0xffff);
272         return;
273         
274     case CMemory::MAP_CPU:
275         SA1.PCBase = Memory.FillRAM - 0x4000;
276         SA1.PC = SA1.PCBase + (address & 0xffff);
277         return;
278         
279     case CMemory::MAP_DSP:
280         SA1.PCBase = Memory.FillRAM - 0x6000;
281         SA1.PC = SA1.PCBase + (address & 0xffff);
282         return;
283         
284     case CMemory::MAP_SA1RAM:
285     case CMemory::MAP_LOROM_SRAM:
286         SA1.PCBase = Memory.SRAM;
287         SA1.PC = SA1.PCBase + (address & 0xffff);
288         return;
289
290     case CMemory::MAP_BWRAM:
291         SA1.PCBase = SA1.BWRAM - 0x6000;
292         SA1.PC = SA1.PCBase + (address & 0xffff);
293         return;
294     case CMemory::MAP_HIROM_SRAM:
295         SA1.PCBase = Memory.SRAM - 0x6000;
296         SA1.PC = SA1.PCBase + (address & 0xffff);
297         return;
298
299     case CMemory::MAP_DEBUG:
300 #ifdef DEBUGGER
301         printf ("SBP %06x\n", address);
302 #endif
303         
304     default:
305     case CMemory::MAP_NONE:
306         SA1.PCBase = Memory.RAM;
307         SA1.PC = Memory.RAM + (address & 0xffff);
308         return;
309     }
310 }
311
312 void S9xSA1ExecuteDuringSleep ()
313 {
314 #if 0
315     if (SA1.Executing)
316     {
317         while (CPU.Cycles < CPU.NextEvent)
318         {
319             S9xSA1MainLoop ();
320             CPU.Cycles += TWO_CYCLES * 2;
321         }
322     }
323 #endif
324 }
325
326 void S9xSetSA1MemMap (uint32 which1, uint8 map)
327 {
328     int c;
329     int start = which1 * 0x100 + 0xc00;
330     int start2 = which1 * 0x200;
331
332     if (which1 >= 2)
333         start2 += 0x400;
334
335     for (c = 0; c < 0x100; c += 16)
336     {
337         uint8 *block = &Memory.ROM [(map & 7) * 0x100000 + (c << 12)];
338         int i;
339
340         for (i = c; i < c + 16; i++)
341             Memory.Map [start + i] = SA1.Map [start + i] = block;
342     }
343     
344     for (c = 0; c < 0x200; c += 16)
345     {
346         uint8 *block = &Memory.ROM [(map & 7) * 0x100000 + (c << 11) - 0x8000];
347         int i;
348
349         for (i = c + 8; i < c + 16; i++)
350             Memory.Map [start2 + i] = SA1.Map [start2 + i] = block;
351     }
352 }
353
354 uint8 S9xGetSA1 (uint32 address)
355 {
356 //      printf ("R: %04x\n", address);
357     switch (address)
358     {
359     case 0x2300:
360         return ((uint8) ((Memory.FillRAM [0x2209] & 0x5f) | 
361                  (CPU.IRQActive & (SA1_IRQ_SOURCE | SA1_DMA_IRQ_SOURCE))));
362     case 0x2301:
363         return ((Memory.FillRAM [0x2200] & 0xf) |
364                 (Memory.FillRAM [0x2301] & 0xf0));
365     case 0x2306:
366         return ((uint8)  SA1.sum);
367     case 0x2307:
368         return ((uint8) (SA1.sum >>  8));
369     case 0x2308:
370         return ((uint8) (SA1.sum >> 16));
371     case 0x2309:
372         return ((uint8) (SA1.sum >> 24));
373     case 0x230a:
374         return ((uint8) (SA1.sum >> 32));
375     case 0x230c:
376         return (Memory.FillRAM [0x230c]);
377     case 0x230d:
378     {
379         uint8 byte = Memory.FillRAM [0x230d];
380
381         if (Memory.FillRAM [0x2258] & 0x80)
382         {
383             S9xSA1ReadVariableLengthData (TRUE, FALSE);
384         }
385         return (byte);
386     }
387     default:    
388 #ifndef __GP32__    
389         printf ("R: %04x\n", address);
390 #endif  
391         break;
392     }
393     return (Memory.FillRAM [address]);
394 }
395
396 void S9xSetSA1 (uint8 byte, uint32 address)
397 {
398 //printf ("W: %02x -> %04x\n", byte, address);
399     switch (address)
400     {
401     case 0x2200:
402         SA1.Waiting = (byte & 0x60) != 0;
403 //      SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes;
404
405         if (!(byte & 0x20) && (Memory.FillRAM [0x2200] & 0x20))
406         {
407             S9xSA1Reset ();
408         }
409         if (byte & 0x80)
410         {
411             Memory.FillRAM [0x2301] |= 0x80;
412             if (Memory.FillRAM [0x220a] & 0x80)
413             {
414                 SA1.Flags |= IRQ_PENDING_FLAG;
415                 SA1.IRQActive |= SNES_IRQ_SOURCE;
416                 SA1.Executing = !SA1.Waiting;// && SA1.S9xOpcodes; // unused
417             }
418         }
419         if (byte & 0x10)
420         {
421             Memory.FillRAM [0x2301] |= 0x10;
422 #ifdef DEBUGGER
423                 printf ("###SA1 NMI\n");
424 #endif
425             if (Memory.FillRAM [0x220a] & 0x10)
426             {
427             }
428         }
429         break;
430
431     case 0x2201:
432         if (((byte ^ Memory.FillRAM [0x2201]) & 0x80) &&
433             (Memory.FillRAM [0x2300] & byte & 0x80))
434         {
435             S9xSetIRQ (SA1_IRQ_SOURCE);
436         }
437         if (((byte ^ Memory.FillRAM [0x2201]) & 0x20) &&
438             (Memory.FillRAM [0x2300] & byte & 0x20))
439         {
440             S9xSetIRQ (SA1_DMA_IRQ_SOURCE);
441         }
442         break;
443     case 0x2202:
444         if (byte & 0x80)
445         {
446             Memory.FillRAM [0x2300] &= ~0x80;
447             S9xClearIRQ (SA1_IRQ_SOURCE);
448         }
449         if (byte & 0x20)
450         {
451             Memory.FillRAM [0x2300] &= ~0x20;
452             S9xClearIRQ (SA1_DMA_IRQ_SOURCE);
453         }
454         break;
455     case 0x2203:
456 //      printf ("SA1 reset vector: %04x\n", byte | (Memory.FillRAM [0x2204] << 8));
457         break;
458     case 0x2204:
459 //      printf ("SA1 reset vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2203]);
460         break;
461
462     case 0x2205:
463 //      printf ("SA1 NMI vector: %04x\n", byte | (Memory.FillRAM [0x2206] << 8));
464         break;
465     case 0x2206:
466 //      printf ("SA1 NMI vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2205]);
467         break;
468
469     case 0x2207:
470 //      printf ("SA1 IRQ vector: %04x\n", byte | (Memory.FillRAM [0x2208] << 8));
471         break;
472     case 0x2208:
473 //      printf ("SA1 IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2207]);
474         break;
475
476     case 0x2209:
477         Memory.FillRAM [0x2209] = byte;
478         if (byte & 0x80)
479             Memory.FillRAM [0x2300] |= 0x80;
480
481         if (byte & Memory.FillRAM [0x2201] & 0x80)
482         {
483             S9xSetIRQ (SA1_IRQ_SOURCE);
484         }
485         break;
486     case 0x220a:
487         if (((byte ^ Memory.FillRAM [0x220a]) & 0x80) &&
488             (Memory.FillRAM [0x2301] & byte & 0x80))
489         {
490             SA1.Flags |= IRQ_PENDING_FLAG;
491             SA1.IRQActive |= SNES_IRQ_SOURCE;
492 //          SA1.Executing = !SA1.Waiting;
493         }
494         if (((byte ^ Memory.FillRAM [0x220a]) & 0x40) &&
495             (Memory.FillRAM [0x2301] & byte & 0x40))
496         {
497             SA1.Flags |= IRQ_PENDING_FLAG;
498             SA1.IRQActive |= TIMER_IRQ_SOURCE;
499 //          SA1.Executing = !SA1.Waiting;
500         }
501         if (((byte ^ Memory.FillRAM [0x220a]) & 0x20) &&
502             (Memory.FillRAM [0x2301] & byte & 0x20))
503         {
504             SA1.Flags |= IRQ_PENDING_FLAG;
505             SA1.IRQActive |= DMA_IRQ_SOURCE;
506 //          SA1.Executing = !SA1.Waiting;
507         }
508         if (((byte ^ Memory.FillRAM [0x220a]) & 0x10) &&
509             (Memory.FillRAM [0x2301] & byte & 0x10))
510         {
511 #ifdef DEBUGGER
512             printf ("###SA1 NMI\n");
513 #endif
514         }
515         break;
516     case 0x220b:
517         if (byte & 0x80)
518         {
519             SA1.IRQActive &= ~SNES_IRQ_SOURCE;
520             Memory.FillRAM [0x2301] &= ~0x80;
521         }
522         if (byte & 0x40)
523         {
524             SA1.IRQActive &= ~TIMER_IRQ_SOURCE;
525             Memory.FillRAM [0x2301] &= ~0x40;
526         }
527         if (byte & 0x20)
528         {
529             SA1.IRQActive &= ~DMA_IRQ_SOURCE;
530             Memory.FillRAM [0x2301] &= ~0x20;
531         }
532         if (byte & 0x10)
533         {
534             // Clear NMI
535             Memory.FillRAM [0x2301] &= ~0x10;
536         }
537         if (!SA1.IRQActive)
538             SA1.Flags &= ~IRQ_PENDING_FLAG;
539         break;
540     case 0x220c:
541 //      printf ("SNES NMI vector: %04x\n", byte | (Memory.FillRAM [0x220d] << 8));
542         break;
543     case 0x220d:
544 //      printf ("SNES NMI vector: %04x\n", (byte << 8) | Memory.FillRAM [0x220c]);
545         break;
546
547     case 0x220e:
548 //      printf ("SNES IRQ vector: %04x\n", byte | (Memory.FillRAM [0x220f] << 8));
549         break;
550     case 0x220f:
551 //      printf ("SNES IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM [0x220e]);
552         break;
553
554     case 0x2210:
555 #if 0
556         printf ("Timer %s\n", (byte & 0x80) ? "linear" : "HV");
557         printf ("Timer H-IRQ %s\n", (byte & 1) ? "enabled" : "disabled");
558         printf ("Timer V-IRQ %s\n", (byte & 2) ? "enabled" : "disabled");
559 #endif
560         break;
561     case 0x2211:
562         printf ("Timer reset\n");
563         break;
564     case 0x2212:
565 #ifndef __GP32__        
566         printf ("H-Timer %04x\n", byte | (Memory.FillRAM [0x2213] << 8));
567 #endif  
568         break;
569     case 0x2213:
570 #ifndef __GP32__            
571         printf ("H-Timer %04x\n", (byte << 8) | Memory.FillRAM [0x2212]);
572 #endif          
573         break;
574     case 0x2214:
575 #ifndef __GP32__            
576         printf ("V-Timer %04x\n", byte | (Memory.FillRAM [0x2215] << 8));
577 #endif          
578         break;
579     case 0x2215:
580 #ifndef __GP32__            
581         printf ("V-Timer %04x\n", (byte << 8) | Memory.FillRAM [0x2214]);
582 #endif          
583         break;
584     case 0x2220:
585     case 0x2221:
586     case 0x2222:
587     case 0x2223:
588         S9xSetSA1MemMap (address - 0x2220, byte);
589 //      printf ("MMC: %02x\n", byte);
590         break;
591     case 0x2224:
592 //      printf ("BWRAM image SNES %02x -> 0x6000\n", byte);
593         Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000;
594         break;
595     case 0x2225:
596 //      printf ("BWRAM image SA1 %02x -> 0x6000 (%02x)\n", byte, Memory.FillRAM [address]);
597         if (byte != Memory.FillRAM [address])
598             S9xSA1SetBWRAMMemMap (byte);
599         break;
600     case 0x2226:
601 //      printf ("BW-RAM SNES write %s\n", (byte & 0x80) ? "enabled" : "disabled");
602         break;
603     case 0x2227:
604 //      printf ("BW-RAM SA1 write %s\n", (byte & 0x80) ? "enabled" : "disabled");
605         break;
606
607     case 0x2228:
608 //      printf ("BW-RAM write protect area %02x\n", byte);
609         break;
610     case 0x2229:
611 //      printf ("I-RAM SNES write protect area %02x\n", byte);
612         break;
613     case 0x222a:
614 //      printf ("I-RAM SA1 write protect area %02x\n", byte);
615         break;
616     case 0x2230:
617 #if 0
618         printf ("SA1 DMA %s\n", (byte & 0x80) ? "enabled" : "disabled");
619         printf ("DMA priority %s\n", (byte & 0x40) ? "DMA" : "SA1");
620         printf ("DMA %s\n", (byte & 0x20) ? "char conv" : "normal");
621         printf ("DMA type %s\n", (byte & 0x10) ? "BW-RAM -> I-RAM" : "SA1 -> I-RAM");
622         printf ("DMA distination %s\n", (byte & 4) ? "BW-RAM" : "I-RAM");
623         printf ("DMA source %s\n", DMAsource [byte & 3]);
624 #endif
625         break;
626     case 0x2231:
627         if (byte & 0x80)
628             SA1.in_char_dma = FALSE;
629 #if 0
630         printf ("CHDEND %s\n", (byte & 0x80) ? "complete" : "incomplete");
631         printf ("DMA colour mode %d\n", byte & 3);
632         printf ("virtual VRAM width %d\n", (byte >> 2) & 7);
633 #endif
634         break;
635     case 0x2232:
636     case 0x2233:
637     case 0x2234:
638         Memory.FillRAM [address] = byte;
639 #if 0
640         printf ("DMA source start %06x\n", 
641                 Memory.FillRAM [0x2232] | (Memory.FillRAM [0x2233] << 8) |
642                 (Memory.FillRAM [0x2234] << 16));
643 #endif
644         break;
645     case 0x2235:
646         Memory.FillRAM [address] = byte;
647         break;
648     case 0x2236:
649         Memory.FillRAM [address] = byte;
650         if ((Memory.FillRAM [0x2230] & 0xa4) == 0x80)
651         {
652             // Normal DMA to I-RAM
653             S9xSA1DMA ();
654         }
655         else
656         if ((Memory.FillRAM [0x2230] & 0xb0) == 0xb0)
657         {
658             Memory.FillRAM [0x2300] |= 0x20;
659             if (Memory.FillRAM [0x2201] & 0x20)
660                 S9xSetIRQ (SA1_DMA_IRQ_SOURCE);
661             SA1.in_char_dma = TRUE;
662         }
663         break;
664     case 0x2237:
665         Memory.FillRAM [address] = byte;
666         if ((Memory.FillRAM [0x2230] & 0xa4) == 0x84)
667         {
668             // Normal DMA to BW-RAM
669             S9xSA1DMA ();
670         }
671 #if 0
672         printf ("DMA dest address %06x\n", 
673                 Memory.FillRAM [0x2235] | (Memory.FillRAM [0x2236] << 8) |
674                 (Memory.FillRAM [0x2237] << 16));
675 #endif
676         break;
677     case 0x2238:
678     case 0x2239:
679         Memory.FillRAM [address] = byte;
680 #if 0
681         printf ("DMA length %04x\n", 
682                 Memory.FillRAM [0x2238] | (Memory.FillRAM [0x2239] << 8));
683 #endif
684         break;
685     case 0x223f:
686         SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4;
687         //printf ("virtual VRAM depth %d\n", (byte & 0x80) ? 2 : 4);
688         break;
689
690     case 0x2240:    case 0x2241:    case 0x2242:    case 0x2243:
691     case 0x2244:    case 0x2245:    case 0x2246:    case 0x2247:
692     case 0x2248:    case 0x2249:    case 0x224a:    case 0x224b:
693     case 0x224c:    case 0x224d:    case 0x224e:
694 #if 0
695         if (!(SA1.Flags & TRACE_FLAG))
696         {
697             TraceSA1 ();
698             Trace ();
699         }
700 #endif
701         Memory.FillRAM [address] = byte;
702         break;
703
704     case 0x224f:
705         Memory.FillRAM [address] = byte;
706         if ((Memory.FillRAM [0x2230] & 0xb0) == 0xa0)
707         {
708             // Char conversion 2 DMA enabled
709             memmove (&Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16,
710                      &Memory.FillRAM [0x2240], 16);
711             SA1.in_char_dma = (SA1.in_char_dma + 1) & 7;
712             if ((SA1.in_char_dma & 3) == 0)
713             {
714                 S9xSA1CharConv2 ();
715             }
716         }
717         break;
718     case 0x2250:
719         if (byte & 2)
720             SA1.sum = 0;
721         SA1.arithmetic_op = byte & 3;
722         break;
723     
724     case 0x2251:
725         SA1.op1 = (SA1.op1 & 0xff00) | byte;
726         break;
727     case 0x2252:
728         SA1.op1 = (SA1.op1 & 0xff) | (byte << 8);
729         break;
730     case 0x2253:
731         SA1.op2 = (SA1.op2 & 0xff00) | byte;
732         break;
733     case 0x2254:
734         SA1.op2 = (SA1.op2 & 0xff) | (byte << 8);
735         switch (SA1.arithmetic_op)
736         {
737         case 0: // multiply
738             SA1.sum = SA1.op1 * SA1.op2;
739             break;
740         case 1: // divide
741             if (SA1.op2 == 0)
742                 SA1.sum = SA1.op1 << 16;
743             else
744             {
745                 SA1.sum = (SA1.op1 / (int) ((uint16) SA1.op2)) |
746                           ((SA1.op1 % (int) ((uint16) SA1.op2)) << 16);
747             }
748             break;
749         case 2:
750         default: // cumulative sum
751             SA1.sum += SA1.op1 * SA1.op2;
752             if (SA1.sum & ((int64) 0xffffff << 32))
753                 SA1.overflow = TRUE;
754             break;
755         }
756         break;
757     case 0x2258:    // Variable bit-field length/auto inc/start.
758         Memory.FillRAM [0x2258] = byte;
759         S9xSA1ReadVariableLengthData (TRUE, FALSE);
760         return;
761     case 0x2259:
762     case 0x225a:
763     case 0x225b:    // Variable bit-field start address
764         Memory.FillRAM [address] = byte;
765         // XXX: ???
766         SA1.variable_bit_pos = 0;
767         S9xSA1ReadVariableLengthData (FALSE, TRUE);
768         return;
769     default:
770 //      printf ("W: %02x->%04x\n", byte, address);
771         break;
772     }
773     if (address >= 0x2200 && address <= 0x22ff)
774         Memory.FillRAM [address] = byte;
775 }
776
777 static void S9xSA1CharConv2 ()
778 {
779     uint32 dest = Memory.FillRAM [0x2235] | (Memory.FillRAM [0x2236] << 8);
780     uint32 offset = (SA1.in_char_dma & 7) ? 0 : 1;
781     int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 :
782                 (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2;
783     int bytes_per_char = 8 * depth;
784     uint8 *p = &Memory.FillRAM [0x3000] + dest + offset * bytes_per_char;
785     uint8 *q = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000] + offset * 64;
786
787     switch (depth)
788     {
789     case 2:
790         break;
791     case 4:
792         break;
793     case 8:
794         for (int l = 0; l < 8; l++, q += 8)
795         {
796             for (int b = 0; b < 8; b++)
797             {
798                 uint8 r = *(q + b);
799                 *(p +  0) = (*(p +  0) << 1) | ((r >> 0) & 1);
800                 *(p +  1) = (*(p +  1) << 1) | ((r >> 1) & 1);
801                 *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
802                 *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
803                 *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
804                 *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
805                 *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
806                 *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
807             }
808             p += 2;
809         }
810         break;
811     }
812 }
813
814 static void S9xSA1DMA ()
815 {
816     uint32 src =  Memory.FillRAM [0x2232] |
817                  (Memory.FillRAM [0x2233] << 8) |
818                  (Memory.FillRAM [0x2234] << 16);
819     uint32 dst =  Memory.FillRAM [0x2235] |
820                  (Memory.FillRAM [0x2236] << 8) |
821                  (Memory.FillRAM [0x2237] << 16);
822     uint32 len =  Memory.FillRAM [0x2238] |
823                  (Memory.FillRAM [0x2239] << 8);
824
825     uint8 *s;
826     uint8 *d;
827
828     switch (Memory.FillRAM [0x2230] & 3)
829     {
830     case 0: // ROM
831         s = SA1.Map [(src >> MEMMAP_SHIFT) & MEMMAP_MASK];
832         if (s >= (uint8 *) CMemory::MAP_LAST)
833             s += (src & 0xffff);
834         else
835             s = Memory.ROM + (src & 0xffff);
836         break;
837     case 1: // BW-RAM
838         src &= CPU.Memory_SRAMMask;
839         len &= CPU.Memory_SRAMMask;
840         s = Memory.SRAM + src;
841         break;
842     default:
843     case 2:
844         src &= 0x3ff;
845         len &= 0x3ff;
846         s = &Memory.FillRAM [0x3000] + src;
847         break;
848     }
849
850     if (Memory.FillRAM [0x2230] & 4)
851     {
852         dst &= CPU.Memory_SRAMMask;
853         len &= CPU.Memory_SRAMMask;
854         d = Memory.SRAM + dst;
855     }
856     else
857     {
858         dst &= 0x3ff;
859         len &= 0x3ff;
860         d = &Memory.FillRAM [0x3000] + dst;
861     }
862     memmove (d, s, len);
863     Memory.FillRAM [0x2301] |= 0x20;
864     
865     if (Memory.FillRAM [0x220a] & 0x20)
866     {
867         SA1.Flags |= IRQ_PENDING_FLAG;
868         SA1.IRQActive |= DMA_IRQ_SOURCE;
869 //      SA1.Executing = !SA1.Waiting;
870     }
871 }
872
873 void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift)
874 {
875     uint32 addr =  Memory.FillRAM [0x2259] |
876                   (Memory.FillRAM [0x225a] << 8) |
877                   (Memory.FillRAM [0x225b] << 16);
878     uint8 shift = Memory.FillRAM [0x2258] & 15;
879
880     if (no_shift)
881         shift = 0;
882     else
883     if (shift == 0)
884         shift = 16;
885
886     uint8 s = shift + SA1.variable_bit_pos;
887
888     if (s >= 16)
889     {
890         addr += (s >> 4) << 1;
891         s &= 15;
892     }
893     uint32 data = S9xSA1GetWord (addr) |
894                   (S9xSA1GetWord (addr + 2) << 16);
895
896     data >>= s;
897     Memory.FillRAM [0x230c] = (uint8) data;
898     Memory.FillRAM [0x230d] = (uint8) (data >> 8);
899     if (inc)
900     {
901         SA1.variable_bit_pos = (SA1.variable_bit_pos + shift) & 15;
902         Memory.FillRAM [0x2259] = (uint8) addr;
903         Memory.FillRAM [0x225a] = (uint8) (addr >> 8);
904         Memory.FillRAM [0x225b] = (uint8) (addr >> 16);
905     }
906 }
907
908 #endif
909