workaround a problem with the harmattan gcc
[drnoksnes] / ppu.h
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 #ifndef _PPU_H_
42 #define _PPU_H_
43
44 #define FIRST_VISIBLE_LINE 1
45
46 extern uint8 GetBank;
47 extern uint16 SignExtend [2];
48
49 #define TILE_2BIT 0
50 #define TILE_4BIT 1
51 #define TILE_8BIT 2
52
53 #define MAX_2BIT_TILES 4096
54 #define MAX_4BIT_TILES 2048
55 #define MAX_8BIT_TILES 1024
56
57 #define PPU_H_BEAM_IRQ_SOURCE   (1 << 0)
58 #define PPU_V_BEAM_IRQ_SOURCE   (1 << 1)
59 #define GSU_IRQ_SOURCE          (1 << 2)
60 #define SA1_IRQ_SOURCE          (1 << 7)
61 #define SA1_DMA_IRQ_SOURCE      (1 << 5)
62
63 struct ClipData {
64     uint32  Count [6];
65     uint32  Left [6][6];
66     uint32  Right [6][6];
67 };
68
69 struct InternalPPU {
70     bool8  ColorsChanged;
71     uint8  HDMA;
72     bool8  HDMAStarted;
73     uint8  MaxBrightness;
74     bool8  LatchedBlanking;
75     bool8  OBJChanged;
76     bool8  RenderThisFrame;
77     bool8  DirectColourMapsNeedRebuild;
78     uint32 FrameCount;
79     uint32 RenderedFramesCount;
80     uint32 DisplayedRenderedFrameCount;
81     uint32 SkippedFrames;
82     uint32 FrameSkip;
83     uint8  *TileCache [3];
84     uint8  *TileCached [3];
85     bool8  FirstVRAMRead;
86     bool8  LatchedInterlace;
87     bool8  DoubleWidthPixels;
88     int    RenderedScreenHeight;
89     int    RenderedScreenWidth;
90     uint32 Red [256];
91     uint32 Green [256];
92     uint32 Blue [256];
93     uint8  *XB;
94     uint16 ScreenColors [256];
95     int    PreviousLine;
96     int    CurrentLine;
97     int    Controller;
98     uint32 Joypads[5];
99     uint32 SuperScope;
100     uint32 Mouse[2];
101     int    PrevMouseX[2];
102     int    PrevMouseY[2];
103     struct ClipData Clip [2];
104 };
105
106 struct SOBJ
107 {
108     short  HPos;
109     uint16 VPos;
110     uint16 Name;
111     uint8  VFlip;
112     uint8  HFlip;
113     uint8  Priority;
114     uint8  Palette;
115     uint8  Size;
116 };
117
118 struct SPPU {
119     uint8  BGMode;
120     uint8  BG3Priority;
121     uint8  Brightness;
122
123     struct {
124         bool8 High;
125         uint8 Increment;
126         uint16 Address;
127         uint16 Mask1;
128         uint16 FullGraphicCount;
129         uint16 Shift;
130     } VMA;
131
132     struct {
133         uint16 SCBase;
134         uint16 VOffset;
135         uint16 HOffset;
136         uint8 BGSize;
137         uint16 NameBase;
138         uint16 SCSize;
139     } BG [4];
140
141     bool8  CGFLIP;
142     uint16 CGDATA [256]; 
143     uint8  FirstSprite;
144     uint8  LastSprite;
145     struct SOBJ OBJ [128];
146     uint8  OAMPriorityRotation;
147     uint16 OAMAddr;
148
149     uint8  OAMFlip;
150     uint16 OAMTileAddress;
151     uint16 IRQVBeamPos;
152     uint16 IRQHBeamPos;
153     uint16 VBeamPosLatched;
154     uint16 HBeamPosLatched;
155
156     uint8  HBeamFlip;
157     uint8  VBeamFlip;
158     uint8  HVBeamCounterLatched;
159
160     short  MatrixA;
161     short  MatrixB;
162     short  MatrixC;
163     short  MatrixD;
164     short  CentreX;
165     short  CentreY;
166     uint8  Joypad1ButtonReadPos;
167     uint8  Joypad2ButtonReadPos;
168
169     uint8  CGADD;
170     uint8  FixedColourRed;
171     uint8  FixedColourGreen;
172     uint8  FixedColourBlue;
173     uint16 SavedOAMAddr;
174     uint16 ScreenHeight;
175     uint32 WRAM;
176     uint8  BG_Forced;
177     bool8  ForcedBlanking;
178     bool8  OBJThroughMain;
179     bool8  OBJThroughSub;
180     uint8  OBJSizeSelect;
181     uint16 OBJNameBase;
182     bool8  OBJAddition;
183     uint8  OAMReadFlip;
184     uint8  OAMData [512 + 32];
185     bool8  VTimerEnabled;
186     bool8  HTimerEnabled;
187     short  HTimerPosition;
188     uint8  Mosaic;
189     bool8  BGMosaic [4];
190     bool8  Mode7HFlip;
191     bool8  Mode7VFlip;
192     uint8  Mode7Repeat;
193     uint8  Window1Left;
194     uint8  Window1Right;
195     uint8  Window2Left;
196     uint8  Window2Right;
197     uint8  ClipCounts [6];
198     uint8  ClipWindowOverlapLogic [6];
199     uint8  ClipWindow1Enable [6];
200     uint8  ClipWindow2Enable [6];
201     bool8  ClipWindow1Inside [6];
202     bool8  ClipWindow2Inside [6];
203     bool8  RecomputeClipWindows;
204     uint8  CGFLIPRead;
205     uint16 OBJNameSelect;
206     bool8  Need16x8Mulitply;
207     uint8  Joypad3ButtonReadPos;
208     uint8  MouseSpeed[2];
209 };
210
211 #define CLIP_OR 0
212 #define CLIP_AND 1
213 #define CLIP_XOR 2
214 #define CLIP_XNOR 3
215
216 struct SDMA {
217     bool8  TransferDirection;
218     bool8  AAddressFixed;
219     bool8  AAddressDecrement;
220     uint8  TransferMode;
221
222     uint8  ABank;
223     uint16 AAddress;
224     uint16 Address;
225     uint8  BAddress;
226
227     // General DMA only:
228     uint16 TransferBytes;
229
230     // H-DMA only:
231     bool8  HDMAIndirectAddressing;
232     uint16 IndirectAddress;
233     uint8  IndirectBank;
234     uint8  Repeat;
235     uint8  LineCount;
236     uint8  FirstLine;
237 };
238
239 START_EXTERN_C
240 void S9xNextController ();
241
242 void S9xUpdateScreen ();
243 void S9xResetPPU ();
244 void S9xFixColourBrightness ();
245 void S9xUpdateJoypads ();
246 void S9xProcessMouse(int which1);
247 void S9xSuperFXExec ();
248
249 void S9xSetPPU (uint8 Byte, uint16 Address);
250 uint8 S9xGetPPU (uint16 Address);
251 void S9xSetCPU (uint8 Byte, uint16 Address);
252 uint8 S9xGetCPU (uint16 Address);
253
254 void S9xInitC4 ();
255 void S9xSetC4 (uint8 Byte, uint16 Address);
256 uint8 S9xGetC4 (uint16 Address);
257 void S9xSetC4RAM (uint8 Byte, uint16 Address);
258 uint8 S9xGetC4RAM (uint16 Address);
259
260 extern struct SPPU PPU;
261 extern struct SDMA DMA [8];
262 extern struct InternalPPU IPPU;
263 END_EXTERN_C
264
265 #include "gfx.h"
266 #include "memmap.h"
267
268 STATIC INLINE uint8 REGISTER_4212()
269 {
270     GetBank = 0;
271     if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE &&
272         CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3)
273         GetBank = 1;
274
275     GetBank |= CPU.Cycles >= Settings.HBlankStart ? 0x40 : 0;
276     if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE)
277         GetBank |= 0x80; /* XXX: 0x80 or 0xc0 ? */
278
279     return (GetBank);
280 }
281
282 STATIC INLINE void FLUSH_REDRAW ()
283 {
284         if (IPPU.PreviousLine != IPPU.CurrentLine)
285                 S9xUpdateScreen();
286 }
287
288 STATIC INLINE void REGISTER_2104 (uint8 byte)
289 {
290     if (PPU.OAMAddr >= 0x110)
291         return;
292         
293     int addr = (PPU.OAMAddr << 1) + (PPU.OAMFlip & 1);
294     
295     if (byte != PPU.OAMData [addr])
296     {
297         FLUSH_REDRAW ();
298         PPU.OAMData [addr] = byte;
299         IPPU.OBJChanged = TRUE;
300         if (addr & 0x200)
301         {
302             // X position high bit, and sprite size (x4)
303             struct SOBJ *pObj = &PPU.OBJ [(addr & 0x1f) * 4];
304
305             pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 0) & 1];
306             pObj++->Size = byte & 2;
307             pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 2) & 1];
308             pObj++->Size = byte & 8;
309             pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 4) & 1];
310             pObj++->Size = byte & 32;
311             pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 6) & 1];
312             pObj->Size = byte & 128;
313         }
314         else
315         {
316             if (addr & 1)
317             {
318                 if (addr & 2)
319                 {
320                     addr = PPU.OAMAddr >> 1;
321                     // Tile within group, priority, h and v flip.
322                     PPU.OBJ[addr].Name &= 0xFF;
323                     PPU.OBJ[addr].Name |= ((uint16) (byte & 1)) << 8;
324                     PPU.OBJ[addr].Palette = (byte >> 1) & 7;
325                     PPU.OBJ[addr].Priority = (byte >> 4) & 3;
326                     PPU.OBJ[addr].HFlip = (byte >> 6) & 1;
327                     PPU.OBJ[addr].VFlip = (byte >> 7) & 1;
328                 }
329                 else
330                 {
331                     // Sprite Y position
332                     PPU.OBJ[PPU.OAMAddr >> 1].VPos = byte;
333                 }
334             }
335             else
336             {
337                 if (addr & 2)
338                 {
339                     // Tile group
340                     
341                     PPU.OBJ[addr = PPU.OAMAddr >> 1].Name &= 0x100;
342                     PPU.OBJ[addr].Name |= byte;
343                 }
344                 else
345                 {
346                     // X position (low)
347                     PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xFF00;
348                     PPU.OBJ[addr].HPos |= byte;
349                 }
350             }
351         }
352     }
353     PPU.OAMFlip ^= 1;
354     if (!(PPU.OAMFlip & 1))
355         PPU.OAMAddr++;
356
357     Memory.FillRAM [0x2104] = byte;
358 }
359
360 STATIC INLINE void REGISTER_2118 (uint8 Byte)
361 {
362     uint32 address;
363     if (PPU.VMA.FullGraphicCount)
364     {
365         uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
366         address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) +
367                          (rem >> PPU.VMA.Shift) +
368                          ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
369         Memory.VRAM [address] = Byte;
370     }
371     else
372     {
373         Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte;
374     }
375     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
376     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
377     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
378     if (!PPU.VMA.High)
379     {
380 #ifdef DEBUGGER
381         if (Settings.TraceVRAM && !CPU.InDMA)
382         {
383             printf ("VRAM write byte: $%04X (%d,%d)\n", PPU.VMA.Address,
384                     Memory.FillRAM[0x2115] & 3,
385                     (Memory.FillRAM [0x2115] & 0x0c) >> 2);
386         }
387 #endif  
388         PPU.VMA.Address += PPU.VMA.Increment;
389     }
390 //    Memory.FillRAM [0x2118] = Byte;
391 }
392
393 STATIC INLINE void REGISTER_2118_tile (uint8 Byte)
394 {
395     uint32 address;
396     uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
397     address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) +
398                  (rem >> PPU.VMA.Shift) +
399                  ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
400     Memory.VRAM [address] = Byte;
401     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
402     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
403     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
404     if (!PPU.VMA.High)
405         PPU.VMA.Address += PPU.VMA.Increment;
406 //    Memory.FillRAM [0x2118] = Byte;
407 }
408
409 STATIC INLINE void REGISTER_2118_linear (uint8 Byte)
410 {
411     uint32 address;
412     Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte;
413     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
414     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
415     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
416     if (!PPU.VMA.High)
417         PPU.VMA.Address += PPU.VMA.Increment;
418 //    Memory.FillRAM [0x2118] = Byte;
419 }
420
421 STATIC INLINE void REGISTER_2119 (uint8 Byte)
422 {
423     uint32 address;
424     if (PPU.VMA.FullGraphicCount)
425     {
426         uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
427         address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) +
428                     (rem >> PPU.VMA.Shift) +
429                     ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF;
430         Memory.VRAM [address] = Byte;
431     }
432     else
433     {
434         Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte;
435     }
436     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
437     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
438     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
439     if (PPU.VMA.High)
440     {
441 #ifdef DEBUGGER
442         if (Settings.TraceVRAM && !CPU.InDMA)
443         {
444             printf ("VRAM write word: $%04X (%d,%d)\n", PPU.VMA.Address,
445                     Memory.FillRAM[0x2115] & 3,
446                     (Memory.FillRAM [0x2115] & 0x0c) >> 2);
447         }
448 #endif  
449         PPU.VMA.Address += PPU.VMA.Increment;
450     }
451 //    Memory.FillRAM [0x2119] = Byte;
452 }
453
454 STATIC INLINE void REGISTER_2119_tile (uint8 Byte)
455 {
456     uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
457     uint32 address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) +
458                     (rem >> PPU.VMA.Shift) +
459                     ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF;
460     Memory.VRAM [address] = Byte;
461     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
462     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
463     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
464     if (PPU.VMA.High)
465         PPU.VMA.Address += PPU.VMA.Increment;
466 //    Memory.FillRAM [0x2119] = Byte;
467 }
468
469 STATIC INLINE void REGISTER_2119_linear (uint8 Byte)
470 {
471     uint32 address;
472     Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte;
473     IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
474     IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
475     IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
476     if (PPU.VMA.High)
477         PPU.VMA.Address += PPU.VMA.Increment;
478 //    Memory.FillRAM [0x2119] = Byte;
479 }
480
481 STATIC INLINE void REGISTER_2122(uint8 Byte)
482 {
483     // CG-RAM (palette) write
484
485     if (PPU.CGFLIP)
486     {
487         if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8))
488         {
489             if (!(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
490                 FLUSH_REDRAW ();
491                         }
492             PPU.CGDATA[PPU.CGADD] &= 0x00FF;
493             PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8;
494             IPPU.ColorsChanged = TRUE;
495
496                 IPPU.Blue [PPU.CGADD] = IPPU.XB [(Byte >> 2) & 0x1f];
497                 IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
498                 IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD],
499                                                              IPPU.Green [PPU.CGADD],
500                                                              IPPU.Blue [PPU.CGADD]);
501         }
502         PPU.CGADD++;
503     }
504     else
505     {
506         if (Byte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff))
507         {
508             if (!(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
509                 FLUSH_REDRAW ();
510                         }
511             PPU.CGDATA[PPU.CGADD] &= 0x7F00;
512             PPU.CGDATA[PPU.CGADD] |= Byte;
513             IPPU.ColorsChanged = TRUE;
514
515                 IPPU.Red [PPU.CGADD] = IPPU.XB [Byte & 0x1f];
516                 IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
517                 IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD],
518                                                              IPPU.Green [PPU.CGADD],
519                                                              IPPU.Blue [PPU.CGADD]);
520         }
521     }
522     PPU.CGFLIP ^= 1;
523 //    Memory.FillRAM [0x2122] = Byte;
524 }
525
526 STATIC INLINE void REGISTER_2180(uint8 Byte)
527 {
528     Memory.RAM[PPU.WRAM++] = Byte;
529     PPU.WRAM &= 0x1FFFF;
530     Memory.FillRAM [0x2180] = Byte;
531 }
532 #endif