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