FDS fixed for asm core
[fceu.git] / ppu.c
1 /**
2  *  For whatever reason, breaking this out of fce.c made sprites not corrupt
3  */
4
5
6 #include        <string.h>
7 #include        <stdio.h>
8 #include        <stdlib.h>
9
10 #include        "types.h"
11 #include        "x6502.h"
12 #include        "fce.h"
13 #include        "sound.h"
14 #include        "svga.h"
15 #include        "netplay.h"
16 #include        "general.h"
17 #include        "endian.h"
18 #include        "version.h"
19 #include        "memory.h"
20
21 #include        "cart.h"
22 #include        "nsf.h"
23 #include        "fds.h"
24 #include        "ines.h"
25 #include        "unif.h"
26 #include        "cheat.h"
27
28 #define MMC5SPRVRAMADR(V)      &MMC5SPRVPage[(V)>>10][(V)]
29 //#define MMC5BGVRAMADR(V)      &MMC5BGVPage[(V)>>10][(V)]
30 #define VRAMADR(V)      &VPage[(V)>>10][(V)]
31
32 #define V_FLIP  0x80
33 #define H_FLIP  0x40
34 #define SP_BACK 0x20
35
36 uint8 SPRAM[0x100];
37 static uint8 SPRBUF[0x100];
38
39 static uint8 sprlinebuf[256+8];
40 extern void BGRender(uint8 *target);
41 extern int tosprite;
42
43
44 static int maxsprites=8;
45
46
47 void FCEUI_DisableSpriteLimitation(int a)
48 {
49  maxsprites=a?64:8;
50 }
51
52
53 //int printed=1;
54 typedef struct {
55         uint8 y,no,atr,x;
56 } SPR __attribute__((aligned(1)));
57
58 typedef struct {
59   //    uint8 ca[2],atr,x;
60         uint8 ca[2],atr,x;
61   //  union {  int z; }
62
63
64 } SPRB __attribute__((aligned(1)));
65
66
67
68 static uint8 nosprites,SpriteBlurp;
69
70 void FetchSpriteData(void)
71 {
72         SPR *spr;
73         uint8 H;
74         int n,vofs;
75
76         spr=(SPR *)SPRAM;
77         H=8;
78
79         nosprites=SpriteBlurp=0;
80
81         vofs=(unsigned int)(PPU[0]&0x8&(((PPU[0]&0x20)^0x20)>>2))<<9;
82         H+=(PPU[0]&0x20)>>2;
83
84         if(!PPU_hook)
85          for(n=63;n>=0;n--,spr++)
86          {
87                 if((unsigned int)(scanline-spr->y)>=H) continue;
88
89                 if(nosprites<maxsprites)
90                 {
91                  if(n==63) SpriteBlurp=1;
92
93                  {
94                   SPRB dst;
95                   uint8 *C;
96                   int t;
97                   unsigned int vadr;
98
99                   t = (int)scanline-(spr->y);
100
101                   if (Sprite16)
102                    vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
103                   else
104                    vadr = (spr->no<<4)+vofs;
105
106                   if (spr->atr&V_FLIP)
107                   {
108                         vadr+=7;
109                         vadr-=t;
110                         vadr+=(PPU[0]&0x20)>>1;
111                         vadr-=t&8;
112                   }
113                   else
114                   {
115                         vadr+=t;
116                         vadr+=t&8;
117                   }
118
119                   /* Fix this geniestage hack */
120                   if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
121                   else C = VRAMADR(vadr);
122
123
124                   dst.ca[0]=C[0];
125                   dst.ca[1]=C[8];
126                   dst.x=spr->x;
127                   dst.atr=spr->atr;
128
129
130                   *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
131                  }
132
133                  nosprites++;
134                 }
135                 else
136                 {
137                   PPU_status|=0x20;
138                   break;
139                 }
140          }
141         else
142          for(n=63;n>=0;n--,spr++)
143          {
144                 if((unsigned int)(scanline-spr->y)>=H) continue;
145
146                 if(nosprites<maxsprites)
147                 {
148                  if(n==63) SpriteBlurp=1;
149
150                  {
151                   SPRB dst;
152                   uint8 *C;
153                   int t;
154                   unsigned int vadr;
155
156                   t = (int)scanline-(spr->y);
157
158                   if (Sprite16)
159                    vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
160                   else
161                    vadr = (spr->no<<4)+vofs;
162
163                   if (spr->atr&V_FLIP)
164                   {
165                         vadr+=7;
166                         vadr-=t;
167                         vadr+=(PPU[0]&0x20)>>1;
168                         vadr-=t&8;
169                   }
170                   else
171                   {
172                         vadr+=t;
173                         vadr+=t&8;
174                   }
175
176                   if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
177                   else C = VRAMADR(vadr);
178                   dst.ca[0]=C[0];
179                   if(nosprites<8)
180                   {
181                    PPU_hook(0x2000);
182                    PPU_hook(vadr);
183                   }
184                   dst.ca[1]=C[8];
185                   dst.x=spr->x;
186                   dst.atr=spr->atr;
187
188
189                   *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
190                  }
191
192                  nosprites++;
193                 }
194                 else
195                 {
196                   PPU_status|=0x20;
197                   break;
198                 }
199          }
200
201         if(nosprites>8) PPU_status|=0x20;  /* Handle case when >8 sprites per
202                                            scanline option is enabled. */
203         else if(PPU_hook)
204         {
205          for(n=0;n<(8-nosprites);n++)
206          {
207                  PPU_hook(0x2000);
208                  PPU_hook(vofs);
209          }
210         }
211
212 }
213
214 #ifdef FRAMESKIP
215 extern int FSkip;
216 #endif
217
218 void RefreshSprite(uint8 *target)
219 {
220         int n, minx=256;
221         SPRB *spr;
222
223         if(!nosprites) return;
224         #ifdef FRAMESKIP
225         if(FSkip)
226         {
227          if(!SpriteBlurp)
228          {
229           nosprites=0;
230           return;
231          }
232          else
233           nosprites=1;
234         }
235         #endif
236
237         nosprites--;
238         spr = (SPRB*)SPRBUF+nosprites;
239
240        for(n=nosprites;n>=0;n--,spr--)
241        {
242         register uint32 J;
243
244         J=spr->ca[0]|spr->ca[1];
245
246         if (J)
247         {
248           register uint8 atr,c1,c2;
249           uint8 *C;
250           uint8 *VB;
251           int x=spr->x;
252           atr=spr->atr;
253
254           if (x < minx)
255           {
256            if (minx == 256) FCEU_dwmemset(sprlinebuf,0x80808080,256); // only clear sprite buff when we encounter first sprite
257            minx = x;
258           }
259                         if(n==0 && SpriteBlurp && !(PPU_status&0x40))
260                         {
261                          int z,ze=x+8;
262                          if(ze>256) {ze=256;}
263                          if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
264                          #ifdef FRAMESKIP
265                          || FSkip
266                          #endif
267                          ))
268                           BGRender(target);
269
270                          if(!(atr&H_FLIP))
271                          {
272                           for(z=x;z<ze;z++)
273                           {
274                            if(J&(0x80>>(z-x)))
275                            {
276                             if(!(target[z]&64))
277                              tosprite=z;
278                            }
279                           }
280                          }
281                          else
282                          {
283                           for(z=x;z<ze;z++)
284                           {
285                            if(J&(1<<(z-x)))
286                            {
287                             if(!(target[z]&64))
288                              tosprite=z;
289                            }
290                           }
291                          }
292                          //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
293                         }
294
295          c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA);
296          c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA);
297
298          C = sprlinebuf+x;
299          VB = (PALRAM+0x10)+((atr&3)<<2);
300
301          {
302           J &= 0xff;
303           if(atr&SP_BACK) J |= 0x4000;
304           if (atr&H_FLIP)
305           {
306            if (J&0x02)  C[1]=VB[c1&3]|(J>>8);
307            if (J&0x01)  *C=VB[c2&3]|(J>>8);
308            c1>>=2;c2>>=2;
309            if (J&0x08)  C[3]=VB[c1&3]|(J>>8);
310            if (J&0x04)  C[2]=VB[c2&3]|(J>>8);
311            c1>>=2;c2>>=2;
312            if (J&0x20)  C[5]=VB[c1&3]|(J>>8);
313            if (J&0x10)  C[4]=VB[c2&3]|(J>>8);
314            c1>>=2;c2>>=2;
315            if (J&0x80)  C[7]=VB[c1]|(J>>8);
316            if (J&0x40)  C[6]=VB[c2]|(J>>8);
317           } else  {
318            if (J&0x02)  C[6]=VB[c1&3]|(J>>8);
319            if (J&0x01)  C[7]=VB[c2&3]|(J>>8);
320            c1>>=2;c2>>=2;
321            if (J&0x08)  C[4]=VB[c1&3]|(J>>8);
322            if (J&0x04)  C[5]=VB[c2&3]|(J>>8);
323            c1>>=2;c2>>=2;
324            if (J&0x20)  C[2]=VB[c1&3]|(J>>8);
325            if (J&0x10)  C[3]=VB[c2&3]|(J>>8);
326            c1>>=2;c2>>=2;
327            if (J&0x80)  *C=VB[c1]|(J>>8);
328            if (J&0x40)  C[1]=VB[c2]|(J>>8);
329           }
330          }
331       }
332      }
333
334      nosprites=0;
335      #ifdef FRAMESKIP
336      if(FSkip) return;
337      #endif
338      if (minx == 256) return; // no visible sprites
339
340      {
341       uint8 n=((PPU[1]&4)^4)<<1;
342       if ((int)n < minx) n = minx & 0xfc;
343       loopskie:
344       {
345        uint32 t=*(uint32 *)(sprlinebuf+n);
346        if(t!=0x80808080)
347        {
348         #ifdef LSB_FIRST
349         uint32 tb=*(uint32 *)(target+n);
350         if(!(t&0x00000080) && (!(t&0x00000040) || (tb&0x00000040))) { // have sprite pixel AND (normal sprite OR behind bg with no bg)
351           tb &= ~0x000000ff; tb |= t & 0x000000ff;
352         }
353
354         if(!(t&0x00008000) && (!(t&0x00004000) || (tb&0x00004000))) {
355           tb &= ~0x0000ff00; tb |= t & 0x0000ff00;
356         }
357
358         if(!(t&0x00800000) && (!(t&0x00400000) || (tb&0x00400000))) {
359           tb &= ~0x00ff0000; tb |= t & 0x00ff0000;
360         }
361
362         if(!(t&0x80000000) && (!(t&0x40000000) || (tb&0x40000000))) {
363           tb &= ~0xff000000; tb |= t & 0xff000000;
364         }
365         *(uint32 *)(target+n)=tb;
366         #else
367         if(!(t&0x80000000))
368         {
369          if(!(t&0x40))       // Normal sprite
370           P[n]=sprlinebuf[n];
371          else if(P[n]&64)        // behind bg sprite
372           P[n]=sprlinebuf[n];
373         }
374
375         if(!(t&0x800000))
376         {
377          if(!(t&0x4000))       // Normal sprite
378           P[n+1]=(sprlinebuf+1)[n];
379          else if(P[n+1]&64)        // behind bg sprite
380           P[n+1]=(sprlinebuf+1)[n];
381         }
382
383         if(!(t&0x8000))
384         {
385          if(!(t&0x400000))       // Normal sprite
386           P[n+2]=(sprlinebuf+2)[n];
387          else if(P[n+2]&64)        // behind bg sprite
388           P[n+2]=(sprlinebuf+2)[n];
389         }
390
391         if(!(t&0x80))
392         {
393          if(!(t&0x40000000))       // Normal sprite
394           P[n+3]=(sprlinebuf+3)[n];
395          else if(P[n+3]&64)        // behind bg sprite
396           P[n+3]=(sprlinebuf+3)[n];
397         }
398         #endif
399        }
400       }
401       n+=4;
402       if(n) goto loopskie;
403      }
404 }
405
406
407
408
409
410 /*
411 void FetchSpriteData(void)
412 {
413         uint8 ns,sb;
414         SPR *spr;
415         uint8 H;
416         int n;
417         int vofs;
418         uint8 P0=PPU[0];
419
420
421         spr=(SPR *)SPRAM;
422         H=8;
423
424         ns=sb=0;
425
426         vofs=(unsigned int)(P0&0x8&(((P0&0x20)^0x20)>>2))<<9;
427         H+=(P0&0x20)>>2;
428
429         if(!PPU_hook)
430          for(n=63;n>=0;n--,spr++)
431          {
432                 if((unsigned int)(scanline-spr->y)>=H) continue;
433                 //printf("%d, %u\n",scanline,(unsigned int)(scanline-spr->y));
434                 if(ns<maxsprites)
435                 {
436                  if(n==63) sb=1;
437
438                  {
439                   SPRB dst;
440                   uint8 *C;
441                   int t;
442                   unsigned int vadr;
443
444                   t = (int)scanline-(spr->y);
445
446                   if (Sprite16)
447                    vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
448                   else
449                    vadr = (spr->no<<4)+vofs;
450
451                   if (spr->atr&V_FLIP)
452                   {
453                         vadr+=7;
454                         vadr-=t;
455                         vadr+=(P0&0x20)>>1;
456                         vadr-=t&8;
457                   }
458                   else
459                   {
460                         vadr+=t;
461                         vadr+=t&8;
462                   }
463
464                   // Fix this geniestage hack
465                   if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
466                   else C = VRAMADR(vadr);
467
468
469                   dst.ca[0]=C[0];
470                   dst.ca[1]=C[8];
471                   dst.x=spr->x;
472                   dst.atr=spr->atr;
473
474                   *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst;
475                  }
476
477                  ns++;
478                 }
479                 else
480                 {
481                   PPU_status|=0x20;
482                   break;
483                 }
484          }
485         else
486          for(n=63;n>=0;n--,spr++)
487          {
488                 if((unsigned int)(scanline-spr->y)>=H) continue;
489
490                 if(ns<maxsprites)
491                 {
492                  if(n==63) sb=1;
493
494                  {
495                   SPRB dst;
496                   uint8 *C;
497                   int t;
498                   unsigned int vadr;
499
500                   t = (int)scanline-(spr->y);
501
502                   if (Sprite16)
503                    vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
504                   else
505                    vadr = (spr->no<<4)+vofs;
506
507                   if (spr->atr&V_FLIP)
508                   {
509                         vadr+=7;
510                         vadr-=t;
511                         vadr+=(P0&0x20)>>1;
512                         vadr-=t&8;
513                   }
514                   else
515                   {
516                         vadr+=t;
517                         vadr+=t&8;
518                   }
519
520                   if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
521                   else C = VRAMADR(vadr);
522                   dst.ca[0]=C[0];
523                   if(ns<8)
524                   {
525                    PPU_hook(0x2000);
526                    PPU_hook(vadr);
527                   }
528                   dst.ca[1]=C[8];
529                   dst.x=spr->x;
530                   dst.atr=spr->atr;
531
532
533                   *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst;
534                  }
535
536                  ns++;
537                 }
538                 else
539                 {
540                   PPU_status|=0x20;
541                   break;
542                 }
543          }
544         //if(ns>=7)
545         //printf("%d %d\n",scanline,ns);
546         if(ns>8) PPU_status|=0x20;      // Handle case when >8 sprites per
547 //                                 scanline option is enabled.
548         else if(PPU_hook)
549         {
550          for(n=0;n<(8-ns);n++)
551          {
552                  PPU_hook(0x2000);
553                  PPU_hook(vofs);
554          }
555         }
556         numsprites=ns;
557         SpriteBlurp=sb;
558 }
559
560
561
562 void RefreshSprite(uint8 *target)
563 {
564
565         int n,sprindex;
566         SPRB *spr;
567         uint8 *P=target;
568
569         //if (printed) {  printf("SPRB: %d  SPR: %d\n", sizeof(SPRB), sizeof(SPR)); printed=0; }
570         if(!numsprites) return;
571
572         FCEU_dwmemset(sprlinebuf,0x80808080,256);
573
574         numsprites--;
575         sprindex=numsprites;
576         spr = (SPRB*)SPRBUF;
577
578         //       for(n=nosprites;n>=0;n--,spr--)
579        for(n=numsprites;n>=0;n--,sprindex--)
580        {
581         uint8 J,atr,c1,c2;
582         int x=spr[sprindex].x;
583         uint8 *C;
584         uint8 *VB;
585
586         P+=x;
587
588         c1=((spr[sprindex].ca[0]>>1)&0x55)|(spr[sprindex].ca[1]&0xAA);
589         c2=(spr[sprindex].ca[0]&0x55)|((spr[sprindex].ca[1]<<1)&0xAA);
590
591         J=spr[sprindex].ca[0]|spr[sprindex].ca[1];
592         atr=spr[sprindex].atr;
593
594                        if(J)
595                        {
596                         if(n==0 && SpriteBlurp && !(PPU_status&0x40))
597                         {
598                          int z,ze=x+8;
599                          if(ze>256) {ze=256;}
600                          if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
601                          #ifdef FRAMESKIP
602                          || FSkip
603                          #endif
604                          ))
605                            // nothing wrong with this
606                          BGRender(target);
607
608                          if(!(atr&H_FLIP))
609                          {
610                           for(z=x;z<ze;z++)
611                           {
612                            if(J&(0x80>>(z-x)))
613                            {
614                             if(!(target[z]&64))
615                              tosprite=z;
616                            }
617                           }
618                          }
619                          else
620                          {
621                           for(z=x;z<ze;z++)
622                           {
623                            if(J&(1<<(z-x)))
624                            {
625                             if(!(target[z]&64))
626                              tosprite=z;
627                            }
628                           }
629                          }
630                          //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
631                         }
632
633          //C = sprlinebuf+(uint8)x;
634          C = &(sprlinebuf[(uint8)x]);
635          VB = (PALRAM+0x10)+((atr&3)<<2);
636
637          if(atr&SP_BACK)
638          {
639           if (atr&H_FLIP)
640           {
641            if (J&0x02)  C[1]=VB[c1&3]|0x40;
642            if (J&0x01)  *C=VB[c2&3]|0x40;
643            c1>>=2;c2>>=2;
644            if (J&0x08)  C[3]=VB[c1&3]|0x40;
645            if (J&0x04)  C[2]=VB[c2&3]|0x40;
646            c1>>=2;c2>>=2;
647            if (J&0x20)  C[5]=VB[c1&3]|0x40;
648            if (J&0x10)  C[4]=VB[c2&3]|0x40;
649            c1>>=2;c2>>=2;
650            if (J&0x80)  C[7]=VB[c1]|0x40;
651            if (J&0x40)  C[6]=VB[c2]|0x40;
652           } else  {
653            if (J&0x02)  C[6]=VB[c1&3]|0x40;
654            if (J&0x01)  C[7]=VB[c2&3]|0x40;
655            c1>>=2;c2>>=2;
656            if (J&0x08)  C[4]=VB[c1&3]|0x40;
657            if (J&0x04)  C[5]=VB[c2&3]|0x40;
658            c1>>=2;c2>>=2;
659            if (J&0x20)  C[2]=VB[c1&3]|0x40;
660            if (J&0x10)  C[3]=VB[c2&3]|0x40;
661            c1>>=2;c2>>=2;
662            if (J&0x80)  *C=VB[c1]|0x40;
663            if (J&0x40)  C[1]=VB[c2]|0x40;
664           }
665          } else {
666           if (atr&H_FLIP)
667           {
668            if (J&0x02)  C[1]=VB[(c1&3)];
669            if (J&0x01)  *C=VB[(c2&3)];
670            c1>>=2;c2>>=2;
671            if (J&0x08)  C[3]=VB[(c1&3)];
672            if (J&0x04)  C[2]=VB[(c2&3)];
673            c1>>=2;c2>>=2;
674            if (J&0x20)  C[5]=VB[(c1&3)];
675            if (J&0x10)  C[4]=VB[(c2&3)];
676            c1>>=2;c2>>=2;
677            if (J&0x80)  C[7]=VB[c1];
678            if (J&0x40)  C[6]=VB[c2];
679           }else{
680            if (J&0x02)  C[6]=VB[(c1&3)];
681            if (J&0x01)  C[7]=VB[(c2&3)];
682            c1>>=2;c2>>=2;
683            if (J&0x08)  C[4]=VB[(c1&3)];
684            if (J&0x04)  C[5]=VB[(c2&3)];
685            c1>>=2;c2>>=2;
686            if (J&0x20)  C[2]=VB[(c1&3)];
687            if (J&0x10)  C[3]=VB[(c2&3)];
688            c1>>=2;c2>>=2;
689            if (J&0x80)  *C=VB[c1];
690            if (J&0x40)  C[1]=VB[c2];
691           }
692          }
693         }
694        P-=x;
695       }
696
697      numsprites=0;
698      #ifdef FRAMESKIP
699      if(FSkip) return;
700      #endif
701
702      {
703       uint8 n=((PPU[1]&4)^4)<<1;
704       loopskie:
705       {
706        uint32 t=*((uint32 *)(&(sprlinebuf[n])));
707        if(t!=0x80808080)
708        {
709         #ifdef LSB_FIRST
710         if(!(t&0x80))
711         {
712          if(!(t&0x40))       // Normal sprite
713           P[n]=sprlinebuf[n];
714          else if(P[n]&64)        // behind bg sprite
715           P[n]=sprlinebuf[n];
716         }
717
718         if(!(t&0x8000))
719         {
720          if(!(t&0x4000))       // Normal sprite
721           P[n+1]=(sprlinebuf+1)[n];
722          else if(P[n+1]&64)        // behind bg sprite
723           P[n+1]=(sprlinebuf+1)[n];
724         }
725
726         if(!(t&0x800000))
727         {
728          if(!(t&0x400000))       // Normal sprite
729           P[n+2]=(sprlinebuf+2)[n];
730          else if(P[n+2]&64)        // behind bg sprite
731           P[n+2]=(sprlinebuf+2)[n];
732         }
733
734         if(!(t&0x80000000))
735         {
736          if(!(t&0x40000000))       // Normal sprite
737           P[n+3]=(sprlinebuf+3)[n];
738          else if(P[n+3]&64)        // behind bg sprite
739           P[n+3]=(sprlinebuf+3)[n];
740         }
741         #else
742         if(!(t&0x80000000))
743         {
744          if(!(t&0x40))       // Normal sprite
745           P[n]=sprlinebuf[n];
746          else if(P[n]&64)        // behind bg sprite
747           P[n]=sprlinebuf[n];
748         }
749
750         if(!(t&0x800000))
751         {
752          if(!(t&0x4000))       // Normal sprite
753           P[n+1]=(sprlinebuf+1)[n];
754          else if(P[n+1]&64)        // behind bg sprite
755           P[n+1]=(sprlinebuf+1)[n];
756         }
757
758         if(!(t&0x8000))
759         {
760          if(!(t&0x400000))       // Normal sprite
761           P[n+2]=(sprlinebuf+2)[n];
762          else if(P[n+2]&64)        // behind bg sprite
763           P[n+2]=(sprlinebuf+2)[n];
764         }
765
766         if(!(t&0x80))
767         {
768          if(!(t&0x40000000))       // Normal sprite
769           P[n+3]=(sprlinebuf+3)[n];
770          else if(P[n+3]&64)        // behind bg sprite
771           P[n+3]=(sprlinebuf+3)[n];
772         }
773         #endif
774        }
775       }
776       n+=4;
777       if(n) goto loopskie;
778      }
779 }
780
781
782 */