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.
52 //#include "netplay.h"
62 extern struct FxInit_s SuperFX;
63 extern struct FxRegs_s GSU;
65 EXTERN_C void S9xSuperFXWriteReg (uint8, uint32);
66 EXTERN_C uint8 S9xSuperFXReadReg (uint32);
69 void S9xUpdateHTimer ()
71 if (PPU.HTimerEnabled)
74 missing.hirq_pos = PPU.IRQHBeamPos;
76 PPU.HTimerPosition = PPU.IRQHBeamPos * Settings.H_Max / SNES_HCOUNTER_MAX;
77 if (PPU.HTimerPosition == Settings.H_Max ||
78 PPU.HTimerPosition == Settings.HBlankStart)
83 if (!PPU.VTimerEnabled || CPU.V_Counter == PPU.IRQVBeamPos)
85 if (PPU.HTimerPosition < CPU.Cycles)
87 // Missed the IRQ on this line already
88 if (CPU.WhichEvent == HBLANK_END_EVENT ||
89 CPU.WhichEvent == HTIMER_AFTER_EVENT)
91 CPU.WhichEvent = HBLANK_END_EVENT;
92 CPU.NextEvent = Settings.H_Max;
96 CPU.WhichEvent = HBLANK_START_EVENT;
97 CPU.NextEvent = Settings.HBlankStart;
102 if (CPU.WhichEvent == HTIMER_BEFORE_EVENT ||
103 CPU.WhichEvent == HBLANK_START_EVENT)
105 if (PPU.HTimerPosition > Settings.HBlankStart)
107 // HTimer was to trigger before h-blank start,
108 // now triggers after start of h-blank
109 CPU.NextEvent = Settings.HBlankStart;
110 CPU.WhichEvent = HBLANK_START_EVENT;
114 CPU.NextEvent = PPU.HTimerPosition;
115 CPU.WhichEvent = HTIMER_BEFORE_EVENT;
120 CPU.WhichEvent = HTIMER_AFTER_EVENT;
121 CPU.NextEvent = PPU.HTimerPosition;
128 void S9xFixColourBrightness ()
130 IPPU.XB = mul_brightness [PPU.Brightness];
132 if (Settings.SixteenBit)
135 for (int i = 0; i < 256; i++)
137 IPPU.Red [i] = IPPU.XB [PPU.CGDATA [i] & 0x1f];
138 IPPU.Green [i] = IPPU.XB [(PPU.CGDATA [i] >> 5) & 0x1f];
139 IPPU.Blue [i] = IPPU.XB [(PPU.CGDATA [i] >> 10) & 0x1f];
140 IPPU.ScreenColors [i] = BUILD_PIXEL (IPPU.Red [i], IPPU.Green [i],
146 /**********************************************************************************************/
148 /* This function sets a PPU Register to a specific byte */
149 /**********************************************************************************************/
150 void S9xSetPPU(uint8 Byte, uint16 Address)
152 if (Address <= 0x2183)
157 // Brightness and screen blank bit
158 if (Byte != Memory.FillRAM[0x2100])
161 if (PPU.Brightness != (Byte & 0xF))
163 IPPU.ColorsChanged = TRUE;
164 IPPU.DirectColourMapsNeedRebuild = TRUE;
165 PPU.Brightness = Byte & 0xF;
166 S9xFixColourBrightness();
167 if (PPU.Brightness > IPPU.MaxBrightness)
168 IPPU.MaxBrightness = PPU.Brightness;
170 if ((Memory.FillRAM[0x2100] & 0x80) != (Byte & 0x80))
172 IPPU.ColorsChanged = TRUE;
173 PPU.ForcedBlanking = (Byte >> 7) & 1;
179 // Sprite (OBJ) tile address
180 if (Byte != Memory.FillRAM[0x2101])
183 PPU.OBJNameBase = (Byte & 3) << 14;
184 PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13;
185 PPU.OBJSizeSelect = (Byte >> 5) & 7;
186 IPPU.OBJChanged = TRUE;
191 // Sprite write address (low)
195 PPU.SavedOAMAddr = PPU.OAMAddr;
196 if (PPU.OAMPriorityRotation)
198 PPU.FirstSprite = PPU.OAMAddr & 0x7f;
200 missing.sprite_priority_rotation = 1;
206 // Sprite register write address (high), sprite priority rotation
208 if ((PPU.OAMPriorityRotation = (Byte & 0x80) == 0 ? 0 : 1))
210 PPU.FirstSprite = PPU.OAMAddr & 0x7f;
212 missing.sprite_priority_rotation = 1;
215 // Only update the sprite write address top bit if the low byte has
216 // been written to first.
219 PPU.OAMAddr &= 0x00FF;
220 PPU.OAMAddr |= (Byte & 1) << 8;
224 PPU.SavedOAMAddr = PPU.OAMAddr;
228 // Sprite register write
234 // Screen mode (0 - 7), background tile sizes and background 3
236 if (Byte != Memory.FillRAM[0x2105])
239 PPU.BG[0].BGSize = (Byte >> 4) & 1;
240 PPU.BG[1].BGSize = (Byte >> 5) & 1;
241 PPU.BG[2].BGSize = (Byte >> 6) & 1;
242 PPU.BG[3].BGSize = (Byte >> 7) & 1;
243 PPU.BGMode = Byte & 7;
244 // BJ: BG3Priority only takes effect if BGMode==1 and the bit is set
245 PPU.BG3Priority = ((Byte & 0x0f) == 0x09);
247 missing.modes[PPU.BGMode] = 1;
253 // Mosaic pixel size and enable
254 if (Byte != Memory.FillRAM[0x2106])
258 if ((Byte & 0xf0) && (Byte & 0x0f))
261 PPU.Mosaic = (Byte >> 4) + 1;
262 PPU.BGMosaic[0] = (Byte & 1) && PPU.Mosaic > 1;
263 PPU.BGMosaic[1] = (Byte & 2) && PPU.Mosaic > 1;
264 PPU.BGMosaic[2] = (Byte & 4) && PPU.Mosaic > 1;
265 PPU.BGMosaic[3] = (Byte & 8) && PPU.Mosaic > 1;
268 case 0x2107 : // [BG0SC]
269 if (Byte != Memory.FillRAM[0x2107])
272 PPU.BG[0].SCSize = Byte & 3;
273 PPU.BG[0].SCBase = (Byte & 0x7c) << 8;
277 case 0x2108 : // [BG1SC]
278 if (Byte != Memory.FillRAM[0x2108])
281 PPU.BG[1].SCSize = Byte & 3;
282 PPU.BG[1].SCBase = (Byte & 0x7c) << 8;
286 case 0x2109 : // [BG2SC]
287 if (Byte != Memory.FillRAM[0x2109])
290 PPU.BG[2].SCSize = Byte & 3;
291 PPU.BG[2].SCBase = (Byte & 0x7c) << 8;
295 case 0x210A : // [BG3SC]
296 if (Byte != Memory.FillRAM[0x210a])
299 PPU.BG[3].SCSize = Byte & 3;
300 PPU.BG[3].SCBase = (Byte & 0x7c) << 8;
304 case 0x210B : // [BG01NBA]
305 if (Byte != Memory.FillRAM[0x210b])
308 PPU.BG[0].NameBase = (Byte & 7) << 12;
309 PPU.BG[1].NameBase = ((Byte >> 4) & 7) << 12;
313 case 0x210C : // [BG23NBA]
314 if (Byte != Memory.FillRAM[0x210c])
317 PPU.BG[2].NameBase = (Byte & 7) << 12;
318 PPU.BG[3].NameBase = ((Byte >> 4) & 7) << 12;
324 ((PPU.BG[0].HOffset >> 8) & 0xff) | ((uint16) Byte << 8);
329 ((PPU.BG[0].VOffset >> 8) & 0xff) | ((uint16) Byte << 8);
333 ((PPU.BG[1].HOffset >> 8) & 0xff) | ((uint16) Byte << 8);
338 ((PPU.BG[1].VOffset >> 8) & 0xff) | ((uint16) Byte << 8);
343 ((PPU.BG[2].HOffset >> 8) & 0xff) | ((uint16) Byte << 8);
348 ((PPU.BG[2].VOffset >> 8) & 0xff) | ((uint16) Byte << 8);
353 ((PPU.BG[3].HOffset >> 8) & 0xff) | ((uint16) Byte << 8);
358 ((PPU.BG[3].VOffset >> 8) & 0xff) | ((uint16) Byte << 8);
362 // VRAM byte/word access flag and increment
363 PPU.VMA.High = (Byte & 0x80) == 0 ? FALSE : TRUE;
367 PPU.VMA.Increment = 1;
370 PPU.VMA.Increment = 32;
373 PPU.VMA.Increment = 128;
376 PPU.VMA.Increment = 128;
381 missing.vram_inc = Byte & 3;
385 static uint16 IncCount[4] = { 0, 32, 64, 128 };
386 static uint16 Shift[4] = { 0, 5, 6, 7 };
388 missing.vram_full_graphic_inc =
391 PPU.VMA.Increment = 1;
392 uint8 i = (Byte & 0x0c) >> 2;
393 PPU.VMA.FullGraphicCount = IncCount[i];
394 PPU.VMA.Mask1 = IncCount[i] * 8 - 1;
395 PPU.VMA.Shift = Shift[i];
398 PPU.VMA.FullGraphicCount = 0;
402 // VRAM read/write address (low)
403 PPU.VMA.Address &= 0xFF00;
404 PPU.VMA.Address |= Byte;
405 IPPU.FirstVRAMRead = TRUE;
409 // VRAM read/write address (high)
410 PPU.VMA.Address &= 0x00FF;
411 PPU.VMA.Address |= Byte << 8;
412 IPPU.FirstVRAMRead = TRUE;
416 // VRAM write data (low)
417 IPPU.FirstVRAMRead = TRUE;
422 // VRAM write data (high)
423 IPPU.FirstVRAMRead = TRUE;
428 // Mode 7 outside rotation area display mode and flipping
429 if (Byte != Memory.FillRAM[0x211a])
432 PPU.Mode7Repeat = Byte >> 6;
433 PPU.Mode7VFlip = (Byte & 2) >> 1;
434 PPU.Mode7HFlip = Byte & 1;
438 // Mode 7 matrix A (low & high)
439 PPU.MatrixA = ((PPU.MatrixA >> 8) & 0xff) | (Byte << 8);
440 PPU.Need16x8Mulitply = TRUE;
443 // Mode 7 matrix B (low & high)
444 PPU.MatrixB = ((PPU.MatrixB >> 8) & 0xff) | (Byte << 8);
445 PPU.Need16x8Mulitply = TRUE;
448 // Mode 7 matrix C (low & high)
449 PPU.MatrixC = ((PPU.MatrixC >> 8) & 0xff) | (Byte << 8);
452 // Mode 7 matrix D (low & high)
453 PPU.MatrixD = ((PPU.MatrixD >> 8) & 0xff) | (Byte << 8);
456 // Mode 7 centre of rotation X (low & high)
457 PPU.CentreX = ((PPU.CentreX >> 8) & 0xff) | (Byte << 8);
460 // Mode 7 centre of rotation Y (low & high)
461 PPU.CentreY = ((PPU.CentreY >> 8) & 0xff) | (Byte << 8);
476 // Window 1 and 2 enable for backgrounds 1 and 2
477 if (Byte != Memory.FillRAM[0x2123])
479 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
482 PPU.ClipWindow1Enable[0] = !!(Byte & 0x02);
483 PPU.ClipWindow1Enable[1] = !!(Byte & 0x20);
484 PPU.ClipWindow2Enable[0] = !!(Byte & 0x08);
485 PPU.ClipWindow2Enable[1] = !!(Byte & 0x80);
486 PPU.ClipWindow1Inside[0] = !(Byte & 0x01);
487 PPU.ClipWindow1Inside[1] = !(Byte & 0x10);
488 PPU.ClipWindow2Inside[0] = !(Byte & 0x04);
489 PPU.ClipWindow2Inside[1] = !(Byte & 0x40);
490 PPU.RecomputeClipWindows = TRUE;
493 missing.window2[1] = 1;
495 missing.window1[1] = 1;
497 missing.window2[0] = 1;
499 missing.window1[0] = 1;
504 // Window 1 and 2 enable for backgrounds 3 and 4
505 if (Byte != Memory.FillRAM[0x2124])
507 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
510 PPU.ClipWindow1Enable[2] = !!(Byte & 0x02);
511 PPU.ClipWindow1Enable[3] = !!(Byte & 0x20);
512 PPU.ClipWindow2Enable[2] = !!(Byte & 0x08);
513 PPU.ClipWindow2Enable[3] = !!(Byte & 0x80);
514 PPU.ClipWindow1Inside[2] = !(Byte & 0x01);
515 PPU.ClipWindow1Inside[3] = !(Byte & 0x10);
516 PPU.ClipWindow2Inside[2] = !(Byte & 0x04);
517 PPU.ClipWindow2Inside[3] = !(Byte & 0x40);
518 PPU.RecomputeClipWindows = TRUE;
521 missing.window2[3] = 1;
523 missing.window1[3] = 1;
525 missing.window2[2] = 1;
527 missing.window1[2] = 1;
532 // Window 1 and 2 enable for objects and colour window
533 if (Byte != Memory.FillRAM[0x2125])
535 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
538 PPU.ClipWindow1Enable[4] = !!(Byte & 0x02);
539 PPU.ClipWindow1Enable[5] = !!(Byte & 0x20);
540 PPU.ClipWindow2Enable[4] = !!(Byte & 0x08);
541 PPU.ClipWindow2Enable[5] = !!(Byte & 0x80);
542 PPU.ClipWindow1Inside[4] = !(Byte & 0x01);
543 PPU.ClipWindow1Inside[5] = !(Byte & 0x10);
544 PPU.ClipWindow2Inside[4] = !(Byte & 0x04);
545 PPU.ClipWindow2Inside[5] = !(Byte & 0x40);
546 PPU.RecomputeClipWindows = TRUE;
549 missing.window2[5] = 1;
551 missing.window1[5] = 1;
553 missing.window2[4] = 1;
555 missing.window1[4] = 1;
560 // Window 1 left position
561 if (Byte != Memory.FillRAM[0x2126])
563 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
566 PPU.Window1Left = Byte;
567 PPU.RecomputeClipWindows = TRUE;
571 // Window 1 right position
572 if (Byte != Memory.FillRAM[0x2127])
574 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
577 PPU.Window1Right = Byte;
578 PPU.RecomputeClipWindows = TRUE;
582 // Window 2 left position
583 if (Byte != Memory.FillRAM[0x2128])
585 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
588 PPU.Window2Left = Byte;
589 PPU.RecomputeClipWindows = TRUE;
593 // Window 2 right position
594 if (Byte != Memory.FillRAM[0x2129])
596 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
599 PPU.Window2Right = Byte;
600 PPU.RecomputeClipWindows = TRUE;
604 // Windows 1 & 2 overlap logic for backgrounds 1 - 4
605 if (Byte != Memory.FillRAM[0x212a])
607 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
610 PPU.ClipWindowOverlapLogic[0] = (Byte & 0x03);
611 PPU.ClipWindowOverlapLogic[1] = (Byte & 0x0c) >> 2;
612 PPU.ClipWindowOverlapLogic[2] = (Byte & 0x30) >> 4;
613 PPU.ClipWindowOverlapLogic[3] = (Byte & 0xc0) >> 6;
614 PPU.RecomputeClipWindows = TRUE;
618 // Windows 1 & 2 overlap logic for objects and colour window
619 if (Byte != Memory.FillRAM[0x212b])
621 if (Settings.os9x_hack&PPU_IGNORE_WINDOW) return;
624 PPU.ClipWindowOverlapLogic[4] = Byte & 0x03;
625 PPU.ClipWindowOverlapLogic[5] = (Byte & 0x0c) >> 2;
626 PPU.RecomputeClipWindows = TRUE;
630 // Main screen designation (backgrounds 1 - 4 and objects)
631 if (Byte != Memory.FillRAM[0x212c])
635 PPU.RecomputeClipWindows = TRUE;
636 Memory.FillRAM[Address] = Byte;
641 // Sub-screen designation (backgrounds 1 - 4 and objects)
642 if (Byte != Memory.FillRAM[0x212d])
648 missing.subscreen = 1;
650 PPU.RecomputeClipWindows = TRUE;
651 Memory.FillRAM[Address] = Byte;
656 // Window mask designation for main screen ?
657 if (Byte != Memory.FillRAM[0x212e])
661 PPU.RecomputeClipWindows = TRUE;
665 // Window mask designation for sub-screen ?
666 if (Byte != Memory.FillRAM[0x212f])
670 PPU.RecomputeClipWindows = TRUE;
674 // Fixed colour addition or screen addition
675 if (Byte != Memory.FillRAM[0x2130])
677 if (Settings.os9x_hack&PPU_IGNORE_ADDSUB) return;
680 PPU.RecomputeClipWindows = TRUE;
682 if ((Byte & 1) && (PPU.BGMode == 3 || PPU.BGMode == 4
689 // Colour addition or subtraction select
690 if (Byte != Memory.FillRAM[0x2131])
692 if (Settings.os9x_hack&PPU_IGNORE_ADDSUB) return;
695 // Backgrounds 1 - 4, objects and backdrop colour add/sub enable
700 if (Memory.FillRAM[0x2130] & 0x02)
701 missing.subscreen_sub = 1;
703 missing.fixed_colour_sub = 1;
708 if (Memory.FillRAM[0x2130] & 0x02)
709 missing.subscreen_add = 1;
711 missing.fixed_colour_add = 1;
714 Memory.FillRAM[0x2131] = Byte;
718 if (Byte != Memory.FillRAM[0x2132])
722 // Colour data for fixed colour addition/subtraction
724 //PPU.FixedColourBlue = Byte & 0x1f;
725 new_fixedcol=(Byte & 0x1f);
726 if (new_fixedcol!=PPU.FixedColourBlue) {if (!(Settings.os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) FLUSH_REDRAW();PPU.FixedColourBlue=new_fixedcol;}
729 //PPU.FixedColourGreen = Byte & 0x1f;
730 new_fixedcol=(Byte & 0x1f);
731 if (new_fixedcol!=PPU.FixedColourGreen) {if (!(Settings.os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) FLUSH_REDRAW();PPU.FixedColourGreen=new_fixedcol;}
734 //PPU.FixedColourRed = Byte & 0x1f;
735 new_fixedcol=(Byte & 0x1f);
736 if (new_fixedcol!=PPU.FixedColourRed) {if (!(Settings.os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) FLUSH_REDRAW();PPU.FixedColourRed=new_fixedcol;}
740 // Colour data for fixed colour addition/subtraction
742 PPU.FixedColourBlue = Byte & 0x1f;
744 PPU.FixedColourGreen = Byte & 0x1f;
746 PPU.FixedColourRed = Byte & 0x1f;*/
752 if (Byte != Memory.FillRAM[0x2133])
756 missing.mode7_bgmode = 1;
758 missing.pseudo_512 = 1;
762 PPU.ScreenHeight = SNES_HEIGHT_EXTENDED;
764 missing.lines_239 = 1;
768 PPU.ScreenHeight = SNES_HEIGHT;
771 missing.sprite_double_height = 1;
774 missing.interlace = 1;
781 // Matrix 16bit x 8bit multiply result (read-only)
785 // Software latch for horizontal and vertical timers (read-only)
788 // OAM read data (read-only)
792 // VRAM read data (read-only)
795 // CG-RAM read data (read-only)
799 // Horizontal and vertical (low/high) read counter (read-only)
802 // PPU status (time over and range over)
805 // NTSC/PAL select and field (read-only)
872 _SPCInPB(Address & 3, Byte);
874 // CPU.Flags |= DEBUG_MODE_FLAG;
875 Memory.FillRAM[Address] = Byte;
876 IAPU.RAM[(Address & 3) + 0xf4] = Byte;
877 #ifdef SPC700_SHUTDOWN
878 CPU.APU_APUExecuting = Settings.APUEnabled;
892 PPU.WRAM |= Byte << 8;
896 PPU.WRAM |= Byte << 16;
906 if (Address >= 0x2200 && Address < 0x23ff)
907 S9xSetSA1(Byte, Address);
909 Memory.FillRAM[Address] = Byte;
914 // Dai Kaijyu Monogatari II
915 if (Address == 0x2801 && Settings.SRTC)
916 S9xSetSRTC(Byte, Address);
917 else if (Address < 0x3000 || Address >= 0x3000 + 768)
920 missing.unknownppu_write = Address;
921 if (Settings.TraceUnknownRegisters)
925 "Unknown register write: $%02X->$%04X\n",
928 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
934 if (!Settings.SuperFX)
940 if ((Memory.FillRAM[0x3030] ^ Byte) & FLG_G)
942 Memory.FillRAM[Address] = Byte;
943 // Go flag has been changed
950 Memory.FillRAM[Address] = Byte;
954 Memory.FillRAM[Address] = Byte;
957 Memory.FillRAM[Address] = Byte;
960 Memory.FillRAM[Address] = Byte & 0x7f;
963 Memory.FillRAM[Address] = Byte & 0x7f;
966 Memory.FillRAM[Address] = Byte;
969 Memory.FillRAM[Address] = Byte;
972 Memory.FillRAM[Address] = Byte;
975 Memory.FillRAM[Address] = Byte;
980 Memory.FillRAM[Address] = Byte;
983 Memory.FillRAM[Address] = Byte;
984 Memory.FillRAM[0x3000 + GSU_SFR] |= FLG_G;
989 Memory.FillRAM[Address] = Byte;
990 if (Address >= 0x3100)
992 FxCacheWriteAccess(Address);
999 Memory.FillRAM[Address] = Byte;
1002 /**********************************************************************************************/
1004 /* This function retrieves a PPU Register */
1005 /**********************************************************************************************/
1006 uint8 S9xGetPPU(uint16 Address)
1010 if (Address <= 0x2190)
1016 return (Memory.FillRAM[Address]);
1019 missing.oam_address_read = 1;
1021 return (uint8) (PPU.OAMAddr);
1023 return (((PPU.OAMAddr >> 8) & 1) | (PPU.OAMPriorityRotation << 7));
1033 return (Memory.FillRAM[Address]);
1043 missing.bg_offset_read = 1;
1045 return (Memory.FillRAM[Address]);
1047 return (Memory.FillRAM[Address]);
1049 return (uint8) (PPU.VMA.Address);
1051 return (PPU.VMA.Address >> 8);
1055 return (Memory.FillRAM[Address]);
1063 missing.matrix_read = 1;
1065 return (Memory.FillRAM[Address]);
1086 return (Memory.FillRAM[Address]);
1091 // 16bit x 8bit multiply read result.
1092 if (PPU.Need16x8Mulitply)
1094 int32 r = (int32) PPU.MatrixA * (int32) (PPU.MatrixB >> 8);
1096 Memory.FillRAM[0x2134] = (uint8) r;
1097 Memory.FillRAM[0x2135] = (uint8) (r >> 8);
1098 Memory.FillRAM[0x2136] = (uint8) (r >> 16);
1099 PPU.Need16x8Mulitply = FALSE;
1102 missing.matrix_multiply = 1;
1104 return (Memory.FillRAM[Address]);
1106 // Latch h and v counters
1108 missing.h_v_latch = 1;
1112 CPU.WaitAddress = CPU.PCAtOpcodeStart;
1115 PPU.HVBeamCounterLatched = 1;
1116 PPU.VBeamPosLatched = (uint16)
1118 PPU.HBeamPosLatched = (uint16) ((CPU.Cycles * SNES_HCOUNTER_MAX) / Settings.H_Max);
1120 // Causes screen flicker for Yoshi's Island if uncommented
1121 //CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
1123 if (SNESGameFixes.NeedInit0x2137)
1124 PPU.VBeamFlip = 0; //jyam sword world sfc2 & godzill
1127 // Read OAM (sprite) control data
1128 if (!PPU.OAMReadFlip)
1130 byte = PPU.OAMData[PPU.OAMAddr << 1];
1134 byte = PPU.OAMData[(PPU.OAMAddr << 1) + 1];
1135 if (++PPU.OAMAddr >= 0x110)
1138 PPU.OAMReadFlip ^= 1;
1140 missing.oam_read = 1;
1145 // Read vram low byte
1147 missing.vram_read = 1;
1149 if (IPPU.FirstVRAMRead)
1150 byte = Memory.VRAM[PPU.VMA.Address << 1];
1151 else if (PPU.VMA.FullGraphicCount)
1153 uint32 addr = PPU.VMA.Address - 1;
1154 uint32 rem = addr & PPU.VMA.Mask1;
1156 (addr & ~PPU.VMA.Mask1)
1157 + (rem >> PPU.VMA.Shift)
1158 + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
1159 byte = Memory.VRAM[((address << 1) - 2) & 0xFFFF];
1162 byte = Memory.VRAM[((PPU.VMA.Address << 1) - 2) & 0xffff];
1166 PPU.VMA.Address += PPU.VMA.Increment;
1167 IPPU.FirstVRAMRead = FALSE;
1171 // Read vram high byte
1173 missing.vram_read = 1;
1175 if (IPPU.FirstVRAMRead)
1176 byte = Memory.VRAM[((PPU.VMA.Address << 1) + 1) & 0xffff];
1177 else if (PPU.VMA.FullGraphicCount)
1179 uint32 addr = PPU.VMA.Address - 1;
1180 uint32 rem = addr & PPU.VMA.Mask1;
1182 (addr & ~PPU.VMA.Mask1)
1183 + (rem >> PPU.VMA.Shift)
1184 + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
1185 byte = Memory.VRAM[((address << 1) - 1) & 0xFFFF];
1188 byte = Memory.VRAM[((PPU.VMA.Address << 1) - 1) & 0xFFFF];
1191 PPU.VMA.Address += PPU.VMA.Increment;
1192 IPPU.FirstVRAMRead = FALSE;
1197 // Read palette data
1199 missing.cgram_read = 1;
1202 byte = PPU.CGDATA[PPU.CGADD++] >> 8;
1204 byte = PPU.CGDATA[PPU.CGADD] & 0xff;
1206 PPU.CGFLIPRead ^= 1;
1210 // Horizontal counter value 0-339
1212 missing.h_counter_read = 1;
1215 byte = PPU.HBeamPosLatched >> 8;
1217 byte = (uint8) PPU.HBeamPosLatched;
1221 // Vertical counter value 0-262
1223 missing.v_counter_read = 1;
1226 byte = PPU.VBeamPosLatched >> 8;
1228 byte = (uint8) PPU.VBeamPosLatched;
1232 // PPU time and range over flags
1233 return (SNESGameFixes._0x213E_ReturnValue);
1236 // NTSC/PAL and which field flags
1237 PPU.VBeamFlip = PPU.HBeamFlip = 0;
1238 return ((Settings.PAL ? 0x10 : 0) | (Memory.FillRAM[0x213f] & 0xc0));
1305 return ((uint8) _SPCOutP[Address & 3]);
1307 // CPU.Flags |= DEBUG_MODE_FLAG;
1308 #ifdef SPC700_SHUTDOWN
1309 CPU.APU_APUExecuting = Settings.APUEnabled;
1312 if(Settings.APUEnabled)
1315 //CPU.WaitAddress = CPU.PCAtOpcodeStart;
1317 if(SNESGameFixes.APU_OutPorts_ReturnValueFix
1318 && Address >= 0x2140
1319 && Address <= 0x2143
1322 return (uint8) ((Address & 1) ?
1323 ((rand() & 0xff00) >> 8) : (rand() & 0xff));
1326 return (APU.OutPorts[Address & 3]);
1329 switch (Settings.SoundSkipMethod)
1333 CPU.BranchSkip = TRUE;
1338 CPU.BranchSkip = TRUE;
1341 if ((Address & 3) < 2)
1347 return ((Address & 3) == 1 ? 0xaa : 0xbb);
1349 return ((r >> 3) & 0xff);
1356 return ((r >> 3) & 0xff);
1358 return (Memory.FillRAM[Address]);
1364 missing.wram_read = 1;
1366 byte = Memory.RAM[PPU.WRAM++];
1367 PPU.WRAM &= 0x1FFFF;
1372 return (Memory.FillRAM[Address]);
1381 return (S9xGetSA1(Address));
1383 if (Address <= 0x2fff || Address >= 0x3000 + 768)
1392 // For Dai Kaijyu Monogatari II
1394 return (S9xGetSRTC(Address));
1399 missing.unknownppu_read = Address;
1400 if (Settings.TraceUnknownRegisters)
1402 sprintf(String, "Unknown register read: $%04X\n", Address);
1403 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
1407 return (0); //Memory.FillRAM[Address]);
1411 if (!Settings.SuperFX)
1413 byte = Memory.FillRAM[Address];
1415 //if (Address != 0x3030 && Address != 0x3031)
1416 //printf ("%04x\n", Address);
1418 if (Address == 0x3030)
1420 CPU.WaitAddress = CPU.PCAtOpcodeStart;
1424 if (Address == 0x3031)
1426 CLEAR_IRQ_SOURCE(GSU_IRQ_SOURCE);
1427 Memory.FillRAM[0x3031] = byte & 0x7f;
1435 /**********************************************************************************************/
1437 /* This function sets a CPU/DMA Register to a specific byte */
1438 /**********************************************************************************************/
1439 void S9xSetCPU(uint8 byte, uint16 Address)
1443 if (Address < 0x4200)
1446 CPU.Cycles += ONE_CYCLE;
1451 // S9xReset reading of old-style joypads
1452 if ((byte & 1) && !(Memory.FillRAM[Address] & 1))
1454 PPU.Joypad1ButtonReadPos = 0;
1455 PPU.Joypad2ButtonReadPos = 0;
1456 PPU.Joypad3ButtonReadPos = 0;
1463 missing.unknowncpu_write = Address;
1464 if (Settings.TraceUnknownRegisters)
1466 sprintf(String, "Unknown register register write: $%02X->$%04X\n", byte, Address);
1467 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
1477 // NMI, V & H IRQ and joypad reading enable flags
1479 && (!SNESGameFixes.umiharakawaseFix || PPU.IRQVBeamPos < 209))
1481 if (!PPU.VTimerEnabled)
1485 missing.virq_pos = PPU.IRQVBeamPos;
1487 PPU.VTimerEnabled = TRUE;
1488 if (PPU.HTimerEnabled)
1490 else if (PPU.IRQVBeamPos == CPU.V_Counter)
1491 S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE);
1496 PPU.VTimerEnabled = FALSE;
1497 #ifndef RC_OPTIMIZED
1498 if (SNESGameFixes.umiharakawaseFix)
1505 if (!PPU.HTimerEnabled)
1509 missing.hirq_pos = PPU.IRQHBeamPos;
1511 PPU.HTimerEnabled = TRUE;
1517 // No need to check for HTimer being disabled as the scanline
1518 // event trigger code won't trigger an H-IRQ unless its enabled.
1519 PPU.HTimerEnabled = FALSE;
1520 PPU.HTimerPosition = Settings.H_Max + 1;
1523 #ifndef RC_OPTIMIZED
1524 if (!Settings.DaffyDuck)
1525 CLEAR_IRQ_SOURCE(PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
1528 && !(Memory.FillRAM[0x4200] & 0x80)
1529 && CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE
1530 && CPU.V_Counter <= PPU.ScreenHeight + (SNESGameFixes.alienVSpredetorFix ? 25 : 15)
1531 && //jyam 15->25 alien vs predetor
1532 // Panic Bomberman clears the NMI pending flag @ scanline 230 before enabling
1533 // NMIs again. The NMI routine crashes the CPU if it is called without the NMI
1534 // pending flag being set...
1535 (Memory.FillRAM[0x4210] & 0x80) && !CPU.NMIActive)
1537 CPU.Flags |= NMI_FLAG;
1538 CPU.NMIActive = TRUE;
1539 CPU.NMICycleCount = CPU.NMITriggerPoint;
1546 // Multiplier (for multply)
1551 uint32 res = Memory.FillRAM[0x4202] * byte;
1553 Memory.FillRAM[0x4216] = (uint8) res;
1554 Memory.FillRAM[0x4217] = (uint8) (res >> 8);
1559 // Low and high muliplier (for divide)
1565 Memory.FillRAM[0x4204] + (Memory.FillRAM[0x4205] << 8);
1566 uint16 div = byte ? a / byte : 0xffff;
1567 uint16 rem = byte ? a % byte : a;
1569 Memory.FillRAM[0x4214] = (uint8) div;
1570 Memory.FillRAM[0x4215] = div >> 8;
1571 Memory.FillRAM[0x4216] = (uint8) rem;
1572 Memory.FillRAM[0x4217] = rem >> 8;
1576 d = PPU.IRQHBeamPos;
1577 PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xFF00) | byte;
1579 if (PPU.HTimerEnabled && PPU.IRQHBeamPos != d)
1584 d = PPU.IRQHBeamPos;
1585 PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xFF) | ((byte & 1) << 8);
1587 if (PPU.HTimerEnabled && PPU.IRQHBeamPos != d)
1593 d = PPU.IRQVBeamPos;
1594 PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xFF00) | byte;
1596 missing.virq_pos = PPU.IRQVBeamPos;
1598 if (PPU.VTimerEnabled && PPU.IRQVBeamPos != d)
1600 if (PPU.HTimerEnabled)
1604 if (PPU.IRQVBeamPos == CPU.V_Counter)
1605 S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE);
1611 d = PPU.IRQVBeamPos;
1612 PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xFF) | ((byte & 1) << 8);
1614 missing.virq_pos = PPU.IRQVBeamPos;
1616 if (PPU.VTimerEnabled && PPU.IRQVBeamPos != d)
1618 if (PPU.HTimerEnabled)
1622 if (PPU.IRQVBeamPos == CPU.V_Counter)
1623 S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE);
1630 missing.dma_this_frame = byte;
1631 missing.dma_channels = byte;
1633 if ((byte & 0x01) != 0)
1635 if ((byte & 0x02) != 0)
1637 if ((byte & 0x04) != 0)
1639 if ((byte & 0x08) != 0)
1641 if ((byte & 0x10) != 0)
1643 if ((byte & 0x20) != 0)
1645 if ((byte & 0x40) != 0)
1647 if ((byte & 0x80) != 0)
1652 missing.hdma_this_frame |= byte;
1653 missing.hdma_channels |= byte;
1655 if (Settings.DisableHDMA)
1657 Memory.FillRAM[0x420c] = byte;
1662 // Cycle speed 0 - 2.68Mhz, 1 - 3.58Mhz (banks 0x80 +)
1663 if ((byte & 1) != (Memory.FillRAM[0x420d] & 1))
1667 CPU.FastROMSpeed = ONE_CYCLE;
1669 missing.fast_rom = 1;
1673 CPU.FastROMSpeed = SLOW_ONE_CYCLE;
1675 Memory.FixROMSpeed();
1683 // NMI ocurred flag (reset on read or write)
1684 Memory.FillRAM[0x4210] = 0;
1687 // IRQ ocurred flag (reset on read or write)
1688 CLEAR_IRQ_SOURCE(PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
1691 // v-blank, h-blank and joypad being scanned flags (read-only)
1693 // I/O Port (read-only)
1696 // Quotent of divide (read-only)
1699 // Multiply product (read-only)
1709 // Joypad values (read-only)
1720 d = (Address >> 4) & 0x7;
1721 DMA[d].TransferDirection = (byte & 128) != 0 ? 1 : 0;
1722 DMA[d].HDMAIndirectAddressing = (byte & 64) != 0 ? 1 : 0;
1723 DMA[d].AAddressDecrement = (byte & 16) != 0 ? 1 : 0;
1724 DMA[d].AAddressFixed = (byte & 8) != 0 ? 1 : 0;
1725 DMA[d].TransferMode = (byte & 7);
1736 DMA[((Address >> 4) & 0x7)].BAddress = byte;
1747 d = (Address >> 4) & 0x7;
1748 DMA[d].AAddress &= 0xFF00;
1749 DMA[d].AAddress |= byte;
1760 d = (Address >> 4) & 0x7;
1761 DMA[d].AAddress &= 0xFF;
1762 DMA[d].AAddress |= byte << 8;
1773 DMA[((Address >> 4) & 0x7)].ABank = byte;
1784 d = (Address >> 4) & 0x7;
1785 DMA[d].TransferBytes &= 0xFF00;
1786 DMA[d].TransferBytes |= byte;
1787 DMA[d].IndirectAddress &= 0xff00;
1788 DMA[d].IndirectAddress |= byte;
1799 d = (Address >> 4) & 0x7;
1800 DMA[d].TransferBytes &= 0xFF;
1801 DMA[d].TransferBytes |= byte << 8;
1802 DMA[d].IndirectAddress &= 0xff;
1803 DMA[d].IndirectAddress |= byte << 8;
1814 DMA[d = ((Address >> 4) & 0x7)].IndirectBank = byte;
1825 d = (Address >> 4) & 7;
1826 DMA[d].Address &= 0xff00;
1827 DMA[d].Address |= byte;
1838 d = (Address >> 4) & 0x7;
1839 DMA[d].Address &= 0xff;
1840 DMA[d].Address |= byte << 8;
1851 d = (Address >> 4) & 0x7;
1852 DMA[d].LineCount = byte & 0x7f;
1853 DMA[d].Repeat = !(byte & 0x80);
1860 //printf ("%02x->%04x\n", byte, Address);
1867 //printf ("%02x->%04x\n", byte, Address);
1869 S9xSetSDD1MemoryMap(Address - 0x4804, byte & 7);
1873 missing.unknowncpu_write = Address;
1874 if (Settings.TraceUnknownRegisters)
1878 "Unknown register write: $%02X->$%04X\n",
1881 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
1886 Memory.FillRAM[Address] = byte;
1889 /**********************************************************************************************/
1891 /* This function retrieves a CPU/DMA Register */
1892 /**********************************************************************************************/
1893 uint8 S9xGetCPU(uint16 Address)
1897 if (Address < 0x4200)
1900 CPU.Cycles += ONE_CYCLE;
1904 // Secret of the Evermore
1911 if (Memory.FillRAM[0x4016] & 1)
1913 if ((!Settings.SwapJoypads
1914 && IPPU.Controller == SNES_MOUSE_SWAPPED)
1915 || (Settings.SwapJoypads
1916 && IPPU.Controller == SNES_MOUSE))
1918 if (++PPU.MouseSpeed[0] > 2)
1919 PPU.MouseSpeed[0] = 0;
1924 int ind = Settings.SwapJoypads ? 1 : 0;
1925 byte = IPPU.Joypads[ind] >> (PPU.Joypad1ButtonReadPos ^ 15);
1926 PPU.Joypad1ButtonReadPos++;
1931 if (Memory.FillRAM[0x4016] & 1)
1933 // MultiPlayer5 adaptor is only allowed to be plugged into port 2
1934 switch (IPPU.Controller)
1936 case SNES_MULTIPLAYER5 :
1938 case SNES_MOUSE_SWAPPED :
1939 if (Settings.SwapJoypads
1940 && ++PPU.MouseSpeed[0] > 2)
1941 PPU.MouseSpeed[0] = 0;
1945 if (!Settings.SwapJoypads
1946 && ++PPU.MouseSpeed[0] > 2)
1947 PPU.MouseSpeed[0] = 0;
1953 int ind = Settings.SwapJoypads ? 0 : 1;
1955 if (IPPU.Controller == SNES_MULTIPLAYER5)
1957 if (Memory.FillRAM[0x4201] & 0x80)
1961 >> (PPU.Joypad2ButtonReadPos ^ 15))
1963 | (((IPPU.Joypads[2]
1964 >> (PPU.Joypad2ButtonReadPos ^ 15))
1967 PPU.Joypad2ButtonReadPos++;
1974 >> (PPU.Joypad3ButtonReadPos ^ 15))
1976 | (((IPPU.Joypads[4]
1977 >> (PPU.Joypad3ButtonReadPos ^ 15))
1980 PPU.Joypad3ButtonReadPos++;
1986 >> (PPU.Joypad2ButtonReadPos++ ^ 15))
1991 missing.unknowncpu_read = Address;
1992 if (Settings.TraceUnknownRegisters)
1994 sprintf(String, "Unknown register read: $%04X\n", Address);
1995 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
2000 return (Memory.FillRAM[Address]);
2005 // BS Dynami Tracer! needs to be able to check if NMIs are enabled
2006 // already, otherwise the game locks up.
2008 // NMI, h & v timers and joypad reading enable
2009 if (SNESGameFixes.Old_Read0x4200)
2012 CPU.WaitAddress = CPU.PCAtOpcodeStart;
2014 return (REGISTER_4212());
2017 // I/O port (output - write only?)
2020 // Multiplier and multiplicand (write)
2024 // Divisor and dividend (write)
2025 return (Memory.FillRAM[Address]);
2027 return (uint8) (PPU.IRQHBeamPos);
2029 return (PPU.IRQHBeamPos >> 8);
2031 return (uint8) (PPU.IRQVBeamPos);
2033 return (PPU.IRQVBeamPos >> 8);
2035 // General purpose DMA enable
2036 // Super Formation Soccer 95 della Serie A UCC Xaqua requires this
2037 // register should not always return zero.
2038 // .. But Aero 2 waits until this register goes zero..
2039 // Just keep toggling the value for now in the hope that it breaks
2040 // the game out of its wait loop...
2041 Memory.FillRAM[0x420b] = !Memory.FillRAM[0x420b];
2042 return (Memory.FillRAM[0x420b]);
2047 // Cycle speed 0 - 2.68Mhz, 1 - 3.58Mhz (banks 0x80 +)
2048 return (Memory.FillRAM[Address]);
2052 return (Memory.FillRAM[Address]);
2055 CPU.WaitAddress = CPU.PCAtOpcodeStart;
2057 byte = Memory.FillRAM[0x4210];
2058 Memory.FillRAM[0x4210] = 0;
2063 & (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE))
2066 // Super Robot Wars Ex ROM bug requires this.
2067 byte |= CPU.Cycles >= Settings.HBlankStart ? 0x40 : 0;
2068 CLEAR_IRQ_SOURCE(PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
2071 // V-blank, h-blank and joypads being read flags (read-only)
2073 CPU.WaitAddress = CPU.PCAtOpcodeStart;
2075 return (REGISTER_4212());
2080 // Quotient of divide result
2083 // Multiplcation result (for multiply) or remainder of
2085 return (Memory.FillRAM[Address]);
2094 // Joypads 1-4 button and direction state.
2095 return (Memory.FillRAM[Address]);
2105 // DMA direction, address type, fixed flag,
2106 return (Memory.FillRAM[Address]);
2116 return (Memory.FillRAM[Address]);
2126 return (Memory.FillRAM[Address]);
2136 return (Memory.FillRAM[Address]);
2146 return (Memory.FillRAM[Address]);
2156 return (Memory.FillRAM[Address]);
2166 return (Memory.FillRAM[Address]);
2176 return (DMA[(Address >> 4) & 7].IndirectBank);
2186 return (Memory.FillRAM[Address]);
2196 return (Memory.FillRAM[Address]);
2207 int d = (Address & 0x70) >> 4;
2208 if (IPPU.HDMA & (1 << d))
2210 return (DMA[d].LineCount);
2212 return (Memory.FillRAM[Address]);
2216 missing.unknowncpu_read = Address;
2217 if (Settings.TraceUnknownRegisters)
2219 sprintf(String, "Unknown register read: $%04X\n", Address);
2220 S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
2226 return (Memory.FillRAM[Address]);
2232 PPU.BG3Priority = 0;
2235 PPU.VMA.Increment = 1;
2236 PPU.VMA.Address = 0;
2237 PPU.VMA.FullGraphicCount = 0;
2240 for (uint8 B = 0; B != 4; B++)
2242 PPU.BG[B].SCBase = 0;
2243 PPU.BG[B].VOffset = 0;
2244 PPU.BG[B].HOffset = 0;
2245 PPU.BG[B].BGSize = 0;
2246 PPU.BG[B].NameBase = 0;
2247 PPU.BG[B].SCSize = 0;
2249 PPU.ClipCounts[B] = 0;
2250 PPU.ClipWindowOverlapLogic[B] = CLIP_OR;
2251 PPU.ClipWindow1Enable[B] = FALSE;
2252 PPU.ClipWindow2Enable[B] = FALSE;
2253 PPU.ClipWindow1Inside[B] = TRUE;
2254 PPU.ClipWindow2Inside[B] = TRUE;
2257 PPU.ClipCounts[4] = 0;
2258 PPU.ClipCounts[5] = 0;
2259 PPU.ClipWindowOverlapLogic[4] = PPU.ClipWindowOverlapLogic[5] = CLIP_OR;
2260 PPU.ClipWindow1Enable[4] = PPU.ClipWindow1Enable[5] = FALSE;
2261 PPU.ClipWindow2Enable[4] = PPU.ClipWindow2Enable[5] = FALSE;
2262 PPU.ClipWindow1Inside[4] = PPU.ClipWindow1Inside[5] = TRUE;
2263 PPU.ClipWindow2Inside[4] = PPU.ClipWindow2Inside[5] = TRUE;
2267 for (c = 0; c < 256; c++)
2269 IPPU.Red[c] = (c & 7) << 2;
2270 IPPU.Green[c] = ((c >> 3) & 7) << 2;
2271 IPPU.Blue[c] = ((c >> 6) & 2) << 3;
2273 IPPU.Red[c] | (IPPU.Green[c] << 5) | (IPPU.Blue[c] << 10);
2276 PPU.FirstSprite = 0;
2277 PPU.LastSprite = 127;
2278 for (int Sprite = 0; Sprite < 128; Sprite++)
2280 PPU.OBJ[Sprite].HPos = 0;
2281 PPU.OBJ[Sprite].VPos = 0;
2282 PPU.OBJ[Sprite].VFlip = 0;
2283 PPU.OBJ[Sprite].HFlip = 0;
2284 PPU.OBJ[Sprite].Priority = 0;
2285 PPU.OBJ[Sprite].Palette = 0;
2286 PPU.OBJ[Sprite].Name = 0;
2287 PPU.OBJ[Sprite].Size = 0;
2289 PPU.OAMPriorityRotation = 0;
2292 PPU.OAMTileAddress = 0;
2294 PPU.IRQVBeamPos = 0;
2295 PPU.IRQHBeamPos = 0;
2296 PPU.VBeamPosLatched = 0;
2297 PPU.HBeamPosLatched = 0;
2301 PPU.HVBeamCounterLatched = 0;
2303 PPU.MatrixA = PPU.MatrixB = PPU.MatrixC = PPU.MatrixD = 0;
2304 PPU.CentreX = PPU.CentreY = 0;
2305 PPU.Joypad1ButtonReadPos = 0;
2306 PPU.Joypad2ButtonReadPos = 0;
2307 PPU.Joypad3ButtonReadPos = 0;
2310 PPU.FixedColourRed = PPU.FixedColourGreen = PPU.FixedColourBlue = 0;
2311 PPU.SavedOAMAddr = 0;
2312 PPU.ScreenHeight = SNES_HEIGHT;
2315 PPU.ForcedBlanking = TRUE;
2316 PPU.OBJThroughMain = FALSE;
2317 PPU.OBJThroughSub = FALSE;
2318 PPU.OBJSizeSelect = 0;
2319 PPU.OBJNameSelect = 0;
2320 PPU.OBJNameBase = 0;
2321 PPU.OBJAddition = FALSE;
2322 PPU.OAMReadFlip = 0;
2323 ZeroMemory(PPU.OAMData, 512 + 32);
2325 PPU.VTimerEnabled = FALSE;
2326 PPU.HTimerEnabled = FALSE;
2327 PPU.HTimerPosition = Settings.H_Max + 1;
2329 PPU.BGMosaic[0] = PPU.BGMosaic[1] = FALSE;
2330 PPU.BGMosaic[2] = PPU.BGMosaic[3] = FALSE;
2331 PPU.Mode7HFlip = FALSE;
2332 PPU.Mode7VFlip = FALSE;
2333 PPU.Mode7Repeat = 0;
2334 PPU.Window1Left = 1;
2335 PPU.Window1Right = 0;
2336 PPU.Window2Left = 1;
2337 PPU.Window2Right = 0;
2338 PPU.RecomputeClipWindows = TRUE;
2340 PPU.Need16x8Mulitply = FALSE;
2341 PPU.MouseSpeed[0] = PPU.MouseSpeed[1] = 0;
2343 IPPU.ColorsChanged = TRUE;
2345 IPPU.HDMAStarted = FALSE;
2346 IPPU.MaxBrightness = 0;
2347 IPPU.LatchedBlanking = 0;
2348 IPPU.OBJChanged = TRUE;
2349 IPPU.RenderThisFrame = TRUE;
2350 IPPU.DirectColourMapsNeedRebuild = TRUE;
2351 IPPU.FrameCount = 0;
2352 IPPU.RenderedFramesCount = 0;
2353 IPPU.DisplayedRenderedFrameCount = 0;
2354 IPPU.SkippedFrames = 0;
2356 ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES);
2357 ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES);
2358 ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES);
2359 IPPU.FirstVRAMRead = FALSE;
2360 IPPU.LatchedInterlace = FALSE;
2361 IPPU.DoubleWidthPixels = FALSE;
2362 IPPU.RenderedScreenWidth = SNES_WIDTH;
2363 IPPU.RenderedScreenHeight = SNES_HEIGHT;
2365 for (c = 0; c < 256; c++)
2366 IPPU.ScreenColors[c] = c;
2367 S9xFixColourBrightness();
2368 IPPU.PreviousLine = IPPU.CurrentLine = 0;
2369 IPPU.Joypads[0] = IPPU.Joypads[1] = IPPU.Joypads[2] = 0;
2370 IPPU.Joypads[3] = IPPU.Joypads[4] = 0;
2371 IPPU.SuperScope = 0;
2372 IPPU.Mouse[0] = IPPU.Mouse[1] = 0;
2373 IPPU.PrevMouseX[0] = IPPU.PrevMouseX[1] = 256 / 2;
2374 IPPU.PrevMouseY[0] = IPPU.PrevMouseY[1] = 224 / 2;
2376 if (Settings.ControllerOption == 0)
2377 IPPU.Controller = SNES_MAX_CONTROLLER_OPTIONS - 1;
2379 IPPU.Controller = Settings.ControllerOption - 1;
2380 S9xNextController();
2382 for (c = 0; c < 2; c++)
2383 memset(& IPPU.Clip[c], 0, sizeof(struct ClipData));
2385 if (Settings.MouseMaster)
2390 for (c = 0; c < 0x8000; c += 0x100)
2391 memset(& Memory.FillRAM[c], c >> 8, 0x100);
2393 ZeroMemory(& Memory.FillRAM[0x2100], 0x100);
2394 ZeroMemory(& Memory.FillRAM[0x4200], 0x100);
2395 ZeroMemory(& Memory.FillRAM[0x4000], 0x100);
2396 // For BS Suttehakkun 2...
2397 ZeroMemory(& Memory.FillRAM[0x1000], 0x1000);
2400 void S9xProcessMouse(int which1)
2405 if ((IPPU.Controller == SNES_MOUSE
2406 || IPPU.Controller == SNES_MOUSE_SWAPPED)
2407 && S9xReadMousePosition(which1, x, y, buttons))
2409 int delta_x, delta_y;
2410 #define MOUSE_SIGNATURE 0x1
2411 IPPU.Mouse[which1] =
2413 | (PPU.MouseSpeed[which1] << 4)
2414 | ((buttons & 1) << 6)
2415 | ((buttons & 2) << 6);
2417 delta_x = x - IPPU.PrevMouseX[which1];
2418 delta_y = y - IPPU.PrevMouseY[which1];
2423 IPPU.PrevMouseX[which1] += 63;
2425 else if (delta_x < -63)
2428 IPPU.PrevMouseX[which1] -= 63;
2431 IPPU.PrevMouseX[which1] = x;
2436 IPPU.PrevMouseY[which1] += 63;
2438 else if (delta_y < -63)
2441 IPPU.PrevMouseY[which1] -= 63;
2444 IPPU.PrevMouseY[which1] = y;
2449 IPPU.Mouse[which1] |= (delta_x | 0x80) << 16;
2452 IPPU.Mouse[which1] |= delta_x << 16;
2457 IPPU.Mouse[which1] |= (delta_y | 0x80) << 24;
2460 IPPU.Mouse[which1] |= delta_y << 24;
2462 if (IPPU.Controller == SNES_MOUSE_SWAPPED)
2463 IPPU.Joypads[0] = IPPU.Mouse[which1];
2465 IPPU.Joypads[1] = IPPU.Mouse[which1];
2469 void ProcessSuperScope()
2474 if (IPPU.Controller == SNES_SUPERSCOPE
2475 && S9xReadSuperScopePosition(x, y, buttons))
2477 #define SUPERSCOPE_SIGNATURE 0x00ff
2481 SUPERSCOPE_SIGNATURE
2482 | ((buttons & 1) << (7 + 8))
2483 | ((buttons & 2) << (5 + 8))
2484 | ((buttons & 4) << (3 + 8))
2485 | ((buttons & 8) << (1 + 8));
2490 if (y > PPU.ScreenHeight - 1)
2491 y = PPU.ScreenHeight - 1;
2495 PPU.VBeamPosLatched = (uint16) (y + 1);
2496 PPU.HBeamPosLatched = (uint16) x;
2497 PPU.HVBeamCounterLatched = TRUE;
2498 Memory.FillRAM[0x213F] |= 0x40;
2499 IPPU.Joypads[1] = scope;
2503 void S9xNextController()
2505 switch (IPPU.Controller)
2507 case SNES_MULTIPLAYER5 :
2508 IPPU.Controller = SNES_JOYPAD;
2511 if (Settings.MouseMaster)
2513 IPPU.Controller = SNES_MOUSE_SWAPPED;
2516 case SNES_MOUSE_SWAPPED :
2517 if (Settings.MouseMaster)
2519 IPPU.Controller = SNES_MOUSE;
2523 if (Settings.SuperScopeMaster)
2525 IPPU.Controller = SNES_SUPERSCOPE;
2528 case SNES_SUPERSCOPE :
2529 if (Settings.MultiPlayer5Master)
2531 IPPU.Controller = SNES_MULTIPLAYER5;
2535 IPPU.Controller = SNES_JOYPAD;
2540 void S9xUpdateJoypads()
2547 for (i = 0; i < 5; i++)
2550 IPPU.Joypads[i] = S9xReadJoypad(i);
2551 if (IPPU.Joypads[i] & SNES_LEFT_MASK)
2552 IPPU.Joypads[i] &= ~SNES_RIGHT_MASK;
2553 if (IPPU.Joypads[i] & SNES_UP_MASK)
2554 IPPU.Joypads[i] &= ~SNES_DOWN_MASK;
2557 //touhaiden controller Fix
2558 if (SNESGameFixes.TouhaidenControllerFix
2559 && (IPPU.Controller == SNES_JOYPAD
2560 || IPPU.Controller == SNES_MULTIPLAYER5))
2562 for (i = 0; i < 5; i++)
2564 if (IPPU.Joypads[i])
2565 IPPU.Joypads[i] |= 0xffff0000;
2569 // Read mouse position if enabled
2570 if (Settings.MouseMaster)
2572 for (i = 0; i < 2; i++)
2576 // Read SuperScope if enabled
2577 if (Settings.SuperScopeMaster)
2578 ProcessSuperScope();
2580 if (Memory.FillRAM[0x4200] & 1)
2582 PPU.Joypad1ButtonReadPos = 16;
2583 if (Memory.FillRAM[0x4201] & 0x80)
2585 PPU.Joypad2ButtonReadPos = 16;
2586 PPU.Joypad3ButtonReadPos = 0;
2590 PPU.Joypad2ButtonReadPos = 0;
2591 PPU.Joypad3ButtonReadPos = 16;
2593 int ind = Settings.SwapJoypads ? 1 : 0;
2595 Memory.FillRAM[0x4218] = (uint8) IPPU.Joypads[ind];
2596 Memory.FillRAM[0x4219] = (uint8) (IPPU.Joypads[ind] >> 8);
2597 Memory.FillRAM[0x421a] = (uint8) IPPU.Joypads[ind ^ 1];
2598 Memory.FillRAM[0x421b] = (uint8) (IPPU.Joypads[ind ^ 1] >> 8);
2599 if (Memory.FillRAM[0x4201] & 0x80)
2601 Memory.FillRAM[0x421c] = (uint8) IPPU.Joypads[ind];
2602 Memory.FillRAM[0x421d] = (uint8) (IPPU.Joypads[ind] >> 8);
2603 Memory.FillRAM[0x421e] = (uint8) IPPU.Joypads[2];
2604 Memory.FillRAM[0x421f] = (uint8) (IPPU.Joypads[2] >> 8);
2608 Memory.FillRAM[0x421c] = (uint8) IPPU.Joypads[3];
2609 Memory.FillRAM[0x421d] = (uint8) (IPPU.Joypads[3] >> 8);
2610 Memory.FillRAM[0x421e] = (uint8) IPPU.Joypads[4];
2611 Memory.FillRAM[0x421f] = (uint8) (IPPU.Joypads[4] >> 8);
2617 void S9xSuperFXExec()
2620 if (Settings.SuperFX)
2622 if ((Memory.FillRAM[0x3000 + GSU_SFR] & FLG_G)
2623 && (Memory.FillRAM[0x3000 + GSU_SCMR] & 0x18) == 0x18)
2625 if (!Settings.WinterGold)
2627 else FxEmulate((Memory.FillRAM[0x3000 + GSU_CLSR] & 1) ? 700 : 350);
2628 int GSUStatus = Memory.FillRAM[0x3000
2629 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8);
2630 if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ)
2632 // Trigger a GSU IRQ.
2633 S9xSetIRQ(GSU_IRQ_SOURCE);
2638 uint32 tmp = (Memory.FillRAM[0x3034] << 16)
2639 + * (uint16 *) & Memory.FillRAM[0x301e];
2641 if (tmp == 0x018428)
2644 & SRAM[0x0064] = 0xbc00;
2645 * (uint16 *) & SRAM[0x002c] = 0x8000;
2648 if (tmp == -1) //0x018428) //0x01bfc3) //0x09edaf) //-1) //0x57edaf)
2650 while (Memory.FillRAM[0x3030] & 0x20)
2661 /* Make the string 32 chars long */
2662 if (strlen(tmp) < 32)
2664 memset(& tmp[strlen(tmp)], ' ', 32 - strlen(tmp));
2668 /* Copy registers (so we can see if any changed) */
2669 vColr = FxGetColorRegister();
2670 vPor = FxGetPlotOptionRegister();
2671 memcpy(avReg, SuperFX.pvRegisters, 0x40);
2673 /* Print the pipe string */
2676 /* Execute the instruction in the pipe */
2678 vError = FxEmulate(1);
2680 /* Check if any registers changed (and print them if they did) */
2681 for (i = 0; i < 16; i++)
2685 ((uint32) avReg[i * 2])
2686 | (((uint32) avReg[(i * 2) + 1]) << 8);
2688 (uint32) (SuperFX.pvRegisters[i * 2])
2689 | (((uint32) SuperFX.pvRegisters[(i * 2) + 1]) << 8);
2691 a = OPCODE_BYTES(vPipe);
2692 if (((r1 + a) & 0xffff) != r2)
2693 printf(" r%d=$%04x", i, r2);
2698 ((uint32) avReg[0x30]) | (((uint32) avReg[0x31]) << 8);
2700 (uint32) (SuperFX.pvRegisters[0x30])
2701 | (((uint32) SuperFX.pvRegisters[0x31]) << 8);
2702 if ((r1 & (1 << 1)) != (r2 & (1 << 1)))
2703 printf(" Z=%d", (uint32) (!!(r2 & (1 << 1))));
2704 if ((r1 & (1 << 2)) != (r2 & (1 << 2)))
2705 printf(" CY=%d", (uint32) (!!(r2 & (1 << 2))));
2706 if ((r1 & (1 << 3)) != (r2 & (1 << 3)))
2707 printf(" S=%d", (uint32) (!!(r2 & (1 << 3))));
2708 if ((r1 & (1 << 4)) != (r2 & (1 << 4)))
2709 printf(" OV=%d", (uint32) (!!(r2 & (1 << 4))));
2710 if ((r1 & (1 << 5)) != (r2 & (1 << 5)))
2711 printf(" G=%d", (uint32) (!!(r2 & (1 << 5))));
2712 if ((r1 & (1 << 6)) != (r2 & (1 << 6)))
2713 printf(" R=%d", (uint32) (!!(r2 & (1 << 6))));
2714 if ((r1 & (1 << 8)) != (r2 & (1 << 8)))
2715 printf(" ALT1=%d", (uint32) (!!(r2 & (1 << 8))));
2716 if ((r1 & (1 << 9)) != (r2 & (1 << 9)))
2717 printf(" ALT2=%d", (uint32) (!!(r2 & (1 << 9))));
2718 if ((r1 & (1 << 10)) != (r2 & (1 << 10)))
2719 printf(" IL=%d", (uint32) (!!(r2 & (1 << 10))));
2720 if ((r1 & (1 << 11)) != (r2 & (1 << 11)))
2721 printf(" IH=%d", (uint32) (!!(r2 & (1 << 11))));
2722 if ((r1 & (1 << 12)) != (r2 & (1 << 12)))
2723 printf(" B=%d", (uint32) (!!(r2 & (1 << 12))));
2724 if ((r1 & (1 << 15)) != (r2 & (1 << 15)))
2725 printf(" IRQ=%d", (uint32) (!!(r2 & (1 << 15))));
2729 uint32 r1 = ((uint32) avReg[0x34]);
2730 uint32 r2 = (uint32) (SuperFX.pvRegisters[0x34]);
2732 printf(" PBR=$%02x", r2);
2736 uint32 r1 = ((uint32) avReg[0x36]);
2737 uint32 r2 = (uint32) (SuperFX.pvRegisters[0x36]);
2739 printf(" ROMBR=$%02x", r2);
2743 uint32 r1 = ((uint32) avReg[0x3c]);
2744 uint32 r2 = (uint32) (SuperFX.pvRegisters[0x3c]);
2746 printf(" RAMBR=$%02x", r2);
2751 ((uint32) avReg[0x3e]) | (((uint32) avReg[0x3f]) << 8);
2753 (uint32) (SuperFX.pvRegisters[0x3e])
2754 | (((uint32) SuperFX.pvRegisters[0x3f]) << 8);
2756 printf(" CBR=$%04x", r2);
2760 if (vColr != FxGetColorRegister())
2761 printf(" COLR=$%02x", FxGetColorRegister());
2765 if (vPor != FxGetPlotOptionRegister())
2766 printf(" POR=$%02x", FxGetPlotOptionRegister());
2775 (Memory.FillRAM[0x3034] << 16)
2776 + (Memory.FillRAM[0x301f] << 8)
2777 + (Memory.FillRAM[0x301e] << 0);
2779 printf("%06x: %d\n", t, FxEmulate(2000000));
2780 // FxEmulate (2000000);
2783 if (!(CPU.Flags & TRACE_FLAG))
2785 static int z = 1; if (z == 0)
2787 extern FILE * trace;
2788 CPU.Flags |= TRACE_FLAG;
2789 trace = fopen("trace.log", "wb");
2795 Memory.FillRAM[0x3030] &= ~0x20;
2796 if (Memory.FillRAM[0x3031] & 0x80)
2798 S9xSetIRQ(GSU_IRQ_SOURCE);