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 S9xUpdateScreen ();
242 void S9xFixColourBrightness ();
243 void S9xUpdateJoypads ();
244 void S9xProcessMouse(int which1);
245 void S9xSuperFXExec ();
247 void S9xSetPPU (uint8 Byte, uint16 Address);
248 uint8 S9xGetPPU (uint16 Address);
249 void S9xSetCPU (uint8 Byte, uint16 Address);
250 uint8 S9xGetCPU (uint16 Address);
253 void S9xSetC4 (uint8 Byte, uint16 Address);
254 uint8 S9xGetC4 (uint16 Address);
255 void S9xSetC4RAM (uint8 Byte, uint16 Address);
256 uint8 S9xGetC4RAM (uint16 Address);
258 extern struct SPPU PPU;
259 extern struct SDMA DMA [8];
260 extern struct InternalPPU IPPU;
266 STATIC INLINE uint8 REGISTER_4212()
269 if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE &&
270 CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3)
273 GetBank |= CPU.Cycles >= Settings.HBlankStart ? 0x40 : 0;
274 if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE)
275 GetBank |= 0x80; /* XXX: 0x80 or 0xc0 ? */
280 STATIC INLINE void FLUSH_REDRAW ()
282 if (IPPU.PreviousLine != IPPU.CurrentLine)
286 STATIC INLINE void REGISTER_2104 (uint8 byte)
288 if (PPU.OAMAddr >= 0x110)
291 int addr = (PPU.OAMAddr << 1) + (PPU.OAMFlip & 1);
293 if (byte != PPU.OAMData [addr])
296 PPU.OAMData [addr] = byte;
297 IPPU.OBJChanged = TRUE;
300 // X position high bit, and sprite size (x4)
301 struct SOBJ *pObj = &PPU.OBJ [(addr & 0x1f) * 4];
303 pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 0) & 1];
304 pObj++->Size = byte & 2;
305 pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 2) & 1];
306 pObj++->Size = byte & 8;
307 pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 4) & 1];
308 pObj++->Size = byte & 32;
309 pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 6) & 1];
310 pObj->Size = byte & 128;
318 addr = PPU.OAMAddr >> 1;
319 // Tile within group, priority, h and v flip.
320 PPU.OBJ[addr].Name &= 0xFF;
321 PPU.OBJ[addr].Name |= ((uint16) (byte & 1)) << 8;
322 PPU.OBJ[addr].Palette = (byte >> 1) & 7;
323 PPU.OBJ[addr].Priority = (byte >> 4) & 3;
324 PPU.OBJ[addr].HFlip = (byte >> 6) & 1;
325 PPU.OBJ[addr].VFlip = (byte >> 7) & 1;
330 PPU.OBJ[PPU.OAMAddr >> 1].VPos = byte;
339 PPU.OBJ[addr = PPU.OAMAddr >> 1].Name &= 0x100;
340 PPU.OBJ[addr].Name |= byte;
345 PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xFF00;
346 PPU.OBJ[addr].HPos |= byte;
352 if (!(PPU.OAMFlip & 1))
355 Memory.FillRAM [0x2104] = byte;
358 STATIC INLINE void REGISTER_2118 (uint8 Byte)
361 if (PPU.VMA.FullGraphicCount)
363 uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
364 address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) +
365 (rem >> PPU.VMA.Shift) +
366 ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
367 Memory.VRAM [address] = Byte;
371 Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte;
373 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
374 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
375 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
379 if (Settings.TraceVRAM && !CPU.InDMA)
381 printf ("VRAM write byte: $%04X (%d,%d)\n", PPU.VMA.Address,
382 Memory.FillRAM[0x2115] & 3,
383 (Memory.FillRAM [0x2115] & 0x0c) >> 2);
386 PPU.VMA.Address += PPU.VMA.Increment;
388 // Memory.FillRAM [0x2118] = Byte;
391 STATIC INLINE void REGISTER_2118_tile (uint8 Byte)
394 uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
395 address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) +
396 (rem >> PPU.VMA.Shift) +
397 ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
398 Memory.VRAM [address] = Byte;
399 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
400 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
401 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
403 PPU.VMA.Address += PPU.VMA.Increment;
404 // Memory.FillRAM [0x2118] = Byte;
407 STATIC INLINE void REGISTER_2118_linear (uint8 Byte)
410 Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte;
411 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
412 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
413 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
415 PPU.VMA.Address += PPU.VMA.Increment;
416 // Memory.FillRAM [0x2118] = Byte;
419 STATIC INLINE void REGISTER_2119 (uint8 Byte)
422 if (PPU.VMA.FullGraphicCount)
424 uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
425 address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) +
426 (rem >> PPU.VMA.Shift) +
427 ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF;
428 Memory.VRAM [address] = Byte;
432 Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte;
434 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
435 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
436 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
440 if (Settings.TraceVRAM && !CPU.InDMA)
442 printf ("VRAM write word: $%04X (%d,%d)\n", PPU.VMA.Address,
443 Memory.FillRAM[0x2115] & 3,
444 (Memory.FillRAM [0x2115] & 0x0c) >> 2);
447 PPU.VMA.Address += PPU.VMA.Increment;
449 // Memory.FillRAM [0x2119] = Byte;
452 STATIC INLINE void REGISTER_2119_tile (uint8 Byte)
454 uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1;
455 uint32 address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) +
456 (rem >> PPU.VMA.Shift) +
457 ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF;
458 Memory.VRAM [address] = Byte;
459 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
460 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
461 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
463 PPU.VMA.Address += PPU.VMA.Increment;
464 // Memory.FillRAM [0x2119] = Byte;
467 STATIC INLINE void REGISTER_2119_linear (uint8 Byte)
470 Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte;
471 IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE;
472 IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE;
473 IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE;
475 PPU.VMA.Address += PPU.VMA.Increment;
476 // Memory.FillRAM [0x2119] = Byte;
479 STATIC INLINE void REGISTER_2122(uint8 Byte)
481 // CG-RAM (palette) write
485 if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8))
487 if (Settings.SixteenBit&& !(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
490 PPU.CGDATA[PPU.CGADD] &= 0x00FF;
491 PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8;
492 IPPU.ColorsChanged = TRUE;
494 if (Settings.SixteenBit)
497 IPPU.Blue [PPU.CGADD] = IPPU.XB [(Byte >> 2) & 0x1f];
498 IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
499 IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD],
500 IPPU.Green [PPU.CGADD],
501 IPPU.Blue [PPU.CGADD]);
508 if (Byte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff))
510 if (Settings.SixteenBit&& !(Settings.os9x_hack&PPU_IGNORE_PALWRITE)){
513 PPU.CGDATA[PPU.CGADD] &= 0x7F00;
514 PPU.CGDATA[PPU.CGADD] |= Byte;
515 IPPU.ColorsChanged = TRUE;
517 if (Settings.SixteenBit)
520 IPPU.Red [PPU.CGADD] = IPPU.XB [Byte & 0x1f];
521 IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
522 IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD],
523 IPPU.Green [PPU.CGADD],
524 IPPU.Blue [PPU.CGADD]);
529 // Memory.FillRAM [0x2122] = Byte;
532 STATIC INLINE void REGISTER_2180(uint8 Byte)
534 Memory.RAM[PPU.WRAM++] = Byte;
536 Memory.FillRAM [0x2180] = Byte;