2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
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).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
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.
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.
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.
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
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
44 #define FIRST_VISIBLE_LINE 1
47 extern uint16 SignExtend [2];
53 #define MAX_2BIT_TILES 4096
54 #define MAX_4BIT_TILES 2048
55 #define MAX_8BIT_TILES 1024
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)
70 bool8_32 ColorsChanged;
74 bool8_32 LatchedBlanking;
76 bool8_32 RenderThisFrame;
77 bool8_32 DirectColourMapsNeedRebuild;
79 uint32 RenderedFramesCount;
80 uint32 DisplayedRenderedFrameCount;
84 uint8 *TileCached [3];
85 bool8_32 FirstVRAMRead;
86 bool8_32 LatchedInterlace;
87 bool8_32 DoubleWidthPixels;
88 int RenderedScreenHeight;
89 int RenderedScreenWidth;
94 uint16 ScreenColors [256];
103 struct ClipData Clip [2];
128 uint16 FullGraphicCount;
145 struct SOBJ OBJ [128];
146 uint8 OAMPriorityRotation;
150 uint16 OAMTileAddress;
153 uint16 VBeamPosLatched;
154 uint16 HBeamPosLatched;
158 uint8 HVBeamCounterLatched;
166 uint8 Joypad1ButtonReadPos;
167 uint8 Joypad2ButtonReadPos;
170 uint8 FixedColourRed;
171 uint8 FixedColourGreen;
172 uint8 FixedColourBlue;
177 bool8_32 ForcedBlanking;
178 bool8_32 OBJThroughMain;
179 bool8_32 OBJThroughSub;
182 bool8_32 OBJAddition;
184 uint8 OAMData [512 + 32];
185 bool8_32 VTimerEnabled;
186 bool8_32 HTimerEnabled;
187 short HTimerPosition;
189 bool8_32 BGMosaic [4];
197 uint8 ClipCounts [6];
198 uint8 ClipWindowOverlapLogic [6];
199 uint8 ClipWindow1Enable [6];
200 uint8 ClipWindow2Enable [6];
201 bool8_32 ClipWindow1Inside [6];
202 bool8_32 ClipWindow2Inside [6];
203 bool8_32 RecomputeClipWindows;
205 uint16 OBJNameSelect;
206 bool8_32 Need16x8Mulitply;
207 uint8 Joypad3ButtonReadPos;
217 bool8_32 TransferDirection;
218 bool8_32 AAddressFixed;
219 bool8_32 AAddressDecrement;
228 uint16 TransferBytes;
231 bool8_32 HDMAIndirectAddressing;
232 uint16 IndirectAddress;
240 void S9xNextController ();
242 void S9xUpdateScreen ();
244 void S9xFixColourBrightness ();
245 void S9xUpdateJoypads ();
246 void S9xProcessMouse(int which1);
247 void S9xSuperFXExec ();
249 void S9xSetPPU (uint8 Byte, uint16 Address);
250 uint8 S9xGetPPU (uint16 Address);
251 void S9xSetCPU (uint8 Byte, uint16 Address);
252 uint8 S9xGetCPU (uint16 Address);
255 void S9xSetC4 (uint8 Byte, uint16 Address);
256 uint8 S9xGetC4 (uint16 Address);
257 void S9xSetC4RAM (uint8 Byte, uint16 Address);
258 uint8 S9xGetC4RAM (uint16 Address);
260 extern struct SPPU PPU;
261 extern struct SDMA DMA [8];
262 extern struct InternalPPU IPPU;
268 STATIC INLINE uint8 REGISTER_4212()
271 if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE &&
272 CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3)
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 ? */
282 STATIC INLINE void FLUSH_REDRAW ()
284 if (IPPU.PreviousLine != IPPU.CurrentLine)
288 STATIC INLINE void REGISTER_2104 (uint8 byte)
290 if (PPU.OAMAddr >= 0x110)
293 int addr = (PPU.OAMAddr << 1) + (PPU.OAMFlip & 1);
295 if (byte != PPU.OAMData [addr])
298 PPU.OAMData [addr] = byte;
299 IPPU.OBJChanged = TRUE;
302 // X position high bit, and sprite size (x4)
303 struct SOBJ *pObj = &PPU.OBJ [(addr & 0x1f) * 4];
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;
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;
332 PPU.OBJ[PPU.OAMAddr >> 1].VPos = byte;
341 PPU.OBJ[addr = PPU.OAMAddr >> 1].Name &= 0x100;
342 PPU.OBJ[addr].Name |= byte;
347 PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xFF00;
348 PPU.OBJ[addr].HPos |= byte;
354 if (!(PPU.OAMFlip & 1))
357 Memory.FillRAM [0x2104] = byte;
360 STATIC INLINE void REGISTER_2118 (uint8 Byte)
363 if (PPU.VMA.FullGraphicCount)
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;
373 Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte;
375 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
376 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
377 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
381 if (Settings.TraceVRAM && !CPU.InDMA)
383 printf ("VRAM write byte: $%04X (%d,%d)\n", PPU.VMA.Address,
384 Memory.FillRAM[0x2115] & 3,
385 (Memory.FillRAM [0x2115] & 0x0c) >> 2);
388 PPU.VMA.Address += PPU.VMA.Increment;
390 // Memory.FillRAM [0x2118] = Byte;
393 STATIC INLINE void REGISTER_2118_tile (uint8 Byte)
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;
405 PPU.VMA.Address += PPU.VMA.Increment;
406 // Memory.FillRAM [0x2118] = Byte;
409 STATIC INLINE void REGISTER_2118_linear (uint8 Byte)
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;
417 PPU.VMA.Address += PPU.VMA.Increment;
418 // Memory.FillRAM [0x2118] = Byte;
421 STATIC INLINE void REGISTER_2119 (uint8 Byte)
424 if (PPU.VMA.FullGraphicCount)
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;
434 Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte;
436 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
437 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
438 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
442 if (Settings.TraceVRAM && !CPU.InDMA)
444 printf ("VRAM write word: $%04X (%d,%d)\n", PPU.VMA.Address,
445 Memory.FillRAM[0x2115] & 3,
446 (Memory.FillRAM [0x2115] & 0x0c) >> 2);
449 PPU.VMA.Address += PPU.VMA.Increment;
451 // Memory.FillRAM [0x2119] = Byte;
454 STATIC INLINE void REGISTER_2119_tile (uint8 Byte)
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;
465 PPU.VMA.Address += PPU.VMA.Increment;
466 // Memory.FillRAM [0x2119] = Byte;
469 STATIC INLINE void REGISTER_2119_linear (uint8 Byte)
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;
477 PPU.VMA.Address += PPU.VMA.Increment;
478 // Memory.FillRAM [0x2119] = Byte;
481 STATIC INLINE void REGISTER_2122(uint8 Byte)
483 // CG-RAM (palette) write
487 if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8))
489 if (!(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
492 PPU.CGDATA[PPU.CGADD] &= 0x00FF;
493 PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8;
494 IPPU.ColorsChanged = TRUE;
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]);
506 if (Byte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff))
508 if (!(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
511 PPU.CGDATA[PPU.CGADD] &= 0x7F00;
512 PPU.CGDATA[PPU.CGADD] |= Byte;
513 IPPU.ColorsChanged = TRUE;
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]);
523 // Memory.FillRAM [0x2122] = Byte;
526 STATIC INLINE void REGISTER_2180(uint8 Byte)
528 Memory.RAM[PPU.WRAM++] = Byte;
530 Memory.FillRAM [0x2180] = Byte;