png screenshot support
[drnoksnes] / fxemu.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 #include "fxemu.h"
42 #include "fxinst.h"
43 #include <stdlib.h>
44 #include <string.h>
45 #include <stdio.h>
46
47 #include "port.h"
48
49 /* The FxChip Emulator's internal variables */
50 struct FxRegs_s GSU = {{0}, 0};
51
52 uint32 (**fx_ppfFunctionTable)(uint32) = 0;
53 void (**fx_ppfPlotTable)() = 0;
54 void (**fx_ppfOpcodeTable)() = 0;
55
56 #if 0
57 void fx_setCache()
58 {
59     uint32 c;
60     GSU.bCacheActive = TRUE;
61     GSU.pvRegisters[0x3e] &= 0xf0;
62     c = (uint32)GSU.pvRegisters[0x3e];
63     c |= ((uint32)GSU.pvRegisters[0x3f])<<8;
64     if(c == GSU.vCacheBaseReg)
65         return;
66     GSU.vCacheBaseReg = c;
67     GSU.vCacheFlags = 0;
68     if(c < (0x10000-512))
69     {
70         uint8 const* t = &ROM(c);
71         memcpy(GSU.pvCache,t,512);
72     }
73     else
74     {
75         uint8 const* t1;
76         uint8 const* t2;
77         uint32 i = 0x10000 - c;
78         t1 = &ROM(c);
79         t2 = &ROM(0);
80         memcpy(GSU.pvCache,t1,i);
81         memcpy(&GSU.pvCache[i],t2,512-i);
82     }
83 }
84 #endif
85
86 void FxCacheWriteAccess(uint16 vAddress)
87 {
88 #if 0
89     if(!GSU.bCacheActive)
90     {
91         uint8 v = GSU.pvCache[GSU.pvCache[vAddress&0x1ff];
92         fx_setCache();
93         GSU.pvCache[GSU.pvCache[vAddress&0x1ff] = v;
94     }
95 #endif
96     if((vAddress & 0x00f) == 0x00f)
97         GSU.vCacheFlags |= 1 << ((vAddress&0x1f0) >> 4);
98 }
99
100 void FxFlushCache()
101 {
102     GSU.vCacheFlags = 0;
103     GSU.vCacheBaseReg = 0;
104     GSU.bCacheActive = FALSE;
105 //    GSU.vPipe = 0x1;
106 }
107
108 static void fx_backupCache()
109 {
110 #if 0
111     uint32 i;
112     uint32 v = GSU.vCacheFlags;
113     uint32 c = USEX16(GSU.vCacheBaseReg);
114     if(v)
115         for(i=0; i<32; i++)
116         {
117             if(v&1)
118             {
119                 if(c < (0x10000-16))
120                 {
121                     uint8 * t = &GSU.pvPrgBank[c];
122                     memcpy(&GSU.avCacheBackup[i<<4],t,16);
123                     memcpy(t,&GSU.pvCache[i<<4],16);
124                 }
125                 else
126                 {
127                     uint8 * t1;
128                     uint8 * t2;
129                     uint32 a = 0x10000 - c;
130                     t1 = &GSU.pvPrgBank[c];
131                     t2 = &GSU.pvPrgBank[0];
132                     memcpy(&GSU.avCacheBackup[i<<4],t1,a);
133                     memcpy(t1,&GSU.pvCache[i<<4],a);
134                     memcpy(&GSU.avCacheBackup[(i<<4)+a],t2,16-a);
135                     memcpy(t2,&GSU.pvCache[(i<<4)+a],16-a);
136                 }               
137             }
138             c = USEX16(c+16);
139             v >>= 1;
140         }
141 #endif
142 }
143
144 static void fx_restoreCache()
145 {
146 #if 0
147     uint32 i;
148     uint32 v = GSU.vCacheFlags;
149     uint32 c = USEX16(GSU.vCacheBaseReg);
150     if(v)
151         for(i=0; i<32; i++)
152         {
153             if(v&1)
154             {
155                 if(c < (0x10000-16))
156                 {
157                     uint8 * t = &GSU.pvPrgBank[c];
158                     memcpy(t,&GSU.avCacheBackup[i<<4],16);
159                     memcpy(&GSU.pvCache[i<<4],t,16);
160                 }
161                 else
162                 {
163                     uint8 * t1;
164                     uint8 * t2;
165                     uint32 a = 0x10000 - c;
166                     t1 = &GSU.pvPrgBank[c];
167                     t2 = &GSU.pvPrgBank[0];
168                     memcpy(t1,&GSU.avCacheBackup[i<<4],a);
169                     memcpy(&GSU.pvCache[i<<4],t1,a);
170                     memcpy(t2,&GSU.avCacheBackup[(i<<4)+a],16-a);
171                     memcpy(&GSU.pvCache[(i<<4)+a],t2,16-a);
172                 }               
173             }
174             c = USEX16(c+16);
175             v >>= 1;
176         }
177 #endif
178 }
179
180 void fx_flushCache()
181 {
182     fx_restoreCache();
183     GSU.vCacheFlags = 0;
184     GSU.bCacheActive = FALSE;
185 }
186
187 static void fx_readRegisterSpace()
188 {
189     int i;
190     uint8 *p;
191     static uint32 avHeight[] = { 128, 160, 192, 256 };
192     static uint32 avMult[] = { 16, 32, 32, 64 };
193
194 #ifndef SUPER_FX
195         abort(); // Tried to run SuperFX game in non SuperFX build.
196 #endif
197
198     GSU.vErrorCode = 0;
199
200     /* Update R0-R15 */
201     p = GSU.pvRegisters;
202     for(i=0; i<16; i++)
203     {
204         GSU.avReg[i] = *p++;
205         GSU.avReg[i] += ((uint32)(*p++)) << 8;
206     }
207
208     /* Update other registers */
209     p = GSU.pvRegisters;
210     GSU.vStatusReg = (uint32)p[GSU_SFR];
211     GSU.vStatusReg |= ((uint32)p[GSU_SFR+1]) << 8;
212     GSU.vPrgBankReg = (uint32)p[GSU_PBR];
213     GSU.vRomBankReg = (uint32)p[GSU_ROMBR];
214     GSU.vRamBankReg = ((uint32)p[GSU_RAMBR]) & (FX_RAM_BANKS-1);
215     GSU.vCacheBaseReg = (uint32)p[GSU_CBR];
216     GSU.vCacheBaseReg |= ((uint32)p[GSU_CBR+1]) << 8;
217
218     /* Update status register variables */
219     GSU.vZero = !(GSU.vStatusReg & FLG_Z);
220     GSU.vSign = (GSU.vStatusReg & FLG_S) << 12;
221     GSU.vOverflow = (GSU.vStatusReg & FLG_OV) << 16;
222     GSU.vCarry = (GSU.vStatusReg & FLG_CY) >> 2;
223     
224     /* Set bank pointers */
225     GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3];
226     GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg];
227     GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg];
228
229     /* Set screen pointers */
230     GSU.pvScreenBase = &GSU.pvRam[ USEX8(p[GSU_SCBR]) << 10 ];
231     i = (int)(!!(p[GSU_SCMR] & 0x04));
232     i |= ((int)(!!(p[GSU_SCMR] & 0x20))) << 1;
233     GSU.vScreenHeight = GSU.vScreenRealHeight = avHeight[i];
234     GSU.vMode = p[GSU_SCMR] & 0x03;
235 #if 0
236     if(GSU.vMode == 2)
237         error illegal color depth GSU.vMode;
238 #endif
239     if(i == 3)
240         GSU.vScreenSize = (256/8) * (256/8) * 32;
241     else
242         GSU.vScreenSize = (GSU.vScreenHeight/8) * (256/8) * avMult[GSU.vMode];
243     if (GSU.vPlotOptionReg & 0x10)
244     {
245         /* OBJ Mode (for drawing into sprites) */
246         GSU.vScreenHeight = 256;
247     }
248 #if 0
249     if(GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536))
250         error illegal address for screen base register
251 #else
252     if(GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536))
253         GSU.pvScreenBase =  GSU.pvRam + (GSU.nRamBanks * 65536) - GSU.vScreenSize;
254 #endif
255     GSU.pfPlot = fx_apfPlotTable[GSU.vMode];
256     GSU.pfRpix = fx_apfPlotTable[GSU.vMode + 5];
257
258     fx_ppfOpcodeTable[0x04c] = GSU.pfPlot;
259     fx_ppfOpcodeTable[0x14c] = GSU.pfRpix;
260     fx_ppfOpcodeTable[0x24c] = GSU.pfPlot;
261     fx_ppfOpcodeTable[0x34c] = GSU.pfRpix;
262
263     fx_computeScreenPointers ();
264
265     fx_backupCache();
266 }
267
268 void fx_computeScreenPointers ()
269 {
270     if (GSU.vMode != GSU.vPrevMode || 
271         GSU.vPrevScreenHeight != GSU.vScreenHeight)
272     {
273         int i;
274
275         /* Make a list of pointers to the start of each screen column */
276         switch (GSU.vScreenHeight)
277         {
278             case 128:
279                 switch (GSU.vMode)
280                 {
281                     case 0:
282                         for (i = 0; i < 32; i++)
283                         {
284                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
285                             GSU.x[i] = i << 8;
286                         }
287                         break;
288                     case 1:
289                         for (i = 0; i < 32; i++)
290                         {
291                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
292                             GSU.x[i] = i << 9;
293                         }
294                         break;
295                     case 2:
296                     case 3:
297                         for (i = 0; i < 32; i++)
298                         {
299                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
300                             GSU.x[i] = i << 10;
301                         }
302                         break;
303                 }
304                 break;
305             case 160:
306                 switch (GSU.vMode)
307                 {
308                     case 0:
309                         for (i = 0; i < 32; i++)
310                         {
311                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
312                             GSU.x[i] = (i << 8) + (i << 6);
313                         }
314                         break;
315                     case 1:
316                         for (i = 0; i < 32; i++)
317                         {
318                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
319                             GSU.x[i] = (i << 9) + (i << 7);
320                         }
321                         break;
322                     case 2:
323                     case 3:
324                         for (i = 0; i < 32; i++)
325                         {
326                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
327                             GSU.x[i] = (i << 10) + (i << 8);
328                         }
329                         break;
330                 }
331                 break;
332             case 192:
333                 switch (GSU.vMode)
334                 {
335                     case 0:
336                         for (i = 0; i < 32; i++)
337                         {
338                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4);
339                             GSU.x[i] = (i << 8) + (i << 7);
340                         }
341                         break;
342                     case 1:
343                         for (i = 0; i < 32; i++)
344                         {
345                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5);
346                             GSU.x[i] = (i << 9) + (i << 8);
347                         }
348                         break;
349                     case 2:
350                     case 3:
351                         for (i = 0; i < 32; i++)
352                         {
353                             GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6);
354                             GSU.x[i] = (i << 10) + (i << 9);
355                         }
356                         break;
357                 }
358                 break;
359             case 256:
360                 switch (GSU.vMode)
361                 {
362                     case 0:
363                         for (i = 0; i < 32; i++)
364                         {
365                             GSU.apvScreen[i] = GSU.pvScreenBase + 
366                                 ((i & 0x10) << 9) + ((i & 0xf) << 8);
367                             GSU.x[i] = ((i & 0x10) << 8) + ((i & 0xf) << 4);
368                         }
369                         break;
370                     case 1:
371                         for (i = 0; i < 32; i++)
372                         {
373                             GSU.apvScreen[i] = GSU.pvScreenBase + 
374                                 ((i & 0x10) << 10) + ((i & 0xf) << 9);
375                             GSU.x[i] = ((i & 0x10) << 9) + ((i & 0xf) << 5);
376                         }
377                         break;
378                     case 2:
379                     case 3:
380                         for (i = 0; i < 32; i++)
381                         {
382                             GSU.apvScreen[i] = GSU.pvScreenBase + 
383                                 ((i & 0x10) << 11) + ((i & 0xf) << 10);
384                             GSU.x[i] = ((i & 0x10) << 10) + ((i & 0xf) << 6);
385                         }
386                         break;
387                 }
388                 break;
389         }
390         GSU.vPrevMode = GSU.vMode;
391         GSU.vPrevScreenHeight = GSU.vScreenHeight;
392     }
393 }
394
395 static void fx_writeRegisterSpace()
396 {
397     int i;
398     uint8 *p;
399     
400     p = GSU.pvRegisters;
401     for(i=0; i<16; i++)
402     {
403         *p++ = (uint8)GSU.avReg[i];
404         *p++ = (uint8)(GSU.avReg[i] >> 8);
405     }
406
407     /* Update status register */
408     if( USEX16(GSU.vZero) == 0 ) SF(Z);
409     else CF(Z);
410     if( GSU.vSign & 0x8000 ) SF(S);
411     else CF(S);
412     if(GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000) SF(OV);
413     else CF(OV);
414     if(GSU.vCarry) SF(CY);
415     else CF(CY);
416     
417     p = GSU.pvRegisters;
418     p[GSU_SFR] = (uint8)GSU.vStatusReg;
419     p[GSU_SFR+1] = (uint8)(GSU.vStatusReg>>8);
420     p[GSU_PBR] = (uint8)GSU.vPrgBankReg;
421     p[GSU_ROMBR] = (uint8)GSU.vRomBankReg;
422     p[GSU_RAMBR] = (uint8)GSU.vRamBankReg;
423     p[GSU_CBR] = (uint8)GSU.vCacheBaseReg;
424     p[GSU_CBR+1] = (uint8)(GSU.vCacheBaseReg>>8);
425     
426     fx_restoreCache();
427 }
428
429 /* Reset the FxChip */
430 void FxReset(struct FxInit_s *psFxInfo)
431 {
432     int i;
433     static uint32 (**appfFunction[])(uint32) = {
434         &fx_apfFunctionTable[0],
435 #if 0
436         &fx_a_apfFunctionTable[0],
437         &fx_r_apfFunctionTable[0],
438         &fx_ar_apfFunctionTable[0],
439 #endif  
440     };
441     static void (**appfPlot[])() = {
442         &fx_apfPlotTable[0],
443 #if 0
444         &fx_a_apfPlotTable[0],
445         &fx_r_apfPlotTable[0],
446         &fx_ar_apfPlotTable[0],
447 #endif  
448     };
449     static void (**appfOpcode[])() = {
450         &fx_apfOpcodeTable[0],
451 #if 0   
452         &fx_a_apfOpcodeTable[0],
453         &fx_r_apfOpcodeTable[0],
454         &fx_ar_apfOpcodeTable[0],
455 #endif  
456     };
457
458     /* Get function pointers for the current emulation mode */
459     fx_ppfFunctionTable = appfFunction[psFxInfo->vFlags & 0x3];
460     fx_ppfPlotTable = appfPlot[psFxInfo->vFlags & 0x3];
461     fx_ppfOpcodeTable = appfOpcode[psFxInfo->vFlags & 0x3];
462     
463     /* Clear all internal variables */
464     memset((uint8*)&GSU,0,sizeof(struct FxRegs_s));
465
466     /* Set default registers */
467     GSU.pvSreg = GSU.pvDreg = &R0;
468
469     /* Set RAM and ROM pointers */
470     GSU.pvRegisters = psFxInfo->pvRegisters;
471     GSU.nRamBanks = psFxInfo->nRamBanks;
472     GSU.pvRam = psFxInfo->pvRam;
473     GSU.nRomBanks = psFxInfo->nRomBanks;
474     GSU.pvRom = psFxInfo->pvRom;
475     GSU.vPrevScreenHeight = ~0;
476     GSU.vPrevMode = ~0;
477
478     /* The GSU can't access more than 2mb (16mbits) */
479     if(GSU.nRomBanks > 0x20)
480         GSU.nRomBanks = 0x20;
481     
482     /* Clear FxChip register space */
483     memset(GSU.pvRegisters,0,0x300);
484
485     /* Set FxChip version Number */
486     GSU.pvRegisters[0x3b] = 0;
487
488     /* Make ROM bank table */
489     for(i=0; i<256; i++)
490     {
491         uint32 b = i & 0x7f;
492         if (b >= 0x40)
493         {
494             if (GSU.nRomBanks > 1)
495                 b %= GSU.nRomBanks;
496             else
497                 b &= 1;
498
499             GSU.apvRomBank[i] = &GSU.pvRom[ b << 16 ];
500         }
501         else
502         {
503             b %= GSU.nRomBanks * 2;
504             GSU.apvRomBank[i] = &GSU.pvRom[ (b << 16) + 0x200000];
505         }
506     }
507
508     /* Make RAM bank table */
509     for(i=0; i<4; i++)
510     {
511         GSU.apvRamBank[i] = &GSU.pvRam[(i % GSU.nRamBanks) << 16];
512         GSU.apvRomBank[0x70 + i] = GSU.apvRamBank[i];
513     }
514     
515     /* Start with a nop in the pipe */
516     GSU.vPipe = 0x01;
517
518     /* Set pointer to GSU cache */
519     GSU.pvCache = &GSU.pvRegisters[0x100];
520
521     fx_readRegisterSpace();
522 }
523
524 static uint8 fx_checkStartAddress()
525 {
526     /* Check if we start inside the cache */
527     if(GSU.bCacheActive && R15 >= GSU.vCacheBaseReg && R15 < (GSU.vCacheBaseReg+512))
528         return TRUE;
529    
530     /*  Check if we're in an unused area */
531     if(GSU.vPrgBankReg < 0x40 && R15 < 0x8000)
532         return FALSE;
533     if(GSU.vPrgBankReg >= 0x60 && GSU.vPrgBankReg <= 0x6f)
534         return FALSE;
535     if(GSU.vPrgBankReg >= 0x74)
536         return FALSE;
537
538     /* Check if we're in RAM and the RAN flag is not set */
539     if(GSU.vPrgBankReg >= 0x70 && GSU.vPrgBankReg <= 0x73 && !(SCMR&(1<<3)) )
540         return FALSE;
541
542     /* If not, we're in ROM, so check if the RON flag is set */
543     if(!(SCMR&(1<<4)))
544         return FALSE;
545     
546     return TRUE;
547 }
548
549 /* Execute until the next stop instruction */
550 int FxEmulate(uint32 nInstructions)
551 {
552     uint32 vCount;
553
554     /* Read registers and initialize GSU session */
555     fx_readRegisterSpace();
556
557     /* Check if the start address is valid */
558     if(!fx_checkStartAddress())
559     {
560         CF(G);
561         fx_writeRegisterSpace();
562 #if 0
563         GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15;
564         return FX_ERROR_ILLEGAL_ADDRESS;
565 #else
566         return 0;
567 #endif
568     }
569
570     /* Execute GSU session */
571     CF(IRQ);
572
573     if(GSU.bBreakPoint)
574         vCount = fx_ppfFunctionTable[FX_FUNCTION_RUN_TO_BREAKPOINT](nInstructions);
575     else
576         vCount = fx_ppfFunctionTable[FX_FUNCTION_RUN](nInstructions);
577
578     /* Store GSU registers */
579     fx_writeRegisterSpace();
580
581     /* Check for error code */
582     if(GSU.vErrorCode)
583         return GSU.vErrorCode;
584     else
585         return vCount;
586 }
587
588 /* Breakpoints */
589 void FxBreakPointSet(uint32 vAddress)
590 {
591     GSU.bBreakPoint = TRUE;
592     GSU.vBreakPoint = USEX16(vAddress);
593 }
594 void FxBreakPointClear()
595 {
596     GSU.bBreakPoint = FALSE;
597 }
598
599 /* Step by step execution */
600 int FxStepOver(uint32 nInstructions)
601 {
602     uint32 vCount;
603     fx_readRegisterSpace();
604
605     /* Check if the start address is valid */
606     if(!fx_checkStartAddress())
607     {
608         CF(G);
609 #if 0
610         GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15;
611         return FX_ERROR_ILLEGAL_ADDRESS;
612 #else
613         return 0;
614 #endif
615     }
616     
617     if( PIPE >= 0xf0 )
618         GSU.vStepPoint = USEX16(R15+3);
619     else if( (PIPE >= 0x05 && PIPE <= 0x0f) || (PIPE >= 0xa0 && PIPE <= 0xaf) )
620         GSU.vStepPoint = USEX16(R15+2);
621     else
622         GSU.vStepPoint = USEX16(R15+1);
623     vCount = fx_ppfFunctionTable[FX_FUNCTION_STEP_OVER](nInstructions);
624     fx_writeRegisterSpace();
625     if(GSU.vErrorCode)
626         return GSU.vErrorCode;
627     else
628         return vCount;
629 }
630
631 /* Errors */
632 int FxGetErrorCode()
633 {
634     return GSU.vErrorCode;
635 }
636
637 int FxGetIllegalAddress()
638 {
639     return GSU.vIllegalAddress;
640 }
641
642 /* Access to internal registers */
643 uint32 FxGetColorRegister()
644 {
645     return GSU.vColorReg & 0xff;
646 }
647
648 uint32 FxGetPlotOptionRegister()
649 {
650     return GSU.vPlotOptionReg & 0x1f;
651 }
652
653 uint32 FxGetSourceRegisterIndex()
654 {
655     return GSU.pvSreg - GSU.avReg;
656 }
657
658 uint32 FxGetDestinationRegisterIndex()
659 {
660     return GSU.pvDreg - GSU.avReg;
661 }
662
663 uint8 FxPipe()
664 {
665     return GSU.vPipe;
666 }