apu/bapu/smp/core/op_pc.cpp000664 001750 001750 00000021510 12720446475 016763 0ustar00sergiosergio000000 000000 case 0x2f: { rd = op_readpc(); if(0)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xf0: { rd = op_readpc(); if(!regs.p.z)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xd0: { rd = op_readpc(); if(regs.p.z)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xb0: { rd = op_readpc(); if(!regs.p.c)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x90: { rd = op_readpc(); if(regs.p.c)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x70: { rd = op_readpc(); if(!regs.p.v)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x50: { rd = op_readpc(); if(regs.p.v)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x30: { rd = op_readpc(); if(!regs.p.n)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x10: { rd = op_readpc(); if(regs.p.n)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x03: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x01) != 0x01)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x13: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x01) == 0x01)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x23: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x02) != 0x02)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x33: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x02) == 0x02)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x43: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x04) != 0x04)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x53: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x04) == 0x04)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x63: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x08) != 0x08)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x73: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x08) == 0x08)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x83: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x10) != 0x10)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x93: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x10) == 0x10)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xa3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x20) != 0x20)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xb3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x20) == 0x20)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xc3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x40) != 0x40)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xd3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x40) == 0x40)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xe3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x80) != 0x80)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xf3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x80) == 0x80)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x2e: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if(regs.a == sp)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xde: { dp = op_readpc(); op_io(); sp = op_readdp(dp + regs.x); rd = op_readpc(); op_io(); if(regs.a == sp)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x6e: { dp = op_readpc(); wr = op_readdp(dp); op_writedp(dp, --wr); rd = op_readpc(); if(wr == 0x00)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0xfe: { rd = op_readpc(); op_io(); regs.y--; op_io(); if(regs.y == 0x00)break; op_io(); op_io(); regs.pc += (int8)rd; break; } case 0x5f: { rd = op_readpc(); rd |= op_readpc() << 8; regs.pc = rd; break; } case 0x1f: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.x; rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; regs.pc = rd; break; } case 0x3f: { rd = op_readpc(); rd |= op_readpc() << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x4f: { rd = op_readpc(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = 0xff00 | rd; break; } case 0x01: { dp = 0xffde - (0 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x11: { dp = 0xffde - (1 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x21: { dp = 0xffde - (2 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x31: { dp = 0xffde - (3 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x41: { dp = 0xffde - (4 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x51: { dp = 0xffde - (5 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x61: { dp = 0xffde - (6 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x71: { dp = 0xffde - (7 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x81: { dp = 0xffde - (8 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x91: { dp = 0xffde - (9 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xa1: { dp = 0xffde - (10 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xb1: { dp = 0xffde - (11 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xc1: { dp = 0xffde - (12 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xd1: { dp = 0xffde - (13 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xe1: { dp = 0xffde - (14 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xf1: { dp = 0xffde - (15 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(); op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x0f: { rd = op_readaddr(0xffde); rd |= op_readaddr(0xffdf) << 8; op_io(); op_io(); op_writestack(regs.pc >> 8); op_writestack(regs.pc); op_writestack(regs.p); regs.pc = rd; regs.p.b = 1; regs.p.i = 0; break; } case 0x6f: { rd = op_readstack(); rd |= op_readstack() << 8; op_io(); op_io(); regs.pc = rd; break; } case 0x7f: { regs.p = op_readstack(); rd = op_readstack(); rd |= op_readstack() << 8; op_io(); op_io(); regs.pc = rd; break; } cpuops.cpp000664 001750 001750 00000343601 12720446475 013741 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "apu/apu.h" // for "Magic WDM" features #ifdef DEBUGGER #include "snapshot.h" #include "display.h" #include "debug.h" #include "missing.h" #endif #ifdef SA1_OPCODES #define AddCycles(n) { SA1.Cycles += (n); } #else #define AddCycles(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } #endif #include "cpuaddr.h" #include "cpuops.h" #include "cpumacro.h" /* ADC ********************************************************************* */ static void Op69M1 (void) { ADC(Immediate8(READ)); } static void Op69M0 (void) { ADC(Immediate16(READ)); } static void Op69Slow (void) { if (CheckMemory()) ADC(Immediate8Slow(READ)); else ADC(Immediate16Slow(READ)); } rOP8 (65M1, Direct, WRAP_BANK, ADC) rOP16(65M0, Direct, WRAP_BANK, ADC) rOPM (65Slow, DirectSlow, WRAP_BANK, ADC) rOP8 (75E1, DirectIndexedXE1, WRAP_BANK, ADC) rOP8 (75E0M1, DirectIndexedXE0, WRAP_BANK, ADC) rOP16(75E0M0, DirectIndexedXE0, WRAP_BANK, ADC) rOPM (75Slow, DirectIndexedXSlow, WRAP_BANK, ADC) rOP8 (72E1, DirectIndirectE1, WRAP_NONE, ADC) rOP8 (72E0M1, DirectIndirectE0, WRAP_NONE, ADC) rOP16(72E0M0, DirectIndirectE0, WRAP_NONE, ADC) rOPM (72Slow, DirectIndirectSlow, WRAP_NONE, ADC) rOP8 (61E1, DirectIndexedIndirectE1, WRAP_NONE, ADC) rOP8 (61E0M1, DirectIndexedIndirectE0, WRAP_NONE, ADC) rOP16(61E0M0, DirectIndexedIndirectE0, WRAP_NONE, ADC) rOPM (61Slow, DirectIndexedIndirectSlow, WRAP_NONE, ADC) rOP8 (71E1, DirectIndirectIndexedE1, WRAP_NONE, ADC) rOP8 (71E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC) rOP16(71E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC) rOP8 (71E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC) rOP16(71E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC) rOPM (71Slow, DirectIndirectIndexedSlow, WRAP_NONE, ADC) rOP8 (67M1, DirectIndirectLong, WRAP_NONE, ADC) rOP16(67M0, DirectIndirectLong, WRAP_NONE, ADC) rOPM (67Slow, DirectIndirectLongSlow, WRAP_NONE, ADC) rOP8 (77M1, DirectIndirectIndexedLong, WRAP_NONE, ADC) rOP16(77M0, DirectIndirectIndexedLong, WRAP_NONE, ADC) rOPM (77Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ADC) rOP8 (6DM1, Absolute, WRAP_NONE, ADC) rOP16(6DM0, Absolute, WRAP_NONE, ADC) rOPM (6DSlow, AbsoluteSlow, WRAP_NONE, ADC) rOP8 (7DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ADC) rOP16(7DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ADC) rOP8 (7DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ADC) rOP16(7DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ADC) rOPM (7DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ADC) rOP8 (79M1X1, AbsoluteIndexedYX1, WRAP_NONE, ADC) rOP16(79M0X1, AbsoluteIndexedYX1, WRAP_NONE, ADC) rOP8 (79M1X0, AbsoluteIndexedYX0, WRAP_NONE, ADC) rOP16(79M0X0, AbsoluteIndexedYX0, WRAP_NONE, ADC) rOPM (79Slow, AbsoluteIndexedYSlow, WRAP_NONE, ADC) rOP8 (6FM1, AbsoluteLong, WRAP_NONE, ADC) rOP16(6FM0, AbsoluteLong, WRAP_NONE, ADC) rOPM (6FSlow, AbsoluteLongSlow, WRAP_NONE, ADC) rOP8 (7FM1, AbsoluteLongIndexedX, WRAP_NONE, ADC) rOP16(7FM0, AbsoluteLongIndexedX, WRAP_NONE, ADC) rOPM (7FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ADC) rOP8 (63M1, StackRelative, WRAP_NONE, ADC) rOP16(63M0, StackRelative, WRAP_NONE, ADC) rOPM (63Slow, StackRelativeSlow, WRAP_NONE, ADC) rOP8 (73M1, StackRelativeIndirectIndexed, WRAP_NONE, ADC) rOP16(73M0, StackRelativeIndirectIndexed, WRAP_NONE, ADC) rOPM (73Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ADC) /* AND ********************************************************************* */ static void Op29M1 (void) { Registers.AL &= Immediate8(READ); SetZN(Registers.AL); } static void Op29M0 (void) { Registers.A.W &= Immediate16(READ); SetZN(Registers.A.W); } static void Op29Slow (void) { if (CheckMemory()) { Registers.AL &= Immediate8Slow(READ); SetZN(Registers.AL); } else { Registers.A.W &= Immediate16Slow(READ); SetZN(Registers.A.W); } } rOP8 (25M1, Direct, WRAP_BANK, AND) rOP16(25M0, Direct, WRAP_BANK, AND) rOPM (25Slow, DirectSlow, WRAP_BANK, AND) rOP8 (35E1, DirectIndexedXE1, WRAP_BANK, AND) rOP8 (35E0M1, DirectIndexedXE0, WRAP_BANK, AND) rOP16(35E0M0, DirectIndexedXE0, WRAP_BANK, AND) rOPM (35Slow, DirectIndexedXSlow, WRAP_BANK, AND) rOP8 (32E1, DirectIndirectE1, WRAP_NONE, AND) rOP8 (32E0M1, DirectIndirectE0, WRAP_NONE, AND) rOP16(32E0M0, DirectIndirectE0, WRAP_NONE, AND) rOPM (32Slow, DirectIndirectSlow, WRAP_NONE, AND) rOP8 (21E1, DirectIndexedIndirectE1, WRAP_NONE, AND) rOP8 (21E0M1, DirectIndexedIndirectE0, WRAP_NONE, AND) rOP16(21E0M0, DirectIndexedIndirectE0, WRAP_NONE, AND) rOPM (21Slow, DirectIndexedIndirectSlow, WRAP_NONE, AND) rOP8 (31E1, DirectIndirectIndexedE1, WRAP_NONE, AND) rOP8 (31E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND) rOP16(31E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND) rOP8 (31E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND) rOP16(31E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND) rOPM (31Slow, DirectIndirectIndexedSlow, WRAP_NONE, AND) rOP8 (27M1, DirectIndirectLong, WRAP_NONE, AND) rOP16(27M0, DirectIndirectLong, WRAP_NONE, AND) rOPM (27Slow, DirectIndirectLongSlow, WRAP_NONE, AND) rOP8 (37M1, DirectIndirectIndexedLong, WRAP_NONE, AND) rOP16(37M0, DirectIndirectIndexedLong, WRAP_NONE, AND) rOPM (37Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, AND) rOP8 (2DM1, Absolute, WRAP_NONE, AND) rOP16(2DM0, Absolute, WRAP_NONE, AND) rOPM (2DSlow, AbsoluteSlow, WRAP_NONE, AND) rOP8 (3DM1X1, AbsoluteIndexedXX1, WRAP_NONE, AND) rOP16(3DM0X1, AbsoluteIndexedXX1, WRAP_NONE, AND) rOP8 (3DM1X0, AbsoluteIndexedXX0, WRAP_NONE, AND) rOP16(3DM0X0, AbsoluteIndexedXX0, WRAP_NONE, AND) rOPM (3DSlow, AbsoluteIndexedXSlow, WRAP_NONE, AND) rOP8 (39M1X1, AbsoluteIndexedYX1, WRAP_NONE, AND) rOP16(39M0X1, AbsoluteIndexedYX1, WRAP_NONE, AND) rOP8 (39M1X0, AbsoluteIndexedYX0, WRAP_NONE, AND) rOP16(39M0X0, AbsoluteIndexedYX0, WRAP_NONE, AND) rOPM (39Slow, AbsoluteIndexedYSlow, WRAP_NONE, AND) rOP8 (2FM1, AbsoluteLong, WRAP_NONE, AND) rOP16(2FM0, AbsoluteLong, WRAP_NONE, AND) rOPM (2FSlow, AbsoluteLongSlow, WRAP_NONE, AND) rOP8 (3FM1, AbsoluteLongIndexedX, WRAP_NONE, AND) rOP16(3FM0, AbsoluteLongIndexedX, WRAP_NONE, AND) rOPM (3FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, AND) rOP8 (23M1, StackRelative, WRAP_NONE, AND) rOP16(23M0, StackRelative, WRAP_NONE, AND) rOPM (23Slow, StackRelativeSlow, WRAP_NONE, AND) rOP8 (33M1, StackRelativeIndirectIndexed, WRAP_NONE, AND) rOP16(33M0, StackRelativeIndirectIndexed, WRAP_NONE, AND) rOPM (33Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, AND) /* ASL ********************************************************************* */ static void Op0AM1 (void) { AddCycles(ONE_CYCLE); ICPU._Carry = (Registers.AL & 0x80) != 0; Registers.AL <<= 1; SetZN(Registers.AL); } static void Op0AM0 (void) { AddCycles(ONE_CYCLE); ICPU._Carry = (Registers.AH & 0x80) != 0; Registers.A.W <<= 1; SetZN(Registers.A.W); } static void Op0ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { ICPU._Carry = (Registers.AL & 0x80) != 0; Registers.AL <<= 1; SetZN(Registers.AL); } else { ICPU._Carry = (Registers.AH & 0x80) != 0; Registers.A.W <<= 1; SetZN(Registers.A.W); } } mOP8 (06M1, Direct, WRAP_BANK, ASL) mOP16(06M0, Direct, WRAP_BANK, ASL) mOPM (06Slow, DirectSlow, WRAP_BANK, ASL) mOP8 (16E1, DirectIndexedXE1, WRAP_BANK, ASL) mOP8 (16E0M1, DirectIndexedXE0, WRAP_BANK, ASL) mOP16(16E0M0, DirectIndexedXE0, WRAP_BANK, ASL) mOPM (16Slow, DirectIndexedXSlow, WRAP_BANK, ASL) mOP8 (0EM1, Absolute, WRAP_NONE, ASL) mOP16(0EM0, Absolute, WRAP_NONE, ASL) mOPM (0ESlow, AbsoluteSlow, WRAP_NONE, ASL) mOP8 (1EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ASL) mOP16(1EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ASL) mOP8 (1EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ASL) mOP16(1EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ASL) mOPM (1ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ASL) /* BIT ********************************************************************* */ static void Op89M1 (void) { ICPU._Zero = Registers.AL & Immediate8(READ); } static void Op89M0 (void) { ICPU._Zero = (Registers.A.W & Immediate16(READ)) != 0; } static void Op89Slow (void) { if (CheckMemory()) ICPU._Zero = Registers.AL & Immediate8Slow(READ); else ICPU._Zero = (Registers.A.W & Immediate16Slow(READ)) != 0; } rOP8 (24M1, Direct, WRAP_BANK, BIT) rOP16(24M0, Direct, WRAP_BANK, BIT) rOPM (24Slow, DirectSlow, WRAP_BANK, BIT) rOP8 (34E1, DirectIndexedXE1, WRAP_BANK, BIT) rOP8 (34E0M1, DirectIndexedXE0, WRAP_BANK, BIT) rOP16(34E0M0, DirectIndexedXE0, WRAP_BANK, BIT) rOPM (34Slow, DirectIndexedXSlow, WRAP_BANK, BIT) rOP8 (2CM1, Absolute, WRAP_NONE, BIT) rOP16(2CM0, Absolute, WRAP_NONE, BIT) rOPM (2CSlow, AbsoluteSlow, WRAP_NONE, BIT) rOP8 (3CM1X1, AbsoluteIndexedXX1, WRAP_NONE, BIT) rOP16(3CM0X1, AbsoluteIndexedXX1, WRAP_NONE, BIT) rOP8 (3CM1X0, AbsoluteIndexedXX0, WRAP_NONE, BIT) rOP16(3CM0X0, AbsoluteIndexedXX0, WRAP_NONE, BIT) rOPM (3CSlow, AbsoluteIndexedXSlow, WRAP_NONE, BIT) /* CMP ********************************************************************* */ static void OpC9M1 (void) { int16 Int16 = (int16) Registers.AL - (int16) Immediate8(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static void OpC9M0 (void) { int32 Int32 = (int32) Registers.A.W - (int32) Immediate16(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static void OpC9Slow (void) { if (CheckMemory()) { int16 Int16 = (int16) Registers.AL - (int16) Immediate8Slow(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } else { int32 Int32 = (int32) Registers.A.W - (int32) Immediate16Slow(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } } rOP8 (C5M1, Direct, WRAP_BANK, CMP) rOP16(C5M0, Direct, WRAP_BANK, CMP) rOPM (C5Slow, DirectSlow, WRAP_BANK, CMP) rOP8 (D5E1, DirectIndexedXE1, WRAP_BANK, CMP) rOP8 (D5E0M1, DirectIndexedXE0, WRAP_BANK, CMP) rOP16(D5E0M0, DirectIndexedXE0, WRAP_BANK, CMP) rOPM (D5Slow, DirectIndexedXSlow, WRAP_BANK, CMP) rOP8 (D2E1, DirectIndirectE1, WRAP_NONE, CMP) rOP8 (D2E0M1, DirectIndirectE0, WRAP_NONE, CMP) rOP16(D2E0M0, DirectIndirectE0, WRAP_NONE, CMP) rOPM (D2Slow, DirectIndirectSlow, WRAP_NONE, CMP) rOP8 (C1E1, DirectIndexedIndirectE1, WRAP_NONE, CMP) rOP8 (C1E0M1, DirectIndexedIndirectE0, WRAP_NONE, CMP) rOP16(C1E0M0, DirectIndexedIndirectE0, WRAP_NONE, CMP) rOPM (C1Slow, DirectIndexedIndirectSlow, WRAP_NONE, CMP) rOP8 (D1E1, DirectIndirectIndexedE1, WRAP_NONE, CMP) rOP8 (D1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP) rOP16(D1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP) rOP8 (D1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP) rOP16(D1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP) rOPM (D1Slow, DirectIndirectIndexedSlow, WRAP_NONE, CMP) rOP8 (C7M1, DirectIndirectLong, WRAP_NONE, CMP) rOP16(C7M0, DirectIndirectLong, WRAP_NONE, CMP) rOPM (C7Slow, DirectIndirectLongSlow, WRAP_NONE, CMP) rOP8 (D7M1, DirectIndirectIndexedLong, WRAP_NONE, CMP) rOP16(D7M0, DirectIndirectIndexedLong, WRAP_NONE, CMP) rOPM (D7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, CMP) rOP8 (CDM1, Absolute, WRAP_NONE, CMP) rOP16(CDM0, Absolute, WRAP_NONE, CMP) rOPM (CDSlow, AbsoluteSlow, WRAP_NONE, CMP) rOP8 (DDM1X1, AbsoluteIndexedXX1, WRAP_NONE, CMP) rOP16(DDM0X1, AbsoluteIndexedXX1, WRAP_NONE, CMP) rOP8 (DDM1X0, AbsoluteIndexedXX0, WRAP_NONE, CMP) rOP16(DDM0X0, AbsoluteIndexedXX0, WRAP_NONE, CMP) rOPM (DDSlow, AbsoluteIndexedXSlow, WRAP_NONE, CMP) rOP8 (D9M1X1, AbsoluteIndexedYX1, WRAP_NONE, CMP) rOP16(D9M0X1, AbsoluteIndexedYX1, WRAP_NONE, CMP) rOP8 (D9M1X0, AbsoluteIndexedYX0, WRAP_NONE, CMP) rOP16(D9M0X0, AbsoluteIndexedYX0, WRAP_NONE, CMP) rOPM (D9Slow, AbsoluteIndexedYSlow, WRAP_NONE, CMP) rOP8 (CFM1, AbsoluteLong, WRAP_NONE, CMP) rOP16(CFM0, AbsoluteLong, WRAP_NONE, CMP) rOPM (CFSlow, AbsoluteLongSlow, WRAP_NONE, CMP) rOP8 (DFM1, AbsoluteLongIndexedX, WRAP_NONE, CMP) rOP16(DFM0, AbsoluteLongIndexedX, WRAP_NONE, CMP) rOPM (DFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, CMP) rOP8 (C3M1, StackRelative, WRAP_NONE, CMP) rOP16(C3M0, StackRelative, WRAP_NONE, CMP) rOPM (C3Slow, StackRelativeSlow, WRAP_NONE, CMP) rOP8 (D3M1, StackRelativeIndirectIndexed, WRAP_NONE, CMP) rOP16(D3M0, StackRelativeIndirectIndexed, WRAP_NONE, CMP) rOPM (D3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, CMP) /* CPX ********************************************************************* */ static void OpE0X1 (void) { int16 Int16 = (int16) Registers.XL - (int16) Immediate8(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static void OpE0X0 (void) { int32 Int32 = (int32) Registers.X.W - (int32) Immediate16(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static void OpE0Slow (void) { if (CheckIndex()) { int16 Int16 = (int16) Registers.XL - (int16) Immediate8Slow(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } else { int32 Int32 = (int32) Registers.X.W - (int32) Immediate16Slow(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } } rOP8 (E4X1, Direct, WRAP_BANK, CPX) rOP16(E4X0, Direct, WRAP_BANK, CPX) rOPX (E4Slow, DirectSlow, WRAP_BANK, CPX) rOP8 (ECX1, Absolute, WRAP_NONE, CPX) rOP16(ECX0, Absolute, WRAP_NONE, CPX) rOPX (ECSlow, AbsoluteSlow, WRAP_NONE, CPX) /* CPY ********************************************************************* */ static void OpC0X1 (void) { int16 Int16 = (int16) Registers.YL - (int16) Immediate8(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static void OpC0X0 (void) { int32 Int32 = (int32) Registers.Y.W - (int32) Immediate16(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static void OpC0Slow (void) { if (CheckIndex()) { int16 Int16 = (int16) Registers.YL - (int16) Immediate8Slow(READ); ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } else { int32 Int32 = (int32) Registers.Y.W - (int32) Immediate16Slow(READ); ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } } rOP8 (C4X1, Direct, WRAP_BANK, CPY) rOP16(C4X0, Direct, WRAP_BANK, CPY) rOPX (C4Slow, DirectSlow, WRAP_BANK, CPY) rOP8 (CCX1, Absolute, WRAP_NONE, CPY) rOP16(CCX0, Absolute, WRAP_NONE, CPY) rOPX (CCSlow, AbsoluteSlow, WRAP_NONE, CPY) /* DEC ********************************************************************* */ static void Op3AM1 (void) { AddCycles(ONE_CYCLE); Registers.AL--; SetZN(Registers.AL); } static void Op3AM0 (void) { AddCycles(ONE_CYCLE); Registers.A.W--; SetZN(Registers.A.W); } static void Op3ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { Registers.AL--; SetZN(Registers.AL); } else { Registers.A.W--; SetZN(Registers.A.W); } } mOP8 (C6M1, Direct, WRAP_BANK, DEC) mOP16(C6M0, Direct, WRAP_BANK, DEC) mOPM (C6Slow, DirectSlow, WRAP_BANK, DEC) mOP8 (D6E1, DirectIndexedXE1, WRAP_BANK, DEC) mOP8 (D6E0M1, DirectIndexedXE0, WRAP_BANK, DEC) mOP16(D6E0M0, DirectIndexedXE0, WRAP_BANK, DEC) mOPM (D6Slow, DirectIndexedXSlow, WRAP_BANK, DEC) mOP8 (CEM1, Absolute, WRAP_NONE, DEC) mOP16(CEM0, Absolute, WRAP_NONE, DEC) mOPM (CESlow, AbsoluteSlow, WRAP_NONE, DEC) mOP8 (DEM1X1, AbsoluteIndexedXX1, WRAP_NONE, DEC) mOP16(DEM0X1, AbsoluteIndexedXX1, WRAP_NONE, DEC) mOP8 (DEM1X0, AbsoluteIndexedXX0, WRAP_NONE, DEC) mOP16(DEM0X0, AbsoluteIndexedXX0, WRAP_NONE, DEC) mOPM (DESlow, AbsoluteIndexedXSlow, WRAP_NONE, DEC) /* EOR ********************************************************************* */ static void Op49M1 (void) { Registers.AL ^= Immediate8(READ); SetZN(Registers.AL); } static void Op49M0 (void) { Registers.A.W ^= Immediate16(READ); SetZN(Registers.A.W); } static void Op49Slow (void) { if (CheckMemory()) { Registers.AL ^= Immediate8Slow(READ); SetZN(Registers.AL); } else { Registers.A.W ^= Immediate16Slow(READ); SetZN(Registers.A.W); } } rOP8 (45M1, Direct, WRAP_BANK, EOR) rOP16(45M0, Direct, WRAP_BANK, EOR) rOPM (45Slow, DirectSlow, WRAP_BANK, EOR) rOP8 (55E1, DirectIndexedXE1, WRAP_BANK, EOR) rOP8 (55E0M1, DirectIndexedXE0, WRAP_BANK, EOR) rOP16(55E0M0, DirectIndexedXE0, WRAP_BANK, EOR) rOPM (55Slow, DirectIndexedXSlow, WRAP_BANK, EOR) rOP8 (52E1, DirectIndirectE1, WRAP_NONE, EOR) rOP8 (52E0M1, DirectIndirectE0, WRAP_NONE, EOR) rOP16(52E0M0, DirectIndirectE0, WRAP_NONE, EOR) rOPM (52Slow, DirectIndirectSlow, WRAP_NONE, EOR) rOP8 (41E1, DirectIndexedIndirectE1, WRAP_NONE, EOR) rOP8 (41E0M1, DirectIndexedIndirectE0, WRAP_NONE, EOR) rOP16(41E0M0, DirectIndexedIndirectE0, WRAP_NONE, EOR) rOPM (41Slow, DirectIndexedIndirectSlow, WRAP_NONE, EOR) rOP8 (51E1, DirectIndirectIndexedE1, WRAP_NONE, EOR) rOP8 (51E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR) rOP16(51E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR) rOP8 (51E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR) rOP16(51E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR) rOPM (51Slow, DirectIndirectIndexedSlow, WRAP_NONE, EOR) rOP8 (47M1, DirectIndirectLong, WRAP_NONE, EOR) rOP16(47M0, DirectIndirectLong, WRAP_NONE, EOR) rOPM (47Slow, DirectIndirectLongSlow, WRAP_NONE, EOR) rOP8 (57M1, DirectIndirectIndexedLong, WRAP_NONE, EOR) rOP16(57M0, DirectIndirectIndexedLong, WRAP_NONE, EOR) rOPM (57Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, EOR) rOP8 (4DM1, Absolute, WRAP_NONE, EOR) rOP16(4DM0, Absolute, WRAP_NONE, EOR) rOPM (4DSlow, AbsoluteSlow, WRAP_NONE, EOR) rOP8 (5DM1X1, AbsoluteIndexedXX1, WRAP_NONE, EOR) rOP16(5DM0X1, AbsoluteIndexedXX1, WRAP_NONE, EOR) rOP8 (5DM1X0, AbsoluteIndexedXX0, WRAP_NONE, EOR) rOP16(5DM0X0, AbsoluteIndexedXX0, WRAP_NONE, EOR) rOPM (5DSlow, AbsoluteIndexedXSlow, WRAP_NONE, EOR) rOP8 (59M1X1, AbsoluteIndexedYX1, WRAP_NONE, EOR) rOP16(59M0X1, AbsoluteIndexedYX1, WRAP_NONE, EOR) rOP8 (59M1X0, AbsoluteIndexedYX0, WRAP_NONE, EOR) rOP16(59M0X0, AbsoluteIndexedYX0, WRAP_NONE, EOR) rOPM (59Slow, AbsoluteIndexedYSlow, WRAP_NONE, EOR) rOP8 (4FM1, AbsoluteLong, WRAP_NONE, EOR) rOP16(4FM0, AbsoluteLong, WRAP_NONE, EOR) rOPM (4FSlow, AbsoluteLongSlow, WRAP_NONE, EOR) rOP8 (5FM1, AbsoluteLongIndexedX, WRAP_NONE, EOR) rOP16(5FM0, AbsoluteLongIndexedX, WRAP_NONE, EOR) rOPM (5FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, EOR) rOP8 (43M1, StackRelative, WRAP_NONE, EOR) rOP16(43M0, StackRelative, WRAP_NONE, EOR) rOPM (43Slow, StackRelativeSlow, WRAP_NONE, EOR) rOP8 (53M1, StackRelativeIndirectIndexed, WRAP_NONE, EOR) rOP16(53M0, StackRelativeIndirectIndexed, WRAP_NONE, EOR) rOPM (53Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, EOR) /* INC ********************************************************************* */ static void Op1AM1 (void) { AddCycles(ONE_CYCLE); Registers.AL++; SetZN(Registers.AL); } static void Op1AM0 (void) { AddCycles(ONE_CYCLE); Registers.A.W++; SetZN(Registers.A.W); } static void Op1ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { Registers.AL++; SetZN(Registers.AL); } else { Registers.A.W++; SetZN(Registers.A.W); } } mOP8 (E6M1, Direct, WRAP_BANK, INC) mOP16(E6M0, Direct, WRAP_BANK, INC) mOPM (E6Slow, DirectSlow, WRAP_BANK, INC) mOP8 (F6E1, DirectIndexedXE1, WRAP_BANK, INC) mOP8 (F6E0M1, DirectIndexedXE0, WRAP_BANK, INC) mOP16(F6E0M0, DirectIndexedXE0, WRAP_BANK, INC) mOPM (F6Slow, DirectIndexedXSlow, WRAP_BANK, INC) mOP8 (EEM1, Absolute, WRAP_NONE, INC) mOP16(EEM0, Absolute, WRAP_NONE, INC) mOPM (EESlow, AbsoluteSlow, WRAP_NONE, INC) mOP8 (FEM1X1, AbsoluteIndexedXX1, WRAP_NONE, INC) mOP16(FEM0X1, AbsoluteIndexedXX1, WRAP_NONE, INC) mOP8 (FEM1X0, AbsoluteIndexedXX0, WRAP_NONE, INC) mOP16(FEM0X0, AbsoluteIndexedXX0, WRAP_NONE, INC) mOPM (FESlow, AbsoluteIndexedXSlow, WRAP_NONE, INC) /* LDA ********************************************************************* */ static void OpA9M1 (void) { Registers.AL = Immediate8(READ); SetZN(Registers.AL); } static void OpA9M0 (void) { Registers.A.W = Immediate16(READ); SetZN(Registers.A.W); } static void OpA9Slow (void) { if (CheckMemory()) { Registers.AL = Immediate8Slow(READ); SetZN(Registers.AL); } else { Registers.A.W = Immediate16Slow(READ); SetZN(Registers.A.W); } } rOP8 (A5M1, Direct, WRAP_BANK, LDA) rOP16(A5M0, Direct, WRAP_BANK, LDA) rOPM (A5Slow, DirectSlow, WRAP_BANK, LDA) rOP8 (B5E1, DirectIndexedXE1, WRAP_BANK, LDA) rOP8 (B5E0M1, DirectIndexedXE0, WRAP_BANK, LDA) rOP16(B5E0M0, DirectIndexedXE0, WRAP_BANK, LDA) rOPM (B5Slow, DirectIndexedXSlow, WRAP_BANK, LDA) rOP8 (B2E1, DirectIndirectE1, WRAP_NONE, LDA) rOP8 (B2E0M1, DirectIndirectE0, WRAP_NONE, LDA) rOP16(B2E0M0, DirectIndirectE0, WRAP_NONE, LDA) rOPM (B2Slow, DirectIndirectSlow, WRAP_NONE, LDA) rOP8 (A1E1, DirectIndexedIndirectE1, WRAP_NONE, LDA) rOP8 (A1E0M1, DirectIndexedIndirectE0, WRAP_NONE, LDA) rOP16(A1E0M0, DirectIndexedIndirectE0, WRAP_NONE, LDA) rOPM (A1Slow, DirectIndexedIndirectSlow, WRAP_NONE, LDA) rOP8 (B1E1, DirectIndirectIndexedE1, WRAP_NONE, LDA) rOP8 (B1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA) rOP16(B1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA) rOP8 (B1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA) rOP16(B1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA) rOPM (B1Slow, DirectIndirectIndexedSlow, WRAP_NONE, LDA) rOP8 (A7M1, DirectIndirectLong, WRAP_NONE, LDA) rOP16(A7M0, DirectIndirectLong, WRAP_NONE, LDA) rOPM (A7Slow, DirectIndirectLongSlow, WRAP_NONE, LDA) rOP8 (B7M1, DirectIndirectIndexedLong, WRAP_NONE, LDA) rOP16(B7M0, DirectIndirectIndexedLong, WRAP_NONE, LDA) rOPM (B7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, LDA) rOP8 (ADM1, Absolute, WRAP_NONE, LDA) rOP16(ADM0, Absolute, WRAP_NONE, LDA) rOPM (ADSlow, AbsoluteSlow, WRAP_NONE, LDA) rOP8 (BDM1X1, AbsoluteIndexedXX1, WRAP_NONE, LDA) rOP16(BDM0X1, AbsoluteIndexedXX1, WRAP_NONE, LDA) rOP8 (BDM1X0, AbsoluteIndexedXX0, WRAP_NONE, LDA) rOP16(BDM0X0, AbsoluteIndexedXX0, WRAP_NONE, LDA) rOPM (BDSlow, AbsoluteIndexedXSlow, WRAP_NONE, LDA) rOP8 (B9M1X1, AbsoluteIndexedYX1, WRAP_NONE, LDA) rOP16(B9M0X1, AbsoluteIndexedYX1, WRAP_NONE, LDA) rOP8 (B9M1X0, AbsoluteIndexedYX0, WRAP_NONE, LDA) rOP16(B9M0X0, AbsoluteIndexedYX0, WRAP_NONE, LDA) rOPM (B9Slow, AbsoluteIndexedYSlow, WRAP_NONE, LDA) rOP8 (AFM1, AbsoluteLong, WRAP_NONE, LDA) rOP16(AFM0, AbsoluteLong, WRAP_NONE, LDA) rOPM (AFSlow, AbsoluteLongSlow, WRAP_NONE, LDA) rOP8 (BFM1, AbsoluteLongIndexedX, WRAP_NONE, LDA) rOP16(BFM0, AbsoluteLongIndexedX, WRAP_NONE, LDA) rOPM (BFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, LDA) rOP8 (A3M1, StackRelative, WRAP_NONE, LDA) rOP16(A3M0, StackRelative, WRAP_NONE, LDA) rOPM (A3Slow, StackRelativeSlow, WRAP_NONE, LDA) rOP8 (B3M1, StackRelativeIndirectIndexed, WRAP_NONE, LDA) rOP16(B3M0, StackRelativeIndirectIndexed, WRAP_NONE, LDA) rOPM (B3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, LDA) /* LDX ********************************************************************* */ static void OpA2X1 (void) { Registers.XL = Immediate8(READ); SetZN(Registers.XL); } static void OpA2X0 (void) { Registers.X.W = Immediate16(READ); SetZN(Registers.X.W); } static void OpA2Slow (void) { if (CheckIndex()) { Registers.XL = Immediate8Slow(READ); SetZN(Registers.XL); } else { Registers.X.W = Immediate16Slow(READ); SetZN(Registers.X.W); } } rOP8 (A6X1, Direct, WRAP_BANK, LDX) rOP16(A6X0, Direct, WRAP_BANK, LDX) rOPX (A6Slow, DirectSlow, WRAP_BANK, LDX) rOP8 (B6E1, DirectIndexedYE1, WRAP_BANK, LDX) rOP8 (B6E0X1, DirectIndexedYE0, WRAP_BANK, LDX) rOP16(B6E0X0, DirectIndexedYE0, WRAP_BANK, LDX) rOPX (B6Slow, DirectIndexedYSlow, WRAP_BANK, LDX) rOP8 (AEX1, Absolute, WRAP_BANK, LDX) rOP16(AEX0, Absolute, WRAP_BANK, LDX) rOPX (AESlow, AbsoluteSlow, WRAP_BANK, LDX) rOP8 (BEX1, AbsoluteIndexedYX1, WRAP_BANK, LDX) rOP16(BEX0, AbsoluteIndexedYX0, WRAP_BANK, LDX) rOPX (BESlow, AbsoluteIndexedYSlow, WRAP_BANK, LDX) /* LDY ********************************************************************* */ static void OpA0X1 (void) { Registers.YL = Immediate8(READ); SetZN(Registers.YL); } static void OpA0X0 (void) { Registers.Y.W = Immediate16(READ); SetZN(Registers.Y.W); } static void OpA0Slow (void) { if (CheckIndex()) { Registers.YL = Immediate8Slow(READ); SetZN(Registers.YL); } else { Registers.Y.W = Immediate16Slow(READ); SetZN(Registers.Y.W); } } rOP8 (A4X1, Direct, WRAP_BANK, LDY) rOP16(A4X0, Direct, WRAP_BANK, LDY) rOPX (A4Slow, DirectSlow, WRAP_BANK, LDY) rOP8 (B4E1, DirectIndexedXE1, WRAP_BANK, LDY) rOP8 (B4E0X1, DirectIndexedXE0, WRAP_BANK, LDY) rOP16(B4E0X0, DirectIndexedXE0, WRAP_BANK, LDY) rOPX (B4Slow, DirectIndexedXSlow, WRAP_BANK, LDY) rOP8 (ACX1, Absolute, WRAP_BANK, LDY) rOP16(ACX0, Absolute, WRAP_BANK, LDY) rOPX (ACSlow, AbsoluteSlow, WRAP_BANK, LDY) rOP8 (BCX1, AbsoluteIndexedXX1, WRAP_BANK, LDY) rOP16(BCX0, AbsoluteIndexedXX0, WRAP_BANK, LDY) rOPX (BCSlow, AbsoluteIndexedXSlow, WRAP_BANK, LDY) /* LSR ********************************************************************* */ static void Op4AM1 (void) { AddCycles(ONE_CYCLE); ICPU._Carry = Registers.AL & 1; Registers.AL >>= 1; SetZN(Registers.AL); } static void Op4AM0 (void) { AddCycles(ONE_CYCLE); ICPU._Carry = Registers.A.W & 1; Registers.A.W >>= 1; SetZN(Registers.A.W); } static void Op4ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { ICPU._Carry = Registers.AL & 1; Registers.AL >>= 1; SetZN(Registers.AL); } else { ICPU._Carry = Registers.A.W & 1; Registers.A.W >>= 1; SetZN(Registers.A.W); } } mOP8 (46M1, Direct, WRAP_BANK, LSR) mOP16(46M0, Direct, WRAP_BANK, LSR) mOPM (46Slow, DirectSlow, WRAP_BANK, LSR) mOP8 (56E1, DirectIndexedXE1, WRAP_BANK, LSR) mOP8 (56E0M1, DirectIndexedXE0, WRAP_BANK, LSR) mOP16(56E0M0, DirectIndexedXE0, WRAP_BANK, LSR) mOPM (56Slow, DirectIndexedXSlow, WRAP_BANK, LSR) mOP8 (4EM1, Absolute, WRAP_NONE, LSR) mOP16(4EM0, Absolute, WRAP_NONE, LSR) mOPM (4ESlow, AbsoluteSlow, WRAP_NONE, LSR) mOP8 (5EM1X1, AbsoluteIndexedXX1, WRAP_NONE, LSR) mOP16(5EM0X1, AbsoluteIndexedXX1, WRAP_NONE, LSR) mOP8 (5EM1X0, AbsoluteIndexedXX0, WRAP_NONE, LSR) mOP16(5EM0X0, AbsoluteIndexedXX0, WRAP_NONE, LSR) mOPM (5ESlow, AbsoluteIndexedXSlow, WRAP_NONE, LSR) /* ORA ********************************************************************* */ static void Op09M1 (void) { Registers.AL |= Immediate8(READ); SetZN(Registers.AL); } static void Op09M0 (void) { Registers.A.W |= Immediate16(READ); SetZN(Registers.A.W); } static void Op09Slow (void) { if (CheckMemory()) { Registers.AL |= Immediate8Slow(READ); SetZN(Registers.AL); } else { Registers.A.W |= Immediate16Slow(READ); SetZN(Registers.A.W); } } rOP8 (05M1, Direct, WRAP_BANK, ORA) rOP16(05M0, Direct, WRAP_BANK, ORA) rOPM (05Slow, DirectSlow, WRAP_BANK, ORA) rOP8 (15E1, DirectIndexedXE1, WRAP_BANK, ORA) rOP8 (15E0M1, DirectIndexedXE0, WRAP_BANK, ORA) rOP16(15E0M0, DirectIndexedXE0, WRAP_BANK, ORA) rOPM (15Slow, DirectIndexedXSlow, WRAP_BANK, ORA) rOP8 (12E1, DirectIndirectE1, WRAP_NONE, ORA) rOP8 (12E0M1, DirectIndirectE0, WRAP_NONE, ORA) rOP16(12E0M0, DirectIndirectE0, WRAP_NONE, ORA) rOPM (12Slow, DirectIndirectSlow, WRAP_NONE, ORA) rOP8 (01E1, DirectIndexedIndirectE1, WRAP_NONE, ORA) rOP8 (01E0M1, DirectIndexedIndirectE0, WRAP_NONE, ORA) rOP16(01E0M0, DirectIndexedIndirectE0, WRAP_NONE, ORA) rOPM (01Slow, DirectIndexedIndirectSlow, WRAP_NONE, ORA) rOP8 (11E1, DirectIndirectIndexedE1, WRAP_NONE, ORA) rOP8 (11E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA) rOP16(11E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA) rOP8 (11E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA) rOP16(11E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA) rOPM (11Slow, DirectIndirectIndexedSlow, WRAP_NONE, ORA) rOP8 (07M1, DirectIndirectLong, WRAP_NONE, ORA) rOP16(07M0, DirectIndirectLong, WRAP_NONE, ORA) rOPM (07Slow, DirectIndirectLongSlow, WRAP_NONE, ORA) rOP8 (17M1, DirectIndirectIndexedLong, WRAP_NONE, ORA) rOP16(17M0, DirectIndirectIndexedLong, WRAP_NONE, ORA) rOPM (17Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ORA) rOP8 (0DM1, Absolute, WRAP_NONE, ORA) rOP16(0DM0, Absolute, WRAP_NONE, ORA) rOPM (0DSlow, AbsoluteSlow, WRAP_NONE, ORA) rOP8 (1DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ORA) rOP16(1DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ORA) rOP8 (1DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ORA) rOP16(1DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ORA) rOPM (1DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ORA) rOP8 (19M1X1, AbsoluteIndexedYX1, WRAP_NONE, ORA) rOP16(19M0X1, AbsoluteIndexedYX1, WRAP_NONE, ORA) rOP8 (19M1X0, AbsoluteIndexedYX0, WRAP_NONE, ORA) rOP16(19M0X0, AbsoluteIndexedYX0, WRAP_NONE, ORA) rOPM (19Slow, AbsoluteIndexedYSlow, WRAP_NONE, ORA) rOP8 (0FM1, AbsoluteLong, WRAP_NONE, ORA) rOP16(0FM0, AbsoluteLong, WRAP_NONE, ORA) rOPM (0FSlow, AbsoluteLongSlow, WRAP_NONE, ORA) rOP8 (1FM1, AbsoluteLongIndexedX, WRAP_NONE, ORA) rOP16(1FM0, AbsoluteLongIndexedX, WRAP_NONE, ORA) rOPM (1FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ORA) rOP8 (03M1, StackRelative, WRAP_NONE, ORA) rOP16(03M0, StackRelative, WRAP_NONE, ORA) rOPM (03Slow, StackRelativeSlow, WRAP_NONE, ORA) rOP8 (13M1, StackRelativeIndirectIndexed, WRAP_NONE, ORA) rOP16(13M0, StackRelativeIndirectIndexed, WRAP_NONE, ORA) rOPM (13Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ORA) /* ROL ********************************************************************* */ static void Op2AM1 (void) { AddCycles(ONE_CYCLE); uint16 w = (((uint16) Registers.AL) << 1) | CheckCarry(); ICPU._Carry = w >= 0x100; Registers.AL = (uint8) w; SetZN(Registers.AL); } static void Op2AM0 (void) { AddCycles(ONE_CYCLE); uint32 w = (((uint32) Registers.A.W) << 1) | CheckCarry(); ICPU._Carry = w >= 0x10000; Registers.A.W = (uint16) w; SetZN(Registers.A.W); } static void Op2ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { uint16 w = (((uint16) Registers.AL) << 1) | CheckCarry(); ICPU._Carry = w >= 0x100; Registers.AL = (uint8) w; SetZN(Registers.AL); } else { uint32 w = (((uint32) Registers.A.W) << 1) | CheckCarry(); ICPU._Carry = w >= 0x10000; Registers.A.W = (uint16) w; SetZN(Registers.A.W); } } mOP8 (26M1, Direct, WRAP_BANK, ROL) mOP16(26M0, Direct, WRAP_BANK, ROL) mOPM (26Slow, DirectSlow, WRAP_BANK, ROL) mOP8 (36E1, DirectIndexedXE1, WRAP_BANK, ROL) mOP8 (36E0M1, DirectIndexedXE0, WRAP_BANK, ROL) mOP16(36E0M0, DirectIndexedXE0, WRAP_BANK, ROL) mOPM (36Slow, DirectIndexedXSlow, WRAP_BANK, ROL) mOP8 (2EM1, Absolute, WRAP_NONE, ROL) mOP16(2EM0, Absolute, WRAP_NONE, ROL) mOPM (2ESlow, AbsoluteSlow, WRAP_NONE, ROL) mOP8 (3EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROL) mOP16(3EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROL) mOP8 (3EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROL) mOP16(3EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROL) mOPM (3ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROL) /* ROR ********************************************************************* */ static void Op6AM1 (void) { AddCycles(ONE_CYCLE); uint16 w = ((uint16) Registers.AL) | (((uint16) CheckCarry()) << 8); ICPU._Carry = w & 1; w >>= 1; Registers.AL = (uint8) w; SetZN(Registers.AL); } static void Op6AM0 (void) { AddCycles(ONE_CYCLE); uint32 w = ((uint32) Registers.A.W) | (((uint32) CheckCarry()) << 16); ICPU._Carry = w & 1; w >>= 1; Registers.A.W = (uint16) w; SetZN(Registers.A.W); } static void Op6ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { uint16 w = ((uint16) Registers.AL) | (((uint16) CheckCarry()) << 8); ICPU._Carry = w & 1; w >>= 1; Registers.AL = (uint8) w; SetZN(Registers.AL); } else { uint32 w = ((uint32) Registers.A.W) | (((uint32) CheckCarry()) << 16); ICPU._Carry = w & 1; w >>= 1; Registers.A.W = (uint16) w; SetZN(Registers.A.W); } } mOP8 (66M1, Direct, WRAP_BANK, ROR) mOP16(66M0, Direct, WRAP_BANK, ROR) mOPM (66Slow, DirectSlow, WRAP_BANK, ROR) mOP8 (76E1, DirectIndexedXE1, WRAP_BANK, ROR) mOP8 (76E0M1, DirectIndexedXE0, WRAP_BANK, ROR) mOP16(76E0M0, DirectIndexedXE0, WRAP_BANK, ROR) mOPM (76Slow, DirectIndexedXSlow, WRAP_BANK, ROR) mOP8 (6EM1, Absolute, WRAP_NONE, ROR) mOP16(6EM0, Absolute, WRAP_NONE, ROR) mOPM (6ESlow, AbsoluteSlow, WRAP_NONE, ROR) mOP8 (7EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROR) mOP16(7EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROR) mOP8 (7EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROR) mOP16(7EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROR) mOPM (7ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROR) /* SBC ********************************************************************* */ static void OpE9M1 (void) { SBC(Immediate8(READ)); } static void OpE9M0 (void) { SBC(Immediate16(READ)); } static void OpE9Slow (void) { if (CheckMemory()) SBC(Immediate8Slow(READ)); else SBC(Immediate16Slow(READ)); } rOP8 (E5M1, Direct, WRAP_BANK, SBC) rOP16(E5M0, Direct, WRAP_BANK, SBC) rOPM (E5Slow, DirectSlow, WRAP_BANK, SBC) rOP8 (F5E1, DirectIndexedXE1, WRAP_BANK, SBC) rOP8 (F5E0M1, DirectIndexedXE0, WRAP_BANK, SBC) rOP16(F5E0M0, DirectIndexedXE0, WRAP_BANK, SBC) rOPM (F5Slow, DirectIndexedXSlow, WRAP_BANK, SBC) rOP8 (F2E1, DirectIndirectE1, WRAP_NONE, SBC) rOP8 (F2E0M1, DirectIndirectE0, WRAP_NONE, SBC) rOP16(F2E0M0, DirectIndirectE0, WRAP_NONE, SBC) rOPM (F2Slow, DirectIndirectSlow, WRAP_NONE, SBC) rOP8 (E1E1, DirectIndexedIndirectE1, WRAP_NONE, SBC) rOP8 (E1E0M1, DirectIndexedIndirectE0, WRAP_NONE, SBC) rOP16(E1E0M0, DirectIndexedIndirectE0, WRAP_NONE, SBC) rOPM (E1Slow, DirectIndexedIndirectSlow, WRAP_NONE, SBC) rOP8 (F1E1, DirectIndirectIndexedE1, WRAP_NONE, SBC) rOP8 (F1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC) rOP16(F1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC) rOP8 (F1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC) rOP16(F1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC) rOPM (F1Slow, DirectIndirectIndexedSlow, WRAP_NONE, SBC) rOP8 (E7M1, DirectIndirectLong, WRAP_NONE, SBC) rOP16(E7M0, DirectIndirectLong, WRAP_NONE, SBC) rOPM (E7Slow, DirectIndirectLongSlow, WRAP_NONE, SBC) rOP8 (F7M1, DirectIndirectIndexedLong, WRAP_NONE, SBC) rOP16(F7M0, DirectIndirectIndexedLong, WRAP_NONE, SBC) rOPM (F7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, SBC) rOP8 (EDM1, Absolute, WRAP_NONE, SBC) rOP16(EDM0, Absolute, WRAP_NONE, SBC) rOPM (EDSlow, AbsoluteSlow, WRAP_NONE, SBC) rOP8 (FDM1X1, AbsoluteIndexedXX1, WRAP_NONE, SBC) rOP16(FDM0X1, AbsoluteIndexedXX1, WRAP_NONE, SBC) rOP8 (FDM1X0, AbsoluteIndexedXX0, WRAP_NONE, SBC) rOP16(FDM0X0, AbsoluteIndexedXX0, WRAP_NONE, SBC) rOPM (FDSlow, AbsoluteIndexedXSlow, WRAP_NONE, SBC) rOP8 (F9M1X1, AbsoluteIndexedYX1, WRAP_NONE, SBC) rOP16(F9M0X1, AbsoluteIndexedYX1, WRAP_NONE, SBC) rOP8 (F9M1X0, AbsoluteIndexedYX0, WRAP_NONE, SBC) rOP16(F9M0X0, AbsoluteIndexedYX0, WRAP_NONE, SBC) rOPM (F9Slow, AbsoluteIndexedYSlow, WRAP_NONE, SBC) rOP8 (EFM1, AbsoluteLong, WRAP_NONE, SBC) rOP16(EFM0, AbsoluteLong, WRAP_NONE, SBC) rOPM (EFSlow, AbsoluteLongSlow, WRAP_NONE, SBC) rOP8 (FFM1, AbsoluteLongIndexedX, WRAP_NONE, SBC) rOP16(FFM0, AbsoluteLongIndexedX, WRAP_NONE, SBC) rOPM (FFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, SBC) rOP8 (E3M1, StackRelative, WRAP_NONE, SBC) rOP16(E3M0, StackRelative, WRAP_NONE, SBC) rOPM (E3Slow, StackRelativeSlow, WRAP_NONE, SBC) rOP8 (F3M1, StackRelativeIndirectIndexed, WRAP_NONE, SBC) rOP16(F3M0, StackRelativeIndirectIndexed, WRAP_NONE, SBC) rOPM (F3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, SBC) /* STA ********************************************************************* */ wOP8 (85M1, Direct, WRAP_BANK, STA) wOP16(85M0, Direct, WRAP_BANK, STA) wOPM (85Slow, DirectSlow, WRAP_BANK, STA) wOP8 (95E1, DirectIndexedXE1, WRAP_BANK, STA) wOP8 (95E0M1, DirectIndexedXE0, WRAP_BANK, STA) wOP16(95E0M0, DirectIndexedXE0, WRAP_BANK, STA) wOPM (95Slow, DirectIndexedXSlow, WRAP_BANK, STA) wOP8 (92E1, DirectIndirectE1, WRAP_NONE, STA) wOP8 (92E0M1, DirectIndirectE0, WRAP_NONE, STA) wOP16(92E0M0, DirectIndirectE0, WRAP_NONE, STA) wOPM (92Slow, DirectIndirectSlow, WRAP_NONE, STA) wOP8 (81E1, DirectIndexedIndirectE1, WRAP_NONE, STA) wOP8 (81E0M1, DirectIndexedIndirectE0, WRAP_NONE, STA) wOP16(81E0M0, DirectIndexedIndirectE0, WRAP_NONE, STA) wOPM (81Slow, DirectIndexedIndirectSlow, WRAP_NONE, STA) wOP8 (91E1, DirectIndirectIndexedE1, WRAP_NONE, STA) wOP8 (91E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA) wOP16(91E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA) wOP8 (91E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA) wOP16(91E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA) wOPM (91Slow, DirectIndirectIndexedSlow, WRAP_NONE, STA) wOP8 (87M1, DirectIndirectLong, WRAP_NONE, STA) wOP16(87M0, DirectIndirectLong, WRAP_NONE, STA) wOPM (87Slow, DirectIndirectLongSlow, WRAP_NONE, STA) wOP8 (97M1, DirectIndirectIndexedLong, WRAP_NONE, STA) wOP16(97M0, DirectIndirectIndexedLong, WRAP_NONE, STA) wOPM (97Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, STA) wOP8 (8DM1, Absolute, WRAP_NONE, STA) wOP16(8DM0, Absolute, WRAP_NONE, STA) wOPM (8DSlow, AbsoluteSlow, WRAP_NONE, STA) wOP8 (9DM1X1, AbsoluteIndexedXX1, WRAP_NONE, STA) wOP16(9DM0X1, AbsoluteIndexedXX1, WRAP_NONE, STA) wOP8 (9DM1X0, AbsoluteIndexedXX0, WRAP_NONE, STA) wOP16(9DM0X0, AbsoluteIndexedXX0, WRAP_NONE, STA) wOPM (9DSlow, AbsoluteIndexedXSlow, WRAP_NONE, STA) wOP8 (99M1X1, AbsoluteIndexedYX1, WRAP_NONE, STA) wOP16(99M0X1, AbsoluteIndexedYX1, WRAP_NONE, STA) wOP8 (99M1X0, AbsoluteIndexedYX0, WRAP_NONE, STA) wOP16(99M0X0, AbsoluteIndexedYX0, WRAP_NONE, STA) wOPM (99Slow, AbsoluteIndexedYSlow, WRAP_NONE, STA) wOP8 (8FM1, AbsoluteLong, WRAP_NONE, STA) wOP16(8FM0, AbsoluteLong, WRAP_NONE, STA) wOPM (8FSlow, AbsoluteLongSlow, WRAP_NONE, STA) wOP8 (9FM1, AbsoluteLongIndexedX, WRAP_NONE, STA) wOP16(9FM0, AbsoluteLongIndexedX, WRAP_NONE, STA) wOPM (9FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, STA) wOP8 (83M1, StackRelative, WRAP_NONE, STA) wOP16(83M0, StackRelative, WRAP_NONE, STA) wOPM (83Slow, StackRelativeSlow, WRAP_NONE, STA) wOP8 (93M1, StackRelativeIndirectIndexed, WRAP_NONE, STA) wOP16(93M0, StackRelativeIndirectIndexed, WRAP_NONE, STA) wOPM (93Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, STA) /* STX ********************************************************************* */ wOP8 (86X1, Direct, WRAP_BANK, STX) wOP16(86X0, Direct, WRAP_BANK, STX) wOPX (86Slow, DirectSlow, WRAP_BANK, STX) wOP8 (96E1, DirectIndexedYE1, WRAP_BANK, STX) wOP8 (96E0X1, DirectIndexedYE0, WRAP_BANK, STX) wOP16(96E0X0, DirectIndexedYE0, WRAP_BANK, STX) wOPX (96Slow, DirectIndexedYSlow, WRAP_BANK, STX) wOP8 (8EX1, Absolute, WRAP_BANK, STX) wOP16(8EX0, Absolute, WRAP_BANK, STX) wOPX (8ESlow, AbsoluteSlow, WRAP_BANK, STX) /* STY ********************************************************************* */ wOP8 (84X1, Direct, WRAP_BANK, STY) wOP16(84X0, Direct, WRAP_BANK, STY) wOPX (84Slow, DirectSlow, WRAP_BANK, STY) wOP8 (94E1, DirectIndexedXE1, WRAP_BANK, STY) wOP8 (94E0X1, DirectIndexedXE0, WRAP_BANK, STY) wOP16(94E0X0, DirectIndexedXE0, WRAP_BANK, STY) wOPX (94Slow, DirectIndexedXSlow, WRAP_BANK, STY) wOP8 (8CX1, Absolute, WRAP_BANK, STY) wOP16(8CX0, Absolute, WRAP_BANK, STY) wOPX (8CSlow, AbsoluteSlow, WRAP_BANK, STY) /* STZ ********************************************************************* */ wOP8 (64M1, Direct, WRAP_BANK, STZ) wOP16(64M0, Direct, WRAP_BANK, STZ) wOPM (64Slow, DirectSlow, WRAP_BANK, STZ) wOP8 (74E1, DirectIndexedXE1, WRAP_BANK, STZ) wOP8 (74E0M1, DirectIndexedXE0, WRAP_BANK, STZ) wOP16(74E0M0, DirectIndexedXE0, WRAP_BANK, STZ) wOPM (74Slow, DirectIndexedXSlow, WRAP_BANK, STZ) wOP8 (9CM1, Absolute, WRAP_NONE, STZ) wOP16(9CM0, Absolute, WRAP_NONE, STZ) wOPM (9CSlow, AbsoluteSlow, WRAP_NONE, STZ) wOP8 (9EM1X1, AbsoluteIndexedXX1, WRAP_NONE, STZ) wOP16(9EM0X1, AbsoluteIndexedXX1, WRAP_NONE, STZ) wOP8 (9EM1X0, AbsoluteIndexedXX0, WRAP_NONE, STZ) wOP16(9EM0X0, AbsoluteIndexedXX0, WRAP_NONE, STZ) wOPM (9ESlow, AbsoluteIndexedXSlow, WRAP_NONE, STZ) /* TRB ********************************************************************* */ mOP8 (14M1, Direct, WRAP_BANK, TRB) mOP16(14M0, Direct, WRAP_BANK, TRB) mOPM (14Slow, DirectSlow, WRAP_BANK, TRB) mOP8 (1CM1, Absolute, WRAP_BANK, TRB) mOP16(1CM0, Absolute, WRAP_BANK, TRB) mOPM (1CSlow, AbsoluteSlow, WRAP_BANK, TRB) /* TSB ********************************************************************* */ mOP8 (04M1, Direct, WRAP_BANK, TSB) mOP16(04M0, Direct, WRAP_BANK, TSB) mOPM (04Slow, DirectSlow, WRAP_BANK, TSB) mOP8 (0CM1, Absolute, WRAP_BANK, TSB) mOP16(0CM0, Absolute, WRAP_BANK, TSB) mOPM (0CSlow, AbsoluteSlow, WRAP_BANK, TSB) /* Branch Instructions ***************************************************** */ // BCC bOP(90E0, Relative, !CheckCarry(), 0, 0) bOP(90E1, Relative, !CheckCarry(), 0, 1) bOP(90Slow, RelativeSlow, !CheckCarry(), 0, CheckEmulation()) // BCS bOP(B0E0, Relative, CheckCarry(), 0, 0) bOP(B0E1, Relative, CheckCarry(), 0, 1) bOP(B0Slow, RelativeSlow, CheckCarry(), 0, CheckEmulation()) // BEQ bOP(F0E0, Relative, CheckZero(), 2, 0) bOP(F0E1, Relative, CheckZero(), 2, 1) bOP(F0Slow, RelativeSlow, CheckZero(), 2, CheckEmulation()) // BMI bOP(30E0, Relative, CheckNegative(), 1, 0) bOP(30E1, Relative, CheckNegative(), 1, 1) bOP(30Slow, RelativeSlow, CheckNegative(), 1, CheckEmulation()) // BNE bOP(D0E0, Relative, !CheckZero(), 1, 0) bOP(D0E1, Relative, !CheckZero(), 1, 1) bOP(D0Slow, RelativeSlow, !CheckZero(), 1, CheckEmulation()) // BPL bOP(10E0, Relative, !CheckNegative(), 1, 0) bOP(10E1, Relative, !CheckNegative(), 1, 1) bOP(10Slow, RelativeSlow, !CheckNegative(), 1, CheckEmulation()) // BRA bOP(80E0, Relative, 1, X, 0) bOP(80E1, Relative, 1, X, 1) bOP(80Slow, RelativeSlow, 1, X, CheckEmulation()) // BVC bOP(50E0, Relative, !CheckOverflow(), 0, 0) bOP(50E1, Relative, !CheckOverflow(), 0, 1) bOP(50Slow, RelativeSlow, !CheckOverflow(), 0, CheckEmulation()) // BVS bOP(70E0, Relative, CheckOverflow(), 0, 0) bOP(70E1, Relative, CheckOverflow(), 0, 1) bOP(70Slow, RelativeSlow, CheckOverflow(), 0, CheckEmulation()) // BRL static void Op82 (void) { S9xSetPCBase(ICPU.ShiftedPB + RelativeLong(JUMP)); } static void Op82Slow (void) { S9xSetPCBase(ICPU.ShiftedPB + RelativeLongSlow(JUMP)); } /* Flag Instructions ******************************************************* */ // CLC static void Op18 (void) { ClearCarry(); AddCycles(ONE_CYCLE); } // SEC static void Op38 (void) { SetCarry(); AddCycles(ONE_CYCLE); } // CLD static void OpD8 (void) { ClearDecimal(); AddCycles(ONE_CYCLE); } // SED static void OpF8 (void) { SetDecimal(); AddCycles(ONE_CYCLE); #ifdef DEBUGGER missing.decimal_mode = 1; #endif } // CLI static void Op58 (void) { ClearIRQ(); AddCycles(ONE_CYCLE); CHECK_FOR_IRQ(); } // SEI static void Op78 (void) { SetIRQ(); AddCycles(ONE_CYCLE); } // CLV static void OpB8 (void) { ClearOverflow(); AddCycles(ONE_CYCLE); } /* DEX/DEY ***************************************************************** */ static void OpCAX1 (void) { AddCycles(ONE_CYCLE); Registers.XL--; SetZN(Registers.XL); } static void OpCAX0 (void) { AddCycles(ONE_CYCLE); Registers.X.W--; SetZN(Registers.X.W); } static void OpCASlow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.XL--; SetZN(Registers.XL); } else { Registers.X.W--; SetZN(Registers.X.W); } } static void Op88X1 (void) { AddCycles(ONE_CYCLE); Registers.YL--; SetZN(Registers.YL); } static void Op88X0 (void) { AddCycles(ONE_CYCLE); Registers.Y.W--; SetZN(Registers.Y.W); } static void Op88Slow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.YL--; SetZN(Registers.YL); } else { Registers.Y.W--; SetZN(Registers.Y.W); } } /* INX/INY ***************************************************************** */ static void OpE8X1 (void) { AddCycles(ONE_CYCLE); Registers.XL++; SetZN(Registers.XL); } static void OpE8X0 (void) { AddCycles(ONE_CYCLE); Registers.X.W++; SetZN(Registers.X.W); } static void OpE8Slow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.XL++; SetZN(Registers.XL); } else { Registers.X.W++; SetZN(Registers.X.W); } } static void OpC8X1 (void) { AddCycles(ONE_CYCLE); Registers.YL++; SetZN(Registers.YL); } static void OpC8X0 (void) { AddCycles(ONE_CYCLE); Registers.Y.W++; SetZN(Registers.Y.W); } static void OpC8Slow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.YL++; SetZN(Registers.YL); } else { Registers.Y.W++; SetZN(Registers.Y.W); } } /* NOP ********************************************************************* */ static void OpEA (void) { AddCycles(ONE_CYCLE); } /* PUSH Instructions ******************************************************* */ #define PushW(w) \ S9xSetWord(w, Registers.S.W - 1, WRAP_BANK, WRITE_10); \ Registers.S.W -= 2; #define PushWE(w) \ Registers.SL--; \ S9xSetWord(w, Registers.S.W, WRAP_PAGE, WRITE_10); \ Registers.SL--; #define PushB(b) \ S9xSetByte(b, Registers.S.W--); #define PushBE(b) \ S9xSetByte(b, Registers.S.W); \ Registers.SL--; // PEA static void OpF4E0 (void) { uint16 val = (uint16) Absolute(NONE); PushW(val); OpenBus = val & 0xff; } static void OpF4E1 (void) { // Note: PEA is a new instruction, // and so doesn't respect the emu-mode stack bounds. uint16 val = (uint16) Absolute(NONE); PushW(val); OpenBus = val & 0xff; Registers.SH = 1; } static void OpF4Slow (void) { uint16 val = (uint16) AbsoluteSlow(NONE); PushW(val); OpenBus = val & 0xff; if (CheckEmulation()) Registers.SH = 1; } // PEI static void OpD4E0 (void) { uint16 val = (uint16) DirectIndirectE0(NONE); PushW(val); OpenBus = val & 0xff; } static void OpD4E1 (void) { // Note: PEI is a new instruction, // and so doesn't respect the emu-mode stack bounds. uint16 val = (uint16) DirectIndirectE1(NONE); PushW(val); OpenBus = val & 0xff; Registers.SH = 1; } static void OpD4Slow (void) { uint16 val = (uint16) DirectIndirectSlow(NONE); PushW(val); OpenBus = val & 0xff; if (CheckEmulation()) Registers.SH = 1; } // PER static void Op62E0 (void) { uint16 val = (uint16) RelativeLong(NONE); PushW(val); OpenBus = val & 0xff; } static void Op62E1 (void) { // Note: PER is a new instruction, // and so doesn't respect the emu-mode stack bounds. uint16 val = (uint16) RelativeLong(NONE); PushW(val); OpenBus = val & 0xff; Registers.SH = 1; } static void Op62Slow (void) { uint16 val = (uint16) RelativeLongSlow(NONE); PushW(val); OpenBus = val & 0xff; if (CheckEmulation()) Registers.SH = 1; } // PHA static void Op48E1 (void) { AddCycles(ONE_CYCLE); PushBE(Registers.AL); OpenBus = Registers.AL; } static void Op48E0M1 (void) { AddCycles(ONE_CYCLE); PushB(Registers.AL); OpenBus = Registers.AL; } static void Op48E0M0 (void) { AddCycles(ONE_CYCLE); PushW(Registers.A.W); OpenBus = Registers.AL; } static void Op48Slow (void) { AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.AL); } else if (CheckMemory()) { PushB(Registers.AL); } else { PushW(Registers.A.W); } OpenBus = Registers.AL; } // PHB static void Op8BE1 (void) { AddCycles(ONE_CYCLE); PushBE(Registers.DB); OpenBus = Registers.DB; } static void Op8BE0 (void) { AddCycles(ONE_CYCLE); PushB(Registers.DB); OpenBus = Registers.DB; } static void Op8BSlow (void) { AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.DB); } else { PushB(Registers.DB); } OpenBus = Registers.DB; } // PHD static void Op0BE0 (void) { AddCycles(ONE_CYCLE); PushW(Registers.D.W); OpenBus = Registers.DL; } static void Op0BE1 (void) { // Note: PHD is a new instruction, // and so doesn't respect the emu-mode stack bounds. AddCycles(ONE_CYCLE); PushW(Registers.D.W); OpenBus = Registers.DL; Registers.SH = 1; } static void Op0BSlow (void) { AddCycles(ONE_CYCLE); PushW(Registers.D.W); OpenBus = Registers.DL; if (CheckEmulation()) Registers.SH = 1; } // PHK static void Op4BE1 (void) { AddCycles(ONE_CYCLE); PushBE(Registers.PB); OpenBus = Registers.PB; } static void Op4BE0 (void) { AddCycles(ONE_CYCLE); PushB(Registers.PB); OpenBus = Registers.PB; } static void Op4BSlow (void) { AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.PB); } else { PushB(Registers.PB); } OpenBus = Registers.PB; } // PHP static void Op08E0 (void) { S9xPackStatus(); AddCycles(ONE_CYCLE); PushB(Registers.PL); OpenBus = Registers.PL; } static void Op08E1 (void) { S9xPackStatus(); AddCycles(ONE_CYCLE); PushBE(Registers.PL); OpenBus = Registers.PL; } static void Op08Slow (void) { S9xPackStatus(); AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.PL); } else { PushB(Registers.PL); } OpenBus = Registers.PL; } // PHX static void OpDAE1 (void) { AddCycles(ONE_CYCLE); PushBE(Registers.XL); OpenBus = Registers.XL; } static void OpDAE0X1 (void) { AddCycles(ONE_CYCLE); PushB(Registers.XL); OpenBus = Registers.XL; } static void OpDAE0X0 (void) { AddCycles(ONE_CYCLE); PushW(Registers.X.W); OpenBus = Registers.XL; } static void OpDASlow (void) { AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.XL); } else if (CheckIndex()) { PushB(Registers.XL); } else { PushW(Registers.X.W); } OpenBus = Registers.XL; } // PHY static void Op5AE1 (void) { AddCycles(ONE_CYCLE); PushBE(Registers.YL); OpenBus = Registers.YL; } static void Op5AE0X1 (void) { AddCycles(ONE_CYCLE); PushB(Registers.YL); OpenBus = Registers.YL; } static void Op5AE0X0 (void) { AddCycles(ONE_CYCLE); PushW(Registers.Y.W); OpenBus = Registers.YL; } static void Op5ASlow (void) { AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushBE(Registers.YL); } else if (CheckIndex()) { PushB(Registers.YL); } else { PushW(Registers.Y.W); } OpenBus = Registers.YL; } /* PULL Instructions ******************************************************* */ #define PullW(w) \ w = S9xGetWord(Registers.S.W + 1, WRAP_BANK); \ Registers.S.W += 2; #define PullWE(w) \ Registers.SL++; \ w = S9xGetWord(Registers.S.W, WRAP_PAGE); \ Registers.SL++; #define PullB(b) \ b = S9xGetByte(++Registers.S.W); #define PullBE(b) \ Registers.SL++; \ b = S9xGetByte(Registers.S.W); // PLA static void Op68E1 (void) { AddCycles(TWO_CYCLES); PullBE(Registers.AL); SetZN(Registers.AL); OpenBus = Registers.AL; } static void Op68E0M1 (void) { AddCycles(TWO_CYCLES); PullB(Registers.AL); SetZN(Registers.AL); OpenBus = Registers.AL; } static void Op68E0M0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.A.W); SetZN(Registers.A.W); OpenBus = Registers.AH; } static void Op68Slow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullBE(Registers.AL); SetZN(Registers.AL); OpenBus = Registers.AL; } else if (CheckMemory()) { PullB(Registers.AL); SetZN(Registers.AL); OpenBus = Registers.AL; } else { PullW(Registers.A.W); SetZN(Registers.A.W); OpenBus = Registers.AH; } } // PLB static void OpABE1 (void) { AddCycles(TWO_CYCLES); PullBE(Registers.DB); SetZN(Registers.DB); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = Registers.DB; } static void OpABE0 (void) { AddCycles(TWO_CYCLES); PullB(Registers.DB); SetZN(Registers.DB); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = Registers.DB; } static void OpABSlow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullBE(Registers.DB); } else { PullB(Registers.DB); } SetZN(Registers.DB); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = Registers.DB; } // PLD static void Op2BE0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.D.W); SetZN(Registers.D.W); OpenBus = Registers.DH; } static void Op2BE1 (void) { // Note: PLD is a new instruction, // and so doesn't respect the emu-mode stack bounds. AddCycles(TWO_CYCLES); PullW(Registers.D.W); SetZN(Registers.D.W); OpenBus = Registers.DH; Registers.SH = 1; } static void Op2BSlow (void) { AddCycles(TWO_CYCLES); PullW(Registers.D.W); SetZN(Registers.D.W); OpenBus = Registers.DH; if (CheckEmulation()) Registers.SH = 1; } // PLP static void Op28E1 (void) { AddCycles(TWO_CYCLES); PullBE(Registers.PL); OpenBus = Registers.PL; SetFlags(MemoryFlag | IndexFlag); S9xUnpackStatus(); S9xFixCycles(); CHECK_FOR_IRQ(); } static void Op28E0 (void) { AddCycles(TWO_CYCLES); PullB(Registers.PL); OpenBus = Registers.PL; S9xUnpackStatus(); if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); CHECK_FOR_IRQ(); } static void Op28Slow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullBE(Registers.PL); OpenBus = Registers.PL; SetFlags(MemoryFlag | IndexFlag); } else { PullB(Registers.PL); OpenBus = Registers.PL; } S9xUnpackStatus(); if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); CHECK_FOR_IRQ(); } // PLX static void OpFAE1 (void) { AddCycles(TWO_CYCLES); PullBE(Registers.XL); SetZN(Registers.XL); OpenBus = Registers.XL; } static void OpFAE0X1 (void) { AddCycles(TWO_CYCLES); PullB(Registers.XL); SetZN(Registers.XL); OpenBus = Registers.XL; } static void OpFAE0X0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.X.W); SetZN(Registers.X.W); OpenBus = Registers.XH; } static void OpFASlow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullBE(Registers.XL); SetZN(Registers.XL); OpenBus = Registers.XL; } else if (CheckIndex()) { PullB(Registers.XL); SetZN(Registers.XL); OpenBus = Registers.XL; } else { PullW(Registers.X.W); SetZN(Registers.X.W); OpenBus = Registers.XH; } } // PLY static void Op7AE1 (void) { AddCycles(TWO_CYCLES); PullBE(Registers.YL); SetZN(Registers.YL); OpenBus = Registers.YL; } static void Op7AE0X1 (void) { AddCycles(TWO_CYCLES); PullB(Registers.YL); SetZN(Registers.YL); OpenBus = Registers.YL; } static void Op7AE0X0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.Y.W); SetZN(Registers.Y.W); OpenBus = Registers.YH; } static void Op7ASlow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullBE(Registers.YL); SetZN(Registers.YL); OpenBus = Registers.YL; } else if (CheckIndex()) { PullB(Registers.YL); SetZN(Registers.YL); OpenBus = Registers.YL; } else { PullW(Registers.Y.W); SetZN(Registers.Y.W); OpenBus = Registers.YH; } } /* Transfer Instructions *************************************************** */ // TAX static void OpAAX1 (void) { AddCycles(ONE_CYCLE); Registers.XL = Registers.AL; SetZN(Registers.XL); } static void OpAAX0 (void) { AddCycles(ONE_CYCLE); Registers.X.W = Registers.A.W; SetZN(Registers.X.W); } static void OpAASlow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.XL = Registers.AL; SetZN(Registers.XL); } else { Registers.X.W = Registers.A.W; SetZN(Registers.X.W); } } // TAY static void OpA8X1 (void) { AddCycles(ONE_CYCLE); Registers.YL = Registers.AL; SetZN(Registers.YL); } static void OpA8X0 (void) { AddCycles(ONE_CYCLE); Registers.Y.W = Registers.A.W; SetZN(Registers.Y.W); } static void OpA8Slow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.YL = Registers.AL; SetZN(Registers.YL); } else { Registers.Y.W = Registers.A.W; SetZN(Registers.Y.W); } } // TCD static void Op5B (void) { AddCycles(ONE_CYCLE); Registers.D.W = Registers.A.W; SetZN(Registers.D.W); } // TCS static void Op1B (void) { AddCycles(ONE_CYCLE); Registers.S.W = Registers.A.W; if (CheckEmulation()) Registers.SH = 1; } // TDC static void Op7B (void) { AddCycles(ONE_CYCLE); Registers.A.W = Registers.D.W; SetZN(Registers.A.W); } // TSC static void Op3B (void) { AddCycles(ONE_CYCLE); Registers.A.W = Registers.S.W; SetZN(Registers.A.W); } // TSX static void OpBAX1 (void) { AddCycles(ONE_CYCLE); Registers.XL = Registers.SL; SetZN(Registers.XL); } static void OpBAX0 (void) { AddCycles(ONE_CYCLE); Registers.X.W = Registers.S.W; SetZN(Registers.X.W); } static void OpBASlow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.XL = Registers.SL; SetZN(Registers.XL); } else { Registers.X.W = Registers.S.W; SetZN(Registers.X.W); } } // TXA static void Op8AM1 (void) { AddCycles(ONE_CYCLE); Registers.AL = Registers.XL; SetZN(Registers.AL); } static void Op8AM0 (void) { AddCycles(ONE_CYCLE); Registers.A.W = Registers.X.W; SetZN(Registers.A.W); } static void Op8ASlow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { Registers.AL = Registers.XL; SetZN(Registers.AL); } else { Registers.A.W = Registers.X.W; SetZN(Registers.A.W); } } // TXS static void Op9A (void) { AddCycles(ONE_CYCLE); Registers.S.W = Registers.X.W; if (CheckEmulation()) Registers.SH = 1; } // TXY static void Op9BX1 (void) { AddCycles(ONE_CYCLE); Registers.YL = Registers.XL; SetZN(Registers.YL); } static void Op9BX0 (void) { AddCycles(ONE_CYCLE); Registers.Y.W = Registers.X.W; SetZN(Registers.Y.W); } static void Op9BSlow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.YL = Registers.XL; SetZN(Registers.YL); } else { Registers.Y.W = Registers.X.W; SetZN(Registers.Y.W); } } // TYA static void Op98M1 (void) { AddCycles(ONE_CYCLE); Registers.AL = Registers.YL; SetZN(Registers.AL); } static void Op98M0 (void) { AddCycles(ONE_CYCLE); Registers.A.W = Registers.Y.W; SetZN(Registers.A.W); } static void Op98Slow (void) { AddCycles(ONE_CYCLE); if (CheckMemory()) { Registers.AL = Registers.YL; SetZN(Registers.AL); } else { Registers.A.W = Registers.Y.W; SetZN(Registers.A.W); } } // TYX static void OpBBX1 (void) { AddCycles(ONE_CYCLE); Registers.XL = Registers.YL; SetZN(Registers.XL); } static void OpBBX0 (void) { AddCycles(ONE_CYCLE); Registers.X.W = Registers.Y.W; SetZN(Registers.X.W); } static void OpBBSlow (void) { AddCycles(ONE_CYCLE); if (CheckIndex()) { Registers.XL = Registers.YL; SetZN(Registers.XL); } else { Registers.X.W = Registers.Y.W; SetZN(Registers.X.W); } } /* XCE ********************************************************************* */ static void OpFB (void) { AddCycles(ONE_CYCLE); uint8 A1 = ICPU._Carry; uint8 A2 = Registers.PH; ICPU._Carry = A2 & 1; Registers.PH = A1; if (CheckEmulation()) { SetFlags(MemoryFlag | IndexFlag); Registers.SH = 1; #ifdef DEBUGGER missing.emulate6502 = 1; #endif } if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); } /* BRK ********************************************************************* */ static void Op00 (void) { #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) S9xTraceMessage("*** BRK"); #endif AddCycles(CPU.MemSpeed); uint16 addr; if (!CheckEmulation()) { PushB(Registers.PB); PushW(Registers.PCw + 1); S9xPackStatus(); PushB(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); addr = S9xGetWord(0xFFE6); } else { PushWE(Registers.PCw + 1); S9xPackStatus(); PushBE(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); addr = S9xGetWord(0xFFFE); } S9xSetPCBase(addr); OpenBus = addr >> 8; } /* IRQ ********************************************************************* */ void S9xOpcode_IRQ (void) { #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) #ifdef SA1_OPCODES S9xTraceMessage("*** SA1 IRQ"); #else S9xTraceMessage("*** IRQ"); #endif #endif // IRQ and NMI do an opcode fetch as their first "IO" cycle. AddCycles(CPU.MemSpeed + ONE_CYCLE); if (!CheckEmulation()) { PushB(Registers.PB); PushW(Registers.PCw); S9xPackStatus(); PushB(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); #ifdef SA1_OPCODES OpenBus = Memory.FillRAM[0x2208]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8)); #else if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40)) { OpenBus = Memory.FillRAM[0x220f]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSetPCBase(Memory.FillRAM[0x220e] | (Memory.FillRAM[0x220f] << 8)); } else { uint16 addr = S9xGetWord(0xFFEE); OpenBus = addr >> 8; S9xSetPCBase(addr); } #endif } else { PushWE(Registers.PCw); S9xPackStatus(); PushBE(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); #ifdef SA1_OPCODES OpenBus = Memory.FillRAM[0x2208]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8)); #else if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40)) { OpenBus = Memory.FillRAM[0x220f]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSetPCBase(Memory.FillRAM[0x220e] | (Memory.FillRAM[0x220f] << 8)); } else { uint16 addr = S9xGetWord(0xFFFE); OpenBus = addr >> 8; S9xSetPCBase(addr); } #endif } } /* NMI ********************************************************************* */ void S9xOpcode_NMI (void) { #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) #ifdef SA1_OPCODES S9xTraceMessage("*** SA1 NMI"); #else S9xTraceMessage("*** NMI"); #endif #endif // IRQ and NMI do an opcode fetch as their first "IO" cycle. AddCycles(CPU.MemSpeed + ONE_CYCLE); if (!CheckEmulation()) { PushB(Registers.PB); PushW(Registers.PCw); S9xPackStatus(); PushB(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); #ifdef SA1_OPCODES OpenBus = Memory.FillRAM[0x2206]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8)); #else if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10)) { OpenBus = Memory.FillRAM[0x220d]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSetPCBase(Memory.FillRAM[0x220c] | (Memory.FillRAM[0x220d] << 8)); } else { uint16 addr = S9xGetWord(0xFFEA); OpenBus = addr >> 8; S9xSetPCBase(addr); } #endif } else { PushWE(Registers.PCw); S9xPackStatus(); PushBE(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); #ifdef SA1_OPCODES OpenBus = Memory.FillRAM[0x2206]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8)); #else if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10)) { OpenBus = Memory.FillRAM[0x220d]; AddCycles(2 * SLOW_ONE_CYCLE); S9xSetPCBase(Memory.FillRAM[0x220c] | (Memory.FillRAM[0x220d] << 8)); } else { uint16 addr = S9xGetWord(0xFFFA); OpenBus = addr >> 8; S9xSetPCBase(addr); } #endif } } /* COP ********************************************************************* */ static void Op02 (void) { #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) S9xTraceMessage("*** COP"); #endif AddCycles(CPU.MemSpeed); uint16 addr; if (!CheckEmulation()) { PushB(Registers.PB); PushW(Registers.PCw + 1); S9xPackStatus(); PushB(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); addr = S9xGetWord(0xFFE4); } else { PushWE(Registers.PCw + 1); S9xPackStatus(); PushBE(Registers.PL); OpenBus = Registers.PL; ClearDecimal(); SetIRQ(); addr = S9xGetWord(0xFFF4); } S9xSetPCBase(addr); OpenBus = addr >> 8; } /* JML ********************************************************************* */ static void OpDC (void) { S9xSetPCBase(AbsoluteIndirectLong(JUMP)); } static void OpDCSlow (void) { S9xSetPCBase(AbsoluteIndirectLongSlow(JUMP)); } static void Op5C (void) { S9xSetPCBase(AbsoluteLong(JUMP)); } static void Op5CSlow (void) { S9xSetPCBase(AbsoluteLongSlow(JUMP)); } /* JMP ********************************************************************* */ static void Op4C (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) Absolute(JUMP))); } static void Op4CSlow (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteSlow(JUMP))); } static void Op6C (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteIndirect(JUMP))); } static void Op6CSlow (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteIndirectSlow(JUMP))); } static void Op7C (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteIndexedIndirect(JUMP))); } static void Op7CSlow (void) { S9xSetPCBase(ICPU.ShiftedPB + ((uint16) AbsoluteIndexedIndirectSlow(JUMP))); } /* JSL/RTL ***************************************************************** */ static void Op22E1 (void) { // Note: JSL is a new instruction, // and so doesn't respect the emu-mode stack bounds. uint32 addr = AbsoluteLong(JSR); PushB(Registers.PB); PushW(Registers.PCw - 1); Registers.SH = 1; S9xSetPCBase(addr); } static void Op22E0 (void) { uint32 addr = AbsoluteLong(JSR); PushB(Registers.PB); PushW(Registers.PCw - 1); S9xSetPCBase(addr); } static void Op22Slow (void) { uint32 addr = AbsoluteLongSlow(JSR); PushB(Registers.PB); PushW(Registers.PCw - 1); if (CheckEmulation()) Registers.SH = 1; S9xSetPCBase(addr); } static void Op6BE1 (void) { // Note: RTL is a new instruction, // and so doesn't respect the emu-mode stack bounds. AddCycles(TWO_CYCLES); PullW(Registers.PCw); PullB(Registers.PB); Registers.SH = 1; Registers.PCw++; S9xSetPCBase(Registers.PBPC); } static void Op6BE0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.PCw); PullB(Registers.PB); Registers.PCw++; S9xSetPCBase(Registers.PBPC); } static void Op6BSlow (void) { AddCycles(TWO_CYCLES); PullW(Registers.PCw); PullB(Registers.PB); if (CheckEmulation()) Registers.SH = 1; Registers.PCw++; S9xSetPCBase(Registers.PBPC); } /* JSR/RTS ***************************************************************** */ static void Op20E1 (void) { uint16 addr = Absolute(JSR); AddCycles(ONE_CYCLE); PushWE(Registers.PCw - 1); S9xSetPCBase(ICPU.ShiftedPB + addr); } static void Op20E0 (void) { uint16 addr = Absolute(JSR); AddCycles(ONE_CYCLE); PushW(Registers.PCw - 1); S9xSetPCBase(ICPU.ShiftedPB + addr); } static void Op20Slow (void) { uint16 addr = AbsoluteSlow(JSR); AddCycles(ONE_CYCLE); if (CheckEmulation()) { PushWE(Registers.PCw - 1); } else { PushW(Registers.PCw - 1); } S9xSetPCBase(ICPU.ShiftedPB + addr); } static void OpFCE1 (void) { // Note: JSR (a,X) is a new instruction, // and so doesn't respect the emu-mode stack bounds. uint16 addr = AbsoluteIndexedIndirect(JSR); PushW(Registers.PCw - 1); Registers.SH = 1; S9xSetPCBase(ICPU.ShiftedPB + addr); } static void OpFCE0 (void) { uint16 addr = AbsoluteIndexedIndirect(JSR); PushW(Registers.PCw - 1); S9xSetPCBase(ICPU.ShiftedPB + addr); } static void OpFCSlow (void) { uint16 addr = AbsoluteIndexedIndirectSlow(JSR); PushW(Registers.PCw - 1); if (CheckEmulation()) Registers.SH = 1; S9xSetPCBase(ICPU.ShiftedPB + addr); } static void Op60E1 (void) { AddCycles(TWO_CYCLES); PullWE(Registers.PCw); AddCycles(ONE_CYCLE); Registers.PCw++; S9xSetPCBase(Registers.PBPC); } static void Op60E0 (void) { AddCycles(TWO_CYCLES); PullW(Registers.PCw); AddCycles(ONE_CYCLE); Registers.PCw++; S9xSetPCBase(Registers.PBPC); } static void Op60Slow (void) { AddCycles(TWO_CYCLES); if (CheckEmulation()) { PullWE(Registers.PCw); } else { PullW(Registers.PCw); } AddCycles(ONE_CYCLE); Registers.PCw++; S9xSetPCBase(Registers.PBPC); } /* MVN/MVP ***************************************************************** */ static void Op54X1 (void) { uint32 SrcBank; Registers.DB = Immediate8(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); Registers.XL++; Registers.YL++; Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } static void Op54X0 (void) { uint32 SrcBank; Registers.DB = Immediate8(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); Registers.X.W++; Registers.Y.W++; Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } static void Op54Slow (void) { uint32 SrcBank; OpenBus = Registers.DB = Immediate8Slow(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8Slow(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); if (CheckIndex()) { Registers.XL++; Registers.YL++; } else { Registers.X.W++; Registers.Y.W++; } Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } static void Op44X1 (void) { uint32 SrcBank; Registers.DB = Immediate8(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); Registers.XL--; Registers.YL--; Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } static void Op44X0 (void) { uint32 SrcBank; Registers.DB = Immediate8(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); Registers.X.W--; Registers.Y.W--; Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } static void Op44Slow (void) { uint32 SrcBank; OpenBus = Registers.DB = Immediate8Slow(NONE); ICPU.ShiftedDB = Registers.DB << 16; OpenBus = SrcBank = Immediate8Slow(NONE); S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W); if (CheckIndex()) { Registers.XL--; Registers.YL--; } else { Registers.X.W--; Registers.Y.W--; } Registers.A.W--; if (Registers.A.W != 0xffff) Registers.PCw -= 3; AddCycles(TWO_CYCLES); } /* REP/SEP ***************************************************************** */ static void OpC2 (void) { uint8 Work8 = ~Immediate8(READ); Registers.PL &= Work8; ICPU._Carry &= Work8; ICPU._Overflow &= (Work8 >> 6); ICPU._Negative &= Work8; ICPU._Zero |= ~Work8 & Zero; AddCycles(ONE_CYCLE); if (CheckEmulation()) { SetFlags(MemoryFlag | IndexFlag); #ifdef DEBUGGER missing.emulate6502 = 1; #endif } if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); CHECK_FOR_IRQ(); } static void OpC2Slow (void) { uint8 Work8 = ~Immediate8Slow(READ); Registers.PL &= Work8; ICPU._Carry &= Work8; ICPU._Overflow &= (Work8 >> 6); ICPU._Negative &= Work8; ICPU._Zero |= ~Work8 & Zero; AddCycles(ONE_CYCLE); if (CheckEmulation()) { SetFlags(MemoryFlag | IndexFlag); #ifdef DEBUGGER missing.emulate6502 = 1; #endif } if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); CHECK_FOR_IRQ(); } static void OpE2 (void) { uint8 Work8 = Immediate8(READ); Registers.PL |= Work8; ICPU._Carry |= Work8 & 1; ICPU._Overflow |= (Work8 >> 6) & 1; ICPU._Negative |= Work8; if (Work8 & Zero) ICPU._Zero = 0; AddCycles(ONE_CYCLE); if (CheckEmulation()) { SetFlags(MemoryFlag | IndexFlag); #ifdef DEBUGGER missing.emulate6502 = 1; #endif } if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); } static void OpE2Slow (void) { uint8 Work8 = Immediate8Slow(READ); Registers.PL |= Work8; ICPU._Carry |= Work8 & 1; ICPU._Overflow |= (Work8 >> 6) & 1; ICPU._Negative |= Work8; if (Work8 & Zero) ICPU._Zero = 0; AddCycles(ONE_CYCLE); if (CheckEmulation()) { SetFlags(MemoryFlag | IndexFlag); #ifdef DEBUGGER missing.emulate6502 = 1; #endif } if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); } /* XBA ********************************************************************* */ static void OpEB (void) { uint8 Work8 = Registers.AL; Registers.AL = Registers.AH; Registers.AH = Work8; SetZN(Registers.AL); AddCycles(TWO_CYCLES); } /* RTI ********************************************************************* */ static void Op40Slow (void) { AddCycles(TWO_CYCLES); if (!CheckEmulation()) { PullB(Registers.PL); S9xUnpackStatus(); PullW(Registers.PCw); PullB(Registers.PB); OpenBus = Registers.PB; ICPU.ShiftedPB = Registers.PB << 16; } else { PullBE(Registers.PL); S9xUnpackStatus(); PullWE(Registers.PCw); OpenBus = Registers.PCh; SetFlags(MemoryFlag | IndexFlag); #ifdef DEBUGGER missing.emulate6502 = 1; #endif } S9xSetPCBase(Registers.PBPC); if (CheckIndex()) { Registers.XH = 0; Registers.YH = 0; } S9xFixCycles(); CHECK_FOR_IRQ(); } /* STP/WAI ***************************************************************** */ // WAI static void OpCB (void) { #ifdef SA1_OPCODES SA1.WaitingForInterrupt = TRUE; Registers.PCw--; AddCycles(TWO_CYCLES); #else CPU.WaitingForInterrupt = TRUE; Registers.PCw--; AddCycles(TWO_CYCLES); #endif } // STP static void OpDB (void) { Registers.PCw--; CPU.Flags |= DEBUG_MODE_FLAG | HALTED_FLAG; AddCycles(ONE_CYCLE); } /* WDM (Reserved S9xOpcode) ************************************************ */ #ifdef DEBUGGER extern FILE *trace, *trace2; #endif static void Op42 (void) { #ifdef DEBUGGER uint8 byte = (uint8) S9xGetWord(Registers.PBPC); #else S9xGetWord(Registers.PBPC); #endif Registers.PCw++; #ifdef DEBUGGER // Hey, let's use this to trigger debug modes. switch (byte) { case 0xdb: // "STP" = Enter debug mode CPU.Flags |= DEBUG_MODE_FLAG; break; #ifndef SA1_OPCODES case 0xe2: // "SEP" = Trace on if (!(CPU.Flags & TRACE_FLAG)) { char buf[25]; CPU.Flags |= TRACE_FLAG; snprintf(buf, 25, "WDM trace on at $%02X:%04X", Registers.PB, Registers.PCw); S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf); if (trace != NULL) fclose(trace); ENSURE_TRACE_OPEN(trace, "WDMtrace.log", "ab") } break; case 0xc2: // "REP" = Trace off if (CPU.Flags & TRACE_FLAG) { char buf[26]; CPU.Flags &= ~TRACE_FLAG; snprintf(buf, 26, "WDM trace off at $%02X:%04X", Registers.PB, Registers.PCw); S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf); if (trace != NULL) fclose(trace); trace = NULL; } break; #endif case 0x42: // "WDM" = Snapshot char filename[PATH_MAX + 1], drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[PATH_MAX + 1], ext[_MAX_EXT + 1]; _splitpath(Memory.ROMFilename, drive, dir, def, ext); snprintf(filename, PATH_MAX, "%s%s%s-%06X.wdm", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, Registers.PBPC & 0xffffff); sprintf(def, "WDM Snapshot at $%02X:%04X: %s", Registers.PB, Registers.PCw, filename); S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, def); S9xFreezeGame(filename); break; default: break; } #endif } /* CPU-S9xOpcodes Definitions ************************************************/ struct SOpcodes S9xOpcodesM1X1[256] = { { Op00 }, { Op01E0M1 }, { Op02 }, { Op03M1 }, { Op04M1 }, { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E0 }, { Op09M1 }, { Op0AM1 }, { Op0BE0 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 }, { Op0FM1 }, { Op10E0 }, { Op11E0M1X1 }, { Op12E0M1 }, { Op13M1 }, { Op14M1 }, { Op15E0M1 }, { Op16E0M1 }, { Op17M1 }, { Op18 }, { Op19M1X1 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X1 }, { Op1EM1X1 }, { Op1FM1 }, { Op20E0 }, { Op21E0M1 }, { Op22E0 }, { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 }, { Op28E0 }, { Op29M1 }, { Op2AM1 }, { Op2BE0 }, { Op2CM1 }, { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E0 }, { Op31E0M1X1 }, { Op32E0M1 }, { Op33M1 }, { Op34E0M1 }, { Op35E0M1 }, { Op36E0M1 }, { Op37M1 }, { Op38 }, { Op39M1X1 }, { Op3AM1 }, { Op3B }, { Op3CM1X1 }, { Op3DM1X1 }, { Op3EM1X1 }, { Op3FM1 }, { Op40Slow }, { Op41E0M1 }, { Op42 }, { Op43M1 }, { Op44X1 }, { Op45M1 }, { Op46M1 }, { Op47M1 }, { Op48E0M1 }, { Op49M1 }, { Op4AM1 }, { Op4BE0 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 }, { Op50E0 }, { Op51E0M1X1 }, { Op52E0M1 }, { Op53M1 }, { Op54X1 }, { Op55E0M1 }, { Op56E0M1 }, { Op57M1 }, { Op58 }, { Op59M1X1 }, { Op5AE0X1 }, { Op5B }, { Op5C }, { Op5DM1X1 }, { Op5EM1X1 }, { Op5FM1 }, { Op60E0 }, { Op61E0M1 }, { Op62E0 }, { Op63M1 }, { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E0M1 }, { Op69M1 }, { Op6AM1 }, { Op6BE0 }, { Op6C }, { Op6DM1 }, { Op6EM1 }, { Op6FM1 }, { Op70E0 }, { Op71E0M1X1 }, { Op72E0M1 }, { Op73M1 }, { Op74E0M1 }, { Op75E0M1 }, { Op76E0M1 }, { Op77M1 }, { Op78 }, { Op79M1X1 }, { Op7AE0X1 }, { Op7B }, { Op7C }, { Op7DM1X1 }, { Op7EM1X1 }, { Op7FM1 }, { Op80E0 }, { Op81E0M1 }, { Op82 }, { Op83M1 }, { Op84X1 }, { Op85M1 }, { Op86X1 }, { Op87M1 }, { Op88X1 }, { Op89M1 }, { Op8AM1 }, { Op8BE0 }, { Op8CX1 }, { Op8DM1 }, { Op8EX1 }, { Op8FM1 }, { Op90E0 }, { Op91E0M1X1 }, { Op92E0M1 }, { Op93M1 }, { Op94E0X1 }, { Op95E0M1 }, { Op96E0X1 }, { Op97M1 }, { Op98M1 }, { Op99M1X1 }, { Op9A }, { Op9BX1 }, { Op9CM1 }, { Op9DM1X1 }, { Op9EM1X1 }, { Op9FM1 }, { OpA0X1 }, { OpA1E0M1 }, { OpA2X1 }, { OpA3M1 }, { OpA4X1 }, { OpA5M1 }, { OpA6X1 }, { OpA7M1 }, { OpA8X1 }, { OpA9M1 }, { OpAAX1 }, { OpABE0 }, { OpACX1 }, { OpADM1 }, { OpAEX1 }, { OpAFM1 }, { OpB0E0 }, { OpB1E0M1X1 }, { OpB2E0M1 }, { OpB3M1 }, { OpB4E0X1 }, { OpB5E0M1 }, { OpB6E0X1 }, { OpB7M1 }, { OpB8 }, { OpB9M1X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM1X1 }, { OpBEX1 }, { OpBFM1 }, { OpC0X1 }, { OpC1E0M1 }, { OpC2 }, { OpC3M1 }, { OpC4X1 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 }, { OpC8X1 }, { OpC9M1 }, { OpCAX1 }, { OpCB }, { OpCCX1 }, { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E0 }, { OpD1E0M1X1 }, { OpD2E0M1 }, { OpD3M1 }, { OpD4E0 }, { OpD5E0M1 }, { OpD6E0M1 }, { OpD7M1 }, { OpD8 }, { OpD9M1X1 }, { OpDAE0X1 }, { OpDB }, { OpDC }, { OpDDM1X1 }, { OpDEM1X1 }, { OpDFM1 }, { OpE0X1 }, { OpE1E0M1 }, { OpE2 }, { OpE3M1 }, { OpE4X1 }, { OpE5M1 }, { OpE6M1 }, { OpE7M1 }, { OpE8X1 }, { OpE9M1 }, { OpEA }, { OpEB }, { OpECX1 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 }, { OpF0E0 }, { OpF1E0M1X1 }, { OpF2E0M1 }, { OpF3M1 }, { OpF4E0 }, { OpF5E0M1 }, { OpF6E0M1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X1 }, { OpFAE0X1 }, { OpFB }, { OpFCE0 }, { OpFDM1X1 }, { OpFEM1X1 }, { OpFFM1 } }; struct SOpcodes S9xOpcodesE1[256] = { { Op00 }, { Op01E1 }, { Op02 }, { Op03M1 }, { Op04M1 }, { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E1 }, { Op09M1 }, { Op0AM1 }, { Op0BE1 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 }, { Op0FM1 }, { Op10E1 }, { Op11E1 }, { Op12E1 }, { Op13M1 }, { Op14M1 }, { Op15E1 }, { Op16E1 }, { Op17M1 }, { Op18 }, { Op19M1X1 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X1 }, { Op1EM1X1 }, { Op1FM1 }, { Op20E1 }, { Op21E1 }, { Op22E1 }, { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 }, { Op28E1 }, { Op29M1 }, { Op2AM1 }, { Op2BE1 }, { Op2CM1 }, { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E1 }, { Op31E1 }, { Op32E1 }, { Op33M1 }, { Op34E1 }, { Op35E1 }, { Op36E1 }, { Op37M1 }, { Op38 }, { Op39M1X1 }, { Op3AM1 }, { Op3B }, { Op3CM1X1 }, { Op3DM1X1 }, { Op3EM1X1 }, { Op3FM1 }, { Op40Slow }, { Op41E1 }, { Op42 }, { Op43M1 }, { Op44X1 }, { Op45M1 }, { Op46M1 }, { Op47M1 }, { Op48E1 }, { Op49M1 }, { Op4AM1 }, { Op4BE1 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 }, { Op50E1 }, { Op51E1 }, { Op52E1 }, { Op53M1 }, { Op54X1 }, { Op55E1 }, { Op56E1 }, { Op57M1 }, { Op58 }, { Op59M1X1 }, { Op5AE1 }, { Op5B }, { Op5C }, { Op5DM1X1 }, { Op5EM1X1 }, { Op5FM1 }, { Op60E1 }, { Op61E1 }, { Op62E1 }, { Op63M1 }, { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E1 }, { Op69M1 }, { Op6AM1 }, { Op6BE1 }, { Op6C }, { Op6DM1 }, { Op6EM1 }, { Op6FM1 }, { Op70E1 }, { Op71E1 }, { Op72E1 }, { Op73M1 }, { Op74E1 }, { Op75E1 }, { Op76E1 }, { Op77M1 }, { Op78 }, { Op79M1X1 }, { Op7AE1 }, { Op7B }, { Op7C }, { Op7DM1X1 }, { Op7EM1X1 }, { Op7FM1 }, { Op80E1 }, { Op81E1 }, { Op82 }, { Op83M1 }, { Op84X1 }, { Op85M1 }, { Op86X1 }, { Op87M1 }, { Op88X1 }, { Op89M1 }, { Op8AM1 }, { Op8BE1 }, { Op8CX1 }, { Op8DM1 }, { Op8EX1 }, { Op8FM1 }, { Op90E1 }, { Op91E1 }, { Op92E1 }, { Op93M1 }, { Op94E1 }, { Op95E1 }, { Op96E1 }, { Op97M1 }, { Op98M1 }, { Op99M1X1 }, { Op9A }, { Op9BX1 }, { Op9CM1 }, { Op9DM1X1 }, { Op9EM1X1 }, { Op9FM1 }, { OpA0X1 }, { OpA1E1 }, { OpA2X1 }, { OpA3M1 }, { OpA4X1 }, { OpA5M1 }, { OpA6X1 }, { OpA7M1 }, { OpA8X1 }, { OpA9M1 }, { OpAAX1 }, { OpABE1 }, { OpACX1 }, { OpADM1 }, { OpAEX1 }, { OpAFM1 }, { OpB0E1 }, { OpB1E1 }, { OpB2E1 }, { OpB3M1 }, { OpB4E1 }, { OpB5E1 }, { OpB6E1 }, { OpB7M1 }, { OpB8 }, { OpB9M1X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM1X1 }, { OpBEX1 }, { OpBFM1 }, { OpC0X1 }, { OpC1E1 }, { OpC2 }, { OpC3M1 }, { OpC4X1 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 }, { OpC8X1 }, { OpC9M1 }, { OpCAX1 }, { OpCB }, { OpCCX1 }, { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E1 }, { OpD1E1 }, { OpD2E1 }, { OpD3M1 }, { OpD4E1 }, { OpD5E1 }, { OpD6E1 }, { OpD7M1 }, { OpD8 }, { OpD9M1X1 }, { OpDAE1 }, { OpDB }, { OpDC }, { OpDDM1X1 }, { OpDEM1X1 }, { OpDFM1 }, { OpE0X1 }, { OpE1E1 }, { OpE2 }, { OpE3M1 }, { OpE4X1 }, { OpE5M1 }, { OpE6M1 }, { OpE7M1 }, { OpE8X1 }, { OpE9M1 }, { OpEA }, { OpEB }, { OpECX1 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 }, { OpF0E1 }, { OpF1E1 }, { OpF2E1 }, { OpF3M1 }, { OpF4E1 }, { OpF5E1 }, { OpF6E1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X1 }, { OpFAE1 }, { OpFB }, { OpFCE1 }, { OpFDM1X1 }, { OpFEM1X1 }, { OpFFM1 } }; struct SOpcodes S9xOpcodesM1X0[256] = { { Op00 }, { Op01E0M1 }, { Op02 }, { Op03M1 }, { Op04M1 }, { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E0 }, { Op09M1 }, { Op0AM1 }, { Op0BE0 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 }, { Op0FM1 }, { Op10E0 }, { Op11E0M1X0 }, { Op12E0M1 }, { Op13M1 }, { Op14M1 }, { Op15E0M1 }, { Op16E0M1 }, { Op17M1 }, { Op18 }, { Op19M1X0 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X0 }, { Op1EM1X0 }, { Op1FM1 }, { Op20E0 }, { Op21E0M1 }, { Op22E0 }, { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 }, { Op28E0 }, { Op29M1 }, { Op2AM1 }, { Op2BE0 }, { Op2CM1 }, { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E0 }, { Op31E0M1X0 }, { Op32E0M1 }, { Op33M1 }, { Op34E0M1 }, { Op35E0M1 }, { Op36E0M1 }, { Op37M1 }, { Op38 }, { Op39M1X0 }, { Op3AM1 }, { Op3B }, { Op3CM1X0 }, { Op3DM1X0 }, { Op3EM1X0 }, { Op3FM1 }, { Op40Slow }, { Op41E0M1 }, { Op42 }, { Op43M1 }, { Op44X0 }, { Op45M1 }, { Op46M1 }, { Op47M1 }, { Op48E0M1 }, { Op49M1 }, { Op4AM1 }, { Op4BE0 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 }, { Op50E0 }, { Op51E0M1X0 }, { Op52E0M1 }, { Op53M1 }, { Op54X0 }, { Op55E0M1 }, { Op56E0M1 }, { Op57M1 }, { Op58 }, { Op59M1X0 }, { Op5AE0X0 }, { Op5B }, { Op5C }, { Op5DM1X0 }, { Op5EM1X0 }, { Op5FM1 }, { Op60E0 }, { Op61E0M1 }, { Op62E0 }, { Op63M1 }, { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E0M1 }, { Op69M1 }, { Op6AM1 }, { Op6BE0 }, { Op6C }, { Op6DM1 }, { Op6EM1 }, { Op6FM1 }, { Op70E0 }, { Op71E0M1X0 }, { Op72E0M1 }, { Op73M1 }, { Op74E0M1 }, { Op75E0M1 }, { Op76E0M1 }, { Op77M1 }, { Op78 }, { Op79M1X0 }, { Op7AE0X0 }, { Op7B }, { Op7C }, { Op7DM1X0 }, { Op7EM1X0 }, { Op7FM1 }, { Op80E0 }, { Op81E0M1 }, { Op82 }, { Op83M1 }, { Op84X0 }, { Op85M1 }, { Op86X0 }, { Op87M1 }, { Op88X0 }, { Op89M1 }, { Op8AM1 }, { Op8BE0 }, { Op8CX0 }, { Op8DM1 }, { Op8EX0 }, { Op8FM1 }, { Op90E0 }, { Op91E0M1X0 }, { Op92E0M1 }, { Op93M1 }, { Op94E0X0 }, { Op95E0M1 }, { Op96E0X0 }, { Op97M1 }, { Op98M1 }, { Op99M1X0 }, { Op9A }, { Op9BX0 }, { Op9CM1 }, { Op9DM1X0 }, { Op9EM1X0 }, { Op9FM1 }, { OpA0X0 }, { OpA1E0M1 }, { OpA2X0 }, { OpA3M1 }, { OpA4X0 }, { OpA5M1 }, { OpA6X0 }, { OpA7M1 }, { OpA8X0 }, { OpA9M1 }, { OpAAX0 }, { OpABE0 }, { OpACX0 }, { OpADM1 }, { OpAEX0 }, { OpAFM1 }, { OpB0E0 }, { OpB1E0M1X0 }, { OpB2E0M1 }, { OpB3M1 }, { OpB4E0X0 }, { OpB5E0M1 }, { OpB6E0X0 }, { OpB7M1 }, { OpB8 }, { OpB9M1X0 }, { OpBAX0 }, { OpBBX0 }, { OpBCX0 }, { OpBDM1X0 }, { OpBEX0 }, { OpBFM1 }, { OpC0X0 }, { OpC1E0M1 }, { OpC2 }, { OpC3M1 }, { OpC4X0 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 }, { OpC8X0 }, { OpC9M1 }, { OpCAX0 }, { OpCB }, { OpCCX0 }, { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E0 }, { OpD1E0M1X0 }, { OpD2E0M1 }, { OpD3M1 }, { OpD4E0 }, { OpD5E0M1 }, { OpD6E0M1 }, { OpD7M1 }, { OpD8 }, { OpD9M1X0 }, { OpDAE0X0 }, { OpDB }, { OpDC }, { OpDDM1X0 }, { OpDEM1X0 }, { OpDFM1 }, { OpE0X0 }, { OpE1E0M1 }, { OpE2 }, { OpE3M1 }, { OpE4X0 }, { OpE5M1 }, { OpE6M1 }, { OpE7M1 }, { OpE8X0 }, { OpE9M1 }, { OpEA }, { OpEB }, { OpECX0 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 }, { OpF0E0 }, { OpF1E0M1X0 }, { OpF2E0M1 }, { OpF3M1 }, { OpF4E0 }, { OpF5E0M1 }, { OpF6E0M1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X0 }, { OpFAE0X0 }, { OpFB }, { OpFCE0 }, { OpFDM1X0 }, { OpFEM1X0 }, { OpFFM1 } }; struct SOpcodes S9xOpcodesM0X0[256] = { { Op00 }, { Op01E0M0 }, { Op02 }, { Op03M0 }, { Op04M0 }, { Op05M0 }, { Op06M0 }, { Op07M0 }, { Op08E0 }, { Op09M0 }, { Op0AM0 }, { Op0BE0 }, { Op0CM0 }, { Op0DM0 }, { Op0EM0 }, { Op0FM0 }, { Op10E0 }, { Op11E0M0X0 }, { Op12E0M0 }, { Op13M0 }, { Op14M0 }, { Op15E0M0 }, { Op16E0M0 }, { Op17M0 }, { Op18 }, { Op19M0X0 }, { Op1AM0 }, { Op1B }, { Op1CM0 }, { Op1DM0X0 }, { Op1EM0X0 }, { Op1FM0 }, { Op20E0 }, { Op21E0M0 }, { Op22E0 }, { Op23M0 }, { Op24M0 }, { Op25M0 }, { Op26M0 }, { Op27M0 }, { Op28E0 }, { Op29M0 }, { Op2AM0 }, { Op2BE0 }, { Op2CM0 }, { Op2DM0 }, { Op2EM0 }, { Op2FM0 }, { Op30E0 }, { Op31E0M0X0 }, { Op32E0M0 }, { Op33M0 }, { Op34E0M0 }, { Op35E0M0 }, { Op36E0M0 }, { Op37M0 }, { Op38 }, { Op39M0X0 }, { Op3AM0 }, { Op3B }, { Op3CM0X0 }, { Op3DM0X0 }, { Op3EM0X0 }, { Op3FM0 }, { Op40Slow }, { Op41E0M0 }, { Op42 }, { Op43M0 }, { Op44X0 }, { Op45M0 }, { Op46M0 }, { Op47M0 }, { Op48E0M0 }, { Op49M0 }, { Op4AM0 }, { Op4BE0 }, { Op4C }, { Op4DM0 }, { Op4EM0 }, { Op4FM0 }, { Op50E0 }, { Op51E0M0X0 }, { Op52E0M0 }, { Op53M0 }, { Op54X0 }, { Op55E0M0 }, { Op56E0M0 }, { Op57M0 }, { Op58 }, { Op59M0X0 }, { Op5AE0X0 }, { Op5B }, { Op5C }, { Op5DM0X0 }, { Op5EM0X0 }, { Op5FM0 }, { Op60E0 }, { Op61E0M0 }, { Op62E0 }, { Op63M0 }, { Op64M0 }, { Op65M0 }, { Op66M0 }, { Op67M0 }, { Op68E0M0 }, { Op69M0 }, { Op6AM0 }, { Op6BE0 }, { Op6C }, { Op6DM0 }, { Op6EM0 }, { Op6FM0 }, { Op70E0 }, { Op71E0M0X0 }, { Op72E0M0 }, { Op73M0 }, { Op74E0M0 }, { Op75E0M0 }, { Op76E0M0 }, { Op77M0 }, { Op78 }, { Op79M0X0 }, { Op7AE0X0 }, { Op7B }, { Op7C }, { Op7DM0X0 }, { Op7EM0X0 }, { Op7FM0 }, { Op80E0 }, { Op81E0M0 }, { Op82 }, { Op83M0 }, { Op84X0 }, { Op85M0 }, { Op86X0 }, { Op87M0 }, { Op88X0 }, { Op89M0 }, { Op8AM0 }, { Op8BE0 }, { Op8CX0 }, { Op8DM0 }, { Op8EX0 }, { Op8FM0 }, { Op90E0 }, { Op91E0M0X0 }, { Op92E0M0 }, { Op93M0 }, { Op94E0X0 }, { Op95E0M0 }, { Op96E0X0 }, { Op97M0 }, { Op98M0 }, { Op99M0X0 }, { Op9A }, { Op9BX0 }, { Op9CM0 }, { Op9DM0X0 }, { Op9EM0X0 }, { Op9FM0 }, { OpA0X0 }, { OpA1E0M0 }, { OpA2X0 }, { OpA3M0 }, { OpA4X0 }, { OpA5M0 }, { OpA6X0 }, { OpA7M0 }, { OpA8X0 }, { OpA9M0 }, { OpAAX0 }, { OpABE0 }, { OpACX0 }, { OpADM0 }, { OpAEX0 }, { OpAFM0 }, { OpB0E0 }, { OpB1E0M0X0 }, { OpB2E0M0 }, { OpB3M0 }, { OpB4E0X0 }, { OpB5E0M0 }, { OpB6E0X0 }, { OpB7M0 }, { OpB8 }, { OpB9M0X0 }, { OpBAX0 }, { OpBBX0 }, { OpBCX0 }, { OpBDM0X0 }, { OpBEX0 }, { OpBFM0 }, { OpC0X0 }, { OpC1E0M0 }, { OpC2 }, { OpC3M0 }, { OpC4X0 }, { OpC5M0 }, { OpC6M0 }, { OpC7M0 }, { OpC8X0 }, { OpC9M0 }, { OpCAX0 }, { OpCB }, { OpCCX0 }, { OpCDM0 }, { OpCEM0 }, { OpCFM0 }, { OpD0E0 }, { OpD1E0M0X0 }, { OpD2E0M0 }, { OpD3M0 }, { OpD4E0 }, { OpD5E0M0 }, { OpD6E0M0 }, { OpD7M0 }, { OpD8 }, { OpD9M0X0 }, { OpDAE0X0 }, { OpDB }, { OpDC }, { OpDDM0X0 }, { OpDEM0X0 }, { OpDFM0 }, { OpE0X0 }, { OpE1E0M0 }, { OpE2 }, { OpE3M0 }, { OpE4X0 }, { OpE5M0 }, { OpE6M0 }, { OpE7M0 }, { OpE8X0 }, { OpE9M0 }, { OpEA }, { OpEB }, { OpECX0 }, { OpEDM0 }, { OpEEM0 }, { OpEFM0 }, { OpF0E0 }, { OpF1E0M0X0 }, { OpF2E0M0 }, { OpF3M0 }, { OpF4E0 }, { OpF5E0M0 }, { OpF6E0M0 }, { OpF7M0 }, { OpF8 }, { OpF9M0X0 }, { OpFAE0X0 }, { OpFB }, { OpFCE0 }, { OpFDM0X0 }, { OpFEM0X0 }, { OpFFM0 } }; struct SOpcodes S9xOpcodesM0X1[256] = { { Op00 }, { Op01E0M0 }, { Op02 }, { Op03M0 }, { Op04M0 }, { Op05M0 }, { Op06M0 }, { Op07M0 }, { Op08E0 }, { Op09M0 }, { Op0AM0 }, { Op0BE0 }, { Op0CM0 }, { Op0DM0 }, { Op0EM0 }, { Op0FM0 }, { Op10E0 }, { Op11E0M0X1 }, { Op12E0M0 }, { Op13M0 }, { Op14M0 }, { Op15E0M0 }, { Op16E0M0 }, { Op17M0 }, { Op18 }, { Op19M0X1 }, { Op1AM0 }, { Op1B }, { Op1CM0 }, { Op1DM0X1 }, { Op1EM0X1 }, { Op1FM0 }, { Op20E0 }, { Op21E0M0 }, { Op22E0 }, { Op23M0 }, { Op24M0 }, { Op25M0 }, { Op26M0 }, { Op27M0 }, { Op28E0 }, { Op29M0 }, { Op2AM0 }, { Op2BE0 }, { Op2CM0 }, { Op2DM0 }, { Op2EM0 }, { Op2FM0 }, { Op30E0 }, { Op31E0M0X1 }, { Op32E0M0 }, { Op33M0 }, { Op34E0M0 }, { Op35E0M0 }, { Op36E0M0 }, { Op37M0 }, { Op38 }, { Op39M0X1 }, { Op3AM0 }, { Op3B }, { Op3CM0X1 }, { Op3DM0X1 }, { Op3EM0X1 }, { Op3FM0 }, { Op40Slow }, { Op41E0M0 }, { Op42 }, { Op43M0 }, { Op44X1 }, { Op45M0 }, { Op46M0 }, { Op47M0 }, { Op48E0M0 }, { Op49M0 }, { Op4AM0 }, { Op4BE0 }, { Op4C }, { Op4DM0 }, { Op4EM0 }, { Op4FM0 }, { Op50E0 }, { Op51E0M0X1 }, { Op52E0M0 }, { Op53M0 }, { Op54X1 }, { Op55E0M0 }, { Op56E0M0 }, { Op57M0 }, { Op58 }, { Op59M0X1 }, { Op5AE0X1 }, { Op5B }, { Op5C }, { Op5DM0X1 }, { Op5EM0X1 }, { Op5FM0 }, { Op60E0 }, { Op61E0M0 }, { Op62E0 }, { Op63M0 }, { Op64M0 }, { Op65M0 }, { Op66M0 }, { Op67M0 }, { Op68E0M0 }, { Op69M0 }, { Op6AM0 }, { Op6BE0 }, { Op6C }, { Op6DM0 }, { Op6EM0 }, { Op6FM0 }, { Op70E0 }, { Op71E0M0X1 }, { Op72E0M0 }, { Op73M0 }, { Op74E0M0 }, { Op75E0M0 }, { Op76E0M0 }, { Op77M0 }, { Op78 }, { Op79M0X1 }, { Op7AE0X1 }, { Op7B }, { Op7C }, { Op7DM0X1 }, { Op7EM0X1 }, { Op7FM0 }, { Op80E0 }, { Op81E0M0 }, { Op82 }, { Op83M0 }, { Op84X1 }, { Op85M0 }, { Op86X1 }, { Op87M0 }, { Op88X1 }, { Op89M0 }, { Op8AM0 }, { Op8BE0 }, { Op8CX1 }, { Op8DM0 }, { Op8EX1 }, { Op8FM0 }, { Op90E0 }, { Op91E0M0X1 }, { Op92E0M0 }, { Op93M0 }, { Op94E0X1 }, { Op95E0M0 }, { Op96E0X1 }, { Op97M0 }, { Op98M0 }, { Op99M0X1 }, { Op9A }, { Op9BX1 }, { Op9CM0 }, { Op9DM0X1 }, { Op9EM0X1 }, { Op9FM0 }, { OpA0X1 }, { OpA1E0M0 }, { OpA2X1 }, { OpA3M0 }, { OpA4X1 }, { OpA5M0 }, { OpA6X1 }, { OpA7M0 }, { OpA8X1 }, { OpA9M0 }, { OpAAX1 }, { OpABE0 }, { OpACX1 }, { OpADM0 }, { OpAEX1 }, { OpAFM0 }, { OpB0E0 }, { OpB1E0M0X1 }, { OpB2E0M0 }, { OpB3M0 }, { OpB4E0X1 }, { OpB5E0M0 }, { OpB6E0X1 }, { OpB7M0 }, { OpB8 }, { OpB9M0X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM0X1 }, { OpBEX1 }, { OpBFM0 }, { OpC0X1 }, { OpC1E0M0 }, { OpC2 }, { OpC3M0 }, { OpC4X1 }, { OpC5M0 }, { OpC6M0 }, { OpC7M0 }, { OpC8X1 }, { OpC9M0 }, { OpCAX1 }, { OpCB }, { OpCCX1 }, { OpCDM0 }, { OpCEM0 }, { OpCFM0 }, { OpD0E0 }, { OpD1E0M0X1 }, { OpD2E0M0 }, { OpD3M0 }, { OpD4E0 }, { OpD5E0M0 }, { OpD6E0M0 }, { OpD7M0 }, { OpD8 }, { OpD9M0X1 }, { OpDAE0X1 }, { OpDB }, { OpDC }, { OpDDM0X1 }, { OpDEM0X1 }, { OpDFM0 }, { OpE0X1 }, { OpE1E0M0 }, { OpE2 }, { OpE3M0 }, { OpE4X1 }, { OpE5M0 }, { OpE6M0 }, { OpE7M0 }, { OpE8X1 }, { OpE9M0 }, { OpEA }, { OpEB }, { OpECX1 }, { OpEDM0 }, { OpEEM0 }, { OpEFM0 }, { OpF0E0 }, { OpF1E0M0X1 }, { OpF2E0M0 }, { OpF3M0 }, { OpF4E0 }, { OpF5E0M0 }, { OpF6E0M0 }, { OpF7M0 }, { OpF8 }, { OpF9M0X1 }, { OpFAE0X1 }, { OpFB }, { OpFCE0 }, { OpFDM0X1 }, { OpFEM0X1 }, { OpFFM0 } }; struct SOpcodes S9xOpcodesSlow[256] = { { Op00 }, { Op01Slow }, { Op02 }, { Op03Slow }, { Op04Slow }, { Op05Slow }, { Op06Slow }, { Op07Slow }, { Op08Slow }, { Op09Slow }, { Op0ASlow }, { Op0BSlow }, { Op0CSlow }, { Op0DSlow }, { Op0ESlow }, { Op0FSlow }, { Op10Slow }, { Op11Slow }, { Op12Slow }, { Op13Slow }, { Op14Slow }, { Op15Slow }, { Op16Slow }, { Op17Slow }, { Op18 }, { Op19Slow }, { Op1ASlow }, { Op1B }, { Op1CSlow }, { Op1DSlow }, { Op1ESlow }, { Op1FSlow }, { Op20Slow }, { Op21Slow }, { Op22Slow }, { Op23Slow }, { Op24Slow }, { Op25Slow }, { Op26Slow }, { Op27Slow }, { Op28Slow }, { Op29Slow }, { Op2ASlow }, { Op2BSlow }, { Op2CSlow }, { Op2DSlow }, { Op2ESlow }, { Op2FSlow }, { Op30Slow }, { Op31Slow }, { Op32Slow }, { Op33Slow }, { Op34Slow }, { Op35Slow }, { Op36Slow }, { Op37Slow }, { Op38 }, { Op39Slow }, { Op3ASlow }, { Op3B }, { Op3CSlow }, { Op3DSlow }, { Op3ESlow }, { Op3FSlow }, { Op40Slow }, { Op41Slow }, { Op42 }, { Op43Slow }, { Op44Slow }, { Op45Slow }, { Op46Slow }, { Op47Slow }, { Op48Slow }, { Op49Slow }, { Op4ASlow }, { Op4BSlow }, { Op4CSlow }, { Op4DSlow }, { Op4ESlow }, { Op4FSlow }, { Op50Slow }, { Op51Slow }, { Op52Slow }, { Op53Slow }, { Op54Slow }, { Op55Slow }, { Op56Slow }, { Op57Slow }, { Op58 }, { Op59Slow }, { Op5ASlow }, { Op5B }, { Op5CSlow }, { Op5DSlow }, { Op5ESlow }, { Op5FSlow }, { Op60Slow }, { Op61Slow }, { Op62Slow }, { Op63Slow }, { Op64Slow }, { Op65Slow }, { Op66Slow }, { Op67Slow }, { Op68Slow }, { Op69Slow }, { Op6ASlow }, { Op6BSlow }, { Op6CSlow }, { Op6DSlow }, { Op6ESlow }, { Op6FSlow }, { Op70Slow }, { Op71Slow }, { Op72Slow }, { Op73Slow }, { Op74Slow }, { Op75Slow }, { Op76Slow }, { Op77Slow }, { Op78 }, { Op79Slow }, { Op7ASlow }, { Op7B }, { Op7CSlow }, { Op7DSlow }, { Op7ESlow }, { Op7FSlow }, { Op80Slow }, { Op81Slow }, { Op82Slow }, { Op83Slow }, { Op84Slow }, { Op85Slow }, { Op86Slow }, { Op87Slow }, { Op88Slow }, { Op89Slow }, { Op8ASlow }, { Op8BSlow }, { Op8CSlow }, { Op8DSlow }, { Op8ESlow }, { Op8FSlow }, { Op90Slow }, { Op91Slow }, { Op92Slow }, { Op93Slow }, { Op94Slow }, { Op95Slow }, { Op96Slow }, { Op97Slow }, { Op98Slow }, { Op99Slow }, { Op9A }, { Op9BSlow }, { Op9CSlow }, { Op9DSlow }, { Op9ESlow }, { Op9FSlow }, { OpA0Slow }, { OpA1Slow }, { OpA2Slow }, { OpA3Slow }, { OpA4Slow }, { OpA5Slow }, { OpA6Slow }, { OpA7Slow }, { OpA8Slow }, { OpA9Slow }, { OpAASlow }, { OpABSlow }, { OpACSlow }, { OpADSlow }, { OpAESlow }, { OpAFSlow }, { OpB0Slow }, { OpB1Slow }, { OpB2Slow }, { OpB3Slow }, { OpB4Slow }, { OpB5Slow }, { OpB6Slow }, { OpB7Slow }, { OpB8 }, { OpB9Slow }, { OpBASlow }, { OpBBSlow }, { OpBCSlow }, { OpBDSlow }, { OpBESlow }, { OpBFSlow }, { OpC0Slow }, { OpC1Slow }, { OpC2Slow }, { OpC3Slow }, { OpC4Slow }, { OpC5Slow }, { OpC6Slow }, { OpC7Slow }, { OpC8Slow }, { OpC9Slow }, { OpCASlow }, { OpCB }, { OpCCSlow }, { OpCDSlow }, { OpCESlow }, { OpCFSlow }, { OpD0Slow }, { OpD1Slow }, { OpD2Slow }, { OpD3Slow }, { OpD4Slow }, { OpD5Slow }, { OpD6Slow }, { OpD7Slow }, { OpD8 }, { OpD9Slow }, { OpDASlow }, { OpDB }, { OpDCSlow }, { OpDDSlow }, { OpDESlow }, { OpDFSlow }, { OpE0Slow }, { OpE1Slow }, { OpE2Slow }, { OpE3Slow }, { OpE4Slow }, { OpE5Slow }, { OpE6Slow }, { OpE7Slow }, { OpE8Slow }, { OpE9Slow }, { OpEA }, { OpEB }, { OpECSlow }, { OpEDSlow }, { OpEESlow }, { OpEFSlow }, { OpF0Slow }, { OpF1Slow }, { OpF2Slow }, { OpF3Slow }, { OpF4Slow }, { OpF5Slow }, { OpF6Slow }, { OpF7Slow }, { OpF8 }, { OpF9Slow }, { OpFASlow }, { OpFB }, { OpFCSlow }, { OpFDSlow }, { OpFESlow }, { OpFFSlow } }; apu/bapu/smp/core/oppseudo_read.cpp000664 001750 001750 00000027527 12720446475 020532 0ustar00sergiosergio000000 000000 case 0x88: { rd = op_readpc(); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x28: { rd = op_readpc(); regs.B.a = op_and(regs.B.a, rd); break; } case 0x68: { rd = op_readpc(); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0xc8: { rd = op_readpc(); regs.x = op_cmp(regs.x, rd); break; } case 0xad: { rd = op_readpc(); regs.B.y = op_cmp(regs.B.y, rd); break; } case 0x48: { rd = op_readpc(); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x08: { rd = op_readpc(); regs.B.a = op_or(regs.B.a, rd); break; } case 0xa8: { rd = op_readpc(); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x86: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x26: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_and(regs.B.a, rd); break; } case 0x66: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x46: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x06: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_or(regs.B.a, rd); break; } case 0xa6: { op_io(); rd = op_readdp(regs.x); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x84: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x24: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_and(regs.B.a, rd); break; } case 0x64: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x3e: { dp = op_readpc(); rd = op_readdp(dp); regs.x = op_cmp(regs.x, rd); break; } case 0x7e: { dp = op_readpc(); rd = op_readdp(dp); regs.B.y = op_cmp(regs.B.y, rd); break; } case 0x44: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x04: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_or(regs.B.a, rd); break; } case 0xa4: { dp = op_readpc(); rd = op_readdp(dp); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x94: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x34: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_and(regs.B.a, rd); break; } case 0x74: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x54: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x14: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_or(regs.B.a, rd); break; } case 0xb4: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x85: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x25: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_and(regs.B.a, rd); break; } case 0x65: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x1e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.x = op_cmp(regs.x, rd); break; } case 0x5e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.y = op_cmp(regs.B.y, rd); break; } case 0x45: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x05: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_or(regs.B.a, rd); break; } case 0xa5: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x95: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x96: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x35: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_and(regs.B.a, rd); break; } case 0x36: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_and(regs.B.a, rd); break; } case 0x75: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x76: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x55: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x56: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x15: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_or(regs.B.a, rd); break; } case 0x16: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_or(regs.B.a, rd); break; } case 0xb5: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0xb6: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.B.y); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x87: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x27: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_and(regs.B.a, rd); break; } case 0x67: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x47: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x07: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_or(regs.B.a, rd); break; } case 0xa7: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x97: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_adc(regs.B.a, rd); break; } case 0x37: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_and(regs.B.a, rd); break; } case 0x77: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_cmp(regs.B.a, rd); break; } case 0x57: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_eor(regs.B.a, rd); break; } case 0x17: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_or(regs.B.a, rd); break; } case 0xb7: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.B.y); regs.B.a = op_sbc(regs.B.a, rd); break; } case 0x99: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_adc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x39: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_and(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x79: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_cmp(wr, rd); (0) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x59: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_eor(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x19: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_or(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0xb9: { op_io(); rd = op_readdp(regs.B.y); wr = op_readdp(regs.x); wr = op_sbc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x89: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x29: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x69: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); break; } case 0x49: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x09: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0xa9: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x98: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x38: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x78: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); break; } case 0x58: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x18: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0xb8: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x7a: { dp = op_readpc(); rd = op_readdp(dp); op_io(); rd |= op_readdp(dp + 1) << 8; regs.ya = op_addw(regs.ya, rd); break; } case 0x9a: { dp = op_readpc(); rd = op_readdp(dp); op_io(); rd |= op_readdp(dp + 1) << 8; regs.ya = op_subw(regs.ya, rd); break; } case 0x5a: { dp = op_readpc(); rd = op_readdp(dp); rd |= op_readdp(dp + 1) << 8; op_cmpw(regs.ya, rd); break; } case 0x4a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !!(rd & (1 << bit)); break; } case 0x6a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !(rd & (1 << bit)); break; } case 0x8a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); break; } case 0xea: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); rd ^= (1 << bit); op_writeaddr(dp, rd); break; } case 0x0a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c | !!(rd & (1 << bit)); break; } case 0x2a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c | !(rd & (1 << bit)); break; } display.h000664 001750 001750 00000017035 12720446475 013541 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _DISPLAY_H_ #define _DISPLAY_H_ #include "snes9x.h" enum s9x_getdirtype { DEFAULT_DIR = 0, HOME_DIR, ROMFILENAME_DIR, ROM_DIR, SRAM_DIR, SNAPSHOT_DIR, SCREENSHOT_DIR, SPC_DIR, CHEAT_DIR, IPS_DIR, BIOS_DIR, LOG_DIR, LAST_DIR }; void S9xUsage (void); char * S9xParseArgs (char **, int); void S9xLoadConfigFiles (char **, int); void S9xSetInfoString (const char *); // Routines the port has to implement even if it doesn't use them void S9xPutImage (int, int); void S9xInitDisplay (int, char **); void S9xDeinitDisplay (void); void S9xTextMode (void); void S9xGraphicsMode (void); void S9xSetPalette (void); void S9xToggleSoundChannel (int); bool8 S9xOpenSnapshotFile (const char *, bool8, STREAM *); void S9xCloseSnapshotFile (STREAM); const char * S9xStringInput (const char *); const char * S9xGetDirectory (enum s9x_getdirtype); const char * S9xGetFilename (const char *, enum s9x_getdirtype); const char * S9xGetFilenameInc (const char *, enum s9x_getdirtype); const char * S9xChooseFilename (bool8); const char * S9xBasename (const char *); // Routines the port has to implement if it uses command-line void S9xExtraUsage (void); void S9xParseArg (char **, int &, int); // Routines the port may implement as needed void S9xExtraDisplayUsage (void); void S9xParseDisplayArg (char **, int &, int); void S9xSetTitle (const char *); void S9xInitInputDevices (void); void S9xProcessEvents (bool8); const char * S9xSelectFilename (const char *, const char *, const char *, const char *); #endif libretro/msvc/msvc-2010.bat000664 001750 001750 00000007745 12720446475 016544 0ustar00sergiosergio000000 000000 @echo off @echo Setting environment for using Microsoft Visual Studio 2010 x86 tools. @call :GetVSCommonToolsDir @if "%VS100COMNTOOLS%"=="" goto error_no_VS100COMNTOOLSDIR @call "%VS100COMNTOOLS%VCVarsQueryRegistry.bat" 32bit No64bit @if "%VSINSTALLDIR%"=="" goto error_no_VSINSTALLDIR @if "%FrameworkDir32%"=="" goto error_no_FrameworkDIR32 @if "%FrameworkVersion32%"=="" goto error_no_FrameworkVer32 @if "%Framework35Version%"=="" goto error_no_Framework35Version @set FrameworkDir=%FrameworkDir32% @set FrameworkVersion=%FrameworkVersion32% @if not "%WindowsSdkDir%" == "" ( @set "PATH=%WindowsSdkDir%bin\NETFX 4.0 Tools;%WindowsSdkDir%bin;%PATH%" @set "INCLUDE=%WindowsSdkDir%include;%INCLUDE%" @set "LIB=%WindowsSdkDir%lib;%LIB%" ) @rem @rem Root of Visual Studio IDE installed files. @rem @set DevEnvDir=%VSINSTALLDIR%Common7\IDE\ @rem PATH @rem ---- @if exist "%VSINSTALLDIR%Team Tools\Performance Tools" ( @set "PATH=%VSINSTALLDIR%Team Tools\Performance Tools;%PATH%" ) @if exist "%ProgramFiles%\HTML Help Workshop" set PATH=%ProgramFiles%\HTML Help Workshop;%PATH% @if exist "%ProgramFiles(x86)%\HTML Help Workshop" set PATH=%ProgramFiles(x86)%\HTML Help Workshop;%PATH% @if exist "%VCINSTALLDIR%VCPackages" set PATH=%VCINSTALLDIR%VCPackages;%PATH% @set PATH=%FrameworkDir%%Framework35Version%;%PATH% @set PATH=%FrameworkDir%%FrameworkVersion%;%PATH% @set PATH=%VSINSTALLDIR%Common7\Tools;%PATH% @if exist "%VCINSTALLDIR%BIN" set PATH=%VCINSTALLDIR%BIN;%PATH% @set PATH=%DevEnvDir%;%PATH% @if exist "%VSINSTALLDIR%VSTSDB\Deploy" ( @set "PATH=%VSINSTALLDIR%VSTSDB\Deploy;%PATH%" ) @if not "%FSHARPINSTALLDIR%" == "" ( @set "PATH=%FSHARPINSTALLDIR%;%PATH%" ) @rem INCLUDE @rem ------- @if exist "%VCINSTALLDIR%ATLMFC\INCLUDE" set INCLUDE=%VCINSTALLDIR%ATLMFC\INCLUDE;%INCLUDE% @if exist "%VCINSTALLDIR%INCLUDE" set INCLUDE=%VCINSTALLDIR%INCLUDE;%INCLUDE% @rem LIB @rem --- @if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIB=%VCINSTALLDIR%ATLMFC\LIB;%LIB% @if exist "%VCINSTALLDIR%LIB" set LIB=%VCINSTALLDIR%LIB;%LIB% @rem LIBPATH @rem ------- @if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIBPATH=%VCINSTALLDIR%ATLMFC\LIB;%LIBPATH% @if exist "%VCINSTALLDIR%LIB" set LIBPATH=%VCINSTALLDIR%LIB;%LIBPATH% @set LIBPATH=%FrameworkDir%%Framework35Version%;%LIBPATH% @set LIBPATH=%FrameworkDir%%FrameworkVersion%;%LIBPATH% @goto end @REM ----------------------------------------------------------------------- :GetVSCommonToolsDir @set VS100COMNTOOLS= @call :GetVSCommonToolsDirHelper32 HKLM > nul 2>&1 @if errorlevel 1 call :GetVSCommonToolsDirHelper32 HKCU > nul 2>&1 @if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKLM > nul 2>&1 @if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKCU > nul 2>&1 @exit /B 0 :GetVSCommonToolsDirHelper32 @for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO ( @if "%%i"=="10.0" ( @SET "VS100COMNTOOLS=%%k" ) ) @if "%VS100COMNTOOLS%"=="" exit /B 1 @SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\" @exit /B 0 :GetVSCommonToolsDirHelper64 @for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO ( @if "%%i"=="10.0" ( @SET "VS100COMNTOOLS=%%k" ) ) @if "%VS100COMNTOOLS%"=="" exit /B 1 @SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\" @exit /B 0 @REM ----------------------------------------------------------------------- :error_no_VS100COMNTOOLSDIR @echo ERROR: Cannot determine the location of the VS Common Tools folder. @goto end :error_no_VSINSTALLDIR @echo ERROR: Cannot determine the location of the VS installation. @goto end :error_no_FrameworkDIR32 @echo ERROR: Cannot determine the location of the .NET Framework 32bit installation. @goto end :error_no_FrameworkVer32 @echo ERROR: Cannot determine the version of the .NET Framework 32bit installation. @goto end :error_no_Framework35Version @echo ERROR: Cannot determine the .NET Framework 3.5 version. @goto end :end msbuild msvc-2010.sln /p:Configuration=Release /target:clean msbuild msvc-2010.sln /p:Configuration=Release exit netplay.h000664 001750 001750 00000025570 12720446475 013553 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _NETPLAY_H_ #define _NETPLAY_H_ /* * Client to server joypad update * * magic 1 * sequence_no 1 * opcode 1 * joypad data 4 * * Server to client joypad update * magic 1 * sequence_no 1 * opcode 1 + num joypads (top 3 bits) * joypad data 4 * n */ //#define NP_DEBUG 1 #define NP_VERSION 10 #define NP_JOYPAD_HIST_SIZE 120 #define NP_DEFAULT_PORT 6096 #define NP_MAX_CLIENTS 8 #define NP_SERV_MAGIC 'S' #define NP_CLNT_MAGIC 'C' #define NP_CLNT_HELLO 0 #define NP_CLNT_JOYPAD 1 #define NP_CLNT_RESET 2 #define NP_CLNT_PAUSE 3 #define NP_CLNT_LOAD_ROM 4 #define NP_CLNT_ROM_IMAGE 5 #define NP_CLNT_FREEZE_FILE 6 #define NP_CLNT_SRAM_DATA 7 #define NP_CLNT_READY 8 #define NP_CLNT_LOADED_ROM 9 #define NP_CLNT_RECEIVED_ROM_IMAGE 10 #define NP_CLNT_WAITING_FOR_ROM_IMAGE 11 #define NP_SERV_HELLO 0 #define NP_SERV_JOYPAD 1 #define NP_SERV_RESET 2 #define NP_SERV_PAUSE 3 #define NP_SERV_LOAD_ROM 4 #define NP_SERV_ROM_IMAGE 5 #define NP_SERV_FREEZE_FILE 6 #define NP_SERV_SRAM_DATA 7 #define NP_SERV_READY 8 struct SNPClient { volatile uint8 SendSequenceNum; volatile uint8 ReceiveSequenceNum; volatile bool8 Connected; volatile bool8 SaidHello; volatile bool8 Paused; volatile bool8 Ready; int Socket; char *ROMName; char *HostName; char *Who; }; enum { NP_SERVER_SEND_ROM_IMAGE, NP_SERVER_SYNC_ALL, NP_SERVER_SYNC_CLIENT, NP_SERVER_SEND_FREEZE_FILE_ALL, NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL, NP_SERVER_RESET_ALL, NP_SERVER_SEND_SRAM_ALL, NP_SERVER_SEND_SRAM }; #define NP_MAX_TASKS 20 struct NPServerTask { uint32 Task; void *Data; }; struct SNPServer { struct SNPClient Clients [NP_MAX_CLIENTS]; int NumClients; volatile struct NPServerTask TaskQueue [NP_MAX_TASKS]; volatile uint32 TaskHead; volatile uint32 TaskTail; int Socket; uint32 FrameTime; uint32 FrameCount; char ROMName [30]; uint32 Joypads [NP_MAX_CLIENTS]; bool8 ClientPaused; uint32 Paused; bool8 SendROMImageOnConnect; bool8 SyncByReset; }; #define NP_MAX_ACTION_LEN 200 struct SNetPlay { volatile uint8 MySequenceNum; volatile uint8 ServerSequenceNum; volatile bool8 Connected; volatile bool8 Abort; volatile uint8 Player; volatile bool8 ClientsReady [NP_MAX_CLIENTS]; volatile bool8 ClientsPaused [NP_MAX_CLIENTS]; volatile bool8 Paused; volatile bool8 PendingWait4Sync; volatile uint8 PercentageComplete; volatile bool8 Waiting4EmulationThread; volatile bool8 Answer; #ifdef __WIN32__ HANDLE ReplyEvent; #endif volatile int Socket; char *ServerHostName; char *ROMName; int Port; volatile uint32 JoypadWriteInd; volatile uint32 JoypadReadInd; uint32 Joypads [NP_JOYPAD_HIST_SIZE][NP_MAX_CLIENTS]; uint32 Frame [NP_JOYPAD_HIST_SIZE]; uint32 FrameCount; uint32 MaxFrameSkip; uint32 MaxBehindFrameCount; bool8 JoypadsReady [NP_JOYPAD_HIST_SIZE][NP_MAX_CLIENTS]; char ActionMsg [NP_MAX_ACTION_LEN]; char ErrorMsg [NP_MAX_ACTION_LEN]; char WarningMsg [NP_MAX_ACTION_LEN]; }; extern "C" struct SNetPlay NetPlay; // // NETPLAY_CLIENT_HELLO message format: // header // frame_time (4) // ROMName (variable) #define WRITE_LONG(p, v) { \ *((p) + 0) = (uint8) ((v) >> 24); \ *((p) + 1) = (uint8) ((v) >> 16); \ *((p) + 2) = (uint8) ((v) >> 8); \ *((p) + 3) = (uint8) ((v) >> 0); \ } #define READ_LONG(p) \ ((((uint8) *((p) + 0)) << 24) | \ (((uint8) *((p) + 1)) << 16) | \ (((uint8) *((p) + 2)) << 8) | \ (((uint8) *((p) + 3)) << 0)) bool8 S9xNPConnectToServer (const char *server_name, int port, const char *rom_name); bool8 S9xNPWaitForHeartBeat (); bool8 S9xNPWaitForHeartBeatDelay (uint32 time_msec = 0); bool8 S9xNPCheckForHeartBeat (uint32 time_msec = 0); uint32 S9xNPGetJoypad (int which1); bool8 S9xNPSendJoypadUpdate (uint32 joypad); void S9xNPDisconnect (); bool8 S9xNPInitialise (); bool8 S9xNPSendData (int fd, const uint8 *data, int len); bool8 S9xNPGetData (int fd, uint8 *data, int len); void S9xNPSyncClients (); void S9xNPStepJoypadHistory (); void S9xNPResetJoypadReadPos (); bool8 S9xNPSendReady (uint8 op = NP_CLNT_READY); bool8 S9xNPSendPause (bool8 pause); void S9xNPReset (); void S9xNPSetAction (const char *action, bool8 force = FALSE); void S9xNPSetError (const char *error); void S9xNPSetWarning (const char *warning); void S9xNPDiscardHeartbeats (); void S9xNPServerQueueSendingFreezeFile (const char *filename); void S9xNPServerQueueSyncAll (); void S9xNPServerQueueSendingROMImage (); void S9xNPServerQueueSendingLoadROMRequest (const char *filename); void S9xNPServerAddTask (uint32 task, void *data); bool8 S9xNPStartServer (int port); void S9xNPStopServer (); #ifdef __WIN32__ #define S9xGetMilliTime timeGetTime #else uint32 S9xGetMilliTime (); #endif #endif libretro/jni/Application.mk000664 001750 001750 00000000051 12720446475 017107 0ustar00sergiosergio000000 000000 APP_STL := stlport_static APP_ABI := all apu/bapu/dsp/blargg_source.h000664 001750 001750 00000005735 12720446475 017220 0ustar00sergiosergio000000 000000 /* Included at the beginning of library source files, after all other #include lines. Sets up helpful macros and services used in my source code. They don't need module an annoying module prefix on their names since they are defined after all other #include lines. */ // snes_spc 0.9.0 #ifndef BLARGG_SOURCE_H #define BLARGG_SOURCE_H // If debugging is enabled, abort program if expr is false. Meant for checking // internal state and consistency. A failed assertion indicates a bug in the module. // void assert( bool expr ); #include // If debugging is enabled and expr is false, abort program. Meant for checking // caller-supplied parameters and operations that are outside the control of the // module. A failed requirement indicates a bug outside the module. // void require( bool expr ); #undef require #define require( expr ) assert( expr ) // Like printf() except output goes to debug log file. Might be defined to do // nothing (not even evaluate its arguments). // void dprintf( const char* format, ... ); static inline void blargg_dprintf_( const char*, ... ) { } #undef dprintf #define dprintf (1) ? (void) 0 : blargg_dprintf_ // If enabled, evaluate expr and if false, make debug log entry with source file // and line. Meant for finding situations that should be examined further, but that // don't indicate a problem. In all cases, execution continues normally. #undef check #define check( expr ) ((void) 0) // If expr yields error string, return it from current function, otherwise continue. #undef RETURN_ERR #define RETURN_ERR( expr ) do { \ blargg_err_t blargg_return_err_ = (expr); \ if ( blargg_return_err_ ) return blargg_return_err_; \ } while ( 0 ) // If ptr is 0, return out of memory error string. #undef CHECK_ALLOC #define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 ) // Avoid any macros which evaluate their arguments multiple times #undef min #undef max #define DEF_MIN_MAX( type ) \ static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\ static inline type max( type x, type y ) { if ( y < x ) return x; return y; } DEF_MIN_MAX( int ) DEF_MIN_MAX( unsigned ) DEF_MIN_MAX( long ) DEF_MIN_MAX( unsigned long ) DEF_MIN_MAX( float ) DEF_MIN_MAX( double ) #undef DEF_MIN_MAX /* // using const references generates crappy code, and I am currenly only using these // for built-in types, so they take arguments by value // TODO: remove inline int min( int x, int y ) template inline T min( T x, T y ) { if ( x < y ) return x; return y; } template inline T max( T x, T y ) { if ( x < y ) return y; return x; } */ // TODO: good idea? bad idea? #undef byte #define byte byte_ typedef unsigned char byte; // deprecated #define BLARGG_CHECK_ALLOC CHECK_ALLOC #define BLARGG_RETURN_ERR RETURN_ERR // BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check #ifdef BLARGG_SOURCE_BEGIN #include BLARGG_SOURCE_BEGIN #endif #endif statemanager.cpp000664 001750 001750 00000010571 12720446475 015100 0ustar00sergiosergio000000 000000 #include "statemanager.h" #include "snapshot.h" /* State Manager Class that records snapshot data for rewinding mostly based on SSNES's rewind code by Themaister */ static inline size_t nearest_pow2_size(size_t v) { size_t orig = v; v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; #if SIZE_MAX >= 0xffff v |= v >> 8; #endif #if SIZE_MAX >= 0xffffffff v |= v >> 16; #endif #if SIZE_MAX >= 0xffffffffffffffff v |= v >> 32; #endif v++; size_t next = v; size_t prev = v >> 1; if ((next - orig) < (orig - prev)) return next; else return prev; } void StateManager::deallocate() { if(buffer) { delete [] buffer; buffer = NULL; } if(tmp_state) { delete [] tmp_state; tmp_state = NULL; } if(in_state) { delete [] in_state; in_state = NULL; } } StateManager::StateManager() { buffer = NULL; tmp_state = NULL; in_state = NULL; init_done = false; } StateManager::~StateManager() { deallocate(); } bool StateManager::init(size_t buffer_size) { init_done = false; deallocate(); real_state_size = S9xFreezeSize(); state_size = real_state_size / sizeof(uint32_t); // Works in multiple of 4. // We need 4-byte aligned state_size to avoid having to enforce this with unneeded memcpy's! if(real_state_size % sizeof(uint32_t)) state_size ++; if (buffer_size <= real_state_size) // Need a sufficient buffer size. return false; top_ptr = 1; buf_size = nearest_pow2_size(buffer_size) / sizeof(uint64_t); // Works in multiple of 8. buf_size_mask = buf_size - 1; if (!(buffer = new uint64_t[buf_size])) return false; if (!(tmp_state = new uint32_t[state_size])) return false; if (!(in_state = new uint32_t[state_size])) return false; memset(tmp_state,0,state_size * sizeof(uint32_t)); memset(in_state,0,state_size * sizeof(uint32_t)); init_done = true; return true; } int StateManager::pop() { if(!init_done) return 0; if (first_pop) { first_pop = false; return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size); } top_ptr = (top_ptr - 1) & buf_size_mask; if (top_ptr == bottom_ptr) // Our stack is completely empty... :v { top_ptr = (top_ptr + 1) & buf_size_mask; return 0; } while (buffer[top_ptr]) { // Apply the xor patch. uint32_t addr = buffer[top_ptr] >> 32; uint32_t xor_ = buffer[top_ptr] & 0xFFFFFFFFU; tmp_state[addr] ^= xor_; top_ptr = (top_ptr - 1) & buf_size_mask; } if (top_ptr == bottom_ptr) // Our stack is completely empty... :v { top_ptr = (top_ptr + 1) & buf_size_mask; } return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size); } void StateManager::reassign_bottom() { bottom_ptr = (top_ptr + 1) & buf_size_mask; while (buffer[bottom_ptr]) // Skip ahead until we find the first 0 (boundary for state delta). bottom_ptr = (bottom_ptr + 1) & buf_size_mask; } void StateManager::generate_delta(const void *data) { bool crossed = false; const uint32_t *old_state = tmp_state; const uint32_t *new_state = (const uint32_t*)data; buffer[top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between. top_ptr &= buf_size_mask; // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft. if (top_ptr == bottom_ptr) crossed = true; for (uint64_t i = 0; i < state_size; i++) { uint64_t xor_ = old_state[i] ^ new_state[i]; // If the data differs (xor != 0), we push that xor on the stack with index and xor. // This can be reversed by reapplying the xor. // This, if states don't really differ much, we'll save lots of space :) // Hopefully this will work really well with save states. if (xor_) { buffer[top_ptr] = (i << 32) | xor_; top_ptr = (top_ptr + 1) & buf_size_mask; if (top_ptr == bottom_ptr) crossed = true; } } if (crossed) reassign_bottom(); } bool StateManager::push() { if(!init_done) return false; if(!S9xFreezeGameMem((uint8 *)in_state,real_state_size)) return false; generate_delta(in_state); uint32 *tmp = tmp_state; tmp_state = in_state; in_state = tmp; first_pop = true; return true; } dma.h000664 001750 001750 00000015256 12720446475 012640 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _DMA_H_ #define _DMA_H_ struct SDMA { bool8 ReverseTransfer; bool8 HDMAIndirectAddressing; bool8 UnusedBit43x0; bool8 AAddressFixed; bool8 AAddressDecrement; uint8 TransferMode; uint8 BAddress; uint16 AAddress; uint8 ABank; uint16 DMACount_Or_HDMAIndirectAddress; uint8 IndirectBank; uint16 Address; uint8 Repeat; uint8 LineCount; uint8 UnknownByte; uint8 DoTransfer; }; #define TransferBytes DMACount_Or_HDMAIndirectAddress #define IndirectAddress DMACount_Or_HDMAIndirectAddress extern struct SDMA DMA[8]; bool8 S9xDoDMA (uint8); void S9xStartHDMA (void); uint8 S9xDoHDMA (uint8); void S9xResetDMA (void); #endif spc7110emu.h000664 001750 001750 00000007544 12720446475 013705 0ustar00sergiosergio000000 000000 /***** * SPC7110 emulator - version 0.03 (2008-08-10) * Copyright (c) 2008, byuu and neviksti * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * The software is provided "as is" and the author disclaims all warranties * with regard to this software including all implied warranties of * merchantibility and fitness, in no event shall the author be liable for * any special, direct, indirect, or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an * action of contract, negligence or other tortious action, arising out of * or in connection with the use or performance of this software. *****/ #ifndef _SPC7110EMU_H_ #define _SPC7110EMU_H_ #include "spc7110dec.h" class SPC7110 { public: void init(); void enable(); void power(); void reset(); unsigned datarom_addr(unsigned addr); unsigned data_pointer(); unsigned data_adjust(); unsigned data_increment(); void set_data_pointer(unsigned addr); void set_data_adjust(unsigned addr); void update_time(int offset = 0); time_t create_time(); uint8 mmio_read (unsigned addr); void mmio_write(unsigned addr, uint8 data); uint8 read (unsigned addr); void write(unsigned addr, uint8 data); //spc7110decomp void decomp_init(); uint8 decomp_read(); SPC7110(); //================== //decompression unit //================== uint8 r4801; //compression table low uint8 r4802; //compression table high uint8 r4803; //compression table bank uint8 r4804; //compression table index uint8 r4805; //decompression buffer index low uint8 r4806; //decompression buffer index high uint8 r4807; //??? uint8 r4808; //??? uint8 r4809; //compression length low uint8 r480a; //compression length high uint8 r480b; //decompression control register uint8 r480c; //decompression status SPC7110Decomp decomp; //============== //data port unit //============== uint8 r4811; //data pointer low uint8 r4812; //data pointer high uint8 r4813; //data pointer bank uint8 r4814; //data adjust low uint8 r4815; //data adjust high uint8 r4816; //data increment low uint8 r4817; //data increment high uint8 r4818; //data port control register uint8 r481x; bool r4814_latch; bool r4815_latch; //========= //math unit //========= uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0 uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1 uint8 r4822; //32-bit dividend B2 uint8 r4823; //32-bit dividend B3 uint8 r4824; //16-bit multiplier B0 uint8 r4825; //16-bit multiplier B1 uint8 r4826; //16-bit divisor B0 uint8 r4827; //16-bit divisor B1 uint8 r4828; //32-bit product B0, 32-bit quotient B0 uint8 r4829; //32-bit product B1, 32-bit quotient B1 uint8 r482a; //32-bit product B2, 32-bit quotient B2 uint8 r482b; //32-bit product B3, 32-bit quotient B3 uint8 r482c; //16-bit remainder B0 uint8 r482d; //16-bit remainder B1 uint8 r482e; //math control register uint8 r482f; //math status //=================== //memory mapping unit //=================== uint8 r4830; //SRAM write enable uint8 r4831; //$[d0-df]:[0000-ffff] mapping uint8 r4832; //$[e0-ef]:[0000-ffff] mapping uint8 r4833; //$[f0-ff]:[0000-ffff] mapping uint8 r4834; //??? unsigned dx_offset; unsigned ex_offset; unsigned fx_offset; //==================== //real-time clock unit //==================== uint8 r4840; //RTC latch uint8 r4841; //RTC index/data port uint8 r4842; //RTC status enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write } rtc_state; enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c } rtc_mode; unsigned rtc_index; static const unsigned months[12]; }; #endif sa1cpu.cpp000664 001750 001750 00000026702 12720446475 013624 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #define CPU SA1 #define ICPU SA1 #define Registers SA1Registers #define OpenBus SA1OpenBus #define S9xGetByte S9xSA1GetByte #define S9xGetWord S9xSA1GetWord #define S9xSetByte S9xSA1SetByte #define S9xSetWord S9xSA1SetWord #define S9xSetPCBase S9xSA1SetPCBase #define S9xOpcodesM1X1 S9xSA1OpcodesM1X1 #define S9xOpcodesM1X0 S9xSA1OpcodesM1X0 #define S9xOpcodesM0X1 S9xSA1OpcodesM0X1 #define S9xOpcodesM0X0 S9xSA1OpcodesM0X0 #define S9xOpcodesE1 S9xSA1OpcodesE1 #define S9xOpcodesSlow S9xSA1OpcodesSlow #define S9xOpcode_IRQ S9xSA1Opcode_IRQ #define S9xOpcode_NMI S9xSA1Opcode_NMI #define S9xUnpackStatus S9xSA1UnpackStatus #define S9xPackStatus S9xSA1PackStatus #define S9xFixCycles S9xSA1FixCycles #define Immediate8 SA1Immediate8 #define Immediate16 SA1Immediate16 #define Relative SA1Relative #define RelativeLong SA1RelativeLong #define Absolute SA1Absolute #define AbsoluteLong SA1AbsoluteLong #define AbsoluteIndirect SA1AbsoluteIndirect #define AbsoluteIndirectLong SA1AbsoluteIndirectLong #define AbsoluteIndexedIndirect SA1AbsoluteIndexedIndirect #define Direct SA1Direct #define DirectIndirectIndexed SA1DirectIndirectIndexed #define DirectIndirectIndexedLong SA1DirectIndirectIndexedLong #define DirectIndexedIndirect SA1DirectIndexedIndirect #define DirectIndexedX SA1DirectIndexedX #define DirectIndexedY SA1DirectIndexedY #define AbsoluteIndexedX SA1AbsoluteIndexedX #define AbsoluteIndexedY SA1AbsoluteIndexedY #define AbsoluteLongIndexedX SA1AbsoluteLongIndexedX #define DirectIndirect SA1DirectIndirect #define DirectIndirectLong SA1DirectIndirectLong #define StackRelative SA1StackRelative #define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed #define SA1_OPCODES #include "cpuops.cpp" static void S9xSA1UpdateTimer (void); void S9xSA1MainLoop (void) { if (Memory.FillRAM[0x2200] & 0x60) { SA1.Cycles += 6; // FIXME S9xSA1UpdateTimer(); return; } // SA-1 NMI if ((Memory.FillRAM[0x2200] & 0x10) && !(Memory.FillRAM[0x220b] & 0x10)) { Memory.FillRAM[0x2301] |= 0x10; Memory.FillRAM[0x220b] |= 0x10; if (SA1.WaitingForInterrupt) { SA1.WaitingForInterrupt = FALSE; SA1Registers.PCw++; } S9xSA1Opcode_NMI(); } else if (!SA1CheckFlag(IRQ)) { // SA-1 Timer IRQ if ((Memory.FillRAM[0x220a] & 0x40) && !(Memory.FillRAM[0x220b] & 0x40)) { Memory.FillRAM[0x2301] |= 0x40; if (SA1.WaitingForInterrupt) { SA1.WaitingForInterrupt = FALSE; SA1Registers.PCw++; } S9xSA1Opcode_IRQ(); } else // SA-1 DMA IRQ if ((Memory.FillRAM[0x220a] & 0x20) && !(Memory.FillRAM[0x220b] & 0x20)) { Memory.FillRAM[0x2301] |= 0x20; if (SA1.WaitingForInterrupt) { SA1.WaitingForInterrupt = FALSE; SA1Registers.PCw++; } S9xSA1Opcode_IRQ(); } else // SA-1 IRQ if ((Memory.FillRAM[0x2200] & 0x80) && !(Memory.FillRAM[0x220b] & 0x80)) { Memory.FillRAM[0x2301] |= 0x80; if (SA1.WaitingForInterrupt) { SA1.WaitingForInterrupt = FALSE; SA1Registers.PCw++; } S9xSA1Opcode_IRQ(); } } for (int i = 0; i < 3 && !(Memory.FillRAM[0x2200] & 0x60); i++) { #ifdef DEBUGGER if (SA1.Flags & TRACE_FLAG) S9xSA1Trace(); #endif register uint8 Op; register struct SOpcodes *Opcodes; if (SA1.PCBase) { SA1OpenBus = Op = SA1.PCBase[Registers.PCw]; Opcodes = SA1.S9xOpcodes; } else { Op = S9xSA1GetByte(Registers.PBPC); Opcodes = S9xOpcodesSlow; } if ((SA1Registers.PCw & MEMMAP_MASK) + SA1.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) { uint32 oldPC = SA1Registers.PBPC; S9xSA1SetPCBase(SA1Registers.PBPC); SA1Registers.PBPC = oldPC; Opcodes = S9xSA1OpcodesSlow; } Registers.PCw++; (*Opcodes[Op].S9xOpcode)(); } S9xSA1UpdateTimer(); } static void S9xSA1UpdateTimer (void) // FIXME { SA1.PrevHCounter = SA1.HCounter; if (Memory.FillRAM[0x2210] & 0x80) { SA1.HCounter += (SA1.Cycles - SA1.PrevCycles); if (SA1.HCounter >= 0x800) { SA1.HCounter -= 0x800; SA1.PrevHCounter -= 0x800; if (++SA1.VCounter >= 0x200) SA1.VCounter = 0; } } else { SA1.HCounter += (SA1.Cycles - SA1.PrevCycles); if (SA1.HCounter >= Timings.H_Max_Master) { SA1.HCounter -= Timings.H_Max_Master; SA1.PrevHCounter -= Timings.H_Max_Master; if (++SA1.VCounter >= Timings.V_Max_Master) SA1.VCounter = 0; } } if (SA1.Cycles >= Timings.H_Max_Master) SA1.Cycles -= Timings.H_Max_Master; SA1.PrevCycles = SA1.Cycles; bool8 thisIRQ = Memory.FillRAM[0x2210] & 0x03; if (Memory.FillRAM[0x2210] & 0x01) { if (SA1.PrevHCounter >= SA1.HTimerIRQPos * ONE_DOT_CYCLE || SA1.HCounter < SA1.HTimerIRQPos * ONE_DOT_CYCLE) thisIRQ = FALSE; } if (Memory.FillRAM[0x2210] & 0x02) { if (SA1.VCounter != SA1.VTimerIRQPos * ONE_DOT_CYCLE) thisIRQ = FALSE; } // SA-1 Timer IRQ control if (!SA1.TimerIRQLastState && thisIRQ) { Memory.FillRAM[0x2301] |= 0x40; if (Memory.FillRAM[0x220a] & 0x40) { Memory.FillRAM[0x220b] &= ~0x40; #ifdef DEBUGGER S9xTraceFormattedMessage("--- SA-1 Timer IRQ triggered prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d", SA1.PrevHCounter, SA1.HCounter, (Memory.FillRAM[0x2210] & 0x01) ? 1 : 0, SA1.HTimerIRQPos * ONE_DOT_CYCLE, (Memory.FillRAM[0x2210] & 0x02) ? 1 : 0, SA1.VTimerIRQPos); #endif } } SA1.TimerIRQLastState = thisIRQ; } messages.h000664 001750 001750 00000015651 12720446475 013705 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _MESSAGES_H_ #define _MESSAGES_H_ // Types of message sent to S9xMessage() enum { S9X_TRACE, S9X_DEBUG, S9X_WARNING, S9X_INFO, S9X_ERROR, S9X_FATAL_ERROR }; // Individual message numbers enum { S9X_ROM_INFO, S9X_HEADERS_INFO, S9X_CONFIG_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, S9X_ROM_INTERLEAVED_INFO, S9X_SOUND_DEVICE_OPEN_FAILED, S9X_APU_STOPPED, S9X_USAGE, S9X_GAME_GENIE_CODE_ERROR, S9X_ACTION_REPLY_CODE_ERROR, S9X_GOLD_FINGER_CODE_ERROR, S9X_DEBUG_OUTPUT, S9X_DMA_TRACE, S9X_HDMA_TRACE, S9X_WRONG_FORMAT, S9X_WRONG_VERSION, S9X_ROM_NOT_FOUND, S9X_FREEZE_FILE_NOT_FOUND, S9X_PPU_TRACE, S9X_TRACE_DSP1, S9X_FREEZE_ROM_NAME, S9X_HEADER_WARNING, S9X_NETPLAY_NOT_SERVER, S9X_FREEZE_FILE_INFO, S9X_TURBO_MODE, S9X_SOUND_NOT_BUILT, S9X_MOVIE_INFO, S9X_WRONG_MOVIE_SNAPSHOT, S9X_NOT_A_MOVIE_SNAPSHOT, S9X_SNAPSHOT_INCONSISTENT, S9X_AVI_INFO }; #endif controls.cpp000664 001750 001750 00000250116 12720446475 014271 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include #include #include #include #include #include #include "snes9x.h" #include "memmap.h" #include "apu/apu.h" #include "snapshot.h" #include "controls.h" #include "crosshairs.h" #include "movie.h" #include "display.h" #ifdef NETPLAY_SUPPORT #include "netplay.h" #endif using namespace std; #define NONE (-2) #define MP5 (-1) #define JOYPAD0 0 #define JOYPAD1 1 #define JOYPAD2 2 #define JOYPAD3 3 #define JOYPAD4 4 #define JOYPAD5 5 #define JOYPAD6 6 #define JOYPAD7 7 #define MOUSE0 8 #define MOUSE1 9 #define SUPERSCOPE 10 #define ONE_JUSTIFIER 11 #define TWO_JUSTIFIERS 12 #define NUMCTLS 13 // This must be LAST #define POLL_ALL NUMCTLS #define SUPERSCOPE_FIRE 0x80 #define SUPERSCOPE_CURSOR 0x40 #define SUPERSCOPE_TURBO 0x20 #define SUPERSCOPE_PAUSE 0x10 #define SUPERSCOPE_OFFSCREEN 0x02 #define JUSTIFIER_TRIGGER 0x80 #define JUSTIFIER_START 0x20 #define JUSTIFIER_SELECT 0x08 #define MAP_UNKNOWN (-1) #define MAP_NONE 0 #define MAP_BUTTON 1 #define MAP_AXIS 2 #define MAP_POINTER 3 #define FLAG_IOBIT0 (Memory.FillRAM[0x4213] & 0x40) #define FLAG_IOBIT1 (Memory.FillRAM[0x4213] & 0x80) #define FLAG_IOBIT(n) ((n) ? (FLAG_IOBIT1) : (FLAG_IOBIT0)) bool8 pad_read = 0, pad_read_last = 0; uint8 read_idx[2 /* ports */][2 /* per port */]; struct exemulti { int32 pos; bool8 data1; s9xcommand_t *script; }; struct crosshair { uint8 set; uint8 img; uint8 fg, bg; }; static struct { int16 x, y; int16 V_adj; bool8 V_var; int16 H_adj; bool8 H_var; bool8 mapped; } pseudopointer[8]; static struct { uint16 buttons; uint16 turbos; uint16 toggleturbo; uint16 togglestick; uint8 turbo_ct; } joypad[8]; static struct { uint8 delta_x, delta_y; int16 old_x, old_y; int16 cur_x, cur_y; uint8 buttons; uint32 ID; struct crosshair crosshair; } mouse[2]; static struct { int16 x, y; uint8 phys_buttons; uint8 next_buttons; uint8 read_buttons; uint32 ID; struct crosshair crosshair; } superscope; static struct { int16 x[2], y[2]; uint8 buttons; bool8 offscreen[2]; uint32 ID[2]; struct crosshair crosshair[2]; } justifier; static struct { int8 pads[4]; } mp5[2]; static set exemultis; static set pollmap[NUMCTLS + 1]; static map keymap; static vector multis; static uint8 turbo_time; static uint8 pseudobuttons[256]; static bool8 FLAG_LATCH = FALSE; static int32 curcontrollers[2] = { NONE, NONE }; static int32 newcontrollers[2] = { JOYPAD0, NONE }; static char buf[256]; static const char *color_names[32] = { "Trans", "Black", "25Grey", "50Grey", "75Grey", "White", "Red", "Orange", "Yellow", "Green", "Cyan", "Sky", "Blue", "Violet", "MagicPink", "Purple", NULL, "tBlack", "t25Grey", "t50Grey", "t75Grey", "tWhite", "tRed", "tOrange", "tYellow", "tGreen", "tCyan", "tSky", "tBlue", "tViolet", "tMagicPink", "tPurple" }; static const char *speed_names[4] = { "Var", "Slow", "Med", "Fast" }; static const int ptrspeeds[4] = { 1, 1, 4, 8 }; // Note: these should be in asciibetical order! #define THE_COMMANDS \ S(BeginRecordingMovie), \ S(ClipWindows), \ S(Debugger), \ S(DecEmuTurbo), \ S(DecFrameRate), \ S(DecFrameTime), \ S(DecTurboSpeed), \ S(EmuTurbo), \ S(EndRecordingMovie), \ S(ExitEmu), \ S(IncEmuTurbo), \ S(IncFrameRate), \ S(IncFrameTime), \ S(IncTurboSpeed), \ S(LoadFreezeFile), \ S(LoadMovie), \ S(LoadOopsFile), \ S(Pause), \ S(QuickLoad000), \ S(QuickLoad001), \ S(QuickLoad002), \ S(QuickLoad003), \ S(QuickLoad004), \ S(QuickLoad005), \ S(QuickLoad006), \ S(QuickLoad007), \ S(QuickLoad008), \ S(QuickLoad009), \ S(QuickLoad010), \ S(QuickSave000), \ S(QuickSave001), \ S(QuickSave002), \ S(QuickSave003), \ S(QuickSave004), \ S(QuickSave005), \ S(QuickSave006), \ S(QuickSave007), \ S(QuickSave008), \ S(QuickSave009), \ S(QuickSave010), \ S(Reset), \ S(SaveFreezeFile), \ S(SaveSPC), \ S(Screenshot), \ S(SeekToFrame), \ S(SoftReset), \ S(SoundChannel0), \ S(SoundChannel1), \ S(SoundChannel2), \ S(SoundChannel3), \ S(SoundChannel4), \ S(SoundChannel5), \ S(SoundChannel6), \ S(SoundChannel7), \ S(SoundChannelsOn), \ S(SwapJoypads), \ S(ToggleBG0), \ S(ToggleBG1), \ S(ToggleBG2), \ S(ToggleBG3), \ S(ToggleEmuTurbo), \ S(ToggleSprites), \ S(ToggleTransparency) \ #define S(x) x enum command_numbers { THE_COMMANDS, LAST_COMMAND }; #undef S #define S(x) #x static const char *command_names[LAST_COMMAND + 1] = { THE_COMMANDS, NULL }; #undef S #undef THE_COMMANDS static void DisplayStateChange (const char *, bool8); static void DoGunLatch (int, int); static int maptype (int); static bool strless (const char *, const char *); static int findstr (const char *, const char **, int); static int get_threshold (const char **); static const char * maptypename (int); static int32 ApplyMulti (s9xcommand_t *, int32, int16); static void do_polling (int); static void UpdatePolledMouse (int); static string& operator += (string &s, int i) { snprintf(buf, sizeof(buf), "%d", i); s.append(buf); return (s); } static string& operator += (string &s, double d) { snprintf(buf, sizeof(buf), "%g", d); s.append(buf); return (s); } static void DisplayStateChange (const char *str, bool8 on) { snprintf(buf, sizeof(buf), "%s: %s", str, on ? "on":"off"); S9xSetInfoString(buf); } static void DoGunLatch (int x, int y) { x += 40; if (x > 295) x = 295; else if (x < 40) x = 40; if (y > PPU.ScreenHeight - 1) y = PPU.ScreenHeight - 1; else if (y < 0) y = 0; PPU.GunVLatch = (uint16) (y + 1); PPU.GunHLatch = (uint16) x; } static int maptype (int t) { switch (t) { case S9xNoMapping: return (MAP_NONE); case S9xButtonJoypad: case S9xButtonMouse: case S9xButtonSuperscope: case S9xButtonJustifier: case S9xButtonCommand: case S9xButtonPseudopointer: case S9xButtonPort: case S9xButtonMulti: return (MAP_BUTTON); case S9xAxisJoypad: case S9xAxisPseudopointer: case S9xAxisPseudobuttons: case S9xAxisPort: return (MAP_AXIS); case S9xPointer: case S9xPointerPort: return (MAP_POINTER); default: return (MAP_UNKNOWN); } } void S9xControlsReset (void) { S9xControlsSoftReset(); mouse[0].buttons &= ~0x30; mouse[1].buttons &= ~0x30; justifier.buttons &= ~JUSTIFIER_SELECT; } void S9xControlsSoftReset (void) { for (set::iterator it = exemultis.begin(); it != exemultis.end(); it++) delete *it; exemultis.clear(); for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) read_idx[i][j]=0; FLAG_LATCH = FALSE; } void S9xUnmapAllControls (void) { S9xControlsReset(); keymap.clear(); for (int i = 0; i < (int) multis.size(); i++) free(multis[i]); multis.clear(); for (int i = 0; i < NUMCTLS + 1; i++) pollmap[i].clear(); for (int i = 0; i < 8; i++) { pseudopointer[i].x = 0; pseudopointer[i].y = 0; pseudopointer[i].H_adj = 0; pseudopointer[i].V_adj = 0; pseudopointer[i].H_var = 0; pseudopointer[i].V_var = 0; pseudopointer[i].mapped = false; joypad[i].buttons = 0; joypad[i].turbos = 0; joypad[i].turbo_ct = 0; } for (int i = 0; i < 2; i++) { mouse[i].old_x = mouse[i].old_y = 0; mouse[i].cur_x = mouse[i].cur_y = 0; mouse[i].buttons = 1; mouse[i].ID = InvalidControlID; if (!(mouse[i].crosshair.set & 1)) mouse[i].crosshair.img = 0; // no image for mouse because its only logical position is game-specific, not known by the emulator if (!(mouse[i].crosshair.set & 2)) mouse[i].crosshair.fg = 5; if (!(mouse[i].crosshair.set & 4)) mouse[i].crosshair.bg = 1; justifier.x[i] = justifier.y[i] = 0; justifier.offscreen[i] = 0; justifier.ID[i] = InvalidControlID; if (!(justifier.crosshair[i].set & 1)) justifier.crosshair[i].img = 4; if (!(justifier.crosshair[i].set & 2)) justifier.crosshair[i].fg = i ? 14 : 12; if (!(justifier.crosshair[i].set & 4)) justifier.crosshair[i].bg = 1; } justifier.buttons = 0; superscope.x = superscope.y = 0; superscope.phys_buttons = 0; superscope.next_buttons = 0; superscope.read_buttons = 0; superscope.ID = InvalidControlID; if (!(superscope.crosshair.set & 1)) superscope.crosshair.img = 2; if (!(superscope.crosshair.set & 2)) superscope.crosshair.fg = 5; if (!(superscope.crosshair.set & 4)) superscope.crosshair.bg = 1; memset(pseudobuttons, 0, sizeof(pseudobuttons)); turbo_time = 1; } void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4) { if (port < 0 || port > 1) return; switch (controller) { case CTL_NONE: break; case CTL_JOYPAD: if (id1 < 0 || id1 > 7) break; newcontrollers[port] = JOYPAD0 + id1; return; case CTL_MOUSE: if (id1 < 0 || id1 > 1) break; if (!Settings.MouseMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled"); break; } newcontrollers[port] = MOUSE0 + id1; return; case CTL_SUPERSCOPE: if (!Settings.SuperScopeMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled"); break; } newcontrollers[port] = SUPERSCOPE; return; case CTL_JUSTIFIER: if (id1 < 0 || id1 > 1) break; if (!Settings.JustifierMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled"); break; } newcontrollers[port] = ONE_JUSTIFIER + id1; return; case CTL_MP5: if (id1 < -1 || id1 > 7) break; if (id2 < -1 || id2 > 7) break; if (id3 < -1 || id3 > 7) break; if (id4 < -1 || id4 > 7) break; if (!Settings.MultiPlayer5Master) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled"); break; } newcontrollers[port] = MP5; mp5[port].pads[0] = (id1 < 0) ? NONE : JOYPAD0 + id1; mp5[port].pads[1] = (id2 < 0) ? NONE : JOYPAD0 + id2; mp5[port].pads[2] = (id3 < 0) ? NONE : JOYPAD0 + id3; mp5[port].pads[3] = (id4 < 0) ? NONE : JOYPAD0 + id4; return; default: fprintf(stderr, "Unknown controller type %d\n", controller); break; } newcontrollers[port] = NONE; } bool S9xVerifyControllers (void) { bool ret = false; int port, i, used[NUMCTLS]; for (i = 0; i < NUMCTLS; used[i++] = 0) ; for (port = 0; port < 2; port++) { switch (i = newcontrollers[port]) { case MOUSE0: case MOUSE1: if (!Settings.MouseMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled"); newcontrollers[port] = NONE; ret = true; break; } if (used[i]++ > 0) { snprintf(buf, sizeof(buf), "Mouse%d used more than once! Disabling extra instances", i - MOUSE0 + 1); S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); newcontrollers[port] = NONE; ret = true; break; } break; case SUPERSCOPE: if (!Settings.SuperScopeMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled"); newcontrollers[port] = NONE; ret = true; break; } if (used[i]++ > 0) { snprintf(buf, sizeof(buf), "Superscope used more than once! Disabling extra instances"); S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); newcontrollers[port] = NONE; ret = true; break; } break; case ONE_JUSTIFIER: case TWO_JUSTIFIERS: if (!Settings.JustifierMaster) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled"); newcontrollers[port] = NONE; ret = true; break; } if (used[ONE_JUSTIFIER]++ > 0) { snprintf(buf, sizeof(buf), "Justifier used more than once! Disabling extra instances"); S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); newcontrollers[port] = NONE; ret = true; break; } break; case MP5: if (!Settings.MultiPlayer5Master) { S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled"); newcontrollers[port] = NONE; ret = true; break; } for (i = 0; i < 4; i++) { if (mp5[port].pads[i] != NONE) { if (used[mp5[port].pads[i] - JOYPAD0]++ > 0) { snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", mp5[port].pads[i] - JOYPAD0 + 1); S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); mp5[port].pads[i] = NONE; ret = true; break; } } } break; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: if (used[i - JOYPAD0]++ > 0) { snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", i - JOYPAD0 + 1); S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); newcontrollers[port] = NONE; ret = true; break; } break; default: break; } } return (ret); } void S9xGetController (int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4) { int i; *controller = CTL_NONE; *id1 = *id2 = *id3 = *id4 = -1; if (port < 0 || port > 1) return; switch (i = newcontrollers[port]) { case MP5: *controller = CTL_MP5; *id1 = (mp5[port].pads[0] == NONE) ? -1 : mp5[port].pads[0] - JOYPAD0; *id2 = (mp5[port].pads[1] == NONE) ? -1 : mp5[port].pads[1] - JOYPAD0; *id3 = (mp5[port].pads[2] == NONE) ? -1 : mp5[port].pads[2] - JOYPAD0; *id4 = (mp5[port].pads[3] == NONE) ? -1 : mp5[port].pads[3] - JOYPAD0; return; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: *controller = CTL_JOYPAD; *id1 = i - JOYPAD0; return; case MOUSE0: case MOUSE1: *controller = CTL_MOUSE; *id1 = i - MOUSE0; return; case SUPERSCOPE: *controller = CTL_SUPERSCOPE; *id1 = 1; return; case ONE_JUSTIFIER: case TWO_JUSTIFIERS: *controller = CTL_JUSTIFIER; *id1 = i - ONE_JUSTIFIER; return; } } void S9xReportControllers (void) { static char mes[128]; char *c = mes; S9xVerifyControllers(); for (int port = 0; port < 2; port++) { c += sprintf(c, "Port %d: ", port + 1); switch (newcontrollers[port]) { case NONE: c += sprintf(c, ". "); break; case MP5: c += sprintf(c, "MP5 with pads"); for (int i = 0; i < 4; i++) { if (mp5[port].pads[i] == NONE) c += sprintf(c, " . "); else c += sprintf(c, " #%d. ", mp5[port].pads[i] + 1 - JOYPAD0); } break; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: c += sprintf(c, "Pad #%d. ", (int) (newcontrollers[port] - JOYPAD0 + 1)); break; case MOUSE0: case MOUSE1: c += sprintf(c, "Mouse #%d. ", (int) (newcontrollers[port] - MOUSE0 + 1)); break; case SUPERSCOPE: if (port == 0) c += sprintf(c, "Superscope (cannot fire). "); else c += sprintf(c, "Superscope. "); break; case ONE_JUSTIFIER: if (port == 0) c += sprintf(c, "Blue Justifier (cannot fire). "); else c += sprintf(c, "Blue Justifier. "); break; case TWO_JUSTIFIERS: if (port == 0) c += sprintf(c, "Blue and Pink Justifiers (cannot fire). "); else c += sprintf(c, "Blue and Pink Justifiers. "); break; } } S9xMessage(S9X_INFO, S9X_CONFIG_INFO, mes); } char * S9xGetCommandName (s9xcommand_t command) { string s; char c; switch (command.type) { case S9xButtonJoypad: if (command.button.joypad.buttons == 0) return (strdup("None")); if (command.button.joypad.buttons & 0x000f) return (strdup("None")); s = "Joypad"; s += command.button.joypad.idx + 1; c = ' '; if (command.button.joypad.toggle) { if (c) s += c; s += "Toggle"; c = 0; } if (command.button.joypad.sticky) { if (c) s += c; s += "Sticky"; c = 0; } if (command.button.joypad.turbo ) { if (c) s += c; s += "Turbo"; c = 0; } c = ' '; if (command.button.joypad.buttons & SNES_UP_MASK ) { s += c; s += "Up"; c = '+'; } if (command.button.joypad.buttons & SNES_DOWN_MASK ) { s += c; s += "Down"; c = '+'; } if (command.button.joypad.buttons & SNES_LEFT_MASK ) { s += c; s += "Left"; c = '+'; } if (command.button.joypad.buttons & SNES_RIGHT_MASK ) { s += c; s += "Right"; c = '+'; } if (command.button.joypad.buttons & SNES_A_MASK ) { s += c; s += "A"; c = '+'; } if (command.button.joypad.buttons & SNES_B_MASK ) { s += c; s += "B"; c = '+'; } if (command.button.joypad.buttons & SNES_X_MASK ) { s += c; s += "X"; c = '+'; } if (command.button.joypad.buttons & SNES_Y_MASK ) { s += c; s += "Y"; c = '+'; } if (command.button.joypad.buttons & SNES_TL_MASK ) { s += c; s += "L"; c = '+'; } if (command.button.joypad.buttons & SNES_TR_MASK ) { s += c; s += "R"; c = '+'; } if (command.button.joypad.buttons & SNES_START_MASK ) { s += c; s += "Start"; c = '+'; } if (command.button.joypad.buttons & SNES_SELECT_MASK) { s += c; s += "Select"; c = '+'; } break; case S9xButtonMouse: if (!command.button.mouse.left && !command.button.mouse.right) return (strdup("None")); s = "Mouse"; s += command.button.mouse.idx + 1; s += " "; if (command.button.mouse.left ) s += "L"; if (command.button.mouse.right) s += "R"; break; case S9xButtonSuperscope: if (!command.button.scope.fire && !command.button.scope.cursor && !command.button.scope.turbo && !command.button.scope.pause && !command.button.scope.aim_offscreen) return (strdup("None")); s = "Superscope"; if (command.button.scope.aim_offscreen) s += " AimOffscreen"; c = ' '; if (command.button.scope.fire ) { s += c; s += "Fire"; c = '+'; } if (command.button.scope.cursor) { s += c; s += "Cursor"; c = '+'; } if (command.button.scope.turbo ) { s += c; s += "ToggleTurbo"; c = '+'; } if (command.button.scope.pause ) { s += c; s += "Pause"; c = '+'; } break; case S9xButtonJustifier: if (!command.button.justifier.trigger && !command.button.justifier.start && !command.button.justifier.aim_offscreen) return (strdup("None")); s = "Justifier"; s += command.button.justifier.idx + 1; if (command.button.justifier.aim_offscreen) s += " AimOffscreen"; c = ' '; if (command.button.justifier.trigger) { s += c; s += "Trigger"; c = '+'; } if (command.button.justifier.start ) { s += c; s += "Start"; c = '+'; } break; case S9xButtonCommand: if (command.button.command >= LAST_COMMAND) return (strdup("None")); return (strdup(command_names[command.button.command])); case S9xPointer: if (!command.pointer.aim_mouse0 && !command.pointer.aim_mouse1 && !command.pointer.aim_scope && !command.pointer.aim_justifier0 && !command.pointer.aim_justifier1) return (strdup("None")); s = "Pointer"; c = ' '; if (command.pointer.aim_mouse0 ) { s += c; s += "Mouse1"; c = '+'; } if (command.pointer.aim_mouse1 ) { s += c; s += "Mouse2"; c = '+'; } if (command.pointer.aim_scope ) { s += c; s += "Superscope"; c = '+'; } if (command.pointer.aim_justifier0) { s += c; s += "Justifier1"; c = '+'; } if (command.pointer.aim_justifier1) { s += c; s += "Justifier2"; c = '+'; } break; case S9xButtonPseudopointer: if (!command.button.pointer.UD && !command.button.pointer.LR) return (strdup("None")); if (command.button.pointer.UD == -2 || command.button.pointer.LR == -2) return (strdup("None")); s = "ButtonToPointer "; s += command.button.pointer.idx + 1; if (command.button.pointer.UD) s += (command.button.pointer.UD == 1) ? 'd' : 'u'; if (command.button.pointer.LR) s += (command.button.pointer.LR == 1) ? 'r' : 'l'; s += " "; s += speed_names[command.button.pointer.speed_type]; break; case S9xAxisJoypad: s = "Joypad"; s += command.axis.joypad.idx + 1; s += " Axis "; switch (command.axis.joypad.axis) { case 0: s += (command.axis.joypad.invert ? "Right/Left" : "Left/Right"); break; case 1: s += (command.axis.joypad.invert ? "Down/Up" : "Up/Down" ); break; case 2: s += (command.axis.joypad.invert ? "A/Y" : "Y/A" ); break; case 3: s += (command.axis.joypad.invert ? "B/X" : "X/B" ); break; case 4: s += (command.axis.joypad.invert ? "R/L" : "L/R" ); break; default: return (strdup("None")); } s += " T="; s += int((command.axis.joypad.threshold + 1) * 1000 / 256) / 10.0; s += "%"; break; case S9xAxisPseudopointer: s = "AxisToPointer "; s += command.axis.pointer.idx + 1; s += command.axis.pointer.HV ? 'v' : 'h'; s += " "; if (command.axis.pointer.invert) s += "-"; s += speed_names[command.axis.pointer.speed_type]; break; case S9xAxisPseudobuttons: s = "AxisToButtons "; s += command.axis.button.negbutton; s += "/"; s += command.axis.button.posbutton; s += " T="; s += int((command.axis.button.threshold + 1) * 1000 / 256) / 10.0; s += "%"; break; case S9xButtonPort: case S9xAxisPort: case S9xPointerPort: return (strdup("BUG: Port should have handled this instead of calling S9xGetCommandName()")); case S9xNoMapping: return (strdup("None")); case S9xButtonMulti: { if (command.button.multi_idx >= (int) multis.size()) return (strdup("None")); s = "{"; if (multis[command.button.multi_idx]->multi_press) s = "+{"; bool sep = false; for (s9xcommand_t *m = multis[command.button.multi_idx]; m->multi_press != 3; m++) { if (m->type == S9xNoMapping) { s += ";"; sep = false; } else { if (sep) s += ","; if (m->multi_press == 1) s += "+"; if (m->multi_press == 2) s += "-"; s += S9xGetCommandName(*m); sep = true; } } s += "}"; break; } default: return (strdup("BUG: Unknown command type")); } return (strdup(s.c_str())); } static bool strless (const char *a, const char *b) { return (strcmp(a, b) < 0); } static int findstr (const char *needle, const char **haystack, int numstr) { const char **r; r = lower_bound(haystack, haystack + numstr, needle, strless); if (r >= haystack + numstr || strcmp(needle, *r)) return (-1); return (r - haystack); } static int get_threshold (const char **ss) { const char *s = *ss; int i; if (s[0] != 'T' || s[1] != '=') return (-1); s += 2; i = 0; if (s[0] == '0') { if (s[1] != '.') return (-1); s++; } else { do { if (*s < '0' || *s > '9') return (-1); i = i * 10 + 10 * (*s - '0'); if (i > 1000) return (-1); s++; } while (*s != '.' && *s != '%'); } if (*s == '.') { if (s[1] < '0' || s[1] > '9' || s[2] != '%') return (-1); i += s[1] - '0'; } if (i > 1000) return (-1); *ss = s; return (i); } s9xcommand_t S9xGetCommandT (const char *name) { s9xcommand_t cmd; int i, j; const char *s; memset(&cmd, 0, sizeof(cmd)); cmd.type = S9xBadMapping; cmd.multi_press = 0; cmd.button_norpt = 0; if (!strcmp(name, "None")) cmd.type = S9xNoMapping; else if (!strncmp(name, "Joypad", 6)) { if (name[6] < '1' || name[6] > '8' || name[7] != ' ') return (cmd); if (!strncmp(name + 8, "Axis ", 5)) { cmd.axis.joypad.idx = name[6] - '1'; s = name + 13; if (!strncmp(s, "Left/Right ", 11)) { j = 0; i = 0; s += 11; } else if (!strncmp(s, "Right/Left ", 11)) { j = 0; i = 1; s += 11; } else if (!strncmp(s, "Up/Down ", 8)) { j = 1; i = 0; s += 8; } else if (!strncmp(s, "Down/Up ", 8)) { j = 1; i = 1; s += 8; } else if (!strncmp(s, "Y/A ", 4)) { j = 2; i = 0; s += 4; } else if (!strncmp(s, "A/Y ", 4)) { j = 2; i = 1; s += 4; } else if (!strncmp(s, "X/B ", 4)) { j = 3; i = 0; s += 4; } else if (!strncmp(s, "B/X ", 4)) { j = 3; i = 1; s += 4; } else if (!strncmp(s, "L/R ", 4)) { j = 4; i = 0; s += 4; } else if (!strncmp(s, "R/L ", 4)) { j = 4; i = 1; s += 4; } else return (cmd); cmd.axis.joypad.axis = j; cmd.axis.joypad.invert = i; i = get_threshold(&s); if (i < 0) return (cmd); cmd.axis.joypad.threshold = (i - 1) * 256 / 1000; cmd.type = S9xAxisJoypad; } else { cmd.button.joypad.idx = name[6] - '1'; s = name + 8; i = 0; if ((cmd.button.joypad.toggle = strncmp(s, "Toggle", 6) ? 0 : 1)) s += i = 6; if ((cmd.button.joypad.sticky = strncmp(s, "Sticky", 6) ? 0 : 1)) s += i = 6; if ((cmd.button.joypad.turbo = strncmp(s, "Turbo", 5) ? 0 : 1)) s += i = 5; if (cmd.button.joypad.toggle && !(cmd.button.joypad.sticky || cmd.button.joypad.turbo)) return (cmd); if (i) { if (*s != ' ') return (cmd); s++; } i = 0; if (!strncmp(s, "Up", 2)) { i |= SNES_UP_MASK; s += 2; if (*s == '+') s++; } if (!strncmp(s, "Down", 4)) { i |= SNES_DOWN_MASK; s += 4; if (*s == '+') s++; } if (!strncmp(s, "Left", 4)) { i |= SNES_LEFT_MASK; s += 4; if (*s == '+') s++; } if (!strncmp(s, "Right", 5)) { i |= SNES_RIGHT_MASK; s += 5; if (*s == '+') s++; } if (*s == 'A') { i |= SNES_A_MASK; s++; if (*s == '+') s++; } if (*s == 'B') { i |= SNES_B_MASK; s++; if (*s == '+') s++; } if (*s == 'X') { i |= SNES_X_MASK; s++; if (*s == '+') s++; } if (*s == 'Y') { i |= SNES_Y_MASK; s++; if (*s == '+') s++; } if (*s == 'L') { i |= SNES_TL_MASK; s++; if (*s == '+') s++; } if (*s == 'R') { i |= SNES_TR_MASK; s++; if (*s == '+') s++; } if (!strncmp(s, "Start", 5)) { i |= SNES_START_MASK; s += 5; if (*s == '+') s++; } if (!strncmp(s, "Select", 6)) { i |= SNES_SELECT_MASK; s += 6; } if (i == 0 || *s != 0 || *(s - 1) == '+') return (cmd); cmd.button.joypad.buttons = i; cmd.type = S9xButtonJoypad; } } else if (!strncmp(name, "Mouse", 5)) { if (name[5] < '1' || name[5] > '2' || name[6] != ' ') return (cmd); cmd.button.mouse.idx = name[5] - '1'; s = name + 7; i = 0; if ((cmd.button.mouse.left = (*s == 'L'))) s += i = 1; if ((cmd.button.mouse.right = (*s == 'R'))) s += i = 1; if (i == 0 || *s != 0) return (cmd); cmd.type = S9xButtonMouse; } else if (!strncmp(name, "Superscope ", 11)) { s = name + 11; i = 0; if ((cmd.button.scope.aim_offscreen = strncmp(s, "AimOffscreen", 12) ? 0 : 1)) { s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); } if ((cmd.button.scope.fire = strncmp(s, "Fire", 4) ? 0 : 1)) { s += i = 4; if (*s == '+') s++; } if ((cmd.button.scope.cursor = strncmp(s, "Cursor", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; } if ((cmd.button.scope.turbo = strncmp(s, "ToggleTurbo", 11) ? 0 : 1)) { s += i = 11; if (*s == '+') s++; } if ((cmd.button.scope.pause = strncmp(s, "Pause", 5) ? 0 : 1)) { s += i = 5; } if (i == 0 || *s != 0 || *(s - 1) == '+') return (cmd); cmd.type = S9xButtonSuperscope; } else if (!strncmp(name, "Justifier", 9)) { if (name[9] < '1' || name[9] > '2' || name[10] != ' ') return (cmd); cmd.button.justifier.idx = name[9] - '1'; s = name + 11; i = 0; if ((cmd.button.justifier.aim_offscreen = strncmp(s, "AimOffscreen", 12) ? 0 : 1)) { s += i = 12; if (*s == ' ') s++; else if (*s != 0) return (cmd); } if ((cmd.button.justifier.trigger = strncmp(s, "Trigger", 7) ? 0 : 1)) { s += i = 7; if (*s == '+') s++; } if ((cmd.button.justifier.start = strncmp(s, "Start", 5) ? 0 : 1)) { s += i = 5; } if (i == 0 || *s != 0 || *(s - 1) == '+') return (cmd); cmd.type = S9xButtonJustifier; } else if (!strncmp(name, "Pointer ", 8)) { s = name + 8; i = 0; if ((cmd.pointer.aim_mouse0 = strncmp(s, "Mouse1", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; } if ((cmd.pointer.aim_mouse1 = strncmp(s, "Mouse2", 6) ? 0 : 1)) { s += i = 6; if (*s == '+') s++; } if ((cmd.pointer.aim_scope = strncmp(s, "Superscope", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; } if ((cmd.pointer.aim_justifier0 = strncmp(s, "Justifier1", 10) ? 0 : 1)) { s += i = 10; if (*s == '+') s++; } if ((cmd.pointer.aim_justifier1 = strncmp(s, "Justifier2", 10) ? 0 : 1)) { s += i = 10; } if (i == 0 || *s != 0 || *(s - 1) == '+') return (cmd); cmd.type = S9xPointer; } else if (!strncmp(name, "ButtonToPointer ", 16)) { if (name[16] < '1' || name[16] > '8') return (cmd); cmd.button.pointer.idx = name[16] - '1'; s = name + 17; i = 0; if ((cmd.button.pointer.UD = (*s == 'u' ? -1 : (*s == 'd' ? 1 : 0)))) s += i = 1; if ((cmd.button.pointer.LR = (*s == 'l' ? -1 : (*s == 'r' ? 1 : 0)))) s += i = 1; if (i == 0 || *(s++) != ' ') return (cmd); for (i = 0; i < 4; i++) if (!strcmp(s, speed_names[i])) break; if (i > 3) return (cmd); cmd.button.pointer.speed_type = i; cmd.type = S9xButtonPseudopointer; } else if (!strncmp(name, "AxisToPointer ", 14)) { if (name[14] < '1' || name[14] > '8') return (cmd); cmd.axis.pointer.idx = name[14] - '1'; s= name + 15; i = 0; if (*s == 'h') cmd.axis.pointer.HV = 0; else if (*s == 'v') cmd.axis.pointer.HV = 1; else return (cmd); if (s[1] != ' ') return (cmd); s += 2; if ((cmd.axis.pointer.invert = *s == '-')) s++; for (i = 0; i < 4; i++) if (!strcmp(s, speed_names[i])) break; if (i > 3) return (cmd); cmd.axis.pointer.speed_type = i; cmd.type = S9xAxisPseudopointer; } else if (!strncmp(name, "AxisToButtons ", 14)) { s = name + 14; if (s[0] == '0') { if (s[1] != '/') return (cmd); cmd.axis.button.negbutton = 0; s += 2; } else { i = 0; do { if (*s < '0' || *s > '9') return (cmd); i = i * 10 + *s - '0'; if (i > 255) return (cmd); } while (*++s != '/'); cmd.axis.button.negbutton = i; s++; } if (s[0] == '0') { if (s[1] != ' ') return (cmd); cmd.axis.button.posbutton = 0; s += 2; } else { i = 0; do { if (*s < '0' || *s > '9') return (cmd); i = i * 10 + *s - '0'; if (i > 255) return (cmd); } while (*++s != ' '); cmd.axis.button.posbutton = i; s++; } i = get_threshold(&s); if (i < 0) return (cmd); cmd.axis.button.threshold = (i - 1) * 256 / 1000; cmd.type = S9xAxisPseudobuttons; } else if (!strncmp(name, "MULTI#", 6)) { i = strtol(name + 6, (char **) &s, 10); if (s != NULL && *s != '\0') return (cmd); if (i >= (int) multis.size()) return (cmd); cmd.button.multi_idx = i; cmd.type = S9xButtonMulti; } else if (((name[0] == '+' && name[1] == '{') || name[0] == '{') && name[strlen(name) - 1] == '}') { if (multis.size() > 2147483640) { fprintf(stderr, "Too many multis!"); return (cmd); } string x; int n; j = 2; for (i = (name[0] == '+') ? 2 : 1; name[i] != '\0'; i++) { if (name[i] == ',' || name[i] == ';') { if (name[i] == ';') j++; if (++j > 2147483640) { fprintf(stderr, "Multi too long!"); return (cmd); } } if (name[i] == '{') return (cmd); } s9xcommand_t *c = (s9xcommand_t *) calloc(j, sizeof(s9xcommand_t)); if (c == NULL) { perror("malloc error while parsing multi"); return (cmd); } n = 0; i = (name[0] == '+') ? 2 : 1; do { if (name[i] == ';') { c[n].type = S9xNoMapping; c[n].multi_press = 0; c[n].button_norpt = 0; j = i; } else if (name[i] == ',') { free(c); return (cmd); } else { uint8 press = 0; if (name[0] == '+') { if (name[i] == '+') press = 1; else if (name[i] == '-') press = 2; else { free(c); return (cmd); } i++; } for (j = i; name[j] != ';' && name[j] != ',' && name[j] != '}'; j++) ; x.assign(name + i, j - i); c[n] = S9xGetCommandT(x.c_str()); c[n].multi_press = press; if (maptype(c[n].type) != MAP_BUTTON) { free(c); return (cmd); } if (name[j] == ';') j--; } i = j + 1; n++; } while (name[i] != '\0'); c[n].type = S9xNoMapping; c[n].multi_press = 3; multis.push_back(c); cmd.button.multi_idx = multis.size() - 1; cmd.type = S9xButtonMulti; } else { i = findstr(name, command_names, LAST_COMMAND); if (i < 0) return (cmd); cmd.type = S9xButtonCommand; cmd.button.command = i; } return (cmd); } const char ** S9xGetAllSnes9xCommands (void) { return (command_names); } s9xcommand_t S9xGetMapping (uint32 id) { if (keymap.count(id) == 0) { s9xcommand_t cmd; cmd.type = S9xNoMapping; return (cmd); } else return (keymap[id]); } static const char * maptypename (int t) { switch (t) { case MAP_NONE: return ("unmapped"); case MAP_BUTTON: return ("button"); case MAP_AXIS: return ("axis"); case MAP_POINTER: return ("pointer"); default: return ("unknown"); } } void S9xUnmapID (uint32 id) { for (int i = 0; i < NUMCTLS + 1; i++) pollmap[i].erase(id); if (mouse[0].ID == id) mouse[0].ID = InvalidControlID; if (mouse[1].ID == id) mouse[1].ID = InvalidControlID; if (superscope.ID == id) superscope.ID = InvalidControlID; if (justifier.ID[0] == id) justifier.ID[0] = InvalidControlID; if (justifier.ID[1] == id) justifier.ID[1] = InvalidControlID; if (id >= PseudoPointerBase) pseudopointer[id - PseudoPointerBase].mapped = false; keymap.erase(id); } bool S9xMapButton (uint32 id, s9xcommand_t mapping, bool poll) { int t; if (id == InvalidControlID) { fprintf(stderr, "Cannot map InvalidControlID\n"); return (false); } t = maptype(mapping.type); if (t == MAP_NONE) { S9xUnmapID(id); return (true); } if (t != MAP_BUTTON) return (false); t = maptype(S9xGetMapping(id).type); if (t != MAP_NONE && t != MAP_BUTTON) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to button\n", id, maptypename(t)); if (id >= PseudoPointerBase) { fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as a button\n", id - PseudoPointerBase); return (false); } t = -1; if (poll) { if (id >= PseudoButtonBase) fprintf(stderr, "INFO: Ignoring attempt to set pseudo-button #%d to polling\n", id - PseudoButtonBase); else { switch (mapping.type) { case S9xButtonJoypad: t = JOYPAD0 + mapping.button.joypad.idx; break; case S9xButtonMouse: t = MOUSE0 + mapping.button.mouse.idx; break; case S9xButtonSuperscope: t = SUPERSCOPE; break; case S9xButtonJustifier: t = ONE_JUSTIFIER + mapping.button.justifier.idx; break; case S9xButtonCommand: case S9xButtonPseudopointer: case S9xButtonPort: case S9xButtonMulti: t = POLL_ALL; break; } } } S9xUnmapID(id); keymap[id] = mapping; if (t >= 0) pollmap[t].insert(id); return (true); } void S9xReportButton (uint32 id, bool pressed) { if (keymap.count(id) == 0) return; if (keymap[id].type == S9xNoMapping) return; if (maptype(keymap[id].type) != MAP_BUTTON) { fprintf(stderr, "ERROR: S9xReportButton called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); return; } if (keymap[id].type == S9xButtonCommand) // skips the "already-pressed check" unless it's a command, as a hack to work around the following problem: if (keymap[id].button_norpt == pressed) // FIXME: this makes the controls "stick" after loading a savestate while recording a movie and holding any button return; keymap[id].button_norpt = pressed; S9xApplyCommand(keymap[id], pressed, 0); } bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll) { int t; if (id == InvalidControlID) { fprintf(stderr, "Cannot map InvalidControlID\n"); return (false); } t = maptype(mapping.type); if (t == MAP_NONE) { S9xUnmapID(id); return (true); } if (t != MAP_POINTER) return (false); t = maptype(S9xGetMapping(id).type); if (t != MAP_NONE && t != MAP_POINTER) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to pointer\n", id, maptypename(t)); if (id < PseudoPointerBase && id >= PseudoButtonBase) { fprintf(stderr, "ERROR: Refusing to map pseudo-button #%d as a pointer\n", id - PseudoButtonBase); return (false); } if (mapping.type == S9xPointer) { if (mapping.pointer.aim_mouse0 && mouse[0].ID != InvalidControlID && mouse[0].ID != id) { fprintf(stderr, "ERROR: Rejecting attempt to control Mouse1 with two pointers\n"); return (false); } if (mapping.pointer.aim_mouse1 && mouse[1].ID != InvalidControlID && mouse[1].ID != id) { fprintf(stderr, "ERROR: Rejecting attempt to control Mouse2 with two pointers\n"); return (false); } if (mapping.pointer.aim_scope && superscope.ID != InvalidControlID && superscope.ID != id) { fprintf(stderr, "ERROR: Rejecting attempt to control SuperScope with two pointers\n"); return (false); } if (mapping.pointer.aim_justifier0 && justifier.ID[0] != InvalidControlID && justifier.ID[0] != id) { fprintf(stderr, "ERROR: Rejecting attempt to control Justifier1 with two pointers\n"); return (false); } if (mapping.pointer.aim_justifier1 && justifier.ID[1] != InvalidControlID && justifier.ID[1] != id) { fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n"); return (false); } } S9xUnmapID(id); if (poll) { if (id >= PseudoPointerBase) fprintf(stderr, "INFO: Ignoring attempt to set pseudo-pointer #%d to polling\n", id - PseudoPointerBase); else { switch (mapping.type) { case S9xPointer: if (mapping.pointer.aim_mouse0 ) pollmap[MOUSE0 ].insert(id); if (mapping.pointer.aim_mouse1 ) pollmap[MOUSE1 ].insert(id); if (mapping.pointer.aim_scope ) pollmap[SUPERSCOPE ].insert(id); if (mapping.pointer.aim_justifier0) pollmap[ONE_JUSTIFIER ].insert(id); if (mapping.pointer.aim_justifier1) pollmap[TWO_JUSTIFIERS].insert(id); break; case S9xPointerPort: pollmap[POLL_ALL].insert(id); break; } } } if (id >= PseudoPointerBase) pseudopointer[id - PseudoPointerBase].mapped = true; keymap[id] = mapping; if (mapping.pointer.aim_mouse0 ) mouse[0].ID = id; if (mapping.pointer.aim_mouse1 ) mouse[1].ID = id; if (mapping.pointer.aim_scope ) superscope.ID = id; if (mapping.pointer.aim_justifier0) justifier.ID[0] = id; if (mapping.pointer.aim_justifier1) justifier.ID[1] = id; return (true); } void S9xReportPointer (uint32 id, int16 x, int16 y) { if (keymap.count(id) == 0) return; if (keymap[id].type == S9xNoMapping) return; if (maptype(keymap[id].type) != MAP_POINTER) { fprintf(stderr, "ERROR: S9xReportPointer called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); return; } S9xApplyCommand(keymap[id], x, y); } bool S9xMapAxis (uint32 id, s9xcommand_t mapping, bool poll) { int t; if (id == InvalidControlID) { fprintf(stderr, "Cannot map InvalidControlID\n"); return (false); } t = maptype(mapping.type); if (t == MAP_NONE) { S9xUnmapID(id); return (true); } if (t != MAP_AXIS) return (false); t = maptype(S9xGetMapping(id).type); if (t != MAP_NONE && t != MAP_AXIS) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to axis\n", id, maptypename(t)); if (id >= PseudoPointerBase) { fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as an axis\n", id - PseudoPointerBase); return (false); } t = -1; if (poll) { switch (mapping.type) { case S9xAxisJoypad: t = JOYPAD0 + mapping.axis.joypad.idx; break; case S9xAxisPseudopointer: case S9xAxisPseudobuttons: case S9xAxisPort: t=POLL_ALL; break; } } S9xUnmapID(id); keymap[id] = mapping; if (t >= 0) pollmap[t].insert(id); return (true); } void S9xReportAxis (uint32 id, int16 value) { if (keymap.count(id) == 0) return; if (keymap[id].type == S9xNoMapping) return; if (maptype(keymap[id].type) != MAP_AXIS) { fprintf(stderr, "ERROR: S9xReportAxis called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); return; } S9xApplyCommand(keymap[id], value, 0); } static int32 ApplyMulti (s9xcommand_t *multi, int32 pos, int16 data1) { while (1) { if (multi[pos].multi_press == 3) return (-1); if (multi[pos].type == S9xNoMapping) break; if (multi[pos].multi_press) S9xApplyCommand(multi[pos], multi[pos].multi_press == 1, 0); else S9xApplyCommand(multi[pos], data1, 0); pos++; } return (pos + 1); } void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2) { int i; switch (cmd.type) { case S9xNoMapping: return; case S9xButtonJoypad: if (cmd.button.joypad.toggle) { if (!data1) return; uint16 r = cmd.button.joypad.buttons; if (cmd.button.joypad.turbo) joypad[cmd.button.joypad.idx].toggleturbo ^= r; if (cmd.button.joypad.sticky) joypad[cmd.button.joypad.idx].togglestick ^= r; } else { uint16 r, s, t, st; s = t = st = 0; r = cmd.button.joypad.buttons; st = r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo; r ^= st; t = r & joypad[cmd.button.joypad.idx].toggleturbo; r ^= t; s = r & joypad[cmd.button.joypad.idx].togglestick; r ^= s; if (cmd.button.joypad.turbo && cmd.button.joypad.sticky) { uint16 x = r; r = st; st = x; x = s; s = t; t = x; } else if (cmd.button.joypad.turbo) { uint16 x = r; r = t; t = x; x = s; s = st; st = x; } else if (cmd.button.joypad.sticky) { uint16 x = r; r = s; s = x; x = t; t = st; st = x; } if (data1) { if (!Settings.UpAndDown && !S9xMoviePlaying()) // if up+down isn't allowed AND we are NOT playing a movie, { if (cmd.button.joypad.buttons & (SNES_LEFT_MASK | SNES_RIGHT_MASK)) { // if we're pressing left or right, then unpress and unturbo them both first // so we don't end up hittnig left AND right accidentally. // Note though that the user can still do it on purpose, if Settings.UpAndDown = true. // This is a feature, look up glitches in tLoZ:aLttP to find out why. joypad[cmd.button.joypad.idx].buttons &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK); joypad[cmd.button.joypad.idx].turbos &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK); } if (cmd.button.joypad.buttons & (SNES_UP_MASK | SNES_DOWN_MASK)) { // and ditto for up/down joypad[cmd.button.joypad.idx].buttons &= ~(SNES_UP_MASK | SNES_DOWN_MASK); joypad[cmd.button.joypad.idx].turbos &= ~(SNES_UP_MASK | SNES_DOWN_MASK); } } joypad[cmd.button.joypad.idx].buttons |= r; joypad[cmd.button.joypad.idx].turbos |= t; joypad[cmd.button.joypad.idx].buttons ^= s; joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & st); joypad[cmd.button.joypad.idx].turbos ^= st; } else { joypad[cmd.button.joypad.idx].buttons &= ~r; joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & t); joypad[cmd.button.joypad.idx].turbos &= ~t; } } return; case S9xButtonMouse: i = 0; if (cmd.button.mouse.left ) i |= 0x40; if (cmd.button.mouse.right) i |= 0x80; if (data1) mouse[cmd.button.mouse.idx].buttons |= i; else mouse[cmd.button.mouse.idx].buttons &= ~i; return; case S9xButtonSuperscope: i = 0; if (cmd.button.scope.fire ) i |= SUPERSCOPE_FIRE; if (cmd.button.scope.cursor ) i |= SUPERSCOPE_CURSOR; if (cmd.button.scope.pause ) i |= SUPERSCOPE_PAUSE; if (cmd.button.scope.aim_offscreen) i |= SUPERSCOPE_OFFSCREEN; if (data1) { superscope.phys_buttons |= i; if (cmd.button.scope.turbo) { superscope.phys_buttons ^= SUPERSCOPE_TURBO; if (superscope.phys_buttons & SUPERSCOPE_TURBO) superscope.next_buttons |= superscope.phys_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR); else superscope.next_buttons &= ~(SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR); } superscope.next_buttons |= i & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR | SUPERSCOPE_PAUSE); if (!S9xMovieActive()) // PPU modification during non-recordable command screws up movie synchronization if ((superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) && curcontrollers[1] == SUPERSCOPE && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN)) DoGunLatch(superscope.x, superscope.y); } else { superscope.phys_buttons &= ~i; superscope.next_buttons &= SUPERSCOPE_OFFSCREEN | ~i; } return; case S9xButtonJustifier: i = 0; if (cmd.button.justifier.trigger) i |= JUSTIFIER_TRIGGER; if (cmd.button.justifier.start ) i |= JUSTIFIER_START; if (cmd.button.justifier.aim_offscreen) justifier.offscreen[cmd.button.justifier.idx] = data1 ? 1 : 0; i >>= cmd.button.justifier.idx; if (data1) justifier.buttons |= i; else justifier.buttons &= ~i; return; case S9xButtonCommand: if (((enum command_numbers) cmd.button.command) >= LAST_COMMAND) { fprintf(stderr, "Unknown command %04x\n", cmd.button.command); return; } if (!data1) { switch (i = cmd.button.command) { case EmuTurbo: Settings.TurboMode = FALSE; break; } } else { switch ((enum command_numbers) (i = cmd.button.command)) { case ExitEmu: S9xExit(); break; case Reset: S9xReset(); break; case SoftReset: S9xMovieUpdateOnReset(); if (S9xMoviePlaying()) S9xMovieStop(TRUE); S9xSoftReset(); break; case EmuTurbo: Settings.TurboMode = TRUE; break; case ToggleEmuTurbo: Settings.TurboMode = !Settings.TurboMode; DisplayStateChange("Turbo mode", Settings.TurboMode); break; case ClipWindows: Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows; DisplayStateChange("Graphic clip windows", !Settings.DisableGraphicWindows); break; case Debugger: #ifdef DEBUGGER CPU.Flags |= DEBUG_MODE_FLAG; #endif break; case IncFrameRate: if (Settings.SkipFrames == AUTO_FRAMERATE) Settings.SkipFrames = 1; else if (Settings.SkipFrames < 10) Settings.SkipFrames++; if (Settings.SkipFrames == AUTO_FRAMERATE) S9xSetInfoString("Auto frame skip"); else { sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1); S9xSetInfoString(buf); } break; case DecFrameRate: if (Settings.SkipFrames <= 1) Settings.SkipFrames = AUTO_FRAMERATE; else if (Settings.SkipFrames != AUTO_FRAMERATE) Settings.SkipFrames--; if (Settings.SkipFrames == AUTO_FRAMERATE) S9xSetInfoString("Auto frame skip"); else { sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1); S9xSetInfoString(buf); } break; case IncEmuTurbo: if (Settings.TurboSkipFrames < 20) Settings.TurboSkipFrames += 1; else if (Settings.TurboSkipFrames < 200) Settings.TurboSkipFrames += 5; sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames); S9xSetInfoString(buf); break; case DecEmuTurbo: if (Settings.TurboSkipFrames > 20) Settings.TurboSkipFrames -= 5; else if (Settings.TurboSkipFrames > 0) Settings.TurboSkipFrames -= 1; sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames); S9xSetInfoString(buf); break; case IncFrameTime: // Increase emulated frame time by 1ms Settings.FrameTime += 1000; sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000); S9xSetInfoString(buf); break; case DecFrameTime: // Decrease emulated frame time by 1ms if (Settings.FrameTime >= 1000) Settings.FrameTime -= 1000; sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000); S9xSetInfoString(buf); break; case IncTurboSpeed: if (turbo_time >= 120) break; turbo_time++; sprintf(buf, "Turbo speed: %d", turbo_time); S9xSetInfoString(buf); break; case DecTurboSpeed: if (turbo_time <= 1) break; turbo_time--; sprintf(buf, "Turbo speed: %d", turbo_time); S9xSetInfoString(buf); break; case LoadFreezeFile: S9xUnfreezeGame(S9xChooseFilename(TRUE)); break; case SaveFreezeFile: S9xFreezeGame(S9xChooseFilename(FALSE)); break; case LoadOopsFile: { char filename[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; _splitpath(Memory.ROMFilename, drive, dir, def, ext); snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops"); if (S9xUnfreezeGame(filename)) { sprintf(buf, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops"); S9xSetInfoString (buf); } else S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Oops file not found"); break; } case Pause: Settings.Paused = !Settings.Paused; DisplayStateChange("Pause", Settings.Paused); #if defined(NETPLAY_SUPPORT) && !defined(__WIN32__) S9xNPSendPause(Settings.Paused); #endif break; case QuickLoad000: case QuickLoad001: case QuickLoad002: case QuickLoad003: case QuickLoad004: case QuickLoad005: case QuickLoad006: case QuickLoad007: case QuickLoad008: case QuickLoad009: case QuickLoad010: { char filename[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; _splitpath(Memory.ROMFilename, drive, dir, def, ext); snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickLoad000); if (S9xUnfreezeGame(filename)) { sprintf(buf, "%s.%03d loaded", def, i - QuickLoad000); S9xSetInfoString(buf); } else S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Freeze file not found"); break; } case QuickSave000: case QuickSave001: case QuickSave002: case QuickSave003: case QuickSave004: case QuickSave005: case QuickSave006: case QuickSave007: case QuickSave008: case QuickSave009: case QuickSave010: { char filename[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; _splitpath(Memory.ROMFilename, drive, dir, def, ext); snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000); sprintf(buf, "%s.%03d saved", def, i - QuickSave000); S9xSetInfoString(buf); S9xFreezeGame(filename); break; } case SaveSPC: S9xDumpSPCSnapshot(); break; case Screenshot: Settings.TakeScreenshot = TRUE; break; case SoundChannel0: case SoundChannel1: case SoundChannel2: case SoundChannel3: case SoundChannel4: case SoundChannel5: case SoundChannel6: case SoundChannel7: S9xToggleSoundChannel(i - SoundChannel0); sprintf(buf, "Sound channel %d toggled", i - SoundChannel0); S9xSetInfoString(buf); break; case SoundChannelsOn: S9xToggleSoundChannel(8); S9xSetInfoString("All sound channels on"); break; case ToggleBG0: Settings.BG_Forced ^= 1; DisplayStateChange("BG#0", !(Settings.BG_Forced & 1)); break; case ToggleBG1: Settings.BG_Forced ^= 2; DisplayStateChange("BG#1", !(Settings.BG_Forced & 2)); break; case ToggleBG2: Settings.BG_Forced ^= 4; DisplayStateChange("BG#2", !(Settings.BG_Forced & 4)); break; case ToggleBG3: Settings.BG_Forced ^= 8; DisplayStateChange("BG#3", !(Settings.BG_Forced & 8)); break; case ToggleSprites: Settings.BG_Forced ^= 16; DisplayStateChange("Sprites", !(Settings.BG_Forced & 16)); break; case ToggleTransparency: Settings.Transparency = !Settings.Transparency; DisplayStateChange("Transparency effects", Settings.Transparency); break; case BeginRecordingMovie: if (S9xMovieActive()) S9xMovieStop(FALSE); S9xMovieCreate(S9xChooseMovieFilename(FALSE), 0xFF, MOVIE_OPT_FROM_RESET, NULL, 0); break; case LoadMovie: if (S9xMovieActive()) S9xMovieStop(FALSE); S9xMovieOpen(S9xChooseMovieFilename(TRUE), FALSE); break; case EndRecordingMovie: if (S9xMovieActive()) S9xMovieStop(FALSE); break; case SwapJoypads: if ((curcontrollers[0] != NONE && !(curcontrollers[0] >= JOYPAD0 && curcontrollers[0] <= JOYPAD7))) { S9xSetInfoString("Cannot swap pads: port 1 is not a joypad"); break; } if ((curcontrollers[1] != NONE && !(curcontrollers[1] >= JOYPAD0 && curcontrollers[1] <= JOYPAD7))) { S9xSetInfoString("Cannot swap pads: port 2 is not a joypad"); break; } newcontrollers[1] = curcontrollers[0]; newcontrollers[0] = curcontrollers[1]; strcpy(buf, "Swap pads: P1="); i = 14; if (newcontrollers[0] == NONE) { strcpy(buf + i, ""); i += 6; } else { sprintf(buf + i, "Joypad%d", newcontrollers[0] - JOYPAD0 + 1); i += 7; } strcpy(buf + i, " P2="); i += 4; if (newcontrollers[1] == NONE) strcpy(buf + i, ""); else sprintf(buf + i, "Joypad%d", newcontrollers[1] - JOYPAD0 + 1); S9xSetInfoString(buf); break; case SeekToFrame: if (S9xMovieActive()) { sprintf(buf, "Select frame number (current: %d)", S9xMovieGetFrameCounter()); const char *frameno = S9xStringInput(buf); if (!frameno) return; int frameDest = atoi(frameno); if (frameDest > 0 && frameDest > (int) S9xMovieGetFrameCounter()) { int distance = frameDest - S9xMovieGetFrameCounter(); Settings.HighSpeedSeek = distance; } } break; case LAST_COMMAND: break; } } return; case S9xPointer: if (cmd.pointer.aim_mouse0) { mouse[0].cur_x = data1; mouse[0].cur_y = data2; } if (cmd.pointer.aim_mouse1) { mouse[1].cur_x = data1; mouse[1].cur_y = data2; } if (cmd.pointer.aim_scope) { superscope.x = data1; superscope.y = data2; } if (cmd.pointer.aim_justifier0) { justifier.x[0] = data1; justifier.y[0] = data2; } if (cmd.pointer.aim_justifier1) { justifier.x[1] = data1; justifier.y[1] = data2; } return; case S9xButtonPseudopointer: if (data1) { if (cmd.button.pointer.UD) { if (!pseudopointer[cmd.button.pointer.idx].V_adj) pseudopointer[cmd.button.pointer.idx].V_adj = cmd.button.pointer.UD * ptrspeeds[cmd.button.pointer.speed_type]; pseudopointer[cmd.button.pointer.idx].V_var = (cmd.button.pointer.speed_type == 0); } if (cmd.button.pointer.LR) { if (!pseudopointer[cmd.button.pointer.idx].H_adj) pseudopointer[cmd.button.pointer.idx].H_adj = cmd.button.pointer.LR * ptrspeeds[cmd.button.pointer.speed_type]; pseudopointer[cmd.button.pointer.idx].H_var = (cmd.button.pointer.speed_type == 0); } } else { if (cmd.button.pointer.UD) { pseudopointer[cmd.button.pointer.idx].V_adj = 0; pseudopointer[cmd.button.pointer.idx].V_var = false; } if (cmd.button.pointer.LR) { pseudopointer[cmd.button.pointer.idx].H_adj = 0; pseudopointer[cmd.button.pointer.idx].H_var = false; } } return; case S9xAxisJoypad: { uint16 pos, neg; switch (cmd.axis.joypad.axis) { case 0: neg = SNES_LEFT_MASK; pos = SNES_RIGHT_MASK; break; case 1: neg = SNES_UP_MASK; pos = SNES_DOWN_MASK; break; case 2: neg = SNES_Y_MASK; pos = SNES_A_MASK; break; case 3: neg = SNES_X_MASK; pos = SNES_B_MASK; break; case 4: neg = SNES_TL_MASK; pos = SNES_TR_MASK; break; default: return; } if (cmd.axis.joypad.invert) data1 = -data1; uint16 p, r; p = r = 0; if (data1 > ((cmd.axis.joypad.threshold + 1) * 127)) p |= pos; else r |= pos; if (data1 <= ((cmd.axis.joypad.threshold + 1) * -127)) p |= neg; else r |= neg; joypad[cmd.axis.joypad.idx].buttons |= p; joypad[cmd.axis.joypad.idx].buttons &= ~r; joypad[cmd.axis.joypad.idx].turbos &= ~(p | r); return; } case S9xAxisPseudopointer: if (data1 == 0) { if (cmd.axis.pointer.HV) { pseudopointer[cmd.axis.pointer.idx].V_adj = 0; pseudopointer[cmd.axis.pointer.idx].V_var = false; } else { pseudopointer[cmd.axis.pointer.idx].H_adj = 0; pseudopointer[cmd.axis.pointer.idx].H_var = false; } } else { if (cmd.axis.pointer.invert) data1 = -data1; if (cmd.axis.pointer.HV) { if (!pseudopointer[cmd.axis.pointer.idx].V_adj) pseudopointer[cmd.axis.pointer.idx].V_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767); pseudopointer[cmd.axis.pointer.idx].V_var = (cmd.axis.pointer.speed_type == 0); } else { if (!pseudopointer[cmd.axis.pointer.idx].H_adj) pseudopointer[cmd.axis.pointer.idx].H_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767); pseudopointer[cmd.axis.pointer.idx].H_var = (cmd.axis.pointer.speed_type == 0); } } return; case S9xAxisPseudobuttons: if (data1 > ((cmd.axis.button.threshold + 1) * 127)) { if (!pseudobuttons[cmd.axis.button.posbutton]) { pseudobuttons[cmd.axis.button.posbutton] = 1; S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, true); } } else { if (pseudobuttons[cmd.axis.button.posbutton]) { pseudobuttons[cmd.axis.button.posbutton] = 0; S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, false); } } if (data1 <= ((cmd.axis.button.threshold + 1) * -127)) { if (!pseudobuttons[cmd.axis.button.negbutton]) { pseudobuttons[cmd.axis.button.negbutton] = 1; S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, true); } } else { if (pseudobuttons[cmd.axis.button.negbutton]) { pseudobuttons[cmd.axis.button.negbutton] = 0; S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, false); } } return; case S9xButtonPort: case S9xAxisPort: case S9xPointerPort: S9xHandlePortCommand(cmd, data1, data2); return; case S9xButtonMulti: if (cmd.button.multi_idx >= (int) multis.size()) return; if (multis[cmd.button.multi_idx]->multi_press && !data1) return; i = ApplyMulti(multis[cmd.button.multi_idx], 0, data1); if (i >= 0) { struct exemulti *e = new struct exemulti; e->pos = i; e->data1 = data1 != 0; e->script = multis[cmd.button.multi_idx]; exemultis.insert(e); } return; default: fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type); return; } } static void do_polling (int mp) { set::iterator itr; if (S9xMoviePlaying()) return; if (pollmap[mp].empty()) return; for (itr = pollmap[mp].begin(); itr != pollmap[mp].end(); itr++) { switch (maptype(keymap[*itr].type)) { case MAP_BUTTON: { bool pressed; if (S9xPollButton(*itr, &pressed)) S9xReportButton(*itr, pressed); break; } case MAP_AXIS: { int16 value; if (S9xPollAxis(*itr, &value)) S9xReportAxis(*itr, value); break; } case MAP_POINTER: { int16 x, y; if (S9xPollPointer(*itr, &x, &y)) S9xReportPointer(*itr, x, y); break; } default: break; } } } static void UpdatePolledMouse (int i) { int16 j; j = mouse[i - MOUSE0].cur_x - mouse[i - MOUSE0].old_x; if (j < -127) { mouse[i - MOUSE0].delta_x = 0xff; mouse[i - MOUSE0].old_x -= 127; } else if (j < 0) { mouse[i - MOUSE0].delta_x = 0x80 | -j; mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x; } else if (j > 127) { mouse[i - MOUSE0].delta_x = 0x7f; mouse[i - MOUSE0].old_x += 127; } else { mouse[i - MOUSE0].delta_x = (uint8) j; mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x; } j = mouse[i - MOUSE0].cur_y - mouse[i - MOUSE0].old_y; if (j < -127) { mouse[i - MOUSE0].delta_y = 0xff; mouse[i - MOUSE0].old_y -= 127; } else if (j < 0) { mouse[i - MOUSE0].delta_y = 0x80 | -j; mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y; } else if (j > 127) { mouse[i - MOUSE0].delta_y = 0x7f; mouse[i - MOUSE0].old_y += 127; } else { mouse[i - MOUSE0].delta_y = (uint8) j; mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y; } } void S9xSetJoypadLatch (bool latch) { if (!latch && FLAG_LATCH) { // 1 written, 'plug in' new controllers now curcontrollers[0] = newcontrollers[0]; curcontrollers[1] = newcontrollers[1]; } if (latch && !FLAG_LATCH) { int i; for (int n = 0; n < 2; n++) { for (int j = 0; j < 2; j++) read_idx[n][j] = 0; switch (i = curcontrollers[n]) { case MP5: for (int j = 0, k = mp5[n].pads[j]; j < 4; k = mp5[n].pads[++j]) { if (k == NONE) continue; do_polling(k); } break; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: do_polling(i); break; case MOUSE0: case MOUSE1: do_polling(i); if (!S9xMoviePlaying()) UpdatePolledMouse(i); break; case SUPERSCOPE: if (superscope.next_buttons & SUPERSCOPE_FIRE) { superscope.next_buttons &= ~SUPERSCOPE_TURBO; superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_TURBO; } if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) { superscope.next_buttons &= ~SUPERSCOPE_OFFSCREEN; superscope.next_buttons |= superscope.phys_buttons & SUPERSCOPE_OFFSCREEN; } superscope.read_buttons = superscope.next_buttons; superscope.next_buttons &= ~SUPERSCOPE_PAUSE; if (!(superscope.phys_buttons & SUPERSCOPE_TURBO)) superscope.next_buttons &= ~(SUPERSCOPE_CURSOR | SUPERSCOPE_FIRE); do_polling(i); break; case TWO_JUSTIFIERS: do_polling(TWO_JUSTIFIERS); // fall through case ONE_JUSTIFIER: justifier.buttons ^= JUSTIFIER_SELECT; do_polling(ONE_JUSTIFIER); break; default: break; } } } FLAG_LATCH = latch; } uint8 S9xReadJOYSERn (int n) { int i, j, r; if (n > 1) n -= 0x4016; assert(n == 0 || n == 1); uint8 bits = (OpenBus & ~3) | ((n == 1) ? 0x1c : 0); if (FLAG_LATCH) { switch (i = curcontrollers[n]) { case MP5: return (bits | 2); case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: return (bits | ((joypad[i - JOYPAD0].buttons & 0x8000) ? 1 : 0)); case MOUSE0: case MOUSE1: mouse[i - MOUSE0].buttons += 0x10; if ((mouse[i - MOUSE0].buttons & 0x30) == 0x30) mouse[i - MOUSE0].buttons &= 0xcf; return (bits); case SUPERSCOPE: return (bits | ((superscope.read_buttons & 0x80) ? 1 : 0)); case ONE_JUSTIFIER: case TWO_JUSTIFIERS: return (bits); default: return (bits); } } else { switch (i = curcontrollers[n]) { case MP5: r = read_idx[n][FLAG_IOBIT(n) ? 0 : 1]++; j = FLAG_IOBIT(n) ? 0 : 2; for (i = 0; i < 2; i++, j++) { if (mp5[n].pads[j] == NONE) continue; if (r >= 16) bits |= 1 << i; else bits |= ((joypad[mp5[n].pads[j] - JOYPAD0].buttons & (0x8000 >> r)) ? 1 : 0) << i; } return (bits); case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: if (read_idx[n][0] >= 16) { read_idx[n][0]++; return (bits | 1); } else return (bits | ((joypad[i - JOYPAD0].buttons & (0x8000 >> read_idx[n][0]++)) ? 1 : 0)); case MOUSE0: case MOUSE1: if (read_idx[n][0] < 8) { read_idx[n][0]++; return (bits); } else if (read_idx[n][0] < 16) return (bits | ((mouse[i - MOUSE0].buttons & (0x8000 >> read_idx[n][0]++)) ? 1 : 0)); else if (read_idx[n][0] < 24) return (bits | ((mouse[i - MOUSE0].delta_y & (0x800000 >> read_idx[n][0]++)) ? 1 : 0)); else if (read_idx[n][0] < 32) return (bits | ((mouse[i - MOUSE0].delta_x & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0)); else { read_idx[n][0]++; return (bits | 1); } case SUPERSCOPE: if (read_idx[n][0] < 8) return (bits | ((superscope.read_buttons & (0x80 >> read_idx[n][0]++)) ? 1 : 0)); else { read_idx[n][0]++; return (bits | 1); } case ONE_JUSTIFIER: if (read_idx[n][0] < 24) return (bits | ((0xaa7000 >> read_idx[n][0]++) & 1)); else if (read_idx[n][0] < 32) return (bits | ((justifier.buttons & (JUSTIFIER_TRIGGER | JUSTIFIER_START | JUSTIFIER_SELECT) & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0)); else { read_idx[n][0]++; return (bits | 1); } case TWO_JUSTIFIERS: if (read_idx[n][0] < 24) return (bits | ((0xaa7000 >> read_idx[n][0]++) & 1)); else if (read_idx[n][0] < 32) return (bits | ((justifier.buttons & (0x80000000 >> read_idx[n][0]++)) ? 1 : 0)); else { read_idx[n][0]++; return (bits | 1); } default: read_idx[n][0]++; return (bits); } } } void S9xDoAutoJoypad (void) { int i, j; S9xSetJoypadLatch(1); S9xSetJoypadLatch(0); S9xMovieUpdate(false); for (int n = 0; n < 2; n++) { switch (i = curcontrollers[n]) { case MP5: j = FLAG_IOBIT(n) ? 0 : 2; for (i = 0; i < 2; i++, j++) { if (mp5[n].pads[j] == NONE) WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, 0); else WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2 + i * 4, joypad[mp5[n].pads[j] - JOYPAD0].buttons); } read_idx[n][FLAG_IOBIT(n) ? 0 : 1] = 16; break; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: read_idx[n][0] = 16; WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, joypad[i - JOYPAD0].buttons); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); break; case MOUSE0: case MOUSE1: read_idx[n][0] = 16; WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, mouse[i - MOUSE0].buttons); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); break; case SUPERSCOPE: read_idx[n][0] = 16; Memory.FillRAM[0x4218 + n * 2] = 0xff; Memory.FillRAM[0x4219 + n * 2] = superscope.read_buttons; WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); break; case ONE_JUSTIFIER: case TWO_JUSTIFIERS: read_idx[n][0] = 16; WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0x000e); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); break; default: WRITE_WORD(Memory.FillRAM + 0x4218 + n * 2, 0); WRITE_WORD(Memory.FillRAM + 0x421c + n * 2, 0); break; } } } void S9xControlEOF (void) { struct crosshair *c; int i, j; PPU.GunVLatch = 1000; // i.e., never latch PPU.GunHLatch = 0; for (int n = 0; n < 2; n++) { switch (i = curcontrollers[n]) { case MP5: for (j = 0, i = mp5[n].pads[j]; j < 4; i = mp5[n].pads[++j]) { if (i == NONE) continue; if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time) { joypad[i - JOYPAD0].turbo_ct = 0; joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos; } } break; case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: if (++joypad[i - JOYPAD0].turbo_ct >= turbo_time) { joypad[i - JOYPAD0].turbo_ct = 0; joypad[i - JOYPAD0].buttons ^= joypad[i - JOYPAD0].turbos; } break; case MOUSE0: case MOUSE1: c = &mouse[i - MOUSE0].crosshair; if (IPPU.RenderThisFrame) S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, mouse[i - MOUSE0].cur_x, mouse[i - MOUSE0].cur_y); break; case SUPERSCOPE: if (n == 1 && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN)) { if (superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) DoGunLatch(superscope.x, superscope.y); c = &superscope.crosshair; if (IPPU.RenderThisFrame) S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, superscope.x, superscope.y); } break; case TWO_JUSTIFIERS: if (n == 1 && !justifier.offscreen[1]) { c = &justifier.crosshair[1]; if (IPPU.RenderThisFrame) S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[1], justifier.y[1]); } i = (justifier.buttons & JUSTIFIER_SELECT) ? 1 : 0; goto do_justifier; case ONE_JUSTIFIER: i = (justifier.buttons & JUSTIFIER_SELECT) ? -1 : 0; do_justifier: if (n == 1) { if (i >= 0 && !justifier.offscreen[i]) DoGunLatch(justifier.x[i], justifier.y[i]); if (!justifier.offscreen[0]) { c = &justifier.crosshair[0]; if (IPPU.RenderThisFrame) S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, justifier.x[0], justifier.y[0]); } } break; default: break; } } for (int n = 0; n < 8; n++) { if (!pseudopointer[n].mapped) continue; if (pseudopointer[n].H_adj) { pseudopointer[n].x += pseudopointer[n].H_adj; if (pseudopointer[n].x < 0) pseudopointer[n].x = 0; else if (pseudopointer[n].x > 255) pseudopointer[n].x = 255; if (pseudopointer[n].H_var) { if (pseudopointer[n].H_adj < 0) { if (pseudopointer[n].H_adj > -ptrspeeds[3]) pseudopointer[n].H_adj--; } else { if (pseudopointer[n].H_adj < ptrspeeds[3]) pseudopointer[n].H_adj++; } } } if (pseudopointer[n].V_adj) { pseudopointer[n].y += pseudopointer[n].V_adj; if (pseudopointer[n].y < 0) pseudopointer[n].y = 0; else if (pseudopointer[n].y > PPU.ScreenHeight - 1) pseudopointer[n].y = PPU.ScreenHeight - 1; if (pseudopointer[n].V_var) { if (pseudopointer[n].V_adj < 0) { if (pseudopointer[n].V_adj > -ptrspeeds[3]) pseudopointer[n].V_adj--; } else { if (pseudopointer[n].V_adj < ptrspeeds[3]) pseudopointer[n].V_adj++; } } } S9xReportPointer(PseudoPointerBase + n, pseudopointer[n].x, pseudopointer[n].y); } set::iterator it, jt; for (it = exemultis.begin(); it != exemultis.end(); it++) { i = ApplyMulti((*it)->script, (*it)->pos, (*it)->data1); if (i >= 0) (*it)->pos = i; else { jt = it; it--; delete *jt; exemultis.erase(jt); } } do_polling(POLL_ALL); S9xMovieUpdate(); pad_read_last = pad_read; pad_read = false; } void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg, const char *bg) { struct crosshair *c; int8 fgcolor = -1, bgcolor = -1; int i, j; if (idx < -1 || idx > 31) { fprintf(stderr, "S9xSetControllerCrosshair() called with invalid index\n"); return; } switch (ctl) { case X_MOUSE1: c = &mouse[0].crosshair; break; case X_MOUSE2: c = &mouse[1].crosshair; break; case X_SUPERSCOPE: c = &superscope.crosshair; break; case X_JUSTIFIER1: c = &justifier.crosshair[0]; break; case X_JUSTIFIER2: c = &justifier.crosshair[1]; break; default: fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl); return; } if (fg) { fgcolor = 0; if (*fg == 't') { fg++; fgcolor = 16; } for (i = 0; i < 16; i++) { for (j = 0; color_names[i][j] && fg[j] == color_names[i][j]; j++) if (isalnum(fg[j])) continue; if (!color_names[i][j]) break; } fgcolor |= i; if (i > 15 || fgcolor == 16) { fprintf(stderr, "S9xSetControllerCrosshair() called with invalid fgcolor\n"); return; } } if (bg) { bgcolor = 0; if (*bg == 't') { bg++; bgcolor = 16; } for (i = 0; i < 16; i++) { for (j = 0; color_names[i][j] && bg[j] == color_names[i][j]; j++) if (isalnum(bg[j])) continue; if (!color_names[i][j]) break; } bgcolor |= i; if (i > 15 || bgcolor == 16) { fprintf(stderr, "S9xSetControllerCrosshair() called with invalid bgcolor\n"); return; } } if (idx != -1) { c->set |= 1; c->img = idx; } if (fgcolor != -1) { c->set |= 2; c->fg = fgcolor; } if (bgcolor != -1) { c->set |= 4; c->bg = bgcolor; } } void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg) { struct crosshair *c; switch (ctl) { case X_MOUSE1: c = &mouse[0].crosshair; break; case X_MOUSE2: c = &mouse[1].crosshair; break; case X_SUPERSCOPE: c = &superscope.crosshair; break; case X_JUSTIFIER1: c = &justifier.crosshair[0]; break; case X_JUSTIFIER2: c = &justifier.crosshair[1]; break; default: fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl); return; } if (idx) *idx = c->img; if (fg) *fg = color_names[c->fg]; if (bg) *bg = color_names[c->bg]; } void S9xControlPreSaveState (struct SControlSnapshot *s) { memset(s, 0, sizeof(*s)); s->ver = 3; for (int j = 0; j < 2; j++) { s->port1_read_idx[j] = read_idx[0][j]; s->port2_read_idx[j] = read_idx[1][j]; } for (int j = 0; j < 2; j++) s->mouse_speed[j] = (mouse[j].buttons & 0x30) >> 4; s->justifier_select = ((justifier.buttons & JUSTIFIER_SELECT) ? 1 : 0); #define COPY(x) { memcpy((char *) s->internal + i, &(x), sizeof(x)); i += sizeof(x); } int i = 0; for (int j = 0; j < 8; j++) COPY(joypad[j].buttons); for (int j = 0; j < 2; j++) { COPY(mouse[j].delta_x); COPY(mouse[j].delta_y); COPY(mouse[j].old_x); COPY(mouse[j].old_y); COPY(mouse[j].cur_x); COPY(mouse[j].cur_y); COPY(mouse[j].buttons); } COPY(superscope.x); COPY(superscope.y); COPY(superscope.phys_buttons); COPY(superscope.next_buttons); COPY(superscope.read_buttons); for (int j = 0; j < 2; j++) COPY(justifier.x[j]); for (int j = 0; j < 2; j++) COPY(justifier.y[j]); COPY(justifier.buttons); for (int j = 0; j < 2; j++) COPY(justifier.offscreen[j]); for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) COPY(mp5[j].pads[k]); assert(i == sizeof(s->internal)); #undef COPY s->pad_read = pad_read; s->pad_read_last = pad_read_last; } void S9xControlPostLoadState (struct SControlSnapshot *s) { if (curcontrollers[0] == MP5 && s->ver < 1) { // Crap. Old snes9x didn't support this. S9xMessage(S9X_WARNING, S9X_FREEZE_FILE_INFO, "Old savestate has no support for MP5 in port 1."); newcontrollers[0] = curcontrollers[0]; curcontrollers[0] = mp5[0].pads[0]; } for (int j = 0; j < 2; j++) { read_idx[0][j] = s->port1_read_idx[j]; read_idx[1][j] = s->port2_read_idx[j]; } for (int j = 0; j < 2; j++) mouse[j].buttons |= (s->mouse_speed[j] & 3) << 4; if (s->justifier_select & 1) justifier.buttons |= JUSTIFIER_SELECT; else justifier.buttons &= ~JUSTIFIER_SELECT; FLAG_LATCH = (Memory.FillRAM[0x4016] & 1) == 1; if (s->ver > 1) { #define COPY(x) { memcpy(&(x), (char *) s->internal + i, sizeof(x)); i += sizeof(x); } int i = 0; for (int j = 0; j < 8; j++) COPY(joypad[j].buttons); for (int j = 0; j < 2; j++) { COPY(mouse[j].delta_x); COPY(mouse[j].delta_y); COPY(mouse[j].old_x); COPY(mouse[j].old_y); COPY(mouse[j].cur_x); COPY(mouse[j].cur_y); COPY(mouse[j].buttons); } COPY(superscope.x); COPY(superscope.y); COPY(superscope.phys_buttons); COPY(superscope.next_buttons); COPY(superscope.read_buttons); for (int j = 0; j < 2; j++) COPY(justifier.x[j]); for (int j = 0; j < 2; j++) COPY(justifier.y[j]); COPY(justifier.buttons); for (int j = 0; j < 2; j++) COPY(justifier.offscreen[j]); for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) COPY(mp5[j].pads[k]); assert(i == sizeof(s->internal)); #undef COPY } if (s->ver > 2) { pad_read = s->pad_read; pad_read_last = s->pad_read_last; } } uint16 MovieGetJoypad (int i) { if (i < 0 || i > 7) return (0); return (joypad[i].buttons); } void MovieSetJoypad (int i, uint16 buttons) { if (i < 0 || i > 7) return; joypad[i].buttons = buttons; } bool MovieGetMouse (int i, uint8 out[5]) { if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1)) return (false); int n = curcontrollers[i] - MOUSE0; uint8 *ptr = out; WRITE_WORD(ptr, mouse[n].cur_x); ptr += 2; WRITE_WORD(ptr, mouse[n].cur_y); ptr += 2; *ptr = mouse[n].buttons; return (true); } void MovieSetMouse (int i, uint8 in[5], bool inPolling) { if (i < 0 || i > 1 || (curcontrollers[i] != MOUSE0 && curcontrollers[i] != MOUSE1)) return; int n = curcontrollers[i] - MOUSE0; uint8 *ptr = in; mouse[n].cur_x = READ_WORD(ptr); ptr += 2; mouse[n].cur_y = READ_WORD(ptr); ptr += 2; mouse[n].buttons = *ptr; if (inPolling) UpdatePolledMouse(curcontrollers[i]); } bool MovieGetScope (int i, uint8 out[6]) { if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE) return (false); uint8 *ptr = out; WRITE_WORD(ptr, superscope.x); ptr += 2; WRITE_WORD(ptr, superscope.y); ptr += 2; *ptr++ = superscope.phys_buttons; *ptr = superscope.next_buttons; return (true); } void MovieSetScope (int i, uint8 in[6]) { if (i < 0 || i > 1 || curcontrollers[i] != SUPERSCOPE) return; uint8 *ptr = in; superscope.x = READ_WORD(ptr); ptr += 2; superscope.y = READ_WORD(ptr); ptr += 2; superscope.phys_buttons = *ptr++; superscope.next_buttons = *ptr; } bool MovieGetJustifier (int i, uint8 out[11]) { if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS)) return (false); uint8 *ptr = out; WRITE_WORD(ptr, justifier.x[0]); ptr += 2; WRITE_WORD(ptr, justifier.x[1]); ptr += 2; WRITE_WORD(ptr, justifier.y[0]); ptr += 2; WRITE_WORD(ptr, justifier.y[1]); ptr += 2; *ptr++ = justifier.buttons; *ptr++ = justifier.offscreen[0]; *ptr = justifier.offscreen[1]; return (true); } void MovieSetJustifier (int i, uint8 in[11]) { if (i < 0 || i > 1 || (curcontrollers[i] != ONE_JUSTIFIER && curcontrollers[i] != TWO_JUSTIFIERS)) return; uint8 *ptr = in; justifier.x[0] = READ_WORD(ptr); ptr += 2; justifier.x[1] = READ_WORD(ptr); ptr += 2; justifier.y[0] = READ_WORD(ptr); ptr += 2; justifier.y[1] = READ_WORD(ptr); ptr += 2; justifier.buttons = *ptr++; justifier.offscreen[0] = *ptr++; justifier.offscreen[1] = *ptr; } snes9x.h000664 001750 001750 00000032263 12720446475 013325 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SNES9X_H_ #define _SNES9X_H_ #ifndef VERSION #define VERSION "1.53" #endif #include "port.h" #include "65c816.h" #include "messages.h" #ifdef ZLIB #include #define FSTREAM gzFile #define READ_FSTREAM(p, l, s) gzread(s, p, l) #define WRITE_FSTREAM(p, l, s) gzwrite(s, p, l) #define GETS_FSTREAM(p, l, s) gzgets(s, p, l) #define GETC_FSTREAM(s) gzgetc(s) #define OPEN_FSTREAM(f, m) gzopen(f, m) #define REOPEN_FSTREAM(f, m) gzdopen(f, m) #define FIND_FSTREAM(f) gztell(f) #define REVERT_FSTREAM(s, o, p) gzseek(s, o, p) #define CLOSE_FSTREAM(s) gzclose(s) #else #define FSTREAM FILE * #define READ_FSTREAM(p, l, s) fread(p, 1, l, s) #define WRITE_FSTREAM(p, l, s) fwrite(p, 1, l, s) #define GETS_FSTREAM(p, l, s) fgets(p, l, s) #define GETC_FSTREAM(s) fgetc(s) #define OPEN_FSTREAM(f, m) fopen(f, m) #define REOPEN_FSTREAM(f, m) fdopen(f, m) #define FIND_FSTREAM(s) ftell(s) #define REVERT_FSTREAM(s, o, p) fseek(s, o, p) #define CLOSE_FSTREAM(s) fclose(s) #endif #include "stream.h" #define STREAM Stream * #define READ_STREAM(p, l, s) s->read(p,l) #define WRITE_STREAM(p, l, s) s->write(p,l) #define GETS_STREAM(p, l, s) s->gets(p,l) #define GETC_STREAM(s) s->get_char() #define OPEN_STREAM(f, m) openStreamFromFSTREAM(f, m) #define REOPEN_STREAM(f, m) reopenStreamFromFd(f, m) #define FIND_STREAM(s) s->pos() #define REVERT_STREAM(s, o, p) s->revert(p, o) #define CLOSE_STREAM(s) s->closeStream() #define SNES_WIDTH 256 #define SNES_HEIGHT 224 #define SNES_HEIGHT_EXTENDED 239 #define MAX_SNES_WIDTH (SNES_WIDTH * 2) #define MAX_SNES_HEIGHT (SNES_HEIGHT_EXTENDED * 2) #define IMAGE_WIDTH (Settings.SupportHiRes ? MAX_SNES_WIDTH : SNES_WIDTH) #define IMAGE_HEIGHT (Settings.SupportHiRes ? MAX_SNES_HEIGHT : SNES_HEIGHT_EXTENDED) #define NTSC_MASTER_CLOCK 21477272.0 #define PAL_MASTER_CLOCK 21281370.0 #define SNES_MAX_NTSC_VCOUNTER 262 #define SNES_MAX_PAL_VCOUNTER 312 #define SNES_HCOUNTER_MAX 341 #define ONE_CYCLE 6 #define SLOW_ONE_CYCLE 8 #define TWO_CYCLES 12 #define ONE_DOT_CYCLE 4 #define SNES_CYCLES_PER_SCANLINE (SNES_HCOUNTER_MAX * ONE_DOT_CYCLE) #define SNES_SCANLINE_TIME (SNES_CYCLES_PER_SCANLINE / NTSC_MASTER_CLOCK) #define SNES_WRAM_REFRESH_HC_v1 530 #define SNES_WRAM_REFRESH_HC_v2 538 #define SNES_WRAM_REFRESH_CYCLES 40 #define SNES_HBLANK_START_HC 1096 // H=274 #define SNES_HDMA_START_HC 1106 // FIXME: not true #define SNES_HBLANK_END_HC 4 // H=1 #define SNES_HDMA_INIT_HC 20 // FIXME: not true #define SNES_RENDER_START_HC (48 * ONE_DOT_CYCLE) // FIXME: Snes9x renders a line at a time. #define SNES_TR_MASK (1 << 4) #define SNES_TL_MASK (1 << 5) #define SNES_X_MASK (1 << 6) #define SNES_A_MASK (1 << 7) #define SNES_RIGHT_MASK (1 << 8) #define SNES_LEFT_MASK (1 << 9) #define SNES_DOWN_MASK (1 << 10) #define SNES_UP_MASK (1 << 11) #define SNES_START_MASK (1 << 12) #define SNES_SELECT_MASK (1 << 13) #define SNES_Y_MASK (1 << 14) #define SNES_B_MASK (1 << 15) #define DEBUG_MODE_FLAG (1 << 0) // debugger #define TRACE_FLAG (1 << 1) // debugger #define SINGLE_STEP_FLAG (1 << 2) // debugger #define BREAK_FLAG (1 << 3) // debugger #define SCAN_KEYS_FLAG (1 << 4) // CPU #define HALTED_FLAG (1 << 12) // APU #define FRAME_ADVANCE_FLAG (1 << 9) #define ROM_NAME_LEN 23 #define AUTO_FRAMERATE 200 struct SCPUState { uint32 Flags; int32 Cycles; int32 PrevCycles; int32 V_Counter; uint8 *PCBase; bool8 NMILine; bool8 IRQLine; bool8 IRQTransition; bool8 IRQLastState; bool8 IRQExternal; int32 IRQPending; int32 MemSpeed; int32 MemSpeedx2; int32 FastROMSpeed; bool8 InDMA; bool8 InHDMA; bool8 InDMAorHDMA; bool8 InWRAMDMAorHDMA; uint8 HDMARanInDMA; int32 CurrentDMAorHDMAChannel; uint8 WhichEvent; int32 NextEvent; bool8 WaitingForInterrupt; uint32 AutoSaveTimer; bool8 SRAMModified; }; enum { HC_HBLANK_START_EVENT = 1, HC_HDMA_START_EVENT = 2, HC_HCOUNTER_MAX_EVENT = 3, HC_HDMA_INIT_EVENT = 4, HC_RENDER_EVENT = 5, HC_WRAM_REFRESH_EVENT = 6 }; struct STimings { int32 H_Max_Master; int32 H_Max; int32 V_Max_Master; int32 V_Max; int32 HBlankStart; int32 HBlankEnd; int32 HDMAInit; int32 HDMAStart; int32 NMITriggerPos; int32 IRQTriggerCycles; int32 WRAMRefreshPos; int32 RenderPos; bool8 InterlaceField; int32 DMACPUSync; // The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly. int32 NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly. int32 IRQPendCount; // This value is just a hack. int32 APUSpeedup; bool8 APUAllowTimeOverflow; }; struct SSettings { bool8 TraceDMA; bool8 TraceHDMA; bool8 TraceVRAM; bool8 TraceUnknownRegisters; bool8 TraceDSP; bool8 TraceHCEvent; bool8 SuperFX; uint8 DSP; bool8 SA1; bool8 C4; bool8 SDD1; bool8 SPC7110; bool8 SPC7110RTC; bool8 OBC1; uint8 SETA; bool8 SRTC; bool8 BS; bool8 BSXItself; bool8 BSXBootup; bool8 MouseMaster; bool8 SuperScopeMaster; bool8 JustifierMaster; bool8 MultiPlayer5Master; bool8 ForceLoROM; bool8 ForceHiROM; bool8 ForceHeader; bool8 ForceNoHeader; bool8 ForceInterleaved; bool8 ForceInterleaved2; bool8 ForceInterleaveGD24; bool8 ForceNotInterleaved; bool8 ForcePAL; bool8 ForceNTSC; bool8 PAL; uint32 FrameTimePAL; uint32 FrameTimeNTSC; uint32 FrameTime; bool8 SoundSync; bool8 SixteenBitSound; uint32 SoundPlaybackRate; uint32 SoundInputRate; bool8 Stereo; bool8 ReverseStereo; bool8 Mute; bool8 SupportHiRes; bool8 Transparency; float SuperFXSpeedPerLine; uint8 BG_Forced; bool8 DisableGraphicWindows; bool8 DisplayFrameRate; bool8 DisplayWatchedAddresses; bool8 DisplayPressedKeys; bool8 DisplayMovieFrame; bool8 AutoDisplayMessages; uint32 InitialInfoStringTimeout; uint16 DisplayColor; bool8 Multi; char CartAName[PATH_MAX + 1]; char CartBName[PATH_MAX + 1]; bool8 DisableGameSpecificHacks; bool8 BlockInvalidVRAMAccessMaster; bool8 BlockInvalidVRAMAccess; int32 HDMATimingHack; bool8 ForcedPause; bool8 Paused; bool8 StopEmulation; uint32 SkipFrames; uint32 TurboSkipFrames; uint32 AutoMaxSkipFrames; bool8 TurboMode; uint32 HighSpeedSeek; bool8 FrameAdvance; bool8 NetPlay; bool8 NetPlayServer; char ServerName[128]; int Port; bool8 MovieTruncate; bool8 MovieNotifyIgnored; bool8 WrongMovieStateProtection; bool8 DumpStreams; int DumpStreamsMaxFrames; bool8 TakeScreenshot; int8 StretchScreenshots; bool8 SnapshotScreenshots; bool8 ApplyCheats; bool8 NoPatch; int32 AutoSaveDelay; bool8 DontSaveOopsSnapshot; bool8 UpAndDown; bool8 OpenGLEnable; }; struct SSNESGameFixes { uint8 SRAMInitialValue; uint8 Uniracers; }; enum { PAUSE_NETPLAY_CONNECT = (1 << 0), PAUSE_TOGGLE_FULL_SCREEN = (1 << 1), PAUSE_EXIT = (1 << 2), PAUSE_MENU = (1 << 3), PAUSE_INACTIVE_WINDOW = (1 << 4), PAUSE_WINDOW_ICONISED = (1 << 5), PAUSE_RESTORE_GUI = (1 << 6), PAUSE_FREEZE_FILE = (1 << 7) }; void S9xSetPause(uint32); void S9xClearPause(uint32); void S9xExit(void); void S9xMessage(int, int, const char *); extern struct SSettings Settings; extern struct SCPUState CPU; extern struct STimings Timings; extern struct SSNESGameFixes SNESGameFixes; extern char String[513]; #endif apu/bapu/smp/core/op_read.b000664 001750 001750 00000010477 12720446475 016745 0ustar00sergiosergio000000 000000 adc_a_const(0x88, adc, a), and_a_const(0x28, and, a), cmp_a_const(0x68, cmp, a), cmp_x_const(0xc8, cmp, x), cmp_y_const(0xad, cmp, y), eor_a_const(0x48, eor, a), or_a_const(0x08, or, a), sbc_a_const(0xa8, sbc, a) { 1:rd = op_readpc(); regs.$2 = op_$1(regs.$2, rd); } adc_a_ix(0x86, adc), and_a_ix(0x26, and), cmp_a_ix(0x66, cmp), eor_a_ix(0x46, eor), or_a_ix(0x06, or), sbc_a_ix(0xa6, sbc) { 1:op_io(); 2:rd = op_readdp(regs.x); regs.a = op_$1(regs.a, rd); } adc_a_dp(0x84, adc, a), and_a_dp(0x24, and, a), cmp_a_dp(0x64, cmp, a), cmp_x_dp(0x3e, cmp, x), cmp_y_dp(0x7e, cmp, y), eor_a_dp(0x44, eor, a), or_a_dp(0x04, or, a), sbc_a_dp(0xa4, sbc, a) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); regs.$2 = op_$1(regs.$2, rd); } adc_a_dpx(0x94, adc), and_a_dpx(0x34, and), cmp_a_dpx(0x74, cmp), eor_a_dpx(0x54, eor), or_a_dpx(0x14, or), sbc_a_dpx(0xb4, sbc) { 1:dp = op_readpc(); 2:op_io(); 3:rd = op_readdp(dp + regs.x); regs.a = op_$1(regs.a, rd); } adc_a_addr(0x85, adc, a), and_a_addr(0x25, and, a), cmp_a_addr(0x65, cmp, a), cmp_x_addr(0x1e, cmp, x), cmp_y_addr(0x5e, cmp, y), eor_a_addr(0x45, eor, a), or_a_addr(0x05, or, a), sbc_a_addr(0xa5, sbc, a) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:rd = op_readaddr(dp); regs.$2 = op_$1(regs.$2, rd); } adc_a_addrx(0x95, adc, x), adc_a_addry(0x96, adc, y), and_a_addrx(0x35, and, x), and_a_addry(0x36, and, y), cmp_a_addrx(0x75, cmp, x), cmp_a_addry(0x76, cmp, y), eor_a_addrx(0x55, eor, x), eor_a_addry(0x56, eor, y), or_a_addrx(0x15, or, x), or_a_addry(0x16, or, y), sbc_a_addrx(0xb5, sbc, x), sbc_a_addry(0xb6, sbc, y) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:op_io(); 4:rd = op_readaddr(dp + regs.$2); regs.a = op_$1(regs.a, rd); } adc_a_idpx(0x87, adc), and_a_idpx(0x27, and), cmp_a_idpx(0x67, cmp), eor_a_idpx(0x47, eor), or_a_idpx(0x07, or), sbc_a_idpx(0xa7, sbc) { 1:dp = op_readpc() + regs.x; 2:op_io(); 3:sp = op_readdp(dp); 4:sp |= op_readdp(dp + 1) << 8; 5:rd = op_readaddr(sp); regs.a = op_$1(regs.a, rd); } adc_a_idpy(0x97, adc), and_a_idpy(0x37, and), cmp_a_idpy(0x77, cmp), eor_a_idpy(0x57, eor), or_a_idpy(0x17, or), sbc_a_idpy(0xb7, sbc) { 1:dp = op_readpc(); 2:op_io(); 3:sp = op_readdp(dp); 4:sp |= op_readdp(dp + 1) << 8; 5:rd = op_readaddr(sp + regs.y); regs.a = op_$1(regs.a, rd); } adc_ix_iy(0x99, adc, 1), and_ix_iy(0x39, and, 1), cmp_ix_iy(0x79, cmp, 0), eor_ix_iy(0x59, eor, 1), or_ix_iy(0x19, or, 1), sbc_ix_iy(0xb9, sbc, 1) { 1:op_io(); 2:rd = op_readdp(regs.y); 3:wr = op_readdp(regs.x); wr = op_$1(wr, rd); 4:($2) ? op_writedp(regs.x, wr) : op_io(); } adc_dp_dp(0x89, adc, 1), and_dp_dp(0x29, and, 1), cmp_dp_dp(0x69, cmp, 0), eor_dp_dp(0x49, eor, 1), or_dp_dp(0x09, or, 1), sbc_dp_dp(0xa9, sbc, 1) { 1:sp = op_readpc(); 2:rd = op_readdp(sp); 3:dp = op_readpc(); 4:wr = op_readdp(dp); 5:wr = op_$1(wr, rd); ($2) ? op_writedp(dp, wr) : op_io(); } adc_dp_const(0x98, adc, 1), and_dp_const(0x38, and, 1), cmp_dp_const(0x78, cmp, 0), eor_dp_const(0x58, eor, 1), or_dp_const(0x18, or, 1), sbc_dp_const(0xb8, sbc, 1) { 1:rd = op_readpc(); 2:dp = op_readpc(); 3:wr = op_readdp(dp); 4:wr = op_$1(wr, rd); ($2) ? op_writedp(dp, wr) : op_io(); } addw_ya_dp(0x7a, addw), subw_ya_dp(0x9a, subw) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); 3:op_io(); 4:rd |= op_readdp(dp + 1) << 8; regs.ya = op_$1(regs.ya, rd); } cmpw_ya_dp(0x5a) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); 3:rd |= op_readdp(dp + 1) << 8; op_cmpw(regs.ya, rd); } and1_bit(0x4a, !!), and1_notbit(0x6a, !) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & $1(rd & (1 << bit)); } eor1_bit(0x8a) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); 4:op_io(); regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); } not1_bit(0xea) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); rd ^= (1 << bit); 4:op_writeaddr(dp, rd); } or1_bit(0x0a, !!), or1_notbit(0x2a, !) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); 4:op_io(); regs.p.c = regs.p.c | $1(rd & (1 << bit)); } cheats.cpp000664 001750 001750 00000036563 12720446475 013705 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "memmap.h" #include "cheats.h" #define WRAM_BITS ALL_BITS #define SRAM_BITS ALL_BITS + (0x20000 >> 5) #define IRAM_BITS ALL_BITS + (0x30000 >> 5) #define BIT_CLEAR(a, v) (a)[(v) >> 5] &= ~(1 << ((v) & 31)) #define TEST_BIT(a, v) ((a)[(v) >> 5] & (1 << ((v) & 31))) #define _S9XCHTC(c, a, b) \ ((c) == S9X_LESS_THAN ? (a) < (b) : \ (c) == S9X_GREATER_THAN ? (a) > (b) : \ (c) == S9X_LESS_THAN_OR_EQUAL ? (a) <= (b) : \ (c) == S9X_GREATER_THAN_OR_EQUAL ? (a) >= (b) : \ (c) == S9X_EQUAL ? (a) == (b) : \ (a) != (b)) #define _S9XCHTD(s, m, o) \ ((s) == S9X_8_BITS ? ((uint8) (*((m) + (o)))) : \ (s) == S9X_16_BITS ? ((uint16) (*((m) + (o)) + (*((m) + (o) + 1) << 8))) : \ (s) == S9X_24_BITS ? ((uint32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16))) : \ ((uint32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16) + (*((m) + (o) + 3) << 24)))) #define _S9XCHTDS(s, m, o) \ ((s) == S9X_8_BITS ? ((int8) (*((m) + (o)))) : \ (s) == S9X_16_BITS ? ((int16) (*((m) + (o)) + (*((m) + (o) + 1) << 8))) : \ (s) == S9X_24_BITS ? (((int32) ((*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16)) << 8)) >> 8): \ ((int32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16) + (*((m) + (o) + 3) << 24)))) static bool8 S9xAllHex (const char *, int); static bool8 S9xAllHex (const char *code, int len) { for (int i = 0; i < len; i++) if ((code[i] < '0' || code[i] > '9') && (code[i] < 'a' || code[i] > 'f') && (code[i] < 'A' || code[i] > 'F')) return (FALSE); return (TRUE); } const char * S9xProActionReplayToRaw (const char *code, uint32 &address, uint8 &byte) { uint32 data = 0; if (strlen(code) != 8 || !S9xAllHex(code, 8) || sscanf(code, "%x", &data) != 1) return ("Invalid Pro Action Replay code - should be 8 hex digits in length."); address = data >> 8; byte = (uint8) data; return (NULL); } const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram, uint8 &num_bytes, uint8 bytes[3]) { char tmp[15]; int i; if (strlen(code) != 14) return ("Invalid Gold Finger code - should be 14 hex digits in length."); strncpy(tmp, code, 5); tmp[5] = 0; if (sscanf(tmp, "%x", &address) != 1) return ("Invalid Gold Finger code."); for (i = 0; i < 3; i++) { unsigned int byte; strncpy(tmp, code + 5 + i * 2, 2); tmp[2] = 0; if (sscanf(tmp, "%x", &byte) != 1) break; bytes[i] = (uint8) byte; } num_bytes = i; sram = code[13] == '1'; return (NULL); } const char * S9xGameGenieToRaw (const char *code, uint32 &address, uint8 &byte) { char new_code[12]; if (strlen(code) != 9 || *(code + 4) != '-' || !S9xAllHex(code, 4) || !S9xAllHex(code + 5, 4)) return ("Invalid Game Genie(tm) code - should be 'xxxx-xxxx'."); strcpy(new_code, "0x"); strncpy(new_code + 2, code, 4); strcpy(new_code + 6, code + 5); static const char *real_hex = "0123456789ABCDEF"; static const char *genie_hex = "DF4709156BC8A23E"; for (int i = 2; i < 10; i++) { if (islower(new_code[i])) new_code[i] = toupper(new_code[i]); int j; for (j = 0; j < 16; j++) { if (new_code[i] == genie_hex[j]) { new_code[i] = real_hex[j]; break; } } if (j == 16) return ("Invalid hex-character in Game Genie(tm) code."); } uint32 data = 0; sscanf(new_code, "%x", &data); byte = (uint8) (data >> 24); address = data & 0xffffff; address = ((address & 0x003c00) << 10) + ((address & 0x00003c) << 14) + ((address & 0xf00000) >> 8) + ((address & 0x000003) << 10) + ((address & 0x00c000) >> 6) + ((address & 0x0f0000) >> 12) + ((address & 0x0003c0) >> 6); return (NULL); } void S9xStartCheatSearch (SCheatData *d) { memmove(d->CWRAM, d->RAM, 0x20000); memmove(d->CSRAM, d->SRAM, 0x10000); memmove(d->CIRAM, &d->FillRAM[0x3000], 0x2000); memset((char *) d->ALL_BITS, 0xff, 0x32000 >> 3); } void S9xSearchForChange (SCheatData *d, S9xCheatComparisonType cmp, S9xCheatDataSize size, bool8 is_signed, bool8 update) { int l, i; switch (size) { case S9X_8_BITS: l = 0; break; case S9X_16_BITS: l = 1; break; case S9X_24_BITS: l = 2; break; default: case S9X_32_BITS: l = 3; break; } if (is_signed) { for (i = 0; i < 0x20000 - l; i++) { if (TEST_BIT(d->WRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->RAM, i), _S9XCHTDS(size, d->CWRAM, i))) { if (update) d->CWRAM[i] = d->RAM[i]; } else BIT_CLEAR(d->WRAM_BITS, i); } for (i = 0; i < 0x10000 - l; i++) { if (TEST_BIT(d->SRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->SRAM, i), _S9XCHTDS(size, d->CSRAM, i))) { if (update) d->CSRAM[i] = d->SRAM[i]; } else BIT_CLEAR(d->SRAM_BITS, i); } for (i = 0; i < 0x2000 - l; i++) { if (TEST_BIT(d->IRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->FillRAM + 0x3000, i), _S9XCHTDS(size, d->CIRAM, i))) { if (update) d->CIRAM[i] = d->FillRAM[i + 0x3000]; } else BIT_CLEAR(d->IRAM_BITS, i); } } else { for (i = 0; i < 0x20000 - l; i++) { if (TEST_BIT(d->WRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->RAM, i), _S9XCHTD(size, d->CWRAM, i))) { if (update) d->CWRAM[i] = d->RAM[i]; } else BIT_CLEAR(d->WRAM_BITS, i); } for (i = 0; i < 0x10000 - l; i++) { if (TEST_BIT(d->SRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->SRAM, i), _S9XCHTD(size, d->CSRAM, i))) { if (update) d->CSRAM[i] = d->SRAM[i]; } else BIT_CLEAR(d->SRAM_BITS, i); } for (i = 0; i < 0x2000 - l; i++) { if (TEST_BIT(d->IRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->FillRAM + 0x3000, i), _S9XCHTD(size, d->CIRAM, i))) { if (update) d->CIRAM[i] = d->FillRAM[i + 0x3000]; } else BIT_CLEAR(d->IRAM_BITS, i); } } for (i = 0x20000 - l; i < 0x20000; i++) BIT_CLEAR(d->WRAM_BITS, i); for (i = 0x10000 - l; i < 0x10000; i++) BIT_CLEAR(d->SRAM_BITS, i); } void S9xSearchForValue (SCheatData *d, S9xCheatComparisonType cmp, S9xCheatDataSize size, uint32 value, bool8 is_signed, bool8 update) { int l, i; switch (size) { case S9X_8_BITS: l = 0; break; case S9X_16_BITS: l = 1; break; case S9X_24_BITS: l = 2; break; default: case S9X_32_BITS: l = 3; break; } if (is_signed) { for (i = 0; i < 0x20000 - l; i++) { if (TEST_BIT(d->WRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->RAM, i), (int32) value)) { if (update) d->CWRAM[i] = d->RAM[i]; } else BIT_CLEAR(d->WRAM_BITS, i); } for (i = 0; i < 0x10000 - l; i++) { if (TEST_BIT(d->SRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->SRAM, i), (int32) value)) { if (update) d->CSRAM[i] = d->SRAM[i]; } else BIT_CLEAR(d->SRAM_BITS, i); } for (i = 0; i < 0x2000 - l; i++) { if (TEST_BIT(d->IRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTDS(size, d->FillRAM + 0x3000, i), (int32) value)) { if (update) d->CIRAM[i] = d->FillRAM[i + 0x3000]; } else BIT_CLEAR(d->IRAM_BITS, i); } } else { for (i = 0; i < 0x20000 - l; i++) { if (TEST_BIT(d->WRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->RAM, i), value)) { if (update) d->CWRAM[i] = d->RAM[i]; } else BIT_CLEAR(d->WRAM_BITS, i); } for (i = 0; i < 0x10000 - l; i++) { if (TEST_BIT(d->SRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->SRAM, i), value)) { if (update) d->CSRAM[i] = d->SRAM[i]; } else BIT_CLEAR(d->SRAM_BITS, i); } for (i = 0; i < 0x2000 - l; i++) { if (TEST_BIT(d->IRAM_BITS, i) && _S9XCHTC(cmp, _S9XCHTD(size, d->FillRAM + 0x3000, i), value)) { if (update) d->CIRAM[i] = d->FillRAM[i + 0x3000]; } else BIT_CLEAR(d->IRAM_BITS, i); } } for (i = 0x20000 - l; i < 0x20000; i++) BIT_CLEAR(d->WRAM_BITS, i); for (i = 0x10000 - l; i < 0x10000; i++) BIT_CLEAR(d->SRAM_BITS, i); } void S9xSearchForAddress (SCheatData *d, S9xCheatComparisonType cmp, S9xCheatDataSize size, uint32 value, bool8 update) { int l, i; switch (size) { case S9X_8_BITS: l = 0; break; case S9X_16_BITS: l = 1; break; case S9X_24_BITS: l = 2; break; default: case S9X_32_BITS: l = 3; break; } for (i = 0; i < 0x20000 - l; i++) { if (TEST_BIT(d->WRAM_BITS, i) && _S9XCHTC(cmp, i, (int32) value)) { if (update) d->CWRAM[i] = d->RAM[i]; } else BIT_CLEAR(d->WRAM_BITS, i); } for (i = 0; i < 0x10000 - l; i++) { if (TEST_BIT(d->SRAM_BITS, i) && _S9XCHTC(cmp, i + 0x20000, (int32) value)) { if (update) d->CSRAM[i] = d->SRAM[i]; } else BIT_CLEAR(d->SRAM_BITS, i); } for (i = 0; i < 0x2000 - l; i++) { if (TEST_BIT(d->IRAM_BITS, i) && _S9XCHTC(cmp, i + 0x30000, (int32) value)) { if (update) d->CIRAM[i] = d->FillRAM[i + 0x3000]; } else BIT_CLEAR(d->IRAM_BITS, i); } for (i = 0x20000 - l; i < 0x20000; i++) BIT_CLEAR(d->WRAM_BITS, i); for (i = 0x10000 - l; i < 0x10000; i++) BIT_CLEAR(d->SRAM_BITS, i); } void S9xOutputCheatSearchResults (SCheatData *d) { int i; for (i = 0; i < 0x20000; i++) { if (TEST_BIT(d->WRAM_BITS, i)) printf("WRAM: %05x: %02x\n", i, d->RAM[i]); } for (i = 0; i < 0x10000; i++) { if (TEST_BIT(d->SRAM_BITS, i)) printf("SRAM: %04x: %02x\n", i, d->SRAM[i]); } for (i = 0; i < 0x2000; i++) { if (TEST_BIT(d->IRAM_BITS, i)) printf("IRAM: %05x: %02x\n", i, d->FillRAM[i + 0x3000]); } } apu/hermite_resampler.h000664 001750 001750 00000006735 12720446475 016375 0ustar00sergiosergio000000 000000 /* Simple resampler based on bsnes's ruby audio library */ #ifndef __HERMITE_RESAMPLER_H #define __HERMITE_RESAMPLER_H #include "resampler.h" #undef CLAMP #undef SHORT_CLAMP #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #define SHORT_CLAMP(n) ((short) CLAMP((n), -32768, 32767)) class HermiteResampler : public Resampler { protected: float r_step; float r_frac; int r_left[4], r_right[4]; static inline float hermite (float mu1, float a, float b, float c, float d) { float mu2, mu3, m0, m1, a0, a1, a2, a3; mu2 = mu1 * mu1; mu3 = mu2 * mu1; m0 = (c - a) * 0.5; m1 = (d - b) * 0.5; a0 = +2 * mu3 - 3 * mu2 + 1; a1 = mu3 - 2 * mu2 + mu1; a2 = mu3 - mu2; a3 = -2 * mu3 + 3 * mu2; return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); } public: HermiteResampler (int num_samples) : Resampler (num_samples) { clear (); } ~HermiteResampler () { } void time_ratio (double ratio) { r_step = ratio; clear (); } void clear (void) { ring_buffer::clear (); r_frac = 1.0; r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; } void read (short *data, int num_samples) { int i_position = start >> 1; int max_samples = buffer_size >> 1; short *internal_buffer = (short *) buffer; int o_position = 0; int consumed = 0; while (o_position < num_samples && consumed < buffer_size) { int s_left = internal_buffer[i_position]; int s_right = internal_buffer[i_position + 1]; float hermite_val[2]; while (r_frac <= 1.0 && o_position < num_samples) { hermite_val[0] = hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3]); hermite_val[1] = hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3]); data[o_position] = SHORT_CLAMP (hermite_val[0]); data[o_position + 1] = SHORT_CLAMP (hermite_val[1]); o_position += 2; r_frac += r_step; } if (r_frac > 1.0) { r_left [0] = r_left [1]; r_left [1] = r_left [2]; r_left [2] = r_left [3]; r_left [3] = s_left; r_right[0] = r_right[1]; r_right[1] = r_right[2]; r_right[2] = r_right[3]; r_right[3] = s_right; r_frac -= 1.0; i_position += 2; if (i_position >= max_samples) i_position -= max_samples; consumed += 2; } } size -= consumed << 1; start += consumed << 1; if (start >= buffer_size) start -= buffer_size; } inline int avail (void) { return (int) floor (((size >> 2) - r_frac) / r_step) * 2; } }; #endif /* __HERMITE_RESAMPLER_H */ srtc.cpp000664 001750 001750 00000016235 12720446475 013403 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ /***** * S-RTC emulation code * Copyright (c) byuu *****/ #include #include "snes9x.h" #include "memmap.h" #include "srtc.h" #include "display.h" #define memory_cartrtc_read(a) RTCData.reg[(a)] #define memory_cartrtc_write(a, b) { RTCData.reg[(a)] = (b); } #define cpu_regs_mdr OpenBus static inline unsigned max (unsigned a, unsigned b) { return ((a > b) ? a : b); } static inline unsigned min (unsigned a, unsigned b) { return ((a < b) ? a : b); } #include "srtcemu.h" #include "srtcemu.cpp" static SRTC srtcemu; void S9xInitSRTC (void) { srtcemu.power(); memset(RTCData.reg, 0, 20); } void S9xResetSRTC (void) { srtcemu.reset(); } void S9xSetSRTC (uint8 data, uint16 address) { srtcemu.mmio_write(address, data); } uint8 S9xGetSRTC (uint16 address) { return (srtcemu.mmio_read(address)); } void S9xSRTCPreSaveState (void) { srtcsnap.rtc_mode = (int32) srtcemu.rtc_mode; srtcsnap.rtc_index = (int32) srtcemu.rtc_index; } void S9xSRTCPostLoadState (int) { srtcemu.rtc_mode = (SRTC::RTC_Mode) srtcsnap.rtc_mode; srtcemu.rtc_index = (signed) srtcsnap.rtc_index; srtcemu.update_time(); } apu/bapu/smp/core/opcycle_pc.cpp000664 001750 001750 00000045676 12720446475 020026 0ustar00sergiosergio000000 000000 case 0x2f: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(0){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xf0: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(!regs.p.z){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xd0: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(regs.p.z){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xb0: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(!regs.p.c){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x90: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(regs.p.c){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x70: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(!regs.p.v){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x50: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(regs.p.v){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x30: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(!regs.p.n){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x10: { switch(opcode_cycle++) { case 1: rd = op_readpc(); if(regs.p.n){ opcode_cycle = 0; break; } break; case 2: op_io(); break; case 3: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x03: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x01) != 0x01){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x13: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x01) == 0x01){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x23: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x02) != 0x02){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x33: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x02) == 0x02){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x43: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x04) != 0x04){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x53: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x04) == 0x04){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x63: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x08) != 0x08){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x73: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x08) == 0x08){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x83: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x10) != 0x10){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x93: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x10) == 0x10){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xa3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x20) != 0x20){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xb3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x20) == 0x20){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xc3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x40) != 0x40){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xd3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x40) == 0x40){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xe3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x80) != 0x80){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xf3: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if((sp & 0x80) == 0x80){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x2e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: sp = op_readdp(dp); break; case 3: rd = op_readpc(); break; case 4: op_io(); if(regs.a == sp){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xde: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp + regs.x); break; case 4: rd = op_readpc(); break; case 5: op_io(); if(regs.a == sp){ opcode_cycle = 0; break; } break; case 6: op_io(); break; case 7: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x6e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: wr = op_readdp(dp); break; case 3: op_writedp(dp, --wr); break; case 4: rd = op_readpc(); if(wr == 0x00){ opcode_cycle = 0; break; } break; case 5: op_io(); break; case 6: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0xfe: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: op_io(); regs.y--; break; case 3: op_io(); if(regs.y == 0x00){ opcode_cycle = 0; break; } break; case 4: op_io(); break; case 5: op_io(); regs.pc += (int8)rd; opcode_cycle = 0; break; } break; } case 0x5f: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: rd |= op_readpc() << 8; regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x1f: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); dp += regs.x; break; case 4: rd = op_readaddr(dp); break; case 5: rd |= op_readaddr(dp + 1) << 8; regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x3f: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: rd |= op_readpc() << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x4f: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: op_io(); break; case 3: op_io(); break; case 4: op_writestack(regs.pc >> 8); break; case 5: op_writestack(regs.pc); regs.pc = 0xff00 | rd; opcode_cycle = 0; break; } break; } case 0x01: { switch(opcode_cycle++) { case 1: dp = 0xffde - (0 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x11: { switch(opcode_cycle++) { case 1: dp = 0xffde - (1 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x21: { switch(opcode_cycle++) { case 1: dp = 0xffde - (2 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x31: { switch(opcode_cycle++) { case 1: dp = 0xffde - (3 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x41: { switch(opcode_cycle++) { case 1: dp = 0xffde - (4 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x51: { switch(opcode_cycle++) { case 1: dp = 0xffde - (5 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x61: { switch(opcode_cycle++) { case 1: dp = 0xffde - (6 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x71: { switch(opcode_cycle++) { case 1: dp = 0xffde - (7 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x81: { switch(opcode_cycle++) { case 1: dp = 0xffde - (8 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x91: { switch(opcode_cycle++) { case 1: dp = 0xffde - (9 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xa1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (10 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xb1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (11 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xc1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (12 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xd1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (13 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xe1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (14 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0xf1: { switch(opcode_cycle++) { case 1: dp = 0xffde - (15 << 1); rd = op_readaddr(dp); break; case 2: rd |= op_readaddr(dp + 1) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_writestack(regs.pc >> 8); break; case 7: op_writestack(regs.pc); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x0f: { switch(opcode_cycle++) { case 1: rd = op_readaddr(0xffde); break; case 2: rd |= op_readaddr(0xffdf) << 8; break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_writestack(regs.pc >> 8); break; case 6: op_writestack(regs.pc); break; case 7: op_writestack(regs.p); regs.pc = rd; regs.p.b = 1; regs.p.i = 0; opcode_cycle = 0; break; } break; } case 0x6f: { switch(opcode_cycle++) { case 1: rd = op_readstack(); break; case 2: rd |= op_readstack() << 8; break; case 3: op_io(); break; case 4: op_io(); regs.pc = rd; opcode_cycle = 0; break; } break; } case 0x7f: { switch(opcode_cycle++) { case 1: regs.p = op_readstack(); break; case 2: rd = op_readstack(); break; case 3: rd |= op_readstack() << 8; break; case 4: op_io(); break; case 5: op_io(); regs.pc = rd; opcode_cycle = 0; break; } break; } fxemu.cpp000664 001750 001750 00000053010 12720446475 013544 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "fxinst.h" #include "fxemu.h" static void FxReset (struct FxInfo_s *); static void fx_readRegisterSpace (void); static void fx_writeRegisterSpace (void); static void fx_updateRamBank (uint8); static void fx_dirtySCBR (void); static bool8 fx_checkStartAddress (void); static uint32 FxEmulate (uint32); static void FxCacheWriteAccess (uint16); static void FxFlushCache (void); void S9xInitSuperFX (void) { memset((uint8 *) &GSU, 0, sizeof(struct FxRegs_s)); } void S9xResetSuperFX (void) { // FIXME: Snes9x can't execute CPU and SuperFX at a time. Don't ask me what is 0.417 :P SuperFX.speedPerLine = (uint32) (Settings.SuperFXSpeedPerLine * ((1.0f / Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max)))); SuperFX.oneLineDone = FALSE; SuperFX.vFlags = 0; CPU.IRQExternal = FALSE; FxReset(&SuperFX); } void S9xSetSuperFX (uint8 byte, uint16 address) { switch (address) { case 0x3030: if ((Memory.FillRAM[0x3030] ^ byte) & FLG_G) { Memory.FillRAM[0x3030] = byte; if (byte & FLG_G) { if (!SuperFX.oneLineDone) { S9xSuperFXExec(); SuperFX.oneLineDone = TRUE; } } else FxFlushCache(); } else Memory.FillRAM[0x3030] = byte; break; case 0x3031: Memory.FillRAM[0x3031] = byte; break; case 0x3033: Memory.FillRAM[0x3033] = byte; break; case 0x3034: Memory.FillRAM[0x3034] = byte & 0x7f; break; case 0x3036: Memory.FillRAM[0x3036] = byte & 0x7f; break; case 0x3037: Memory.FillRAM[0x3037] = byte; break; case 0x3038: Memory.FillRAM[0x3038] = byte; fx_dirtySCBR(); break; case 0x3039: Memory.FillRAM[0x3039] = byte; break; case 0x303a: Memory.FillRAM[0x303a] = byte; break; case 0x303b: break; case 0x303c: Memory.FillRAM[0x303c] = byte; fx_updateRamBank(byte); break; case 0x303f: Memory.FillRAM[0x303f] = byte; break; case 0x301f: Memory.FillRAM[0x301f] = byte; Memory.FillRAM[0x3000 + GSU_SFR] |= FLG_G; if (!SuperFX.oneLineDone) { S9xSuperFXExec(); SuperFX.oneLineDone = TRUE; } break; default: Memory.FillRAM[address] = byte; if (address >= 0x3100) FxCacheWriteAccess(address); break; } } uint8 S9xGetSuperFX (uint16 address) { uint8 byte; byte = Memory.FillRAM[address]; if (address == 0x3031) { CPU.IRQExternal = FALSE; Memory.FillRAM[0x3031] = byte & 0x7f; } return (byte); } void S9xSuperFXExec (void) { if ((Memory.FillRAM[0x3000 + GSU_SFR] & FLG_G) && (Memory.FillRAM[0x3000 + GSU_SCMR] & 0x18) == 0x18) { FxEmulate((Memory.FillRAM[0x3000 + GSU_CLSR] & 1) ? SuperFX.speedPerLine * 2 : SuperFX.speedPerLine); uint16 GSUStatus = Memory.FillRAM[0x3000 + GSU_SFR] | (Memory.FillRAM[0x3000 + GSU_SFR + 1] << 8); if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ) CPU.IRQExternal = TRUE; } } static void FxReset (struct FxInfo_s *psFxInfo) { // Clear all internal variables memset((uint8 *) &GSU, 0, sizeof(struct FxRegs_s)); // Set default registers GSU.pvSreg = GSU.pvDreg = &R0; // Set RAM and ROM pointers GSU.pvRegisters = psFxInfo->pvRegisters; GSU.nRamBanks = psFxInfo->nRamBanks; GSU.pvRam = psFxInfo->pvRam; GSU.nRomBanks = psFxInfo->nRomBanks; GSU.pvRom = psFxInfo->pvRom; GSU.vPrevScreenHeight = ~0; GSU.vPrevMode = ~0; // The GSU can't access more than 2mb (16mbits) if (GSU.nRomBanks > 0x20) GSU.nRomBanks = 0x20; // Clear FxChip register space memset(GSU.pvRegisters, 0, 0x300); // Set FxChip version Number GSU.pvRegisters[0x3b] = 0; // Make ROM bank table for (int i = 0; i < 256; i++) { uint32 b = i & 0x7f; if (b >= 0x40) { if (GSU.nRomBanks > 1) b %= GSU.nRomBanks; else b &= 1; GSU.apvRomBank[i] = &GSU.pvRom[b << 16]; } else { b %= GSU.nRomBanks * 2; GSU.apvRomBank[i] = &GSU.pvRom[(b << 16) + 0x200000]; } } // Make RAM bank table for (int i = 0; i < 4; i++) { GSU.apvRamBank[i] = &GSU.pvRam[(i % GSU.nRamBanks) << 16]; GSU.apvRomBank[0x70 + i] = GSU.apvRamBank[i]; } // Start with a nop in the pipe GSU.vPipe = 0x01; // Set pointer to GSU cache GSU.pvCache = &GSU.pvRegisters[0x100]; fx_readRegisterSpace(); } static void fx_readRegisterSpace (void) { static uint32 avHeight[] = { 128, 160, 192, 256 }; static uint32 avMult[] = { 16, 32, 32, 64 }; uint8 *p; int n; GSU.vErrorCode = 0; // Update R0-R15 p = GSU.pvRegisters; for (int i = 0; i < 16; i++) { GSU.avReg[i] = *p++; GSU.avReg[i] += ((uint32) (*p++)) << 8; } // Update other registers p = GSU.pvRegisters; GSU.vStatusReg = (uint32) p[GSU_SFR]; GSU.vStatusReg |= ((uint32) p[GSU_SFR + 1]) << 8; GSU.vPrgBankReg = (uint32) p[GSU_PBR]; GSU.vRomBankReg = (uint32) p[GSU_ROMBR]; GSU.vRamBankReg = ((uint32) p[GSU_RAMBR]) & (FX_RAM_BANKS - 1); GSU.vCacheBaseReg = (uint32) p[GSU_CBR]; GSU.vCacheBaseReg |= ((uint32) p[GSU_CBR + 1]) << 8; // Update status register variables GSU.vZero = !(GSU.vStatusReg & FLG_Z); GSU.vSign = (GSU.vStatusReg & FLG_S) << 12; GSU.vOverflow = (GSU.vStatusReg & FLG_OV) << 16; GSU.vCarry = (GSU.vStatusReg & FLG_CY) >> 2; // Set bank pointers GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3]; GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg]; GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg]; // Set screen pointers GSU.pvScreenBase = &GSU.pvRam[USEX8(p[GSU_SCBR]) << 10]; n = (int) (!!(p[GSU_SCMR] & 0x04)); n |= ((int) (!!(p[GSU_SCMR] & 0x20))) << 1; GSU.vScreenHeight = GSU.vScreenRealHeight = avHeight[n]; GSU.vMode = p[GSU_SCMR] & 0x03; if (n == 3) GSU.vScreenSize = (256 / 8) * (256 / 8) * 32; else GSU.vScreenSize = (GSU.vScreenHeight / 8) * (256 / 8) * avMult[GSU.vMode]; if (GSU.vPlotOptionReg & 0x10) // OBJ Mode (for drawing into sprites) GSU.vScreenHeight = 256; if (GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536)) GSU.pvScreenBase = GSU.pvRam + (GSU.nRamBanks * 65536) - GSU.vScreenSize; GSU.pfPlot = fx_PlotTable[GSU.vMode]; GSU.pfRpix = fx_PlotTable[GSU.vMode + 5]; fx_OpcodeTable[0x04c] = GSU.pfPlot; fx_OpcodeTable[0x14c] = GSU.pfRpix; fx_OpcodeTable[0x24c] = GSU.pfPlot; fx_OpcodeTable[0x34c] = GSU.pfRpix; fx_computeScreenPointers(); //fx_backupCache(); } static void fx_writeRegisterSpace (void) { uint8 *p; p = GSU.pvRegisters; for (int i = 0; i < 16; i++) { *p++ = (uint8) GSU.avReg[i]; *p++ = (uint8) (GSU.avReg[i] >> 8); } // Update status register if (USEX16(GSU.vZero) == 0) SF(Z); else CF(Z); if (GSU.vSign & 0x8000) SF(S); else CF(S); if (GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000) SF(OV); else CF(OV); if (GSU.vCarry) SF(CY); else CF(CY); p = GSU.pvRegisters; p[GSU_SFR] = (uint8) GSU.vStatusReg; p[GSU_SFR + 1] = (uint8) (GSU.vStatusReg >> 8); p[GSU_PBR] = (uint8) GSU.vPrgBankReg; p[GSU_ROMBR] = (uint8) GSU.vRomBankReg; p[GSU_RAMBR] = (uint8) GSU.vRamBankReg; p[GSU_CBR] = (uint8) GSU.vCacheBaseReg; p[GSU_CBR + 1] = (uint8) (GSU.vCacheBaseReg >> 8); //fx_restoreCache(); } // Update RamBankReg and RAM Bank pointer static void fx_updateRamBank (uint8 byte) { // Update BankReg and Bank pointer GSU.vRamBankReg = (uint32) byte & (FX_RAM_BANKS - 1); GSU.pvRamBank = GSU.apvRamBank[byte & 0x3]; } // SCBR write seen. We need to update our cached screen pointers static void fx_dirtySCBR (void) { GSU.vSCBRDirty = TRUE; } static bool8 fx_checkStartAddress (void) { // Check if we start inside the cache if (GSU.bCacheActive && R15 >= GSU.vCacheBaseReg && R15 < (GSU.vCacheBaseReg + 512)) return (TRUE); /* // Check if we're in an unused area if (GSU.vPrgBankReg < 0x40 && R15 < 0x8000) return (FALSE); */ if (GSU.vPrgBankReg >= 0x60 && GSU.vPrgBankReg <= 0x6f) return (FALSE); if (GSU.vPrgBankReg >= 0x74) return (FALSE); // Check if we're in RAM and the RAN flag is not set if (GSU.vPrgBankReg >= 0x70 && GSU.vPrgBankReg <= 0x73 && !(SCMR & (1 << 3))) return (FALSE); // If not, we're in ROM, so check if the RON flag is set if (!(SCMR & (1 << 4))) return (FALSE); return (TRUE); } // Execute until the next stop instruction static uint32 FxEmulate (uint32 nInstructions) { uint32 vCount; // Read registers and initialize GSU session fx_readRegisterSpace(); // Check if the start address is valid if (!fx_checkStartAddress()) { CF(G); fx_writeRegisterSpace(); /* GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15; return (FX_ERROR_ILLEGAL_ADDRESS); */ return (0); } // Execute GSU session CF(IRQ); /* if (GSU.bBreakPoint) vCount = fx_run_to_breakpoint(nInstructions); else */ vCount = fx_run(nInstructions); // Store GSU registers fx_writeRegisterSpace(); // Check for error code if (GSU.vErrorCode) return (GSU.vErrorCode); else return (vCount); } void fx_computeScreenPointers (void) { if (GSU.vMode != GSU.vPrevMode || GSU.vPrevScreenHeight != GSU.vScreenHeight || GSU.vSCBRDirty) { GSU.vSCBRDirty = FALSE; // Make a list of pointers to the start of each screen column switch (GSU.vScreenHeight) { case 128: switch (GSU.vMode) { case 0: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); GSU.x[i] = i << 8; } break; case 1: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); GSU.x[i] = i << 9; } break; case 2: case 3: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); GSU.x[i] = i << 10; } break; } break; case 160: switch (GSU.vMode) { case 0: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); GSU.x[i] = (i << 8) + (i << 6); } break; case 1: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); GSU.x[i] = (i << 9) + (i << 7); } break; case 2: case 3: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); GSU.x[i] = (i << 10) + (i << 8); } break; } break; case 192: switch (GSU.vMode) { case 0: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); GSU.x[i] = (i << 8) + (i << 7); } break; case 1: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); GSU.x[i] = (i << 9) + (i << 8); } break; case 2: case 3: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); GSU.x[i] = (i << 10) + (i << 9); } break; } break; case 256: switch (GSU.vMode) { case 0: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 9) + ((i & 0xf) << 8); GSU.x[i] = ((i & 0x10) << 8) + ((i & 0xf) << 4); } break; case 1: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 10) + ((i & 0xf) << 9); GSU.x[i] = ((i & 0x10) << 9) + ((i & 0xf) << 5); } break; case 2: case 3: for (int i = 0; i < 32; i++) { GSU.apvScreen[i] = GSU.pvScreenBase + ((i & 0x10) << 11) + ((i & 0xf) << 10); GSU.x[i] = ((i & 0x10) << 10) + ((i & 0xf) << 6); } break; } break; } GSU.vPrevMode = GSU.vMode; GSU.vPrevScreenHeight = GSU.vScreenHeight; } } // Write access to the cache static void FxCacheWriteAccess (uint16 vAddress) { /* if (!GSU.bCacheActive) { uint8 v = GSU.pvCache[GSU.pvCache[vAddress & 0x1ff]; fx_setCache(); GSU.pvCache[GSU.pvCache[vAddress & 0x1ff] = v; } */ if ((vAddress & 0x00f) == 0x00f) GSU.vCacheFlags |= 1 << ((vAddress & 0x1f0) >> 4); } static void FxFlushCache (void) { GSU.vCacheFlags = 0; GSU.vCacheBaseReg = 0; GSU.bCacheActive = FALSE; //GSU.vPipe = 0x1; } void fx_flushCache (void) { //fx_restoreCache(); GSU.vCacheFlags = 0; GSU.bCacheActive = FALSE; } /* static void fx_setCache (void) { uint32 c; GSU.bCacheActive = TRUE; GSU.pvRegisters[0x3e] &= 0xf0; c = (uint32) GSU.pvRegisters[0x3e]; c |= ((uint32) GSU.pvRegisters[0x3f]) << 8; if (c == GSU.vCacheBaseReg) return; GSU.vCacheBaseReg = c; GSU.vCacheFlags = 0; if (c < (0x10000 - 512)) { const uint8 *t = &ROM(c); memcpy(GSU.pvCache, t, 512); } else { const uint8 *t1, *t2; uint32 i = 0x10000 - c; t1 = &ROM(c); t2 = &ROM(0); memcpy(GSU.pvCache, t1, i); memcpy(&GSU.pvCache[i], t2, 512 - i); } } */ /* static void fx_backupCache (void) { uint32 v = GSU.vCacheFlags; uint32 c = USEX16(GSU.vCacheBaseReg); if (v) { for (int i = 0; i < 32; i++) { if (v & 1) { if (c < (0x10000 - 16)) { uint8 *t = &GSU.pvPrgBank[c]; memcpy(&GSU.avCacheBackup[i << 4], t, 16); memcpy(t, &GSU.pvCache[i << 4], 16); } else { uint8 *t1, *t2; uint32 a = 0x10000 - c; t1 = &GSU.pvPrgBank[c]; t2 = &GSU.pvPrgBank[0]; memcpy(&GSU.avCacheBackup[i << 4], t1, a); memcpy(t1, &GSU.pvCache[i << 4], a); memcpy(&GSU.avCacheBackup[(i << 4) + a], t2, 16 - a); memcpy(t2, &GSU.pvCache[(i << 4) + a], 16 - a); } } c = USEX16(c + 16); v >>= 1; } } } */ /* static void fx_restoreCache() { uint32 v = GSU.vCacheFlags; uint32 c = USEX16(GSU.vCacheBaseReg); if (v) { for (int i = 0; i < 32; i++) { if (v & 1) { if (c < (0x10000 - 16)) { uint8 *t = &GSU.pvPrgBank[c]; memcpy(t, &GSU.avCacheBackup[i << 4], 16); memcpy(&GSU.pvCache[i << 4], t, 16); } else { uint8 *t1, *t2; uint32 a = 0x10000 - c; t1 = &GSU.pvPrgBank[c]; t2 = &GSU.pvPrgBank[0]; memcpy(t1, &GSU.avCacheBackup[i << 4], a); memcpy(&GSU.pvCache[i << 4], t1, a); memcpy(t2, &GSU.avCacheBackup[(i << 4) + a], 16 - a); memcpy(&GSU.pvCache[(i << 4) + a], t2, 16 - a); } } c = USEX16(c + 16); v >>= 1; } } } */ // Breakpoints /* static void FxBreakPointSet (uint32 vAddress) { GSU.bBreakPoint = TRUE; GSU.vBreakPoint = USEX16(vAddress); } */ /* static void FxBreakPointClear (void) { GSU.bBreakPoint = FALSE; } */ // Step by step execution /* static uint32 FxStepOver (uint32 nInstructions) { uint32 vCount; fx_readRegisterSpace(); if (!fx_checkStartAddress()) { CF(G); #if 0 GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15; return (FX_ERROR_ILLEGAL_ADDRESS); #else return (0); #endif } if (PIPE >= 0xf0) GSU.vStepPoint = USEX16(R15 + 3); else if ((PIPE >= 0x05 && PIPE <= 0x0f) || (PIPE >= 0xa0 && PIPE <= 0xaf)) GSU.vStepPoint = USEX16(R15 + 2); else GSU.vStepPoint = USEX16(R15 + 1); vCount = fx_step_over(nInstructions); fx_writeRegisterSpace(); if (GSU.vErrorCode) return (GSU.vErrorCode); else return (vCount); } */ // Errors /* static int FxGetErrorCode (void) { return (GSU.vErrorCode); } */ /* static int FxGetIllegalAddress (void) { return (GSU.vIllegalAddress); } */ // Access to internal registers /* static uint32 FxGetColorRegister (void) { return (GSU.vColorReg & 0xff); } */ /* static uint32 FxGetPlotOptionRegister (void) { return (GSU.vPlotOptionReg & 0x1f); } */ /* static uint32 FxGetSourceRegisterIndex (void) { return (GSU.pvSreg - GSU.avReg); } */ /* static uint32 FxGetDestinationRegisterIndex (void) { return (GSU.pvDreg - GSU.avReg); } */ // Get the byte currently in the pipe /* static uint8 FxPipe (void) { return (GSU.vPipe); } */ debug.h000664 001750 001750 00000015144 12720446475 013161 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef DEBUGGER #ifndef _DEBUG_H_ #define _DEBUG_H_ #include struct SBreakPoint { bool8 Enabled; uint8 Bank; uint16 Address; }; #define ENSURE_TRACE_OPEN(fp, file, mode) \ if (!fp) \ { \ std::string fn = S9xGetDirectory(LOG_DIR); \ fn += SLASH_STR file; \ fp = fopen(fn.c_str(), mode); \ } extern struct SBreakPoint S9xBreakpoint[6]; void S9xDoDebug (void); void S9xTrace (void); void S9xSA1Trace (void); void S9xTraceMessage (const char *); void S9xTraceFormattedMessage (const char *, ...); void S9xPrintHVPosition (char *); #endif #endif apu/bapu/smp/core/op_rmw.cpp000664 001750 001750 00000007323 12720446475 017174 0ustar00sergiosergio000000 000000 case 0xbc: { op_io(); regs.a = op_inc(regs.a); break; } case 0x3d: { op_io(); regs.x = op_inc(regs.x); break; } case 0xfc: { op_io(); regs.y = op_inc(regs.y); break; } case 0x9c: { op_io(); regs.a = op_dec(regs.a); break; } case 0x1d: { op_io(); regs.x = op_dec(regs.x); break; } case 0xdc: { op_io(); regs.y = op_dec(regs.y); break; } case 0x1c: { op_io(); regs.a = op_asl(regs.a); break; } case 0x5c: { op_io(); regs.a = op_lsr(regs.a); break; } case 0x3c: { op_io(); regs.a = op_rol(regs.a); break; } case 0x7c: { op_io(); regs.a = op_ror(regs.a); break; } case 0xab: { dp = op_readpc(); rd = op_readdp(dp); rd = op_inc(rd); op_writedp(dp, rd); break; } case 0x8b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_dec(rd); op_writedp(dp, rd); break; } case 0x0b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_asl(rd); op_writedp(dp, rd); break; } case 0x4b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_lsr(rd); op_writedp(dp, rd); break; } case 0x2b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_rol(rd); op_writedp(dp, rd); break; } case 0x6b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_ror(rd); op_writedp(dp, rd); break; } case 0xbb: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_inc(rd); op_writedp(dp + regs.x, rd); break; } case 0x9b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_dec(rd); op_writedp(dp + regs.x, rd); break; } case 0x1b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_asl(rd); op_writedp(dp + regs.x, rd); break; } case 0x5b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_lsr(rd); op_writedp(dp + regs.x, rd); break; } case 0x3b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_rol(rd); op_writedp(dp + regs.x, rd); break; } case 0x7b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_ror(rd); op_writedp(dp + regs.x, rd); break; } case 0xac: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_inc(rd); op_writeaddr(dp, rd); break; } case 0x8c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_dec(rd); op_writeaddr(dp, rd); break; } case 0x0c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_asl(rd); op_writeaddr(dp, rd); break; } case 0x4c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_lsr(rd); op_writeaddr(dp, rd); break; } case 0x2c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_rol(rd); op_writeaddr(dp, rd); break; } case 0x6c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_ror(rd); op_writeaddr(dp, rd); break; } case 0x0e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.p.n = !!((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); op_readaddr(dp); op_writeaddr(dp, rd | regs.a); break; } case 0x4e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.p.n = !!((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); op_readaddr(dp); op_writeaddr(dp, rd &~ regs.a); break; } case 0x3a: { dp = op_readpc(); rd = op_readdp(dp); rd++; op_writedp(dp++, rd); rd += op_readdp(dp) << 8; op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); break; } case 0x1a: { dp = op_readpc(); rd = op_readdp(dp); rd--; op_writedp(dp++, rd); rd += op_readdp(dp) << 8; op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); break; } server.cpp000664 001750 001750 00000124207 12720446475 013735 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef NETPLAY_SUPPORT #ifdef _DEBUG #define NP_DEBUG 1 #endif #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "snes9x.h" #ifdef __WIN32__ #include #include #include "win32/wsnes9x.h" #define ioctl ioctlsocket #define close closesocket #define read(a,b,c) recv(a, b, c, 0) #define write(a,b,c) send(a, b, c, 0) #define gettimeofday(a,b) S9xGetTimeOfDay (a) #define exit(a) _endthread() void S9xGetTimeOfDay (struct timeval *n); #else #include #include #include #include #include #include #include #include #ifdef __SVR4 #include #endif #endif // !__WIN32__ #include "memmap.h" #include "snapshot.h" #include "netplay.h" #ifdef __WIN32__ #define NP_ONE_CLIENT 1 #else #define NP_ONE_CLIENT 0 #endif struct SNPServer NPServer; extern unsigned long START; void S9xNPSendToAllClients (uint8 *data, int len); bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len); void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len); void S9xNPNoClientReady (int start_index = NP_ONE_CLIENT); void S9xNPRecomputePause (); void S9xNPWaitForEmulationToComplete (); void S9xNPSendROMImageToAllClients (); bool8 S9xNPSendROMImageToClient (int client); void S9xNPSendSRAMToClient (int c); void S9xNPSendSRAMToAllClients (); void S9xNPSyncClient (int); void S9xNPSendROMLoadRequest (const char *filename); void S9xNPSendFreezeFileToAllClients (const char *filename); void S9xNPStopServer (); void S9xNPShutdownClient (int c, bool8 report_error = FALSE) { if (NPServer.Clients [c].Connected) { NPServer.Clients [c].Connected = FALSE; NPServer.Clients [c].SaidHello = FALSE; close (NPServer.Clients [c].Socket); #ifdef NP_DEBUG printf ("SERVER: Player %d disconnecting @%ld\n", c + 1, S9xGetMilliTime () - START); #endif if (report_error) { sprintf (NetPlay.ErrorMsg, "Player %d on '%s' has disconnected.", c + 1, NPServer.Clients [c].HostName); S9xNPSetWarning (NetPlay.ErrorMsg); } if (NPServer.Clients [c].HostName) { free ((char *) NPServer.Clients [c].HostName); NPServer.Clients [c].HostName = NULL; } if (NPServer.Clients [c].ROMName) { free ((char *) NPServer.Clients [c].ROMName); NPServer.Clients [c].ROMName = NULL; } if (NPServer.Clients [c].Who) { free ((char *) NPServer.Clients [c].Who); NPServer.Clients [c].Who = NULL; } NPServer.Joypads [c] = 0; NPServer.NumClients--; S9xNPRecomputePause (); } } static bool8 S9xNPSGetData (int socket, uint8 *data, int length) { int len = length; uint8 *ptr = data; do { int num_bytes = len; // Read the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > 512) num_bytes = 512; int got = read (socket, (char *) ptr, num_bytes); if (got < 0) { if (errno == EINTR #ifdef EAGAIN || errno == EAGAIN #endif #ifdef EWOULDBLOCK || errno == EWOULDBLOCK #endif #ifdef WSAEWOULDBLOCK || errno == WSAEWOULDBLOCK #endif ) continue; #ifdef WSAEMSGSIZE if (errno != WSAEMSGSIZE) return (FALSE); else { got = num_bytes; #ifdef NP_DEBUG printf ("SERVER: WSAEMSGSIZE, actual bytes %d while receiving data @%d\n", got, S9xGetMilliTime () - START); #endif } #else return (FALSE); #endif } else if (got == 0) return (FALSE); len -= got; ptr += got; } while (len > 0); return (TRUE); } static bool8 S9xNPSSendData (int fd, const uint8 *data, int length) { int Percent = 0; int len = length; int chunk = length / 50; if (chunk < 1024) chunk = 1024; do { int num_bytes = len; // Write the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > chunk) num_bytes = chunk; int sent; sent = write (fd, (char *) data, len); if (sent < 0) { if (errno == EINTR #ifdef EAGAIN || errno == EAGAIN #endif #ifdef EWOULDBLOCK || errno == EWOULDBLOCK #endif ) { #ifdef NP_DEBUG printf ("SERVER: EINTR, EAGAIN or EWOULDBLOCK while sending data @%ld\n", S9xGetMilliTime () - START); #endif continue; } return (FALSE); } else if (sent == 0) return (FALSE); len -= sent; data += sent; if (length > 1024) { Percent = (uint8) (((length - len) * 100) / length); #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER, Percent, Percent); Sleep (0); #endif } } while (len > 0); return (TRUE); } void S9xNPSendHeartBeat () { int len = 3; uint8 data [3 + 4 * 5]; uint8 *ptr = data; int n; for (n = NP_MAX_CLIENTS - 1; n >= 0; n--) { if (NPServer.Clients [n].SaidHello) break; } if (n >= 0) { bool8 Paused = NPServer.Paused != 0; NPServer.FrameCount++; *ptr++ = NP_SERV_MAGIC; *ptr++ = 0; // Individual client sequence number will get placed here *ptr++ = NP_SERV_JOYPAD | (n << 6) | ((Paused != 0) << 5); WRITE_LONG (ptr, NPServer.FrameCount); len += 4; ptr += 4; int i; for (i = 0; i <= n; i++) { WRITE_LONG (ptr, NPServer.Joypads [i]); len += 4; ptr += 4; } S9xNPSendToAllClients (data, len); } } void S9xNPSendToAllClients (uint8 *data, int len) { int i; for (i = 0; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].SaidHello) { data [1] = NPServer.Clients [i].SendSequenceNum++; if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) S9xNPShutdownClient (i, TRUE); } } } void S9xNPProcessClient (int c) { uint8 header [7]; uint8 *data; uint32 len; uint8 *ptr; if (!S9xNPSGetData (NPServer.Clients [c].Socket, header, 7)) { S9xNPSetWarning ("SERVER: Failed to get message header from client.\n"); S9xNPShutdownClient (c, TRUE); return; } if (header [0] != NP_CLNT_MAGIC) { S9xNPSetWarning ("SERVER: Bad header magic value received from client.\n"); S9xNPShutdownClient (c, TRUE); return; } if (header [1] != NPServer.Clients [c].ReceiveSequenceNum) { #ifdef NP_DEBUG printf ("SERVER: Messages lost from '%s', expected %d, got %d\n", NPServer.Clients [c].HostName ? NPServer.Clients [c].HostName : "Unknown", NPServer.Clients [c].ReceiveSequenceNum, header [1]); #endif sprintf (NetPlay.WarningMsg, "SERVER: Messages lost from '%s', expected %d, got %d\n", NPServer.Clients [c].HostName ? NPServer.Clients [c].HostName : "Unknown", NPServer.Clients [c].ReceiveSequenceNum, header [1]); NPServer.Clients [c].ReceiveSequenceNum = header [1] + 1; S9xNPSetWarning (NetPlay.WarningMsg); } else NPServer.Clients [c].ReceiveSequenceNum++; len = READ_LONG (&header [3]); switch (header [2] & 0x3f) { case NP_CLNT_HELLO: #ifdef NP_DEBUG printf ("SERVER: Got HELLO from client @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Got HELLO from client...", TRUE); if (len > 0x10000) { S9xNPSetWarning ("SERVER: Client HELLO message length error."); S9xNPShutdownClient (c, TRUE); return; } data = new uint8 [len - 7]; if (!S9xNPSGetData (NPServer.Clients [c].Socket, data, len - 7)) { S9xNPSetWarning ("SERVER: Failed to get HELLO message content from client."); S9xNPShutdownClient (c, TRUE); return; } if (NPServer.NumClients <= NP_ONE_CLIENT) { NPServer.FrameTime = READ_LONG (data); strncpy (NPServer.ROMName, (char *) &data [4], 29); NPServer.ROMName [29] = 0; } NPServer.Clients [c].ROMName = strdup ((char *) &data [4]); #ifdef NP_DEBUG printf ("SERVER: Client is playing: %s, Frame Time: %d @%ld\n", data + 4, READ_LONG (data), S9xGetMilliTime () - START); #endif NPServer.Clients [c].SendSequenceNum = 0; len = 7 + 1 + 1 + 4 + strlen (NPServer.ROMName) + 1; delete[] data; ptr = data = new uint8 [len]; *ptr++ = NP_SERV_MAGIC; *ptr++ = NPServer.Clients [c].SendSequenceNum++; if (NPServer.SendROMImageOnConnect && NPServer.NumClients > NP_ONE_CLIENT) *ptr++ = NP_SERV_HELLO | 0x80; else *ptr++ = NP_SERV_HELLO; WRITE_LONG (ptr, len); ptr += 4; *ptr++ = NP_VERSION; *ptr++ = c + 1; WRITE_LONG (ptr, NPServer.FrameCount); ptr += 4; strcpy ((char *) ptr, NPServer.ROMName); #ifdef NP_DEBUG printf ("SERVER: Sending welcome information to client @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("SERVER: Sending welcome information to new client...", TRUE); if (!S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) { S9xNPSetWarning ("SERVER: Failed to send welcome message to client."); S9xNPShutdownClient (c, TRUE); return; } delete[] data; #ifdef NP_DEBUG printf ("SERVER: Waiting for a response from the client @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("SERVER: Waiting for a response from the client...", TRUE); break; case NP_CLNT_LOADED_ROM: #ifdef NP_DEBUG printf ("SERVER: Client %d loaded requested ROM @%ld...\n", c, S9xGetMilliTime () - START); #endif NPServer.Clients [c].SaidHello = TRUE; NPServer.Clients [c].Ready = FALSE; NPServer.Clients [c].Paused = FALSE; S9xNPRecomputePause (); S9xNPWaitForEmulationToComplete (); if (NPServer.SyncByReset) { S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); } else S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); break; case NP_CLNT_RECEIVED_ROM_IMAGE: #ifdef NP_DEBUG printf ("SERVER: Client %d received ROM image @%ld...\n", c, S9xGetMilliTime () - START); #endif NPServer.Clients [c].SaidHello = TRUE; NPServer.Clients [c].Ready = FALSE; NPServer.Clients [c].Paused = FALSE; S9xNPRecomputePause (); S9xNPWaitForEmulationToComplete (); if (NPServer.SyncByReset) { S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); } else S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); break; case NP_CLNT_WAITING_FOR_ROM_IMAGE: #ifdef NP_DEBUG printf ("SERVER: Client %d waiting for ROM image @%ld...\n", c, S9xGetMilliTime () - START); #endif NPServer.Clients [c].SaidHello = TRUE; NPServer.Clients [c].Ready = FALSE; NPServer.Clients [c].Paused = FALSE; S9xNPRecomputePause (); S9xNPSendROMImageToClient (c); break; case NP_CLNT_READY: #ifdef NP_DEBUG printf ("SERVER: Client %d ready @%ld...\n", c, S9xGetMilliTime () - START); #endif if (NPServer.Clients [c].SaidHello) { NPServer.Clients [c].Paused = FALSE; NPServer.Clients [c].Ready = TRUE; S9xNPRecomputePause (); break; } NPServer.Clients [c].SaidHello = TRUE; NPServer.Clients [c].Ready = TRUE; NPServer.Clients [c].Paused = FALSE; S9xNPRecomputePause (); //printf ("SERVER: SaidHello = TRUE, SeqNum = %d @%d\n", NPServer.Clients [c].SendSequenceNum, S9xGetMilliTime () - START); if (NPServer.NumClients > NP_ONE_CLIENT) { if (!NPServer.SendROMImageOnConnect) { S9xNPWaitForEmulationToComplete (); if (NPServer.SyncByReset) { S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); } else #ifdef __WIN32__ S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); #else /* We need to resync all clients on new player connect as we don't have a 'reference game' */ S9xNPServerAddTask (NP_SERVER_SYNC_ALL, (void *) c); #endif } } else { NPServer.Clients [c].Ready = TRUE; S9xNPRecomputePause (); } break; case NP_CLNT_JOYPAD: NPServer.Joypads [c] = len; break; case NP_CLNT_PAUSE: #ifdef NP_DEBUG printf ("SERVER: Client %d Paused: %s @%ld\n", c, (header [2] & 0x80) ? "YES" : "NO", S9xGetMilliTime () - START); #endif NPServer.Clients [c].Paused = (header [2] & 0x80) != 0; if (NPServer.Clients [c].Paused) sprintf (NetPlay.WarningMsg, "SERVER: Client %d has paused.", c + 1); else sprintf (NetPlay.WarningMsg, "SERVER: Client %d has resumed.", c + 1); S9xNPSetWarning (NetPlay.WarningMsg); S9xNPRecomputePause (); break; } } void S9xNPAcceptClient (int Listen, bool8 block) { struct sockaddr_in remote_address; struct linger val2; struct hostent *host; int new_fd; int i; #ifdef NP_DEBUG printf ("SERVER: attempting to accept new client connection @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("SERVER: Attempting to accept client connection...", TRUE); memset (&remote_address, 0, sizeof (remote_address)); socklen_t len = sizeof (remote_address); new_fd = accept (Listen, (struct sockaddr *)&remote_address, &len); S9xNPSetAction ("Setting socket options...", TRUE); val2.l_onoff = 1; val2.l_linger = 0; if (setsockopt (new_fd, SOL_SOCKET, SO_LINGER, (char *) &val2, sizeof (val2)) < 0) { S9xNPSetError ("Setting socket options failed."); close (new_fd); return; } for (i = 0; i < NP_MAX_CLIENTS; i++) { if (!NPServer.Clients [i].Connected) { NPServer.NumClients++; NPServer.Clients [i].Socket = new_fd; NPServer.Clients [i].SendSequenceNum = 0; NPServer.Clients [i].ReceiveSequenceNum = 0; NPServer.Clients [i].Connected = TRUE; NPServer.Clients [i].SaidHello = FALSE; NPServer.Clients [i].Paused = FALSE; NPServer.Clients [i].Ready = FALSE; NPServer.Clients [i].ROMName = NULL; NPServer.Clients [i].HostName = NULL; NPServer.Clients [i].Who = NULL; break; } } if (i >= NP_MAX_CLIENTS) { S9xNPSetError ("SERVER: Maximum number of NetPlay Clients have already connected."); close (new_fd); return; } if (remote_address.sin_family == AF_INET) { #ifdef NP_DEBUG printf ("SERVER: Looking up new client's hostname @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("SERVER: Looking up new client's hostname...", TRUE); host = gethostbyaddr ((char *) &remote_address.sin_addr, sizeof (remote_address.sin_addr), AF_INET); if (host) { #ifdef NP_DEBUG printf ("SERVER: resolved new client's hostname (%s) @%ld\n", host->h_name, S9xGetMilliTime () - START); #endif sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, host->h_name); NPServer.Clients [i].HostName = strdup (host->h_name); } else { char *ip = inet_ntoa (remote_address.sin_addr); if (ip) NPServer.Clients [i].HostName = strdup (ip); #ifdef NP_DEBUG printf ("SERVER: couldn't resolve new client's hostname (%s) @%ld\n", ip ? ip : "Unknown", S9xGetMilliTime () - START); #endif sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, ip ? ip : "Unknown"); } S9xNPSetWarning (NetPlay.WarningMsg); } #ifdef NP_DEBUG printf ("SERVER: waiting for HELLO message from new client @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("SERVER: Waiting for HELLO message from new client..."); } static bool8 server_continue = TRUE; static bool8 S9xNPServerInit (int port) { struct sockaddr_in address; int i; int val; if (!S9xNPInitialise ()) return (FALSE); for (i = 0; i < NP_MAX_CLIENTS; i++) { NPServer.Clients [i].SendSequenceNum = 0; NPServer.Clients [i].ReceiveSequenceNum = 0; NPServer.Clients [i].Connected = FALSE; NPServer.Clients [i].SaidHello = FALSE; NPServer.Clients [i].Paused = FALSE; NPServer.Clients [i].Ready = FALSE; NPServer.Clients [i].Socket = 0; NPServer.Clients [i].ROMName = NULL; NPServer.Clients [i].HostName = NULL; NPServer.Clients [i].Who = NULL; NPServer.Joypads [i] = 0; } NPServer.NumClients = 0; NPServer.FrameCount = 0; #ifdef NP_DEBUG printf ("SERVER: Creating socket @%ld\n", S9xGetMilliTime () - START); #endif if ((NPServer.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) { S9xNPSetError ("NetPlay Server: Can't create listening socket."); return (FALSE); } val = 1; setsockopt (NPServer.Socket, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof (val)); memset (&address, 0, sizeof (address)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl (INADDR_ANY); address.sin_port = htons (port); #ifdef NP_DEBUG printf ("SERVER: Binding socket to address and port @%ld\n", S9xGetMilliTime () - START); #endif if (bind (NPServer.Socket, (struct sockaddr *) &address, sizeof (address)) < 0) { S9xNPSetError ("NetPlay Server: Can't bind socket to port number.\nPort already in use?"); return (FALSE); } #ifdef NP_DEBUG printf ("SERVER: Getting socket to listen @%ld\n", S9xGetMilliTime () - START); #endif if (listen (NPServer.Socket, NP_MAX_CLIENTS) < 0) { S9xNPSetError ("NetPlay Server: Can't get new socket to listen."); return (FALSE); } #ifdef NP_DEBUG printf ("SERVER: Init complete @%ld\n", S9xGetMilliTime () - START); #endif return (TRUE); } void S9xNPSendServerPause (bool8 paused) { #ifdef NP_DEBUG printf ("SERVER: Pause - %s @%ld\n", paused ? "YES" : "NO", S9xGetMilliTime () - START); #endif uint8 pause [7]; uint8 *ptr = pause; *ptr++ = NP_SERV_MAGIC; *ptr++ = 0; *ptr++ = NP_SERV_PAUSE | (paused ? 0x20 : 0); WRITE_LONG (ptr, NPServer.FrameCount); S9xNPSendToAllClients (pause, 7); } void S9xNPServerLoop (void *) { #ifdef __WIN32__ BOOL success = FALSE; #else bool8 success = FALSE; static struct timeval next1 = {0, 0}; struct timeval now; #endif int pausedState = -1, newPausedState = -1; while (server_continue) { fd_set read_fds; struct timeval timeout; int res; int i; int max_fd = NPServer.Socket; #ifdef __WIN32__ Sleep (0); #endif if (success && !(Settings.Paused && !Settings.FrameAdvance) && !Settings.StopEmulation && !Settings.ForcedPause && !NPServer.Paused) { S9xNPSendHeartBeat (); newPausedState = 0; } else { newPausedState = 1; } if(pausedState != newPausedState) { pausedState = newPausedState; // S9xNPSendServerPause(pausedState); // XXX: doesn't seem to work yet... } do { FD_ZERO (&read_fds); FD_SET (NPServer.Socket, &read_fds); for (i = 0; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].Connected) { FD_SET (NPServer.Clients [i].Socket, &read_fds); if (NPServer.Clients [i].Socket > max_fd) max_fd = NPServer.Clients [i].Socket; } } timeout.tv_sec = 0; timeout.tv_usec = 1000; res = select (max_fd + 1, &read_fds, NULL, NULL, &timeout); if (res > 0) { if (FD_ISSET (NPServer.Socket, &read_fds)) S9xNPAcceptClient (NPServer.Socket, FALSE); for (i = 0; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].Connected && FD_ISSET (NPServer.Clients [i].Socket, &read_fds)) { S9xNPProcessClient (i); } } } } while (res > 0); #ifdef __WIN32__ success = WaitForSingleObject (GUI.ServerTimerSemaphore, 200) == WAIT_OBJECT_0; #else while (gettimeofday (&now, NULL) < 0) ; /* If there is no known "next" frame, initialize it now */ if (next1.tv_sec == 0) { next1 = now; ++next1.tv_usec; } success=FALSE; if (timercmp(&next1, &now, >)) { /* If we're ahead of time, sleep a while */ unsigned timeleft = (next1.tv_sec - now.tv_sec) * 1000000 + next1.tv_usec - now.tv_usec; usleep(timeleft<(200*1000)?timeleft:(200*1000)); } if (!timercmp(&next1, &now, >)) { /* Calculate the timestamp of the next frame. */ next1.tv_usec += Settings.FrameTime; if (next1.tv_usec >= 1000000) { next1.tv_sec += next1.tv_usec / 1000000; next1.tv_usec %= 1000000; } success=TRUE; } #endif while (NPServer.TaskHead != NPServer.TaskTail) { void *task_data = NPServer.TaskQueue [NPServer.TaskHead].Data; #if defined(NP_DEBUG) && NP_DEBUG == 2 printf ("SERVER: task %d @%ld\n", NPServer.TaskQueue [NPServer.TaskHead].Task, S9xGetMilliTime () - START); #endif switch (NPServer.TaskQueue [NPServer.TaskHead].Task) { case NP_SERVER_SEND_ROM_IMAGE: S9xNPSendROMImageToAllClients (); break; case NP_SERVER_SYNC_CLIENT: NPServer.Clients [(pint) task_data].Ready = FALSE; S9xNPRecomputePause (); S9xNPSyncClient ((pint) task_data); break; case NP_SERVER_SYNC_ALL: S9xNPSyncClients (); break; case NP_SERVER_SEND_FREEZE_FILE_ALL: S9xNPSendFreezeFileToAllClients ((char *) task_data); free ((char *) task_data); break; case NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL: S9xNPSendROMLoadRequest ((char *) task_data); free ((char *) task_data); break; case NP_SERVER_RESET_ALL: S9xNPNoClientReady (0); S9xNPWaitForEmulationToComplete (); S9xNPSetAction ("SERVER: Sending RESET to all clients...", TRUE); #ifdef NP_DEBUG printf ("SERVER: Sending RESET to all clients @%ld\n", S9xGetMilliTime () - START); #endif { uint8 reset [7]; uint8 *ptr; ptr = reset; *ptr++ = NP_SERV_MAGIC; *ptr++ = 0; *ptr++ = NP_SERV_RESET; WRITE_LONG (ptr, NPServer.FrameCount); S9xNPSendToAllClients (reset, 7); } S9xNPSetAction ("", TRUE); break; case NP_SERVER_SEND_SRAM: NPServer.Clients [(pint) task_data].Ready = FALSE; S9xNPRecomputePause (); S9xNPWaitForEmulationToComplete (); S9xNPSendSRAMToClient ((pint) task_data); break; case NP_SERVER_SEND_SRAM_ALL: S9xNPNoClientReady (); S9xNPWaitForEmulationToComplete (); S9xNPSendSRAMToAllClients (); break; default: S9xNPSetError ("SERVER: *** Unknown task ***\n"); break; } NPServer.TaskHead = (NPServer.TaskHead + 1) % NP_MAX_TASKS; } } #ifdef NP_DEBUG printf ("SERVER: Server thread exiting @%ld\n", S9xGetMilliTime () - START); #endif // OV2: S9xNPStopServer has already been called if we get here // S9xNPStopServer (); } bool8 S9xNPStartServer (int port) { static int p; #ifdef NP_DEBUG printf ("SERVER: Starting server on port %d @%ld\n", port, S9xGetMilliTime () - START); #endif p = port; server_continue = TRUE; if (S9xNPServerInit (port)) #ifdef __WIN32__ return (_beginthread (S9xNPServerLoop, 0, &p) != (uintptr_t)(~0)); #else S9xNPServerLoop(NULL); return (TRUE); #endif return (FALSE); } void S9xNPStopServer () { #ifdef NP_DEBUG printf ("SERVER: Stopping server @%ld\n", S9xGetMilliTime () - START); #endif server_continue = FALSE; close (NPServer.Socket); for (int i = 0; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].Connected) S9xNPShutdownClient(i, FALSE); } } #ifdef __WIN32__ void S9xGetTimeOfDay (struct timeval *n) { unsigned long t = S9xGetMilliTime (); n->tv_sec = t / 1000; n->tv_usec = (t % 1000) * 1000; } #endif void S9xNPSendROMImageToAllClients () { S9xNPNoClientReady (); S9xNPWaitForEmulationToComplete (); int c; for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) { if (NPServer.Clients [c].SaidHello) S9xNPSendROMImageToClient (c); } if (NPServer.SyncByReset) { S9xNPServerAddTask (NP_SERVER_SEND_SRAM_ALL, 0); S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); } else S9xNPSyncClient (-1); } bool8 S9xNPSendROMImageToClient (int c) { #ifdef NP_DEBUG printf ("SERVER: Sending ROM image to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); #endif sprintf (NetPlay.ActionMsg, "Sending ROM image to player %d...", c + 1); S9xNPSetAction (NetPlay.ActionMsg, TRUE); uint8 header [7 + 1 + 4]; uint8 *ptr = header; int len = sizeof (header) + Memory.CalculatedSize + strlen (Memory.ROMFilename) + 1; *ptr++ = NP_SERV_MAGIC; *ptr++ = NPServer.Clients [c].SendSequenceNum++; *ptr++ = NP_SERV_ROM_IMAGE; WRITE_LONG (ptr, len); ptr += 4; *ptr++ = Memory.HiROM; WRITE_LONG (ptr, Memory.CalculatedSize); if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, sizeof (header)) || !S9xNPSSendData (NPServer.Clients [c].Socket, Memory.ROM, Memory.CalculatedSize) || !S9xNPSSendData (NPServer.Clients [c].Socket, (uint8 *) Memory.ROMFilename, strlen (Memory.ROMFilename) + 1)) { S9xNPShutdownClient (c, TRUE); return (FALSE); } return (TRUE); } void S9xNPSyncClients () { S9xNPNoClientReady (); S9xNPSyncClient (-1); } void S9xNPSyncClient (int client) { #ifdef HAVE_MKSTEMP char fname[] = "/tmp/snes9x_fztmpXXXXXX"; int fd=-1; #else char fname [L_tmpnam]; #endif S9xNPWaitForEmulationToComplete (); S9xNPSetAction ("SERVER: Freezing game...", TRUE); #ifdef HAVE_MKSTEMP if ( ((fd=mkstemp(fname)) >= 0) && S9xFreezeGame(fname) ) #else if ( tmpnam(fname) && S9xFreezeGame(fname) ) #endif { uint8 *data; uint32 len; S9xNPSetAction ("SERVER: Loading freeze file...", TRUE); if (S9xNPLoadFreezeFile (fname, data, len)) { int c; if (client < 0) { for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) { if (NPServer.Clients [c].SaidHello) { NPServer.Clients [c].Ready = FALSE; S9xNPRecomputePause (); S9xNPSendFreezeFile (c, data, len); } } } else { NPServer.Clients [client].Ready = FALSE; S9xNPRecomputePause (); S9xNPSendFreezeFile (client, data, len); } delete data; } remove (fname); } #ifdef HAVE_MKSTEMP if (fd != -1) close(fd); #endif } bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len) { FILE *ff; if ((ff = fopen (fname, "rb"))) { fseek (ff, 0, SEEK_END); len = ftell (ff); fseek (ff, 0, SEEK_SET); data = new uint8 [len]; bool8 ok = (fread (data, 1, len, ff) == len); fclose (ff); return (ok); } return (FALSE); } void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len) { #ifdef NP_DEBUG printf ("SERVER: Sending freeze file to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); #endif sprintf (NetPlay.ActionMsg, "SERVER: Sending freeze-file to player %d...", c + 1); S9xNPSetAction (NetPlay.ActionMsg, TRUE); uint8 header [7 + 4]; uint8 *ptr = header; *ptr++ = NP_SERV_MAGIC; *ptr++ = NPServer.Clients [c].SendSequenceNum++; *ptr++ = NP_SERV_FREEZE_FILE; WRITE_LONG (ptr, len + 7 + 4); ptr += 4; WRITE_LONG (ptr, NPServer.FrameCount); if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, 7 + 4) || !S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) { S9xNPShutdownClient (c, TRUE); } S9xNPSetAction ("", TRUE); } void S9xNPRecomputePause () { int c; for (c = 0; c < NP_MAX_CLIENTS; c++) { if (NPServer.Clients [c].SaidHello && (!NPServer.Clients [c].Ready || NPServer.Clients [c].Paused)) { #if defined(NP_DEBUG) && NP_DEBUG == 2 printf ("SERVER: Paused because of client %d (%d,%d) @%ld\n", c, NPServer.Clients [c].Ready, NPServer.Clients [c].Paused, S9xGetMilliTime () - START); #endif NPServer.Paused = TRUE; return; } } #if defined(NP_DEBUG) && NP_DEBUG == 2 printf ("SERVER: not paused @%ld\n", S9xGetMilliTime () - START); #endif NPServer.Paused = FALSE; } void S9xNPNoClientReady (int start_index) { int c; for (c = start_index; c < NP_MAX_CLIENTS; c++) NPServer.Clients [c].Ready = FALSE; S9xNPRecomputePause (); } void S9xNPSendROMLoadRequest (const char *filename) { S9xNPNoClientReady (); int len = 7 + strlen (filename) + 1; uint8 *data = new uint8 [len]; uint8 *ptr = data; *ptr++ = NP_SERV_MAGIC; *ptr++ = 0; *ptr++ = NP_SERV_LOAD_ROM; WRITE_LONG (ptr, len); ptr += 4; strcpy ((char *) ptr, filename); for (int i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].SaidHello) { #ifdef NP_DEBUG printf ("SERVER: Sending load ROM requesting to player %d @%ld\n", i + 1, S9xGetMilliTime () - START); #endif sprintf (NetPlay.WarningMsg, "SERVER: sending ROM load request to player %d...", i + 1); S9xNPSetAction (NetPlay.WarningMsg, TRUE); data [1] = NPServer.Clients [i].SendSequenceNum++; if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) { S9xNPShutdownClient (i, TRUE); } } } delete[] data; } void S9xNPSendSRAMToAllClients () { int i; for (i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].SaidHello) S9xNPSendSRAMToClient (i); } } void S9xNPSendSRAMToClient (int c) { #ifdef NP_DEBUG printf ("SERVER: Sending S-RAM data to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); #endif uint8 sram [7]; int SRAMSize = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0; if (SRAMSize > 0x10000) SRAMSize = 0x10000; int len = 7 + SRAMSize; sprintf (NetPlay.ActionMsg, "SERVER: Sending S-RAM to player %d...", c + 1); S9xNPSetAction (NetPlay.ActionMsg, TRUE); uint8 *ptr = sram; *ptr++ = NP_SERV_MAGIC; *ptr++ = NPServer.Clients [c].SendSequenceNum++; *ptr++ = NP_SERV_SRAM_DATA; WRITE_LONG (ptr, len); if (!S9xNPSSendData (NPServer.Clients [c].Socket, sram, sizeof (sram)) || (len > 7 && !S9xNPSSendData (NPServer.Clients [c].Socket, Memory.SRAM, len - 7))) { S9xNPShutdownClient (c, TRUE); } } void S9xNPSendFreezeFileToAllClients (const char *filename) { uint8 *data; uint32 len; if (NPServer.NumClients > NP_ONE_CLIENT && S9xNPLoadFreezeFile (filename, data, len)) { S9xNPNoClientReady (); for (int c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) { if (NPServer.Clients [c].SaidHello) S9xNPSendFreezeFile (c, data, len); } delete data; } } void S9xNPServerAddTask (uint32 task, void *data) { NPServer.TaskQueue [NPServer.TaskTail].Task = task; NPServer.TaskQueue [NPServer.TaskTail].Data = data; NPServer.TaskTail = (NPServer.TaskTail + 1) % NP_MAX_TASKS; } void S9xNPReset () { S9xNPNoClientReady (0); S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); } void S9xNPWaitForEmulationToComplete () { #ifdef NP_DEBUG printf ("SERVER: WaitForEmulationToComplete start @%ld\n", S9xGetMilliTime () - START); #endif while (!NetPlay.PendingWait4Sync && NetPlay.Connected && !Settings.ForcedPause && !Settings.StopEmulation && !(Settings.Paused && !Settings.FrameAdvance)) { #ifdef __WIN32__ Sleep (40); #endif } #ifdef NP_DEBUG printf ("SERVER: WaitForEmulationToComplete end @%ld\n", S9xGetMilliTime () - START); #endif } void S9xNPServerQueueSyncAll () { if (Settings.NetPlay && Settings.NetPlayServer && NPServer.NumClients > NP_ONE_CLIENT) { S9xNPNoClientReady (); S9xNPDiscardHeartbeats (); S9xNPServerAddTask (NP_SERVER_SYNC_ALL, 0); } } void S9xNPServerQueueSendingROMImage () { if (Settings.NetPlay && Settings.NetPlayServer && NPServer.NumClients > NP_ONE_CLIENT) { S9xNPNoClientReady (); S9xNPDiscardHeartbeats (); S9xNPServerAddTask (NP_SERVER_SEND_ROM_IMAGE, 0); } } void S9xNPServerQueueSendingFreezeFile (const char *filename) { if (Settings.NetPlay && Settings.NetPlayServer && NPServer.NumClients > NP_ONE_CLIENT) { S9xNPNoClientReady (); S9xNPDiscardHeartbeats (); S9xNPServerAddTask (NP_SERVER_SEND_FREEZE_FILE_ALL, (void *) strdup (filename)); } } void S9xNPServerQueueSendingLoadROMRequest (const char *filename) { if (Settings.NetPlay && Settings.NetPlayServer && NPServer.NumClients > NP_ONE_CLIENT) { S9xNPNoClientReady (); S9xNPDiscardHeartbeats (); S9xNPServerAddTask (NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL, (void *) strdup (filename)); } } #ifndef __WIN32__ uint32 S9xGetMilliTime () { static bool8 first = TRUE; static long start_sec; struct timeval tv; gettimeofday (&tv, NULL); if (first) { start_sec = tv.tv_sec; first = FALSE; } return ((uint32) ((tv.tv_sec - start_sec) * 1000 + tv.tv_usec / 1000)); } #endif #endif pixform.h000664 001750 001750 00000037335 12720446475 013565 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _PIXFORM_H_ #define _PIXFORM_H_ #ifdef GFX_MULTI_FORMAT enum { RGB565, RGB555, BGR565, BGR555, GBR565, GBR555, RGB5551 }; #define BUILD_PIXEL(R, G, B) ((*GFX.BuildPixel) (R, G, B)) #define BUILD_PIXEL2(R, G, B) ((*GFX.BuildPixel2) (R, G, B)) #define DECOMPOSE_PIXEL(PIX, R, G, B) ((*GFX.DecomposePixel) (PIX, R, G, B)) extern uint32 MAX_RED; extern uint32 MAX_GREEN; extern uint32 MAX_BLUE; extern uint32 RED_LOW_BIT_MASK; extern uint32 GREEN_LOW_BIT_MASK; extern uint32 BLUE_LOW_BIT_MASK; extern uint32 RED_HI_BIT_MASK; extern uint32 GREEN_HI_BIT_MASK; extern uint32 BLUE_HI_BIT_MASK; extern uint32 FIRST_COLOR_MASK; extern uint32 SECOND_COLOR_MASK; extern uint32 THIRD_COLOR_MASK; extern uint32 ALPHA_BITS_MASK; extern uint32 GREEN_HI_BIT; extern uint32 RGB_LOW_BITS_MASK; extern uint32 RGB_HI_BITS_MASK; extern uint32 RGB_HI_BITS_MASKx2; extern uint32 RGB_REMOVE_LOW_BITS_MASK; extern uint32 FIRST_THIRD_COLOR_MASK; extern uint32 TWO_LOW_BITS_MASK; extern uint32 HIGH_BITS_SHIFTED_TWO_MASK; extern uint32 SPARE_RGB_BIT_MASK; #endif /* RGB565 format */ #define BUILD_PIXEL_RGB565(R, G, B) (((int) (R) << 11) | ((int) (G) << 6) | (int) (B)) #define BUILD_PIXEL2_RGB565(R, G, B) (((int) (R) << 11) | ((int) (G) << 5) | (int) (B)) #define DECOMPOSE_PIXEL_RGB565(PIX, R, G, B) { (R) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (B) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_RGB565 (1 << 5) #define MAX_RED_RGB565 31 #define MAX_GREEN_RGB565 63 #define MAX_BLUE_RGB565 31 #define RED_LOW_BIT_MASK_RGB565 0x0800 #define GREEN_LOW_BIT_MASK_RGB565 0x0020 #define BLUE_LOW_BIT_MASK_RGB565 0x0001 #define RED_HI_BIT_MASK_RGB565 0x8000 #define GREEN_HI_BIT_MASK_RGB565 0x0400 #define BLUE_HI_BIT_MASK_RGB565 0x0010 #define FIRST_COLOR_MASK_RGB565 0xF800 #define SECOND_COLOR_MASK_RGB565 0x07E0 #define THIRD_COLOR_MASK_RGB565 0x001F #define ALPHA_BITS_MASK_RGB565 0x0000 /* RGB555 format */ #define BUILD_PIXEL_RGB555(R, G, B) (((int) (R) << 10) | ((int) (G) << 5) | (int) (B)) #define BUILD_PIXEL2_RGB555(R, G, B) (((int) (R) << 10) | ((int) (G) << 5) | (int) (B)) #define DECOMPOSE_PIXEL_RGB555(PIX, R, G, B) { (R) = (PIX) >> 10; (G) = ((PIX) >> 5) & 0x1f; (B) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_RGB555 (1 << 15) #define MAX_RED_RGB555 31 #define MAX_GREEN_RGB555 31 #define MAX_BLUE_RGB555 31 #define RED_LOW_BIT_MASK_RGB555 0x0400 #define GREEN_LOW_BIT_MASK_RGB555 0x0020 #define BLUE_LOW_BIT_MASK_RGB555 0x0001 #define RED_HI_BIT_MASK_RGB555 0x4000 #define GREEN_HI_BIT_MASK_RGB555 0x0200 #define BLUE_HI_BIT_MASK_RGB555 0x0010 #define FIRST_COLOR_MASK_RGB555 0x7C00 #define SECOND_COLOR_MASK_RGB555 0x03E0 #define THIRD_COLOR_MASK_RGB555 0x001F #define ALPHA_BITS_MASK_RGB555 0x0000 /* BGR565 format */ #define BUILD_PIXEL_BGR565(R, G, B) (((int) (B) << 11) | ((int) (G) << 6) | (int) (R)) #define BUILD_PIXEL2_BGR565(R, G, B) (((int) (B) << 11) | ((int) (G) << 5) | (int) (R)) #define DECOMPOSE_PIXEL_BGR565(PIX, R, G, B) { (B) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (R) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_BGR565 (1 << 5) #define MAX_RED_BGR565 31 #define MAX_GREEN_BGR565 63 #define MAX_BLUE_BGR565 31 #define RED_LOW_BIT_MASK_BGR565 0x0001 #define GREEN_LOW_BIT_MASK_BGR565 0x0040 #define BLUE_LOW_BIT_MASK_BGR565 0x0800 #define RED_HI_BIT_MASK_BGR565 0x0010 #define GREEN_HI_BIT_MASK_BGR565 0x0400 #define BLUE_HI_BIT_MASK_BGR565 0x8000 #define FIRST_COLOR_MASK_BGR565 0xF800 #define SECOND_COLOR_MASK_BGR565 0x07E0 #define THIRD_COLOR_MASK_BGR565 0x001F #define ALPHA_BITS_MASK_BGR565 0x0000 /* BGR555 format */ #define BUILD_PIXEL_BGR555(R, G, B) (((int) (B) << 10) | ((int) (G) << 5) | (int) (R)) #define BUILD_PIXEL2_BGR555(R, G, B) (((int) (B) << 10) | ((int) (G) << 5) | (int) (R)) #define DECOMPOSE_PIXEL_BGR555(PIX, R, G, B) { (B) = (PIX) >> 10; (G) = ((PIX) >> 5) & 0x1f; (R) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_BGR555 (1 << 15) #define MAX_RED_BGR555 31 #define MAX_GREEN_BGR555 31 #define MAX_BLUE_BGR555 31 #define RED_LOW_BIT_MASK_BGR555 0x0001 #define GREEN_LOW_BIT_MASK_BGR555 0x0020 #define BLUE_LOW_BIT_MASK_BGR555 0x0400 #define RED_HI_BIT_MASK_BGR555 0x0010 #define GREEN_HI_BIT_MASK_BGR555 0x0200 #define BLUE_HI_BIT_MASK_BGR555 0x4000 #define FIRST_COLOR_MASK_BGR555 0x7C00 #define SECOND_COLOR_MASK_BGR555 0x03E0 #define THIRD_COLOR_MASK_BGR555 0x001F #define ALPHA_BITS_MASK_BGR555 0x0000 /* GBR565 format */ #define BUILD_PIXEL_GBR565(R, G, B) (((int) (G) << 11) | ((int) (B) << 6) | (int) (R)) #define BUILD_PIXEL2_GBR565(R, G, B) (((int) (G) << 11) | ((int) (B) << 5) | (int) (R)) #define DECOMPOSE_PIXEL_GBR565(PIX, R, G, B) { (G) = (PIX) >> 11; (B) = ((PIX) >> 6) & 0x1f; (R) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_GBR565 (1 << 5) #define MAX_RED_GBR565 31 #define MAX_GREEN_GBR565 31 #define MAX_BLUE_GBR565 63 #define RED_LOW_BIT_MASK_GBR565 0x0001 #define GREEN_LOW_BIT_MASK_GBR565 0x0800 #define BLUE_LOW_BIT_MASK_GBR565 0x0040 #define RED_HI_BIT_MASK_GBR565 0x0010 #define GREEN_HI_BIT_MASK_GBR565 0x8000 #define BLUE_HI_BIT_MASK_GBR565 0x0400 #define FIRST_COLOR_MASK_GBR565 0xF800 #define SECOND_COLOR_MASK_GBR565 0x07E0 #define THIRD_COLOR_MASK_GBR565 0x001F #define ALPHA_BITS_MASK_GBR565 0x0000 /* GBR555 format */ #define BUILD_PIXEL_GBR555(R, G, B) (((int) (G) << 10) | ((int) (B) << 5) | (int) (R)) #define BUILD_PIXEL2_GBR555(R, G, B) (((int) (G) << 10) | ((int) (B) << 5) | (int) (R)) #define DECOMPOSE_PIXEL_GBR555(PIX, R, G, B) { (G) = (PIX) >> 10; (B) = ((PIX) >> 5) & 0x1f; (R) = (PIX) & 0x1f; } #define SPARE_RGB_BIT_MASK_GBR555 (1 << 15) #define MAX_RED_GBR555 31 #define MAX_GREEN_GBR555 31 #define MAX_BLUE_GBR555 31 #define RED_LOW_BIT_MASK_GBR555 0x0001 #define GREEN_LOW_BIT_MASK_GBR555 0x0400 #define BLUE_LOW_BIT_MASK_GBR555 0x0020 #define RED_HI_BIT_MASK_GBR555 0x0010 #define GREEN_HI_BIT_MASK_GBR555 0x4000 #define BLUE_HI_BIT_MASK_GBR555 0x0200 #define FIRST_COLOR_MASK_GBR555 0x7C00 #define SECOND_COLOR_MASK_GBR555 0x03E0 #define THIRD_COLOR_MASK_GBR555 0x001F #define ALPHA_BITS_MASK_GBR555 0x0000 /* RGB5551 format */ #define BUILD_PIXEL_RGB5551(R, G, B) (((int) (R) << 11) | ((int) (G) << 6) | (int) ((B) << 1) | 1) #define BUILD_PIXEL2_RGB5551(R, G, B) (((int) (R) << 11) | ((int) (G) << 6) | (int) ((B) << 1) | 1) #define DECOMPOSE_PIXEL_RGB5551(PIX, R, G, B) { (R) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (B) = ((PIX) >> 1) & 0x1f; } #define SPARE_RGB_BIT_MASK_RGB5551 (1) #define MAX_RED_RGB5551 31 #define MAX_GREEN_RGB5551 31 #define MAX_BLUE_RGB5551 31 #define RED_LOW_BIT_MASK_RGB5551 0x0800 #define GREEN_LOW_BIT_MASK_RGB5551 0x0040 #define BLUE_LOW_BIT_MASK_RGB5551 0x0002 #define RED_HI_BIT_MASK_RGB5551 0x8000 #define GREEN_HI_BIT_MASK_RGB5551 0x0400 #define BLUE_HI_BIT_MASK_RGB5551 0x0020 #define FIRST_COLOR_MASK_RGB5551 0xf800 #define SECOND_COLOR_MASK_RGB5551 0x07c0 #define THIRD_COLOR_MASK_RGB5551 0x003e #define ALPHA_BITS_MASK_RGB5551 0x0001 #ifndef GFX_MULTI_FORMAT #define CONCAT(X, Y) X##Y // C pre-processor needs a two stage macro define to enable it to concat // to macro names together to form the name of another macro. #define BUILD_PIXEL_D(F, R, G, B) CONCAT(BUILD_PIXEL_,F) (R, G, B) #define BUILD_PIXEL2_D(F, R, G, B) CONCAT(BUILD_PIXEL2_,F) (R, G, B) #define DECOMPOSE_PIXEL_D(F, PIX, R, G, B) CONCAT(DECOMPOSE_PIXEL_,F) (PIX, R, G, B) #define BUILD_PIXEL(R, G, B) BUILD_PIXEL_D(PIXEL_FORMAT, R, G, B) #define BUILD_PIXEL2(R, G, B) BUILD_PIXEL2_D(PIXEL_FORMAT, R, G, B) #define DECOMPOSE_PIXEL(PIX, R, G, B) DECOMPOSE_PIXEL_D(PIXEL_FORMAT, PIX, R, G, B) #define MAX_RED_D(F) CONCAT(MAX_RED_, F) #define MAX_GREEN_D(F) CONCAT(MAX_GREEN_, F) #define MAX_BLUE_D(F) CONCAT(MAX_BLUE_, F) #define RED_LOW_BIT_MASK_D(F) CONCAT(RED_LOW_BIT_MASK_, F) #define GREEN_LOW_BIT_MASK_D(F) CONCAT(GREEN_LOW_BIT_MASK_, F) #define BLUE_LOW_BIT_MASK_D(F) CONCAT(BLUE_LOW_BIT_MASK_, F) #define RED_HI_BIT_MASK_D(F) CONCAT(RED_HI_BIT_MASK_, F) #define GREEN_HI_BIT_MASK_D(F) CONCAT(GREEN_HI_BIT_MASK_, F) #define BLUE_HI_BIT_MASK_D(F) CONCAT(BLUE_HI_BIT_MASK_, F) #define FIRST_COLOR_MASK_D(F) CONCAT(FIRST_COLOR_MASK_, F) #define SECOND_COLOR_MASK_D(F) CONCAT(SECOND_COLOR_MASK_, F) #define THIRD_COLOR_MASK_D(F) CONCAT(THIRD_COLOR_MASK_, F) #define ALPHA_BITS_MASK_D(F) CONCAT(ALPHA_BITS_MASK_, F) #define MAX_RED MAX_RED_D(PIXEL_FORMAT) #define MAX_GREEN MAX_GREEN_D(PIXEL_FORMAT) #define MAX_BLUE MAX_BLUE_D(PIXEL_FORMAT) #define RED_LOW_BIT_MASK RED_LOW_BIT_MASK_D(PIXEL_FORMAT) #define GREEN_LOW_BIT_MASK GREEN_LOW_BIT_MASK_D(PIXEL_FORMAT) #define BLUE_LOW_BIT_MASK BLUE_LOW_BIT_MASK_D(PIXEL_FORMAT) #define RED_HI_BIT_MASK RED_HI_BIT_MASK_D(PIXEL_FORMAT) #define GREEN_HI_BIT_MASK GREEN_HI_BIT_MASK_D(PIXEL_FORMAT) #define BLUE_HI_BIT_MASK BLUE_HI_BIT_MASK_D(PIXEL_FORMAT) #define FIRST_COLOR_MASK FIRST_COLOR_MASK_D(PIXEL_FORMAT) #define SECOND_COLOR_MASK SECOND_COLOR_MASK_D(PIXEL_FORMAT) #define THIRD_COLOR_MASK THIRD_COLOR_MASK_D(PIXEL_FORMAT) #define ALPHA_BITS_MASK ALPHA_BITS_MASK_D(PIXEL_FORMAT) #define GREEN_HI_BIT ((MAX_GREEN + 1) >> 1) #define RGB_LOW_BITS_MASK (RED_LOW_BIT_MASK | GREEN_LOW_BIT_MASK | BLUE_LOW_BIT_MASK) #define RGB_HI_BITS_MASK (RED_HI_BIT_MASK | GREEN_HI_BIT_MASK | BLUE_HI_BIT_MASK) #define RGB_HI_BITS_MASKx2 ((RED_HI_BIT_MASK | GREEN_HI_BIT_MASK | BLUE_HI_BIT_MASK) << 1) #define RGB_REMOVE_LOW_BITS_MASK (~RGB_LOW_BITS_MASK) #define FIRST_THIRD_COLOR_MASK (FIRST_COLOR_MASK | THIRD_COLOR_MASK) #define TWO_LOW_BITS_MASK (RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1)) #define HIGH_BITS_SHIFTED_TWO_MASK (((FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & ~TWO_LOW_BITS_MASK ) >> 2) #endif #endif stream.cpp000664 001750 001750 00000027343 12720446475 013725 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ // Abstract the details of reading from zip files versus FILE *'s. #include #ifdef UNZIP_SUPPORT #include "unzip.h" #endif #include "snes9x.h" #include "stream.h" // Generic constructor/destructor Stream::Stream (void) { return; } Stream::~Stream (void) { return; } // Generic getline function, based on gets. Reimlpement if you can do better. char * Stream::getline (void) { bool eof; std::string ret; ret = getline(eof); if (ret.size() == 0 && eof) return (NULL); return (strdup(ret.c_str())); } std::string Stream::getline (bool &eof) { char buf[1024]; std::string ret; eof = false; ret.clear(); do { if (gets(buf, sizeof(buf)) == NULL) { eof = true; break; } ret.append(buf); } while (*ret.rbegin() != '\n'); return (ret); } // snes9x.h FSTREAM Stream fStream::fStream (FSTREAM f) { fp = f; } fStream::~fStream (void) { return; } int fStream::get_char (void) { return (GETC_FSTREAM(fp)); } char * fStream::gets (char *buf, size_t len) { return (GETS_FSTREAM(buf, len, fp)); } size_t fStream::read (void *buf, size_t len) { return (READ_FSTREAM(buf, len, fp)); } size_t fStream::write (void *buf, size_t len) { return (WRITE_FSTREAM(buf, len, fp)); } size_t fStream::pos (void) { return (FIND_FSTREAM(fp)); } size_t fStream::size (void) { size_t sz; REVERT_FSTREAM(fp,0L,SEEK_END); sz = FIND_FSTREAM(fp); REVERT_FSTREAM(fp,0L,SEEK_SET); return sz; } int fStream::revert (size_t from, size_t offset) { return (REVERT_FSTREAM(fp, offset, from)); } void fStream::closeStream() { CLOSE_FSTREAM(fp); delete this; } // unzip Stream #ifdef UNZIP_SUPPORT unzStream::unzStream (unzFile &v) { file = v; head = NULL; numbytes = 0; } unzStream::~unzStream (void) { return; } int unzStream::get_char (void) { unsigned char c; if (numbytes <= 0) { numbytes = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); if (numbytes <= 0) return (EOF); head = buffer; } c = *head; head++; numbytes--; return ((int) c); } char * unzStream::gets (char *buf, size_t len) { size_t i; int c; for (i = 0; i < len - 1; i++) { c = get_char(); if (c == EOF) { if (i == 0) return (NULL); break; } buf[i] = (char) c; if (buf[i] == '\n') break; } buf[i] = '\0'; return (buf); } size_t unzStream::read (void *buf, size_t len) { if (len == 0) return (len); if (len <= numbytes) { memcpy(buf, head, len); numbytes -= len; head += len; return (len); } size_t numread = 0; if (numbytes > 0) { memcpy(buf, head, numbytes); numread += numbytes; head = NULL; numbytes = 0; } int l = unzReadCurrentFile(file, (uint8 *)buf + numread, len - numread); if (l > 0) numread += l; return (numread); } // not supported size_t unzStream::write (void *buf, size_t len) { return (0); } size_t unzStream::pos (void) { return (unztell(file)); } size_t unzStream::size (void) { unz_file_info info; unzGetCurrentFileInfo(file,&info,NULL,0,NULL,0,NULL,0); return info.uncompressed_size; } // not supported int unzStream::revert (size_t from, size_t offset) { return -1; } void unzStream::closeStream() { unzCloseCurrentFile(file); delete this; } #endif // memory Stream memStream::memStream (uint8 *source, size_t sourceSize) { mem = head = source; msize = remaining = sourceSize; readonly = false; } memStream::memStream (const uint8 *source, size_t sourceSize) { mem = head = const_cast(source); msize = remaining = sourceSize; readonly = true; } memStream::~memStream (void) { return; } int memStream::get_char (void) { if(!remaining) return EOF; remaining--; return *head++; } char * memStream::gets (char *buf, size_t len) { size_t i; int c; for (i = 0; i < len - 1; i++) { c = get_char(); if (c == EOF) { if (i == 0) return (NULL); break; } buf[i] = (char) c; if (buf[i] == '\n') break; } buf[i] = '\0'; return (buf); } size_t memStream::read (void *buf, size_t len) { size_t bytes = len < remaining ? len : remaining; memcpy(buf,head,bytes); head += bytes; remaining -= bytes; return bytes; } size_t memStream::write (void *buf, size_t len) { if(readonly) return 0; size_t bytes = len < remaining ? len : remaining; memcpy(head,buf,bytes); head += bytes; remaining -= bytes; return bytes; } size_t memStream::pos (void) { return msize - remaining; } size_t memStream::size (void) { return msize; } int memStream::revert (size_t from, size_t offset) { size_t pos = from + offset; if(pos > msize) return -1; head = mem + pos; remaining = msize - pos; return 0; } void memStream::closeStream() { delete [] mem; delete this; } // dummy Stream nulStream::nulStream (void) { bytes_written = 0; } nulStream::~nulStream (void) { return; } int nulStream::get_char (void) { return 0; } char * nulStream::gets (char *buf, size_t len) { *buf = '\0'; return NULL; } size_t nulStream::read (void *buf, size_t len) { return 0; } size_t nulStream::write (void *buf, size_t len) { bytes_written += len; return len; } size_t nulStream::pos (void) { return 0; } size_t nulStream::size (void) { return bytes_written; } int nulStream::revert (size_t from, size_t offset) { bytes_written = from + offset; return 0; } void nulStream::closeStream() { delete this; } Stream *openStreamFromFSTREAM(const char* filename, const char* mode) { FSTREAM f = OPEN_FSTREAM(filename,mode); if(!f) return NULL; return new fStream(f); } Stream *reopenStreamFromFd(int fd, const char* mode) { FSTREAM f = REOPEN_FSTREAM(fd,mode); if(!f) return NULL; return new fStream(f); } gfx.h000664 001750 001750 00000025200 12720446475 012651 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _GFX_H_ #define _GFX_H_ struct SGFX { uint16 *Screen; uint16 *SubScreen; uint8 *ZBuffer; uint8 *SubZBuffer; uint32 Pitch; uint32 ScreenSize; uint16 *S; uint8 *DB; uint16 *X2; uint16 *ZERO; uint32 RealPPL; // true PPL of Screen buffer uint32 PPL; // number of pixels on each of Screen buffer uint32 LinesPerTile; // number of lines in 1 tile (4 or 8 due to interlace) uint16 *ScreenColors; // screen colors for rendering main uint16 *RealScreenColors; // screen colors, ignoring color window clipping uint8 Z1; // depth for comparison uint8 Z2; // depth to save uint32 FixedColour; uint8 DoInterlace; uint8 InterlaceFrame; uint32 StartY; uint32 EndY; bool8 ClipColors; uint8 OBJWidths[128]; uint8 OBJVisibleTiles[128]; struct ClipData *Clip; struct { uint8 RTOFlags; int16 Tiles; struct { int8 Sprite; uint8 Line; } OBJ[32]; } OBJLines[SNES_HEIGHT_EXTENDED]; #ifdef GFX_MULTI_FORMAT uint32 PixelFormat; uint32 (*BuildPixel) (uint32, uint32, uint32); uint32 (*BuildPixel2) (uint32, uint32, uint32); void (*DecomposePixel) (uint32, uint32 &, uint32 &, uint32 &); #endif void (*DrawBackdropMath) (uint32, uint32, uint32); void (*DrawBackdropNomath) (uint32, uint32, uint32); void (*DrawTileMath) (uint32, uint32, uint32, uint32); void (*DrawTileNomath) (uint32, uint32, uint32, uint32); void (*DrawClippedTileMath) (uint32, uint32, uint32, uint32, uint32, uint32); void (*DrawClippedTileNomath) (uint32, uint32, uint32, uint32, uint32, uint32); void (*DrawMosaicPixelMath) (uint32, uint32, uint32, uint32, uint32, uint32); void (*DrawMosaicPixelNomath) (uint32, uint32, uint32, uint32, uint32, uint32); void (*DrawMode7BG1Math) (uint32, uint32, int); void (*DrawMode7BG1Nomath) (uint32, uint32, int); void (*DrawMode7BG2Math) (uint32, uint32, int); void (*DrawMode7BG2Nomath) (uint32, uint32, int); const char *InfoString; uint32 InfoStringTimeout; char FrameDisplayString[256]; }; struct SBG { uint8 (*ConvertTile) (uint8 *, uint32, uint32); uint8 (*ConvertTileFlip) (uint8 *, uint32, uint32); uint32 TileSizeH; uint32 TileSizeV; uint32 OffsetSizeH; uint32 OffsetSizeV; uint32 TileShift; uint32 TileAddress; uint32 NameSelect; uint32 SCBase; uint32 StartPalette; uint32 PaletteShift; uint32 PaletteMask; uint8 EnableMath; uint8 InterlaceLine; uint8 *Buffer; uint8 *BufferFlip; uint8 *Buffered; uint8 *BufferedFlip; bool8 DirectColourMode; }; struct SLineData { struct { uint16 VOffset; uint16 HOffset; } BG[4]; }; struct SLineMatrixData { short MatrixA; short MatrixB; short MatrixC; short MatrixD; short CentreX; short CentreY; short M7HOFS; short M7VOFS; }; extern uint16 BlackColourMap[256]; extern uint16 DirectColourMaps[8][256]; extern uint8 mul_brightness[16][32]; extern struct SBG BG; extern struct SGFX GFX; #define H_FLIP 0x4000 #define V_FLIP 0x8000 #define BLANK_TILE 2 #define COLOR_ADD1_2(C1, C2) \ ((((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \ ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \ ((C1) & (C2) & RGB_LOW_BITS_MASK)) | ALPHA_BITS_MASK) #define COLOR_ADD(C1, C2) \ (GFX.X2[((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \ ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \ ((C1) & (C2) & RGB_LOW_BITS_MASK)] | \ (((C1) ^ (C2)) & RGB_LOW_BITS_MASK)) #define COLOR_SUB1_2(C1, C2) \ GFX.ZERO[(((C1) | RGB_HI_BITS_MASKx2) - \ ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1] inline uint16 COLOR_SUB (uint16 C1, uint16 C2) { uint16 mC1, mC2, v = ALPHA_BITS_MASK; mC1 = C1 & FIRST_COLOR_MASK; mC2 = C2 & FIRST_COLOR_MASK; if (mC1 > mC2) v += (mC1 - mC2); mC1 = C1 & SECOND_COLOR_MASK; mC2 = C2 & SECOND_COLOR_MASK; if (mC1 > mC2) v += (mC1 - mC2); mC1 = C1 & THIRD_COLOR_MASK; mC2 = C2 & THIRD_COLOR_MASK; if (mC1 > mC2) v += (mC1 - mC2); return (v); } void S9xStartScreenRefresh (void); void S9xEndScreenRefresh (void); void S9xUpdateScreen (void); void S9xBuildDirectColourMaps (void); void RenderLine (uint8); void S9xComputeClipWindows (void); void S9xDisplayChar (uint16 *, uint8); // called automatically unless Settings.AutoDisplayMessages is false void S9xDisplayMessages (uint16 *, int, int, int, int); #ifdef GFX_MULTI_FORMAT bool8 S9xSetRenderPixelFormat (int); #endif // external port interface which must be implemented or initialised for each port bool8 S9xGraphicsInit (void); void S9xGraphicsDeinit (void); bool8 S9xInitUpdate (void); bool8 S9xDeinitUpdate (int, int); bool8 S9xContinueUpdate (int, int); void S9xReRefresh (void); void S9xSetPalette (void); void S9xSyncSpeed (void); // called instead of S9xDisplayString if set to non-NULL extern void (*S9xCustomDisplayString) (const char *, int, int, bool); #endif dsp3.cpp000664 001750 001750 00000076441 12720446475 013306 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" static void (*SetDSP3) (void); static const uint16 DSP3_DataROM[1024] = { 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0000, 0x000f, 0x0400, 0x0200, 0x0140, 0x0400, 0x0200, 0x0040, 0x007d, 0x007e, 0x007e, 0x007b, 0x007c, 0x007d, 0x007b, 0x007c, 0x0002, 0x0020, 0x0030, 0x0000, 0x000d, 0x0019, 0x0026, 0x0032, 0x003e, 0x004a, 0x0056, 0x0062, 0x006d, 0x0079, 0x0084, 0x008e, 0x0098, 0x00a2, 0x00ac, 0x00b5, 0x00be, 0x00c6, 0x00ce, 0x00d5, 0x00dc, 0x00e2, 0x00e7, 0x00ec, 0x00f1, 0x00f5, 0x00f8, 0x00fb, 0x00fd, 0x00ff, 0x0100, 0x0100, 0x0100, 0x00ff, 0x00fd, 0x00fb, 0x00f8, 0x00f5, 0x00f1, 0x00ed, 0x00e7, 0x00e2, 0x00dc, 0x00d5, 0x00ce, 0x00c6, 0x00be, 0x00b5, 0x00ac, 0x00a2, 0x0099, 0x008e, 0x0084, 0x0079, 0x006e, 0x0062, 0x0056, 0x004a, 0x003e, 0x0032, 0x0026, 0x0019, 0x000d, 0x0000, 0xfff3, 0xffe7, 0xffdb, 0xffce, 0xffc2, 0xffb6, 0xffaa, 0xff9e, 0xff93, 0xff87, 0xff7d, 0xff72, 0xff68, 0xff5e, 0xff54, 0xff4b, 0xff42, 0xff3a, 0xff32, 0xff2b, 0xff25, 0xff1e, 0xff19, 0xff14, 0xff0f, 0xff0b, 0xff08, 0xff05, 0xff03, 0xff01, 0xff00, 0xff00, 0xff00, 0xff01, 0xff03, 0xff05, 0xff08, 0xff0b, 0xff0f, 0xff13, 0xff18, 0xff1e, 0xff24, 0xff2b, 0xff32, 0xff3a, 0xff42, 0xff4b, 0xff54, 0xff5d, 0xff67, 0xff72, 0xff7c, 0xff87, 0xff92, 0xff9e, 0xffa9, 0xffb5, 0xffc2, 0xffce, 0xffda, 0xffe7, 0xfff3, 0x002b, 0x007f, 0x0020, 0x00ff, 0xff00, 0xffbe, 0x0000, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0x0045, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc5, 0x0003, 0x0004, 0x0005, 0x0047, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, 0x0009, 0x004a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x004e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0053, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x0059, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x0068, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0071, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x007b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x005d, 0x0000, 0x0000, 0x0000, 0x0000, 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x006b, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0044, 0x0000, 0x0000, 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0054, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0065, 0xffbe, 0x0000, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0xfead, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc5, 0x0003, 0x0004, 0x0005, 0xfeaf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, 0x0009, 0xfeb2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0xfeb6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0xfebb, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0xfec1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0xfec8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0xfed0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0xfed9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0xfee3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0xfeb8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0xfec5, 0x0000, 0x0000, 0x0000, 0x0000, 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0xfed3, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0xfeac, 0x0000, 0x0000, 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0xfebc, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0xfecd, 0x0154, 0x0218, 0x0110, 0x00b0, 0x00cc, 0x00b0, 0x0088, 0x00b0, 0x0044, 0x00b0, 0x0000, 0x00b0, 0x00fe, 0xff07, 0x0002, 0x00ff, 0x00f8, 0x0007, 0x00fe, 0x00ee, 0x07ff, 0x0200, 0x00ef, 0xf800, 0x0700, 0x00ee, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0044, 0x0088, 0x00cc, 0x0110, 0x0154, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; static bool8 DSP3_GetBits (uint8); //static void DSP3_MemorySize (void); static void DSP3_TestMemory (void); static void DSP3_DumpDataROM (void); static void DSP3_MemoryDump (void); static void DSP3_Coordinate (void); static void DSP3_Command (void); static void DSP3_Decode_Data (void); static void DSP3_Decode_Tree (void); static void DSP3_Decode_Symbols (void); static void DSP3_Decode (void); static void DSP3_Decode_A (void); static void DSP3_Convert (void); static void DSP3_Convert_A (void); static void DSP3_OP03 (void); static void DSP3_OP06 (void); static void DSP3_OP07 (void); static void DSP3_OP07_A (void); static void DSP3_OP07_B (void); static void DSP3_OP0C (void); //static void DSP3_OP0C_A (void); static void DSP3_OP10 (void); static void DSP3_OP1C (void); static void DSP3_OP1C_A (void); static void DSP3_OP1C_B (void); static void DSP3_OP1C_C (void); static void DSP3_OP1E (void); static void DSP3_OP1E_A (void); static void DSP3_OP1E_A1 (void); static void DSP3_OP1E_A2 (void); static void DSP3_OP1E_A3 (void); static void DSP3_OP1E_B (void); static void DSP3_OP1E_B1 (void); static void DSP3_OP1E_B2 (void); static void DSP3_OP1E_C (void); static void DSP3_OP1E_C1 (void); static void DSP3_OP1E_C2 (void); static void DSP3_OP1E_D (int16, int16 *, int16 *); static void DSP3_OP1E_D1 (int16, int16 *, int16 *); static void DSP3_OP3E (void); void DSP3_Reset (void) { DSP3.DR = 0x0080; DSP3.SR = 0x0084; SetDSP3 = &DSP3_Command; } /* static void DSP3_MemorySize (void) { DSP3.DR = 0x0300; SetDSP3 = &DSP3_Reset; } */ static void DSP3_TestMemory (void) { DSP3.DR = 0x0000; SetDSP3 = &DSP3_Reset; } static void DSP3_DumpDataROM (void) { DSP3.DR = DSP3_DataROM[DSP3.MemoryIndex++]; if (DSP3.MemoryIndex == 1024) SetDSP3 = &DSP3_Reset; } static void DSP3_MemoryDump (void) { DSP3.MemoryIndex = 0; SetDSP3 = &DSP3_DumpDataROM; DSP3_DumpDataROM(); } static void DSP3_OP06 (void) { DSP3.WinLo = (uint8) (DSP3.DR); DSP3.WinHi = (uint8) (DSP3.DR >> 8); DSP3_Reset(); } static void DSP3_OP03 (void) { int16 Lo = (uint8) (DSP3.DR); int16 Hi = (uint8) (DSP3.DR >> 8); int16 Ofs = (DSP3.WinLo * Hi << 1) + (Lo << 1); DSP3.DR = Ofs >> 1; SetDSP3 = &DSP3_Reset; } static void DSP3_OP07_B (void) { int16 Ofs = (DSP3.WinLo * DSP3.AddHi << 1) + (DSP3.AddLo << 1); DSP3.DR = Ofs >> 1; SetDSP3 = &DSP3_Reset; } static void DSP3_OP07_A (void) { int16 Lo = (uint8) (DSP3.DR); int16 Hi = (uint8) (DSP3.DR >> 8); if (Lo & 1) Hi += (DSP3.AddLo & 1); DSP3.AddLo += Lo; DSP3.AddHi += Hi; if (DSP3.AddLo < 0) DSP3.AddLo += DSP3.WinLo; else if (DSP3.AddLo >= DSP3.WinLo) DSP3.AddLo -= DSP3.WinLo; if (DSP3.AddHi < 0) DSP3.AddHi += DSP3.WinHi; else if (DSP3.AddHi >= DSP3.WinHi) DSP3.AddHi -= DSP3.WinHi; DSP3.DR = DSP3.AddLo | (DSP3.AddHi << 8) | ((DSP3.AddHi >> 8) & 0xff); SetDSP3 = &DSP3_OP07_B; } static void DSP3_OP07 (void) { uint32 dataOfs = ((DSP3.DR << 1) + 0x03b2) & 0x03ff; DSP3.AddHi = DSP3_DataROM[dataOfs]; DSP3.AddLo = DSP3_DataROM[dataOfs + 1]; SetDSP3 = &DSP3_OP07_A; DSP3.SR = 0x0080; } static void DSP3_Coordinate (void) { DSP3.Index++; switch (DSP3.Index) { case 3: if (DSP3.DR == 0xffff) DSP3_Reset(); break; case 4: DSP3.X = DSP3.DR; break; case 5: DSP3.Y = DSP3.DR; DSP3.DR = 1; break; case 6: DSP3.DR = DSP3.X; break; case 7: DSP3.DR = DSP3.Y; DSP3.Index = 0; break; } } static void DSP3_Convert_A (void) { if (DSP3.BMIndex < 8) { DSP3.Bitmap[DSP3.BMIndex++] = (uint8) (DSP3.DR); DSP3.Bitmap[DSP3.BMIndex++] = (uint8) (DSP3.DR >> 8); if (DSP3.BMIndex == 8) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { DSP3.Bitplane[j] <<= 1; DSP3.Bitplane[j] |= (DSP3.Bitmap[i] >> j) & 1; } } DSP3.BPIndex = 0; DSP3.Count--; } } if (DSP3.BMIndex == 8) { if (DSP3.BPIndex == 8) { if (!DSP3.Count) DSP3_Reset(); DSP3.BMIndex = 0; } else { DSP3.DR = DSP3.Bitplane[DSP3.BPIndex++]; DSP3.DR |= DSP3.Bitplane[DSP3.BPIndex++] << 8; } } } static void DSP3_Convert (void) { DSP3.Count = DSP3.DR; DSP3.BMIndex = 0; SetDSP3 = &DSP3_Convert_A; } static bool8 DSP3_GetBits (uint8 Count) { if (!DSP3.BitsLeft) { DSP3.BitsLeft = Count; DSP3.ReqBits = 0; } do { if (!DSP3.BitCount) { DSP3.SR = 0xC0; return (FALSE); } DSP3.ReqBits <<= 1; if (DSP3.ReqData & 0x8000) DSP3.ReqBits++; DSP3.ReqData <<= 1; DSP3.BitCount--; DSP3.BitsLeft--; } while (DSP3.BitsLeft); return (TRUE); } static void DSP3_Decode_Data (void) { if (!DSP3.BitCount) { if (DSP3.SR & 0x40) { DSP3.ReqData = DSP3.DR; DSP3.BitCount += 16; } else { DSP3.SR = 0xC0; return; } } if (DSP3.LZCode == 1) { if (!DSP3_GetBits(1)) return; if (DSP3.ReqBits) DSP3.LZLength = 12; else DSP3.LZLength = 8; DSP3.LZCode++; } if (DSP3.LZCode == 2) { if (!DSP3_GetBits(DSP3.LZLength)) return; DSP3.LZCode = 0; DSP3.Outwords--; if (!DSP3.Outwords) SetDSP3 = &DSP3_Reset; DSP3.SR = 0x80; DSP3.DR = DSP3.ReqBits; return; } if (DSP3.BaseCode == 0xffff) { if (!DSP3_GetBits(DSP3.BaseLength)) return; DSP3.BaseCode = DSP3.ReqBits; } if (!DSP3_GetBits(DSP3.CodeLengths[DSP3.BaseCode])) return; DSP3.Symbol = DSP3.Codes[DSP3.CodeOffsets[DSP3.BaseCode] + DSP3.ReqBits]; DSP3.BaseCode = 0xffff; if (DSP3.Symbol & 0xff00) { DSP3.Symbol += 0x7f02; DSP3.LZCode++; } else { DSP3.Outwords--; if (!DSP3.Outwords) SetDSP3 = &DSP3_Reset; } DSP3.SR = 0x80; DSP3.DR = DSP3.Symbol; } static void DSP3_Decode_Tree (void) { if (!DSP3.BitCount) { DSP3.ReqData = DSP3.DR; DSP3.BitCount += 16; } if (!DSP3.BaseCodes) { DSP3_GetBits(1); if (DSP3.ReqBits) { DSP3.BaseLength = 3; DSP3.BaseCodes = 8; } else { DSP3.BaseLength = 2; DSP3.BaseCodes = 4; } } while (DSP3.BaseCodes) { if (!DSP3_GetBits(3)) return; DSP3.ReqBits++; DSP3.CodeLengths[DSP3.Index] = (uint8) DSP3.ReqBits; DSP3.CodeOffsets[DSP3.Index] = DSP3.Symbol; DSP3.Index++; DSP3.Symbol += 1 << DSP3.ReqBits; DSP3.BaseCodes--; } DSP3.BaseCode = 0xffff; DSP3.LZCode = 0; SetDSP3 = &DSP3_Decode_Data; if (DSP3.BitCount) DSP3_Decode_Data(); } static void DSP3_Decode_Symbols (void) { DSP3.ReqData = DSP3.DR; DSP3.BitCount += 16; do { if (DSP3.BitCommand == 0xffff) { if (!DSP3_GetBits(2)) return; DSP3.BitCommand = DSP3.ReqBits; } switch (DSP3.BitCommand) { case 0: if (!DSP3_GetBits(9)) return; DSP3.Symbol = DSP3.ReqBits; break; case 1: DSP3.Symbol++; break; case 2: if (!DSP3_GetBits(1)) return; DSP3.Symbol += 2 + DSP3.ReqBits; break; case 3: if (!DSP3_GetBits(4)) return; DSP3.Symbol += 4 + DSP3.ReqBits; break; } DSP3.BitCommand = 0xffff; DSP3.Codes[DSP3.Index++] = DSP3.Symbol; DSP3.Codewords--; } while (DSP3.Codewords); DSP3.Index = 0; DSP3.Symbol = 0; DSP3.BaseCodes = 0; SetDSP3 = &DSP3_Decode_Tree; if (DSP3.BitCount) DSP3_Decode_Tree(); } static void DSP3_Decode_A (void) { DSP3.Outwords = DSP3.DR; SetDSP3 = &DSP3_Decode_Symbols; DSP3.BitCount = 0; DSP3.BitsLeft = 0; DSP3.Symbol = 0; DSP3.Index = 0; DSP3.BitCommand = 0xffff; DSP3.SR = 0xC0; } static void DSP3_Decode (void) { DSP3.Codewords = DSP3.DR; SetDSP3 = &DSP3_Decode_A; } // Opcodes 1E/3E bit-perfect to 'dsp3-intro' log // src: adapted from SD Gundam X/G-Next static void DSP3_OP3E (void) { DSP3. op3e_x = (uint8) (DSP3.DR & 0x00ff); DSP3. op3e_y = (uint8) ((DSP3.DR & 0xff00) >> 8); DSP3_OP03(); DSP3.op1e_terrain[DSP3.DR] = 0x00; DSP3.op1e_cost[DSP3.DR] = 0xff; DSP3.op1e_weight[DSP3.DR] = 0; DSP3.op1e_max_search_radius = 0; DSP3.op1e_max_path_radius = 0; } static void DSP3_OP1E (void) { DSP3.op1e_min_radius = (uint8) (DSP3.DR & 0x00ff); DSP3.op1e_max_radius = (uint8) ((DSP3.DR & 0xff00) >> 8); if (DSP3.op1e_min_radius == 0) DSP3.op1e_min_radius++; if (DSP3.op1e_max_search_radius >= DSP3.op1e_min_radius) DSP3.op1e_min_radius = DSP3.op1e_max_search_radius + 1; if (DSP3.op1e_max_radius > DSP3.op1e_max_search_radius) DSP3.op1e_max_search_radius = DSP3.op1e_max_radius; DSP3.op1e_lcv_radius = DSP3.op1e_min_radius; DSP3.op1e_lcv_steps = DSP3.op1e_min_radius; DSP3.op1e_lcv_turns = 6; DSP3.op1e_turn = 0; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_min_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); DSP3_OP1E_A(); } static void DSP3_OP1E_A (void) { if (DSP3.op1e_lcv_steps == 0) { DSP3.op1e_lcv_radius++; DSP3.op1e_lcv_steps = DSP3.op1e_lcv_radius; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_lcv_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); } if (DSP3.op1e_lcv_radius > DSP3.op1e_max_radius) { DSP3.op1e_turn++; DSP3.op1e_lcv_turns--; DSP3.op1e_lcv_radius = DSP3.op1e_min_radius; DSP3.op1e_lcv_steps = DSP3.op1e_min_radius; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_min_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); } if (DSP3.op1e_lcv_turns == 0) { DSP3.DR = 0xffff; DSP3.SR = 0x0080; SetDSP3 = &DSP3_OP1E_B; return; } DSP3.DR = (uint8) (DSP3.op1e_x) | ((uint8) (DSP3.op1e_y) << 8); DSP3_OP03(); DSP3.op1e_cell = DSP3.DR; DSP3.SR = 0x0080; SetDSP3 = &DSP3_OP1E_A1; } static void DSP3_OP1E_A1 (void) { DSP3.SR = 0x0084; SetDSP3 = &DSP3_OP1E_A2; } static void DSP3_OP1E_A2 (void) { DSP3.op1e_terrain[DSP3.op1e_cell] = (uint8) (DSP3.DR & 0x00ff); DSP3.SR = 0x0084; SetDSP3 = &DSP3_OP1E_A3; } static void DSP3_OP1E_A3 (void) { DSP3.op1e_cost[DSP3.op1e_cell] = (uint8) (DSP3.DR & 0x00ff); if (DSP3.op1e_lcv_radius == 1) { if (DSP3.op1e_terrain[DSP3.op1e_cell] & 1) DSP3.op1e_weight[DSP3.op1e_cell] = 0xff; else DSP3.op1e_weight[DSP3.op1e_cell] = DSP3.op1e_cost[DSP3.op1e_cell]; } else DSP3.op1e_weight[DSP3.op1e_cell] = 0xff; DSP3_OP1E_D((int16) (DSP3.op1e_turn + 2), &DSP3.op1e_x, &DSP3.op1e_y); DSP3.op1e_lcv_steps--; DSP3.SR = 0x0080; DSP3_OP1E_A(); } static void DSP3_OP1E_B (void) { DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; DSP3.op1e_lcv_radius = 1; DSP3.op1e_search = 0; DSP3_OP1E_B1(); SetDSP3 = &DSP3_OP1E_C; } static void DSP3_OP1E_B1 (void) { while (DSP3.op1e_lcv_radius < DSP3.op1e_max_radius) { DSP3.op1e_y--; DSP3.op1e_lcv_turns = 6; DSP3.op1e_turn = 5; while (DSP3.op1e_lcv_turns) { DSP3.op1e_lcv_steps = DSP3.op1e_lcv_radius; while (DSP3.op1e_lcv_steps) { DSP3_OP1E_D1(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); if (0 <= DSP3.op1e_y && DSP3.op1e_y < DSP3.WinHi && 0 <= DSP3.op1e_x && DSP3.op1e_x < DSP3.WinLo) { DSP3.DR = (uint8) (DSP3.op1e_x) | ((uint8) (DSP3.op1e_y) << 8); DSP3_OP03(); DSP3.op1e_cell = DSP3.DR; if (DSP3.op1e_cost[DSP3.op1e_cell] < 0x80 && DSP3.op1e_terrain[DSP3.op1e_cell] < 0x40) DSP3_OP1E_B2(); // end cell perimeter } DSP3.op1e_lcv_steps--; } // end search line DSP3.op1e_turn--; if (DSP3.op1e_turn == 0) DSP3.op1e_turn = 6; DSP3.op1e_lcv_turns--; } // end circle search DSP3.op1e_lcv_radius++; } // end radius search } static void DSP3_OP1E_B2 (void) { int16 cell; int16 path; int16 x, y; int16 lcv_turns; path = 0xff; lcv_turns = 6; while (lcv_turns) { x = DSP3.op1e_x; y = DSP3.op1e_y; DSP3_OP1E_D1(lcv_turns, &x, &y); DSP3.DR = (uint8) (x) | ((uint8) (y) << 8); DSP3_OP03(); cell = DSP3.DR; if (0 <= y && y < DSP3.WinHi && 0 <= x && x < DSP3.WinLo) { if (DSP3.op1e_terrain[cell] < 0x80 || DSP3.op1e_weight[cell] == 0) { if (DSP3.op1e_weight[cell] < path) path = DSP3.op1e_weight[cell]; } } // end step travel lcv_turns--; } // end while turns if (path != 0xff) DSP3.op1e_weight[DSP3.op1e_cell] = path + DSP3.op1e_cost[DSP3.op1e_cell]; } static void DSP3_OP1E_C (void) { DSP3.op1e_min_radius = (uint8) (DSP3.DR & 0x00ff); DSP3.op1e_max_radius = (uint8) ((DSP3.DR & 0xff00) >> 8); if (DSP3.op1e_min_radius == 0) DSP3.op1e_min_radius++; if (DSP3.op1e_max_path_radius >= DSP3.op1e_min_radius) DSP3.op1e_min_radius = DSP3.op1e_max_path_radius + 1; if (DSP3.op1e_max_radius > DSP3.op1e_max_path_radius) DSP3.op1e_max_path_radius = DSP3.op1e_max_radius; DSP3.op1e_lcv_radius = DSP3.op1e_min_radius; DSP3.op1e_lcv_steps = DSP3.op1e_min_radius; DSP3.op1e_lcv_turns = 6; DSP3.op1e_turn = 0; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_min_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); DSP3_OP1E_C1(); } static void DSP3_OP1E_C1 (void) { if (DSP3.op1e_lcv_steps == 0) { DSP3.op1e_lcv_radius++; DSP3.op1e_lcv_steps = DSP3.op1e_lcv_radius; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_lcv_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); } if (DSP3.op1e_lcv_radius > DSP3.op1e_max_radius) { DSP3.op1e_turn++; DSP3.op1e_lcv_turns--; DSP3.op1e_lcv_radius = DSP3.op1e_min_radius; DSP3.op1e_lcv_steps = DSP3.op1e_min_radius; DSP3.op1e_x = DSP3. op3e_x; DSP3.op1e_y = DSP3. op3e_y; for (int lcv = 0; lcv < DSP3.op1e_min_radius; lcv++) DSP3_OP1E_D(DSP3.op1e_turn, &DSP3.op1e_x, &DSP3.op1e_y); } if (DSP3.op1e_lcv_turns == 0) { DSP3.DR = 0xffff; DSP3.SR = 0x0080; SetDSP3 = &DSP3_Reset; return; } DSP3.DR = (uint8) (DSP3.op1e_x) | ((uint8) (DSP3.op1e_y) << 8); DSP3_OP03(); DSP3.op1e_cell = DSP3.DR; DSP3.SR = 0x0080; SetDSP3 = &DSP3_OP1E_C2; } static void DSP3_OP1E_C2 (void) { DSP3.DR = DSP3.op1e_weight[DSP3.op1e_cell]; DSP3_OP1E_D((int16) (DSP3.op1e_turn + 2), &DSP3.op1e_x, &DSP3.op1e_y); DSP3.op1e_lcv_steps--; DSP3.SR = 0x0084; SetDSP3 = &DSP3_OP1E_C1; } static void DSP3_OP1E_D (int16 move, int16 *lo, int16 *hi) { uint32 dataOfs = ((move << 1) + 0x03b2) & 0x03ff; int16 Lo; int16 Hi; DSP3.AddHi = DSP3_DataROM[dataOfs]; DSP3.AddLo = DSP3_DataROM[dataOfs + 1]; Lo = (uint8) (*lo); Hi = (uint8) (*hi); if (Lo & 1) Hi += (DSP3.AddLo & 1); DSP3.AddLo += Lo; DSP3.AddHi += Hi; if (DSP3.AddLo < 0) DSP3.AddLo += DSP3.WinLo; else if (DSP3.AddLo >= DSP3.WinLo) DSP3.AddLo -= DSP3.WinLo; if (DSP3.AddHi < 0) DSP3.AddHi += DSP3.WinHi; else if (DSP3.AddHi >= DSP3.WinHi) DSP3.AddHi -= DSP3.WinHi; *lo = DSP3.AddLo; *hi = DSP3.AddHi; } static void DSP3_OP1E_D1 (int16 move, int16 *lo, int16 *hi) { const uint16 HiAdd[] = { 0x00, 0xFF, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0xFF, 0x00 }; const uint16 LoAdd[] = { 0x00, 0x00, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x00 }; int16 Lo; int16 Hi; if ((*lo) & 1) DSP3.AddHi = HiAdd[move + 8]; else DSP3.AddHi = HiAdd[move + 0]; DSP3.AddLo = LoAdd[move]; Lo = (uint8) (*lo); Hi = (uint8) (*hi); if (Lo & 1) Hi += (DSP3.AddLo & 1); DSP3.AddLo += Lo; DSP3.AddHi += Hi; *lo = DSP3.AddLo; *hi = DSP3.AddHi; } static void DSP3_OP10 (void) { if (DSP3.DR == 0xffff) DSP3_Reset(); else // absorb 2 bytes DSP3.DR = DSP3.DR; } /* static void DSP3_OP0C_A (void) { // absorb 2 bytes DSP3.DR = 0; SetDSP3 = &DSP3_Reset; } */ static void DSP3_OP0C (void) { // absorb 2 bytes DSP3.DR = 0; //SetDSP3 = &DSP3_OP0C_A; SetDSP3 = &DSP3_Reset; } static void DSP3_OP1C_C (void) { // return 2 bytes DSP3.DR = 0; SetDSP3 = &DSP3_Reset; } static void DSP3_OP1C_B (void) { // return 2 bytes DSP3.DR = 0; SetDSP3 = &DSP3_OP1C_C; } static void DSP3_OP1C_A (void) { // absorb 2 bytes SetDSP3 = &DSP3_OP1C_B; } static void DSP3_OP1C (void) { // absorb 2 bytes SetDSP3 = &DSP3_OP1C_A; } static void DSP3_Command (void) { if (DSP3.DR < 0x40) { switch (DSP3.DR) { case 0x02: SetDSP3 = &DSP3_Coordinate; break; case 0x03: SetDSP3 = &DSP3_OP03; break; case 0x06: SetDSP3 = &DSP3_OP06; break; case 0x07: SetDSP3 = &DSP3_OP07; return; case 0x0c: SetDSP3 = &DSP3_OP0C; break; case 0x0f: SetDSP3 = &DSP3_TestMemory; break; case 0x10: SetDSP3 = &DSP3_OP10; break; case 0x18: SetDSP3 = &DSP3_Convert; break; case 0x1c: SetDSP3 = &DSP3_OP1C; break; case 0x1e: SetDSP3 = &DSP3_OP1E; break; case 0x1f: SetDSP3 = &DSP3_MemoryDump; break; case 0x38: SetDSP3 = &DSP3_Decode; break; case 0x3e: SetDSP3 = &DSP3_OP3E; break; default: return; } DSP3.SR = 0x0080; DSP3.Index = 0; } } void DSP3SetByte (uint8 byte, uint16 address) { if (address < DSP0.boundary) { if (DSP3.SR & 0x04) { DSP3.DR = (DSP3.DR & 0xff00) + byte; (*SetDSP3)(); } else { DSP3.SR ^= 0x10; if (DSP3.SR & 0x10) DSP3.DR = (DSP3.DR & 0xff00) + byte; else { DSP3.DR = (DSP3.DR & 0x00ff) + (byte << 8); (*SetDSP3)(); } } } } uint8 DSP3GetByte (uint16 address) { if (address < DSP0.boundary) { uint8 byte; if (DSP3.SR & 0x04) { byte = (uint8) DSP3.DR; (*SetDSP3)(); } else { DSP3.SR ^= 0x10; if (DSP3.SR & 0x10) byte = (uint8) (DSP3.DR); else { byte = (uint8) (DSP3.DR >> 8); (*SetDSP3)(); } } return (byte); } return (uint8) DSP3.SR; } apu/bapu/smp/core/oppseudo_rmw.cpp000664 001750 001750 00000007401 12720446475 020411 0ustar00sergiosergio000000 000000 case 0xbc: { op_io(); regs.B.a = op_inc(regs.B.a); break; } case 0x3d: { op_io(); regs.x = op_inc(regs.x); break; } case 0xfc: { op_io(); regs.B.y = op_inc(regs.B.y); break; } case 0x9c: { op_io(); regs.B.a = op_dec(regs.B.a); break; } case 0x1d: { op_io(); regs.x = op_dec(regs.x); break; } case 0xdc: { op_io(); regs.B.y = op_dec(regs.B.y); break; } case 0x1c: { op_io(); regs.B.a = op_asl(regs.B.a); break; } case 0x5c: { op_io(); regs.B.a = op_lsr(regs.B.a); break; } case 0x3c: { op_io(); regs.B.a = op_rol(regs.B.a); break; } case 0x7c: { op_io(); regs.B.a = op_ror(regs.B.a); break; } case 0xab: { dp = op_readpc(); rd = op_readdp(dp); rd = op_inc(rd); op_writedp(dp, rd); break; } case 0x8b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_dec(rd); op_writedp(dp, rd); break; } case 0x0b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_asl(rd); op_writedp(dp, rd); break; } case 0x4b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_lsr(rd); op_writedp(dp, rd); break; } case 0x2b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_rol(rd); op_writedp(dp, rd); break; } case 0x6b: { dp = op_readpc(); rd = op_readdp(dp); rd = op_ror(rd); op_writedp(dp, rd); break; } case 0xbb: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_inc(rd); op_writedp(dp + regs.x, rd); break; } case 0x9b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_dec(rd); op_writedp(dp + regs.x, rd); break; } case 0x1b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_asl(rd); op_writedp(dp + regs.x, rd); break; } case 0x5b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_lsr(rd); op_writedp(dp + regs.x, rd); break; } case 0x3b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_rol(rd); op_writedp(dp + regs.x, rd); break; } case 0x7b: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); rd = op_ror(rd); op_writedp(dp + regs.x, rd); break; } case 0xac: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_inc(rd); op_writeaddr(dp, rd); break; } case 0x8c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_dec(rd); op_writeaddr(dp, rd); break; } case 0x0c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_asl(rd); op_writeaddr(dp, rd); break; } case 0x4c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_lsr(rd); op_writeaddr(dp, rd); break; } case 0x2c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_rol(rd); op_writeaddr(dp, rd); break; } case 0x6c: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); rd = op_ror(rd); op_writeaddr(dp, rd); break; } case 0x0e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.p.n = !!((regs.B.a - rd) & 0x80); regs.p.z = ((regs.B.a - rd) == 0); op_readaddr(dp); op_writeaddr(dp, rd | regs.B.a); break; } case 0x4e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.p.n = !!((regs.B.a - rd) & 0x80); regs.p.z = ((regs.B.a - rd) == 0); op_readaddr(dp); op_writeaddr(dp, rd &~ regs.B.a); break; } case 0x3a: { dp = op_readpc(); rd = op_readdp(dp); rd++; op_writedp(dp++, rd); rd += op_readdp(dp) << 8; op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); break; } case 0x1a: { dp = op_readpc(); rd = op_readdp(dp); rd--; op_writedp(dp++, rd); rd += op_readdp(dp) << 8; op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); break; } apu/bapu/smp/debugger/debugger.hpp000664 001750 001750 00000001123 12720446475 020306 0ustar00sergiosergio000000 000000 class SMPDebugger : public SMP, public ChipDebugger { public: bool property(unsigned id, string &name, string &value); function step_event; enum Usage { UsageRead = 0x80, UsageWrite = 0x40, UsageExec = 0x20, }; uint8 *usage; uint16 opcode_pc; bool opcode_edge; void op_step(); uint8 op_read(uint16 addr); void op_write(uint16 addr, uint8 data); SMPDebugger(); ~SMPDebugger(); //disassembler void disassemble_opcode(char *output, uint16 addr); inline uint8 disassemble_read(uint16 addr); inline uint16 relb(int8 offset, int op_len); }; cpuaddr.h000664 001750 001750 00000042005 12720446475 013511 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CPUADDR_H_ #define _CPUADDR_H_ typedef enum { NONE = 0, READ = 1, WRITE = 2, MODIFY = 3, JUMP = 5, JSR = 8 } AccessMode; static inline uint8 Immediate8Slow (AccessMode a) { uint8 val = S9xGetByte(Registers.PBPC); if (a & READ) OpenBus = val; Registers.PCw++; return (val); } static inline uint8 Immediate8 (AccessMode a) { uint8 val = CPU.PCBase[Registers.PCw]; if (a & READ) OpenBus = val; AddCycles(CPU.MemSpeed); Registers.PCw++; return (val); } static inline uint16 Immediate16Slow (AccessMode a) { uint16 val = S9xGetWord(Registers.PBPC, WRAP_BANK); if (a & READ) OpenBus = (uint8) (val >> 8); Registers.PCw += 2; return (val); } static inline uint16 Immediate16 (AccessMode a) { uint16 val = READ_WORD(CPU.PCBase + Registers.PCw); if (a & READ) OpenBus = (uint8) (val >> 8); AddCycles(CPU.MemSpeedx2); Registers.PCw += 2; return (val); } static inline uint32 RelativeSlow (AccessMode a) // branch $xx { int8 offset = Immediate8Slow(a); return ((int16) Registers.PCw + offset) & 0xffff; } static inline uint32 Relative (AccessMode a) // branch $xx { int8 offset = Immediate8(a); return ((int16) Registers.PCw + offset) & 0xffff; } static inline uint32 RelativeLongSlow (AccessMode a) // BRL $xxxx { int16 offset = Immediate16Slow(a); return ((int32) Registers.PCw + offset) & 0xffff; } static inline uint32 RelativeLong (AccessMode a) // BRL $xxxx { int16 offset = Immediate16(a); return ((int32) Registers.PCw + offset) & 0xffff; } static inline uint32 AbsoluteIndexedIndirectSlow (AccessMode a) // (a,X) { uint16 addr; if (a & JSR) { // JSR (a,X) pushes the old address in the middle of loading the new. // OpenBus needs to be set to account for this. addr = Immediate8Slow(READ); if (a == JSR) OpenBus = Registers.PCl; addr |= Immediate8Slow(READ) << 8; } else addr = Immediate16Slow(READ); AddCycles(ONE_CYCLE); addr += Registers.X.W; // Address load wraps within the bank uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); OpenBus = addr2 >> 8; return (addr2); } static inline uint32 AbsoluteIndexedIndirect (AccessMode a) // (a,X) { uint16 addr = Immediate16Slow(READ); addr += Registers.X.W; // Address load wraps within the bank uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); OpenBus = addr2 >> 8; return (addr2); } static inline uint32 AbsoluteIndirectLongSlow (AccessMode a) // [a] { uint16 addr = Immediate16Slow(READ); // No info on wrapping, but it doesn't matter anyway due to mirroring uint32 addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return (addr2); } static inline uint32 AbsoluteIndirectLong (AccessMode a) // [a] { uint16 addr = Immediate16(READ); // No info on wrapping, but it doesn't matter anyway due to mirroring uint32 addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return (addr2); } static inline uint32 AbsoluteIndirectSlow (AccessMode a) // (a) { // No info on wrapping, but it doesn't matter anyway due to mirroring uint16 addr2 = S9xGetWord(Immediate16Slow(READ)); OpenBus = addr2 >> 8; return (addr2); } static inline uint32 AbsoluteIndirect (AccessMode a) // (a) { // No info on wrapping, but it doesn't matter anyway due to mirroring uint16 addr2 = S9xGetWord(Immediate16(READ)); OpenBus = addr2 >> 8; return (addr2); } static inline uint32 AbsoluteSlow (AccessMode a) // a { return (ICPU.ShiftedDB | Immediate16Slow(a)); } static inline uint32 Absolute (AccessMode a) // a { return (ICPU.ShiftedDB | Immediate16(a)); } static inline uint32 AbsoluteLongSlow (AccessMode a) // l { uint32 addr = Immediate16Slow(READ); // JSR l pushes the old bank in the middle of loading the new. // OpenBus needs to be set to account for this. if (a == JSR) OpenBus = Registers.PB; addr |= Immediate8Slow(a) << 16; return (addr); } static inline uint32 AbsoluteLong (AccessMode a) // l { uint32 addr = READ_3WORD(CPU.PCBase + Registers.PCw); AddCycles(CPU.MemSpeedx2 + CPU.MemSpeed); if (a & READ) OpenBus = addr >> 16; Registers.PCw += 3; return (addr); } static inline uint32 DirectSlow (AccessMode a) // d { uint16 addr = Immediate8Slow(a) + Registers.D.W; if (Registers.DL != 0) AddCycles(ONE_CYCLE); return (addr); } static inline uint32 Direct (AccessMode a) // d { uint16 addr = Immediate8(a) + Registers.D.W; if (Registers.DL != 0) AddCycles(ONE_CYCLE); return (addr); } static inline uint32 DirectIndirectSlow (AccessMode a) // (d) { uint32 addr = S9xGetWord(DirectSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = (uint8) (addr >> 8); addr |= ICPU.ShiftedDB; return (addr); } static inline uint32 DirectIndirectE0 (AccessMode a) // (d) { uint32 addr = S9xGetWord(Direct(READ)); if (a & READ) OpenBus = (uint8) (addr >> 8); addr |= ICPU.ShiftedDB; return (addr); } static inline uint32 DirectIndirectE1 (AccessMode a) // (d) { uint32 addr = S9xGetWord(DirectSlow(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = (uint8) (addr >> 8); addr |= ICPU.ShiftedDB; return (addr); } static inline uint32 DirectIndirectIndexedSlow (AccessMode a) // (d),Y { uint32 addr = DirectIndirectSlow(a); if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 DirectIndirectIndexedE0X0 (AccessMode a) // (d),Y { uint32 addr = DirectIndirectE0(a); AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 DirectIndirectIndexedE0X1 (AccessMode a) // (d),Y { uint32 addr = DirectIndirectE0(a); if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 DirectIndirectIndexedE1 (AccessMode a) // (d),Y { uint32 addr = DirectIndirectE1(a); if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 DirectIndirectLongSlow (AccessMode a) // [d] { uint16 addr = DirectSlow(READ); uint32 addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return (addr2); } static inline uint32 DirectIndirectLong (AccessMode a) // [d] { uint16 addr = Direct(READ); uint32 addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return (addr2); } static inline uint32 DirectIndirectIndexedLongSlow (AccessMode a) // [d],Y { return (DirectIndirectLongSlow(a) + Registers.Y.W); } static inline uint32 DirectIndirectIndexedLong (AccessMode a) // [d],Y { return (DirectIndirectLong(a) + Registers.Y.W); } static inline uint32 DirectIndexedXSlow (AccessMode a) // d,X { pair addr; addr.W = DirectSlow(a); if (!CheckEmulation() || Registers.DL) addr.W += Registers.X.W; else addr.B.l += Registers.XL; AddCycles(ONE_CYCLE); return (addr.W); } static inline uint32 DirectIndexedXE0 (AccessMode a) // d,X { uint16 addr = Direct(a) + Registers.X.W; AddCycles(ONE_CYCLE); return (addr); } static inline uint32 DirectIndexedXE1 (AccessMode a) // d,X { if (Registers.DL) return (DirectIndexedXE0(a)); else { pair addr; addr.W = Direct(a); addr.B.l += Registers.XL; AddCycles(ONE_CYCLE); return (addr.W); } } static inline uint32 DirectIndexedYSlow (AccessMode a) // d,Y { pair addr; addr.W = DirectSlow(a); if (!CheckEmulation() || Registers.DL) addr.W += Registers.Y.W; else addr.B.l += Registers.YL; AddCycles(ONE_CYCLE); return (addr.W); } static inline uint32 DirectIndexedYE0 (AccessMode a) // d,Y { uint16 addr = Direct(a) + Registers.Y.W; AddCycles(ONE_CYCLE); return (addr); } static inline uint32 DirectIndexedYE1 (AccessMode a) // d,Y { if (Registers.DL) return (DirectIndexedYE0(a)); else { pair addr; addr.W = Direct(a); addr.B.l += Registers.YL; AddCycles(ONE_CYCLE); return (addr.W); } } static inline uint32 DirectIndexedIndirectSlow (AccessMode a) // (d,X) { uint32 addr = S9xGetWord(DirectIndexedXSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = (uint8) (addr >> 8); return (ICPU.ShiftedDB | addr); } static inline uint32 DirectIndexedIndirectE0 (AccessMode a) // (d,X) { uint32 addr = S9xGetWord(DirectIndexedXE0(READ)); if (a & READ) OpenBus = (uint8) (addr >> 8); return (ICPU.ShiftedDB | addr); } static inline uint32 DirectIndexedIndirectE1 (AccessMode a) // (d,X) { uint32 addr = S9xGetWord(DirectIndexedXE1(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = (uint8) (addr >> 8); return (ICPU.ShiftedDB | addr); } static inline uint32 AbsoluteIndexedXSlow (AccessMode a) // a,X { uint32 addr = AbsoluteSlow(a); if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.XL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.X.W); } static inline uint32 AbsoluteIndexedXX0 (AccessMode a) // a,X { uint32 addr = Absolute(a); AddCycles(ONE_CYCLE); return (addr + Registers.X.W); } static inline uint32 AbsoluteIndexedXX1 (AccessMode a) // a,X { uint32 addr = Absolute(a); if (a & WRITE || (addr & 0xff) + Registers.XL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.X.W); } static inline uint32 AbsoluteIndexedYSlow (AccessMode a) // a,Y { uint32 addr = AbsoluteSlow(a); if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 AbsoluteIndexedYX0 (AccessMode a) // a,Y { uint32 addr = Absolute(a); AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 AbsoluteIndexedYX1 (AccessMode a) // a,Y { uint32 addr = Absolute(a); if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100) AddCycles(ONE_CYCLE); return (addr + Registers.Y.W); } static inline uint32 AbsoluteLongIndexedXSlow (AccessMode a) // l,X { return (AbsoluteLongSlow(a) + Registers.X.W); } static inline uint32 AbsoluteLongIndexedX (AccessMode a) // l,X { return (AbsoluteLong(a) + Registers.X.W); } static inline uint32 StackRelativeSlow (AccessMode a) // d,S { uint16 addr = Immediate8Slow(a) + Registers.S.W; AddCycles(ONE_CYCLE); return (addr); } static inline uint32 StackRelative (AccessMode a) // d,S { uint16 addr = Immediate8(a) + Registers.S.W; AddCycles(ONE_CYCLE); return (addr); } static inline uint32 StackRelativeIndirectIndexedSlow (AccessMode a) // (d,S),Y { uint32 addr = S9xGetWord(StackRelativeSlow(READ)); if (a & READ) OpenBus = (uint8) (addr >> 8); addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff; AddCycles(ONE_CYCLE); return (addr); } static inline uint32 StackRelativeIndirectIndexed (AccessMode a) // (d,S),Y { uint32 addr = S9xGetWord(StackRelative(READ)); if (a & READ) OpenBus = (uint8) (addr >> 8); addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff; AddCycles(ONE_CYCLE); return (addr); } #endif clip.cpp000664 001750 001750 00000026012 12720446475 013351 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" static uint8 region_map[6][6] = { { 0, 0x01, 0x03, 0x07, 0x0f, 0x1f }, { 0, 0, 0x02, 0x06, 0x0e, 0x1e }, { 0, 0, 0, 0x04, 0x0c, 0x1c }, { 0, 0, 0, 0, 0x08, 0x18 }, { 0, 0, 0, 0, 0, 0x10 } }; static inline uint8 CalcWindowMask (int, uint8, uint8); static inline void StoreWindowRegions (uint8, struct ClipData *, int, int16 *, uint8 *, bool8, bool8 s = FALSE); static inline uint8 CalcWindowMask (int i, uint8 W1, uint8 W2) { if (!PPU.ClipWindow1Enable[i]) { if (!PPU.ClipWindow2Enable[i]) return (0); else { if (!PPU.ClipWindow2Inside[i]) return (~W2); return (W2); } } else { if (!PPU.ClipWindow2Enable[i]) { if (!PPU.ClipWindow1Inside[i]) return (~W1); return (W1); } else { if (!PPU.ClipWindow1Inside[i]) W1 = ~W1; if (!PPU.ClipWindow2Inside[i]) W2 = ~W2; switch (PPU.ClipWindowOverlapLogic[i]) { case 0: // OR return (W1 | W2); case 1: // AND return (W1 & W2); case 2: // XOR return (W1 ^ W2); case 3: // XNOR return (~(W1 ^ W2)); } } } // Never get here return (0); } static inline void StoreWindowRegions (uint8 Mask, struct ClipData *Clip, int n_regions, int16 *windows, uint8 *drawing_modes, bool8 sub, bool8 StoreMode0) { int ct = 0; for (int j = 0; j < n_regions; j++) { int DrawMode = drawing_modes[j]; if (sub) DrawMode |= 1; if (Mask & (1 << j)) DrawMode = 0; if (!StoreMode0 && !DrawMode) continue; if (ct > 0 && Clip->Right[ct - 1] == windows[j] && Clip->DrawMode[ct - 1] == DrawMode) Clip->Right[ct - 1] = windows[j + 1]; // This region borders with and has the same drawing mode as the previous region: merge them. else { // Add a new region to the BG Clip->Left[ct] = windows[j]; Clip->Right[ct] = windows[j + 1]; Clip->DrawMode[ct] = DrawMode; ct++; } } Clip->Count = ct; } void S9xComputeClipWindows (void) { int16 windows[6] = { 0, 256, 256, 256, 256, 256 }; uint8 drawing_modes[5] = { 0, 0, 0, 0, 0 }; int n_regions = 1; int i, j; // Calculate window regions. We have at most 5 regions, because we have 6 control points // (screen edges, window 1 left & right, and window 2 left & right). if (PPU.Window1Left <= PPU.Window1Right) { if (PPU.Window1Left > 0) { windows[2] = 256; windows[1] = PPU.Window1Left; n_regions = 2; } if (PPU.Window1Right < 255) { windows[n_regions + 1] = 256; windows[n_regions] = PPU.Window1Right + 1; n_regions++; } } if (PPU.Window2Left <= PPU.Window2Right) { for (i = 0; i <= n_regions; i++) { if (PPU.Window2Left == windows[i]) break; if (PPU.Window2Left < windows[i]) { for (j = n_regions; j >= i; j--) windows[j + 1] = windows[j]; windows[i] = PPU.Window2Left; n_regions++; break; } } for (; i <= n_regions; i++) { if (PPU.Window2Right + 1 == windows[i]) break; if (PPU.Window2Right + 1 < windows[i]) { for (j = n_regions; j >= i; j--) windows[j + 1] = windows[j]; windows[i] = PPU.Window2Right + 1; n_regions++; break; } } } // Get a bitmap of which regions correspond to each window. uint8 W1, W2; if (PPU.Window1Left <= PPU.Window1Right) { for (i = 0; windows[i] != PPU.Window1Left; i++) ; for (j = i; windows[j] != PPU.Window1Right + 1; j++) ; W1 = region_map[i][j]; } else W1 = 0; if (PPU.Window2Left <= PPU.Window2Right) { for (i = 0; windows[i] != PPU.Window2Left; i++) ; for (j = i; windows[j] != PPU.Window2Right + 1; j++) ; W2 = region_map[i][j]; } else W2 = 0; // Color Window affects the drawing mode for each region. // Modes are: 3=Draw as normal, 2=clip color (math only), 1=no math (draw only), 0=nothing. uint8 CW_color = 0, CW_math = 0; uint8 CW = CalcWindowMask(5, W1, W2); switch (Memory.FillRAM[0x2130] & 0xc0) { case 0x00: CW_color = 0; break; case 0x40: CW_color = ~CW; break; case 0x80: CW_color = CW; break; case 0xc0: CW_color = 0xff; break; } switch (Memory.FillRAM[0x2130] & 0x30) { case 0x00: CW_math = 0; break; case 0x10: CW_math = ~CW; break; case 0x20: CW_math = CW; break; case 0x30: CW_math = 0xff; break; } for (i = 0; i < n_regions; i++) { if (!(CW_color & (1 << i))) drawing_modes[i] |= 1; if (!(CW_math & (1 << i))) drawing_modes[i] |= 2; } // Store backdrop clip window (draw everywhere color window allows) StoreWindowRegions(0, &IPPU.Clip[0][5], n_regions, windows, drawing_modes, FALSE, TRUE); StoreWindowRegions(0, &IPPU.Clip[1][5], n_regions, windows, drawing_modes, TRUE, TRUE); // Store per-BG and OBJ clip windows for (j = 0; j < 5; j++) { uint8 W = Settings.DisableGraphicWindows ? 0 : CalcWindowMask(j, W1, W2); for (int sub = 0; sub < 2; sub++) { if (Memory.FillRAM[sub + 0x212e] & (1 << j)) StoreWindowRegions(W, &IPPU.Clip[sub][j], n_regions, windows, drawing_modes, sub); else StoreWindowRegions(0, &IPPU.Clip[sub][j], n_regions, windows, drawing_modes, sub); } } } conffile.cpp000664 001750 001750 00000045016 12720446475 014214 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include #include #include #include "conffile.h" #ifdef __WIN32__ #define snprintf _snprintf // needs ANSI compliant name #endif #define SORT_SECTIONS_BY_SIZE // output using namespace std; bool ConfigFile::defaultAutoAdd = false; bool ConfigFile::niceAlignment = false; bool ConfigFile::showComments = true; bool ConfigFile::alphaSort = true; bool ConfigFile::timeSort = false; static ConfigFile* curConfigFile = NULL; // for section_then_key_less ConfigFile::ConfigFile(void) { Clear(); } void ConfigFile::Clear(void){ data.clear(); sectionSizes.ClearSections(); linectr = 0; } bool ConfigFile::LoadFile(const char *filename){ FSTREAM s; bool ret=false; const char *n, *n2; if((s=OPEN_FSTREAM(filename, "r"))){ n=filename; n2=strrchr(n, '/'); if(n2!=NULL) n=n2+1; n2=strrchr(n, '\\'); if(n2!=NULL) n=n2+1; LoadFile(new fStream(s), n); CLOSE_FSTREAM(s); ret = true; } else { fprintf(stderr, "Couldn't open conffile "); perror(filename); } return ret; } void ConfigFile::LoadFile(Stream *r, const char *name){ curConfigFile = this; string l, key, val; string section; string comment; int i, line, line2; bool eof; line=line2=0; section.clear(); do { line=line2++; l=r->getline(eof); ConfigEntry::trim(l); if(l.size()==0) continue; if(l[0]=='#' || l[0]==';'){ // comment continue; } if(l[0]=='['){ if(*l.rbegin()!=']'){ if(name) fprintf(stderr, "%s:", name); fprintf(stderr, "[%d]: Ignoring invalid section header\n", line); continue; } section.assign(l, 1, l.size()-2); continue; } while(*l.rbegin()=='\\'){ l.erase(l.size()-1); line2++; val=r->getline(eof); if(eof){ fprintf(stderr, "Unexpected EOF reading config file"); if(name) fprintf(stderr, " '%s'", name); fprintf(stderr, "\n"); return; } ConfigEntry::trim(val); l+=val; } i=l.find('='); if(i<0){ if(name) fprintf(stderr, "%s:", name); fprintf(stderr, "[%d]: Ignoring invalid entry\n", line); continue; } key=l.substr(0,i); ConfigEntry::trim(key); val=l.substr(i+1); comment = ConfigEntry::trimCommented(val); if(val.size() > 0 && val[0]=='"' && *val.rbegin()=='"') val=val.substr(1, val.size()-2); ConfigEntry e(line, section, key, val); e.comment = comment; if(data.erase(e)) sectionSizes.DecreaseSectionSize(e.section); data.insert(e); sectionSizes.IncreaseSectionSize(e.section); } while(!eof); curConfigFile = NULL; } bool ConfigFile::SaveTo(const char *filename){ string section; FILE *fp; if((fp=fopen(filename, "w"))==NULL){ fprintf(stderr, "Couldn't write conffile "); perror(filename); return false; } curConfigFile = this; section.clear(); set tmp; fprintf(fp, "# Config file output by snes9x\n"); time_t t=time(NULL); fprintf(fp, "# %s", ctime(&t)); #ifdef SORT_SECTIONS_BY_SIZE std::set data2; for(set::iterator k=data.begin(); k!=data.end(); k++){ ConfigEntry e (k->line, k->section, k->key, k->val); e.comment = k->comment; data2.insert(e); } #else #define data2 data #define section_then_key_less key_less #endif for(set::iterator j=data2.begin(); ; j++){ if(j==data2.end() || j->section!=section){ if(!tmp.empty()){ fprintf(fp, "\n[%s]\n", section.c_str()); unsigned int maxKeyLen=0, maxValLen=0; int maxLeftDiv=0; int maxRightDiv=-1; if(niceAlignment){ for(set::iterator i=tmp.begin(); i!=tmp.end(); i++){ int len3 = i->key.find_last_of(':'); maxRightDiv = MAX(maxRightDiv, len3); len3 = i->key.length() - len3; maxLeftDiv = MAX(maxLeftDiv, len3); maxKeyLen = MAX(maxKeyLen, i->key.length()+3); if(showComments){ string o=i->val; ConfigEntry::trim(o); unsigned int len = o.length(); for(signed int j=len-1;j>=0;j--) if(o.at(j)=='#') len++; if(o!=i->val) len+=2; maxValLen = MAX(maxValLen, len); } } if(maxValLen>48) maxValLen=48; // limit spacing } for(set::iterator i=tmp.begin(); i!=tmp.end(); i++){ string o=i->val; ConfigEntry::trim(o); if(o!=i->val) o="\""+i->val+"\""; int off=0, len3=0; for(;;){ int k=o.find('#',off); if(k>=0){ o.insert(k,1,'#'); // re-double any comment characters off=k+2; if(off<(int)o.length()) continue; } break; } if(niceAlignment){ len3=i->key.find_last_of(':'); int len3sub=0; if(len3 < maxRightDiv){ for(int j=len3;jkey.length(); for(unsigned int j=i->key.length()+len3+3;jkey.c_str()); for(int j=0;jkey.c_str(), o.c_str()); if(showComments && !i->comment.empty()){ if(niceAlignment) for(unsigned int j=o.length();jcomment.c_str()); } fprintf(fp, "\n"); } } if(j==data2.end()) break; section=j->section; tmp.clear(); } tmp.insert(*j); } curConfigFile = NULL; #undef data2 #undef section_then_key_less if(ferror(fp)) { fp = fp; } fclose(fp); return true; } /***********************************************/ string ConfigFile::Get(const char *key){ set::iterator i; i=data.find(ConfigEntry(key)); i->used=true; return i->val; } bool ConfigFile::Has(const char *key){ return data.find(ConfigEntry(key))!=data.end(); } // exists and isn't completely empty (any side-effects are intentional) bool ConfigFile::Exists(const char *key){ const char* val = GetString(key, NULL); return val && *val; } string ConfigFile::GetString(const char *key, string def){ if(!Exists(key)) return def; return Get(key); } char *ConfigFile::GetString(const char *key, char *out, uint32 outlen){ if(!Exists(key)) return NULL; memset(out, 0, outlen); string o=Get(key); if(outlen>0){ outlen--; if(o.size()::iterator i; i=data.find(ConfigEntry(key)); if(i==data.end()) { if(defaultAutoAdd) SetString(key,""); //SetString(key, def?def:""); return def; } i->used=true; // This should be OK, until this key gets removed const std::string &iVal = i->val; return iVal.c_str(); } char *ConfigFile::GetStringDup(const char *key, const char *def){ const char *c=GetString(key, def); if(c==NULL) return NULL; return strdup(c); } bool ConfigFile::SetString(const char *key, string val, const char *comment){ set::iterator i; bool ret=false; bool found; ConfigEntry e(key, val); if(comment && *comment) e.comment = comment; e.used=true; i=data.find(e); found=(i==data.end()); if(!found){ e.line=i->line; data.erase(e); sectionSizes.DecreaseSectionSize(e.section); ret=true; } if((found && (!alphaSort || timeSort)) || (!alphaSort && timeSort)) e.line = linectr++; data.insert(e); sectionSizes.IncreaseSectionSize(e.section); return ret; } int32 ConfigFile::GetInt(const char *key, int32 def, bool *bad){ if(bad) *bad=false; if(!Exists(key)) return def; char *c; int32 i; string o=Get(key); i=strtol(o.c_str(), &c, 10); if(c!=NULL && *c!='\0'){ i=def; if(bad) *bad=true; } return i; } bool ConfigFile::SetInt(const char *key, int32 val, const char *comment){ char buf[20]; snprintf(buf, sizeof(buf), "%d", (int)val); return SetString(key, buf, comment); } uint32 ConfigFile::GetUInt(const char *key, uint32 def, int base, bool *bad){ if(bad) *bad=false; if(!Exists(key)) return def; if(base!=8 && base!=10 && base!=16) base=0; char *c; uint32 i; string o=Get(key); i=strtol(o.c_str(), &c, base); if(c!=NULL && *c!='\0'){ i=def; if(bad) *bad=true; } return i; } bool ConfigFile::SetUInt(const char *key, uint32 val, int base, const char *comment){ char buf[20]; switch(base){ case 10: default: snprintf(buf, sizeof(buf), "%u", (unsigned int)val); break; case 8: snprintf(buf, sizeof(buf), "%#o", (unsigned int)val); break; case 16: snprintf(buf, sizeof(buf), "%#x", (unsigned int)val); break; } return SetString(key, buf, comment); } bool ConfigFile::GetBool(const char *key, bool def, bool *bad){ if(bad) *bad=false; if(!Exists(key)) return def; string o=Get(key); const char *c=o.c_str(); if(!strcasecmp(c, "true") || !strcasecmp(c, "1") || !strcasecmp(c, "yes") || !strcasecmp(c, "on")) return true; if(!strcasecmp(c, "false") || !strcasecmp(c, "0") || !strcasecmp(c, "no") || !strcasecmp(c, "off")) return false; if(bad) *bad=true; return def; } bool ConfigFile::SetBool(const char *key, bool val, const char *true_val, const char *false_val, const char *comment){ return SetString(key, val?true_val:false_val, comment); } const char* ConfigFile::GetComment(const char *key) { set::iterator i; i=data.find(ConfigEntry(key)); if(i==data.end()) return NULL; // This should be OK, until this key gets removed const std::string &iCom = i->comment; return iCom.c_str(); } bool ConfigFile::DeleteKey(const char *key){ ConfigEntry e = ConfigEntry(key); if(data.erase(e)) { sectionSizes.DecreaseSectionSize(e.section); return true; } return false; } /***********************************************/ bool ConfigFile::DeleteSection(const char *section){ set::iterator s, e; for(s=data.begin(); s!=data.end() && s->section!=section; s++) ; if(s==data.end()) return false; for(e=s; e!=data.end() && e->section==section; e++) ; data.erase(s, e); sectionSizes.DeleteSection(section); return true; } ConfigFile::secvec_t ConfigFile::GetSection(const char *section){ secvec_t v; set::iterator i; v.clear(); for(i=data.begin(); i!=data.end(); i++){ if(i->section!=section) continue; v.push_back(std::pair(i->key, i->val)); } return v; } int ConfigFile::GetSectionSize(const std::string section){ return sectionSizes.GetSectionSize(section); } // Clears all key-value pairs that didn't receive a "Get" or "Exists" command void ConfigFile::ClearUnused() { set::iterator i; again: for(i=data.begin(); i!=data.end(); i++){ if(!i->used){ data.erase(i); goto again; } } } void ConfigFile::ClearLines() { set::iterator i; for(i=data.begin(); i!=data.end(); i++){ *(const_cast(&i->line)) = -1; } } bool ConfigFile::ConfigEntry::section_then_key_less::operator()(const ConfigEntry &a, const ConfigEntry &b) { if(curConfigFile && a.section!=b.section){ const int sva = curConfigFile->GetSectionSize(a.section); const int svb = curConfigFile->GetSectionSize(b.section); if(svasvb) return false; return a.section #include #include #ifndef __LIBRETRO__ #include #endif #include #include #ifdef HAVE_STRINGS_H #include #endif #include #ifdef __WIN32__ #ifndef NOMINMAX #define NOMINMAX #endif #include #endif #define GFX_MULTI_FORMAT #ifdef __WIN32__ //#define RIGHTSHIFT_IS_SAR #define RIGHTSHIFT_int8_IS_SAR #define RIGHTSHIFT_int16_IS_SAR #define RIGHTSHIFT_int32_IS_SAR #ifndef __WIN32_LIBSNES__ #define SNES_JOY_READ_CALLBACKS #endif //__WIN32_LIBSNES__ #endif #ifdef __MACOSX__ #undef GFX_MULTI_FORMAT #define PIXEL_FORMAT RGB555 #endif #ifndef snes9x_types_defined #define snes9x_types_defined typedef unsigned char bool8; #ifdef HAVE_STDINT_H #include typedef intptr_t pint; typedef int8_t int8; typedef uint8_t uint8; typedef int16_t int16; typedef uint16_t uint16; typedef int32_t int32; typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; #else // HAVE_STDINT_H #ifdef __WIN32__ typedef intptr_t pint; typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; typedef signed __int64 int64; typedef unsigned __int64 uint64; typedef int8 int8_t; typedef uint8 uint8_t; typedef int16 int16_t; typedef uint16 uint16_t; typedef int32 int32_t; typedef uint32 uint32_t; typedef int64 int64_t; typedef uint64 uint64_t; typedef int socklen_t; #else // __WIN32__ typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; #ifdef __GNUC__ // long long is not part of ISO C++ __extension__ #endif typedef long long int64; typedef unsigned long long uint64; #ifdef PTR_NOT_INT typedef long pint; #else // __PTR_NOT_INT typedef int pint; #endif // __PTR_NOT_INT #endif // __WIN32__ #endif // HAVE_STDINT_H #endif // snes9x_types_defined #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define START_EXTERN_C extern "C" { #define END_EXTERN_C } #ifndef __WIN32__ #ifndef PATH_MAX #define PATH_MAX 1024 #endif #define _MAX_DRIVE 1 #define _MAX_DIR PATH_MAX #define _MAX_FNAME PATH_MAX #define _MAX_EXT PATH_MAX #define _MAX_PATH PATH_MAX #else #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #endif #ifndef __WIN32__ void _splitpath (const char *, char *, char *, char *, char *); void _makepath (char *, const char *, const char *, const char *, const char *); #define S9xDisplayString DisplayStringFromBottom #else // __WIN32__ #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp #ifndef __WIN32_LIBSNES__ void WinDisplayStringFromBottom(const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap); #define S9xDisplayString WinDisplayStringFromBottom void SetInfoDlgColor(unsigned char, unsigned char, unsigned char); #define SET_UI_COLOR(r,g,b) SetInfoDlgColor(r,g,b) #else // __WIN32_LIBSNES__ #define S9xDisplayString DisplayStringFromBottom #endif // __WIN32_LIBSNES__ #endif // __WIN32__ #ifdef __DJGPP #define SLASH_STR "\\" #define SLASH_CHAR '\\' #else #define SLASH_STR "/" #define SLASH_CHAR '/' #endif #ifndef SIG_PF #define SIG_PF void (*) (int) #endif #ifdef __linux #define TITLE "Snes9x: Linux" #define SYS_CONFIG_FILE "/etc/snes9x/snes9x.conf" #endif #ifndef TITLE #define TITLE "Snes9x" #endif #if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || defined(_XBOX1) || defined(ARM) || defined(ANDROID) #define LSB_FIRST #define FAST_LSB_WORD_ACCESS #else #define MSB_FIRST #endif #ifdef FAST_LSB_WORD_ACCESS #define READ_WORD(s) (*(uint16 *) (s)) #define READ_3WORD(s) (*(uint32 *) (s) & 0x00ffffff) #define READ_DWORD(s) (*(uint32 *) (s)) #define WRITE_WORD(s, d) *(uint16 *) (s) = (d) #define WRITE_3WORD(s, d) *(uint16 *) (s) = (uint16) (d), *((uint8 *) (s) + 2) = (uint8) ((d) >> 16) #define WRITE_DWORD(s, d) *(uint32 *) (s) = (d) #else #define READ_WORD(s) (*(uint8 *) (s) | (*((uint8 *) (s) + 1) << 8)) #define READ_3WORD(s) (*(uint8 *) (s) | (*((uint8 *) (s) + 1) << 8) | (*((uint8 *) (s) + 2) << 16)) #define READ_DWORD(s) (*(uint8 *) (s) | (*((uint8 *) (s) + 1) << 8) | (*((uint8 *) (s) + 2) << 16) | (*((uint8 *) (s) + 3) << 24)) #define WRITE_WORD(s, d) *(uint8 *) (s) = (uint8) (d), *((uint8 *) (s) + 1) = (uint8) ((d) >> 8) #define WRITE_3WORD(s, d) *(uint8 *) (s) = (uint8) (d), *((uint8 *) (s) + 1) = (uint8) ((d) >> 8), *((uint8 *) (s) + 2) = (uint8) ((d) >> 16) #define WRITE_DWORD(s, d) *(uint8 *) (s) = (uint8) (d), *((uint8 *) (s) + 1) = (uint8) ((d) >> 8), *((uint8 *) (s) + 2) = (uint8) ((d) >> 16), *((uint8 *) (s) + 3) = (uint8) ((d) >> 24) #endif #define SWAP_WORD(s) (s) = (((s) & 0xff) << 8) | (((s) & 0xff00) >> 8) #define SWAP_DWORD(s) (s) = (((s) & 0xff) << 24) | (((s) & 0xff00) << 8) | (((s) & 0xff0000) >> 8) | (((s) & 0xff000000) >> 24) #include "pixform.h" #endif docs/snes9x-license.txt000664 001750 001750 00000013575 12720446475 016272 0ustar00sergiosergio000000 000000 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. apu/apu.cpp000664 001750 001750 00000050627 12720446475 014005 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "apu.h" #include "snapshot.h" #include "display.h" #include "hermite_resampler.h" #include "bapu/snes/snes.hpp" #define APU_DEFAULT_INPUT_RATE 32000 #define APU_MINIMUM_SAMPLE_COUNT 512 #define APU_MINIMUM_SAMPLE_BLOCK 128 #define APU_NUMERATOR_NTSC 15664 #define APU_DENOMINATOR_NTSC 328125 #define APU_NUMERATOR_PAL 34176 #define APU_DENOMINATOR_PAL 709379 namespace SNES { #include "bapu/dsp/blargg_endian.h" CPU cpu; } namespace spc { static apu_callback sa_callback = NULL; static void *extra_data = NULL; static bool8 sound_in_sync = TRUE; static bool8 sound_enabled = FALSE; static int buffer_size; static int lag_master = 0; static int lag = 0; static uint8 *landing_buffer = NULL; static uint8 *shrink_buffer = NULL; static Resampler *resampler = NULL; static int32 reference_time; static uint32 remainder; static const int timing_hack_numerator = 256; static int timing_hack_denominator = 256; /* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup if necessary on game load. */ static uint32 ratio_numerator = APU_NUMERATOR_NTSC; static uint32 ratio_denominator = APU_DENOMINATOR_NTSC; } static void EightBitize (uint8 *, int); static void DeStereo (uint8 *, int); static void ReverseStereo (uint8 *, int); static void UpdatePlaybackRate (void); static void SPCSnapshotCallback (void); static inline int S9xAPUGetClock (int32); static inline int S9xAPUGetClockRemainder (int32); static void EightBitize (uint8 *buffer, int sample_count) { uint8 *buf8 = (uint8 *) buffer; int16 *buf16 = (int16 *) buffer; for (int i = 0; i < sample_count; i++) buf8[i] = (uint8) ((buf16[i] / 256) + 128); } static void DeStereo (uint8 *buffer, int sample_count) { int16 *buf = (int16 *) buffer; int32 s1, s2; for (int i = 0; i < sample_count >> 1; i++) { s1 = (int32) buf[2 * i]; s2 = (int32) buf[2 * i + 1]; buf[i] = (int16) ((s1 + s2) >> 1); } } static void ReverseStereo (uint8 *src_buffer, int sample_count) { int16 *buffer = (int16 *) src_buffer; for (int i = 0; i < sample_count; i += 2) { buffer[i + 1] ^= buffer[i]; buffer[i] ^= buffer[i + 1]; buffer[i + 1] ^= buffer[i]; } } bool8 S9xMixSamples (uint8 *buffer, int sample_count) { static int shrink_buffer_size = -1; uint8 *dest; if (!Settings.SixteenBitSound || !Settings.Stereo) { /* We still need both stereo samples for generating the mono sample */ if (!Settings.Stereo) sample_count <<= 1; /* We still have to generate 16-bit samples for bit-dropping, too */ if (shrink_buffer_size < (sample_count << 1)) { delete[] spc::shrink_buffer; spc::shrink_buffer = new uint8[sample_count << 1]; shrink_buffer_size = sample_count << 1; } dest = spc::shrink_buffer; } else dest = buffer; if (Settings.Mute) { memset(dest, 0, sample_count << 1); spc::resampler->clear(); return (FALSE); } else { if (spc::resampler->avail() >= (sample_count + spc::lag)) { spc::resampler->read((short *) dest, sample_count); if (spc::lag == spc::lag_master) spc::lag = 0; } else { memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1)); if (spc::lag == 0) spc::lag = spc::lag_master; return (FALSE); } } if (Settings.ReverseStereo && Settings.Stereo) ReverseStereo(dest, sample_count); if (!Settings.Stereo || !Settings.SixteenBitSound) { if (!Settings.Stereo) { DeStereo(dest, sample_count); sample_count >>= 1; } if (!Settings.SixteenBitSound) EightBitize(dest, sample_count); memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0))); } return (TRUE); } int S9xGetSampleCount (void) { return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1)); } /* TODO: Attach */ void S9xFinalizeSamples (void) { if (!Settings.Mute) { if (!spc::resampler->push((short *) spc::landing_buffer, SNES::dsp.spc_dsp.sample_count ())) { /* We weren't able to process the entire buffer. Potential overrun. */ spc::sound_in_sync = FALSE; if (Settings.SoundSync && !Settings.TurboMode) return; } } if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute) spc::sound_in_sync = TRUE; else if (spc::resampler->space_empty() >= spc::resampler->space_filled()) spc::sound_in_sync = TRUE; else spc::sound_in_sync = FALSE; SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); } void S9xLandSamples (void) { if (spc::sa_callback != NULL) spc::sa_callback(spc::extra_data); else S9xFinalizeSamples(); } void S9xClearSamples (void) { spc::resampler->clear(); spc::lag = spc::lag_master; } bool8 S9xSyncSound (void) { if (!Settings.SoundSync || spc::sound_in_sync) return (TRUE); S9xLandSamples(); return (spc::sound_in_sync); } void S9xSetSamplesAvailableCallback (apu_callback callback, void *data) { spc::sa_callback = callback; spc::extra_data = data; } static void UpdatePlaybackRate (void) { if (Settings.SoundInputRate == 0) Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE; double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator); spc::resampler->time_ratio(time_ratio); } bool8 S9xInitSound (int buffer_ms, int lag_ms) { // buffer_ms : buffer size given in millisecond // lag_ms : allowable time-lag given in millisecond int sample_count = buffer_ms * 32000 / 1000; int lag_sample_count = lag_ms * 32000 / 1000; spc::lag_master = lag_sample_count; if (Settings.Stereo) spc::lag_master <<= 1; spc::lag = spc::lag_master; if (sample_count < APU_MINIMUM_SAMPLE_COUNT) sample_count = APU_MINIMUM_SAMPLE_COUNT; spc::buffer_size = sample_count; if (Settings.Stereo) spc::buffer_size <<= 1; if (Settings.SixteenBitSound) spc::buffer_size <<= 1; printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count); if (spc::landing_buffer) delete[] spc::landing_buffer; spc::landing_buffer = new uint8[spc::buffer_size * 2]; if (!spc::landing_buffer) return (FALSE); /* The resampler and spc unit use samples (16-bit short) as arguments. Use 2x in the resampler for buffer leveling with SoundSync */ if (!spc::resampler) { spc::resampler = new HermiteResampler(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); if (!spc::resampler) { delete[] spc::landing_buffer; return (FALSE); } } else spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); UpdatePlaybackRate(); spc::sound_enabled = S9xOpenSoundDevice(); return (spc::sound_enabled); } void S9xSetSoundControl (uint8 voice_switch) { SNES::dsp.spc_dsp.set_stereo_switch (voice_switch << 8 | voice_switch); } void S9xSetSoundMute (bool8 mute) { Settings.Mute = mute; if (!spc::sound_enabled) Settings.Mute = TRUE; } void S9xDumpSPCSnapshot (void) { SNES::dsp.spc_dsp.dump_spc_snapshot(); } static void SPCSnapshotCallback (void) { S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR)); printf("Dumped key-on triggered spc snapshot.\n"); } bool8 S9xInitAPU (void) { spc::landing_buffer = NULL; spc::shrink_buffer = NULL; spc::resampler = NULL; return (TRUE); } void S9xDeinitAPU (void) { if (spc::resampler) { delete spc::resampler; spc::resampler = NULL; } if (spc::landing_buffer) { delete[] spc::landing_buffer; spc::landing_buffer = NULL; } if (spc::shrink_buffer) { delete[] spc::shrink_buffer; spc::shrink_buffer = NULL; } } static inline int S9xAPUGetClock (int32 cpucycles) { return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / spc::ratio_denominator; } static inline int S9xAPUGetClockRemainder (int32 cpucycles) { return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % spc::ratio_denominator; } uint8 S9xAPUReadPort (int port) { S9xAPUExecute (); return ((uint8) SNES::smp.port_read (port & 3)); } void S9xAPUWritePort (int port, uint8 byte) { S9xAPUExecute (); SNES::cpu.port_write (port & 3, byte); } void S9xAPUSetReferenceTime (int32 cpucycles) { spc::reference_time = cpucycles; } void S9xAPUExecute (void) { SNES::smp.clock -= S9xAPUGetClock (CPU.Cycles); SNES::smp.enter (); spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles); S9xAPUSetReferenceTime(CPU.Cycles); } void S9xAPUEndScanline (void) { S9xAPUExecute(); SNES::dsp.synchronize(); if (SNES::dsp.spc_dsp.sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync) S9xLandSamples(); } void S9xAPUTimingSetSpeedup (int ticks) { if (ticks != 0) printf("APU speedup hack: %d\n", ticks); spc::timing_hack_denominator = 256 - ticks; spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC; spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC; spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator; UpdatePlaybackRate(); } void S9xResetAPU (void) { spc::reference_time = 0; spc::remainder = 0; SNES::cpu.reset (); SNES::cpu.frequency = Settings.PAL ? PAL_MASTER_CLOCK : NTSC_MASTER_CLOCK; SNES::smp.power (); SNES::dsp.power (); SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback); spc::resampler->clear(); } void S9xSoftResetAPU (void) { spc::reference_time = 0; spc::remainder = 0; SNES::cpu.reset (); SNES::smp.reset (); SNES::dsp.reset (); SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); spc::resampler->clear(); } void S9xAPUSaveState (uint8 *block) { uint8 *ptr = block; SNES::smp.save_state (&ptr); SNES::dsp.save_state (&ptr); SNES::set_le32(ptr, spc::reference_time); ptr += sizeof(int32); SNES::set_le32(ptr, spc::remainder); ptr += sizeof(int32); SNES::set_le32(ptr, SNES::dsp.clock); ptr += sizeof(int32); memcpy (ptr, SNES::cpu.registers, 4); ptr += sizeof(int32); memset (ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE-(ptr-block)); } void S9xAPULoadState (uint8 *block) { uint8 *ptr = block; SNES::smp.load_state (&ptr); SNES::dsp.load_state (&ptr); spc::reference_time = SNES::get_le32(ptr); ptr += sizeof(int32); spc::remainder = SNES::get_le32(ptr); ptr += sizeof(int32); SNES::dsp.clock = SNES::get_le32(ptr); ptr += sizeof(int32); memcpy (SNES::cpu.registers, ptr, 4); } static void to_var_from_buf (uint8 **buf, void *var, size_t size) { memcpy(var, *buf, size); *buf += size; } #undef IF_0_THEN_256 #define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) void S9xAPULoadBlarggState(uint8 *oldblock) { uint8 *ptr = oldblock; SNES::SPC_State_Copier copier(&ptr,to_var_from_buf); copier.copy(SNES::smp.apuram,0x10000); // RAM uint8_t regs_in [0x10]; uint8_t regs [0x10]; uint16_t pc, spc_time, dsp_time; uint8_t a,x,y,psw,sp; copier.copy(regs,0x10); // REGS copier.copy(regs_in,0x10); // REGS_IN // CPU Regs pc = copier.copy_int( 0, sizeof(uint16_t) ); a = copier.copy_int( 0, sizeof(uint8_t) ); x = copier.copy_int( 0, sizeof(uint8_t) ); y = copier.copy_int( 0, sizeof(uint8_t) ); psw = copier.copy_int( 0, sizeof(uint8_t) ); sp = copier.copy_int( 0, sizeof(uint8_t) ); copier.extra(); // times spc_time = copier.copy_int( 0, sizeof(uint16_t) ); dsp_time = copier.copy_int( 0, sizeof(uint16_t) ); int cur_time = S9xAPUGetClock(CPU.Cycles); // spc_time is absolute, dsp_time is relative // smp.clock is relative, dsp.clock relative but counting upwards SNES::smp.clock = spc_time - cur_time; SNES::dsp.clock = -1 * dsp_time; // DSP SNES::dsp.load_state(&ptr); // Timers uint16_t next_time[3]; uint8_t divider[3], counter[3]; for ( int i = 0; i < 3; i++ ) { next_time[i] = copier.copy_int( 0, sizeof(uint16_t) ); divider[i] = copier.copy_int( 0, sizeof(uint8_t) ); counter[i] = copier.copy_int( 0, sizeof(uint8_t) ); copier.extra(); } // construct timers out of available parts from blargg smp SNES::smp.timer0.enable = regs[1] >> 0 & 1; // regs[1] = CONTROL SNES::smp.timer0.target = IF_0_THEN_256(regs[10]); // regs[10+i] = TiTARGET // blargg counts time, get ticks through timer frequency // (assume tempo = 256) SNES::smp.timer0.stage1_ticks = 128 - (next_time[0] - cur_time) / 128; SNES::smp.timer0.stage2_ticks = divider[0]; SNES::smp.timer0.stage3_ticks = counter[0]; SNES::smp.timer1.enable = regs[1] >> 1 & 1; SNES::smp.timer1.target = IF_0_THEN_256(regs[11]); SNES::smp.timer1.stage1_ticks = 128 - (next_time[1] - cur_time) / 128; SNES::smp.timer1.stage2_ticks = divider[0]; SNES::smp.timer1.stage3_ticks = counter[0]; SNES::smp.timer2.enable = regs[1] >> 2 & 1; SNES::smp.timer2.target = IF_0_THEN_256(regs[12]); SNES::smp.timer2.stage1_ticks = 16 - (next_time[2] - cur_time) / 16; SNES::smp.timer2.stage2_ticks = divider[0]; SNES::smp.timer2.stage3_ticks = counter[0]; copier.extra(); SNES::smp.opcode_number = 0; SNES::smp.opcode_cycle = 0; SNES::smp.regs.pc = pc; SNES::smp.regs.sp = sp; SNES::smp.regs.B.a = a; SNES::smp.regs.x = x; SNES::smp.regs.B.y = y; // blargg's psw has same layout as byuu's flags SNES::smp.regs.p = psw; // blargg doesn't explicitly store iplrom_enable SNES::smp.status.iplrom_enable = regs[1] & 0x80; SNES::smp.status.dsp_addr = regs[2]; SNES::smp.status.ram00f8 = regs_in[8]; SNES::smp.status.ram00f9 = regs_in[9]; // default to 0 - we are on an opcode boundary, shouldn't matter SNES::smp.rd=SNES::smp.wr=SNES::smp.dp=SNES::smp.sp=SNES::smp.ya=SNES::smp.bit=0; spc::reference_time = SNES::get_le32(ptr); ptr += sizeof(int32); spc::remainder = SNES::get_le32(ptr); ptr += sizeof(int32); // blargg stores CPUIx in regs_in memcpy (SNES::cpu.registers, regs_in + 4, 4); } bool8 S9xSPCDump (const char *filename) { FILE *fs; uint8 buf[SPC_FILE_SIZE]; size_t ignore; fs = fopen(filename, "wb"); if (!fs) return (FALSE); S9xSetSoundMute(TRUE); SNES::smp.save_spc (buf); if ((ignore = fwrite(buf, SPC_FILE_SIZE, 1, fs)) <= 0) fprintf (stderr, "Couldn't write file %s.\n", filename); fclose(fs); S9xSetSoundMute(FALSE); return (TRUE); } docs/gpl-2.0.txt000664 001750 001750 00000043103 12720446475 014466 0ustar00sergiosergio000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. bsx.cpp000664 001750 001750 00000063243 12720446475 013225 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ // Dreamer Nom wrote: // Large thanks to John Weidman for all his initial research // Thanks to Seph3 for his modem notes #include "snes9x.h" #include "memmap.h" #include "display.h" //#define BSX_DEBUG #define BIOS_SIZE 0x100000 #define FLASH_SIZE 0x200000 #define PSRAM_SIZE 0x80000 #define Map Memory.Map #define BlockIsRAM Memory.BlockIsRAM #define BlockIsROM Memory.BlockIsROM #define RAM Memory.RAM #define SRAM Memory.SRAM #define PSRAM Memory.BSRAM #define BIOSROM Memory.BIOSROM #define MAP_BSX Memory.MAP_BSX #define MAP_CPU Memory.MAP_CPU #define MAP_PPU Memory.MAP_PPU #define MAP_NONE Memory.MAP_NONE #define BSXPPUBASE 0x2180 struct SBSX_RTC { int hours; int minutes; int seconds; int ticks; }; static struct SBSX_RTC BSX_RTC; // flash card vendor information static const uint8 flashcard[20] = { 0x4D, 0x00, 0x50, 0x00, // vendor id 0x00, 0x00, // ? 0x2B, 0x00, // 2MB Flash (1MB = 0x2A) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8 init2192[32] = // FIXME { 00, 00, 00, 00, 00, // unknown 01, 01, 00, 00, 00, 00, // seconds (?) 00, // minutes 00, // hours 10, 10, 10, 10, 10, // unknown 10, 10, 10, 10, 10, // dummy 00, 00, 00, 00, 00, 00, 00, 00, 00 }; static bool8 FlashMode; static uint32 FlashSize; static uint8 *MapROM, *FlashROM; static void BSX_Map_SNES (void); static void BSX_Map_LoROM (void); static void BSX_Map_HiROM (void); static void BSX_Map_MMC (void); static void BSX_Map_FlashIO (void); static void BSX_Map_SRAM (void); static void BSX_Map_PSRAM (void); static void BSX_Map_BIOS (void); static void BSX_Map_RAM (void); static void BSX_Map_Dirty (void); static void BSX_Map (void); static void BSX_Set_Bypass_FlashIO (uint16, uint8); static uint8 BSX_Get_Bypass_FlashIO (uint16); static bool8 BSX_LoadBIOS (void); static void map_psram_mirror_sub (uint32); static int is_bsx (unsigned char *); static void BSX_Map_SNES (void) { // These maps will be partially overwritten int c; // Banks 00->3F and 80->BF for (c = 0; c < 0x400; c += 16) { Map[c + 0] = Map[c + 0x800] = RAM; Map[c + 1] = Map[c + 0x801] = RAM; BlockIsRAM[c + 0] = BlockIsRAM[c + 0x800] = TRUE; BlockIsRAM[c + 1] = BlockIsRAM[c + 0x801] = TRUE; Map[c + 2] = Map[c + 0x802] = (uint8 *) MAP_PPU; Map[c + 3] = Map[c + 0x803] = (uint8 *) MAP_PPU; Map[c + 4] = Map[c + 0x804] = (uint8 *) MAP_CPU; Map[c + 5] = Map[c + 0x805] = (uint8 *) MAP_CPU; Map[c + 6] = Map[c + 0x806] = (uint8 *) MAP_NONE; Map[c + 7] = Map[c + 0x807] = (uint8 *) MAP_NONE; } } static void BSX_Map_LoROM (void) { // These maps will be partially overwritten int i, c; // Banks 00->3F and 80->BF for (c = 0; c < 0x400; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000; BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; } } // Banks 40->7F and C0->FF for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 8; i++) Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize]; for (i = c + 8; i < c + 16; i++) Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize] - 0x8000; for (i = c; i < c + 16; i++) { BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable; BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable; } } } static void BSX_Map_HiROM (void) { // These maps will be partially overwritten int i, c; // Banks 00->3F and 80->BF for (c = 0; c < 0x400; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize]; BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; } } // Banks 40->7F and C0->FF for (c = 0; c < 0x400; c += 16) { for (i = c; i < c + 16; i++) { Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 12) % FlashSize]; BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable; BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable; } } } static void BSX_Map_MMC (void) { int c; // Banks 01->0E:5000-5FFF for (c = 0x010; c < 0x0F0; c += 16) { Map[c + 5] = (uint8 *) MAP_BSX; BlockIsRAM[c + 5] = BlockIsROM[c + 5] = FALSE; } } static void BSX_Map_FlashIO (void) { int c; if (BSX.MMC[0x0C] || BSX.MMC[0x0D]) { // Bank C0:0000, 2AAA, 5555, FF00-FF1F for (c = 0; c < 16; c++) { Map[c + 0xC00] = (uint8 *) MAP_BSX; BlockIsRAM[c + 0xC00] = TRUE; BlockIsROM[c + 0xC00] = FALSE; } } } static void BSX_Map_SRAM (void) { int c; // Banks 10->17:5000-5FFF for (c = 0x100; c < 0x180; c += 16) { Map[c + 5] = (uint8 *) SRAM + ((c & 0x70) << 8) - 0x5000; BlockIsRAM[c + 5] = TRUE; BlockIsROM[c + 5] = FALSE; } } static void map_psram_mirror_sub (uint32 bank) { int i, c; bank <<= 4; if (BSX.MMC[0x02]) { for (c = 0; c < 0x100; c += 16) { for (i = c; i < c + 16; i++) { Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; BlockIsRAM[i + bank] = TRUE; BlockIsROM[i + bank] = FALSE; } } } else { for (c = 0; c < 0x100; c += 16) { for (i = c; i < c + 8; i++) Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE]; for (i = c + 8; i < c + 16; i++) Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000; for (i = c; i < c + 16; i++) { BlockIsRAM[i + bank] = TRUE; BlockIsROM[i + bank] = FALSE; } } } } static void BSX_Map_PSRAM (void) { int c; // Banks 70->77:0000-FFFF // FIXME: could be toggled by $03 for (c = 0; c < 0x80; c++) { Map[c + 0x700] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; BlockIsRAM[c + 0x700] = TRUE; BlockIsROM[c + 0x700] = FALSE; } // Banks 20->3F:6000-7FFF mirrors 70->77:6000-7FFF for (c = 0x200; c < 0x400; c += 16) { Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; BlockIsRAM[c + 6] = TRUE; BlockIsRAM[c + 7] = TRUE; BlockIsROM[c + 6] = FALSE; BlockIsROM[c + 7] = FALSE; } if (!BSX.MMC[0x05]) // Banks 40->4F:0000-FFFF mirrors 70->77:0000-7FFF map_psram_mirror_sub(0x40); if (!BSX.MMC[0x06]) // Banks 50->5F:0000-FFFF mirrors 70->77:0000-7FFF map_psram_mirror_sub(0x50); // FIXME if (!BSX.MMC[0x03]) // Banks 60->6F:0000-FFFF mirrors 70->77:0000-7FFF (?) map_psram_mirror_sub(0x60); } static void BSX_Map_BIOS (void) { int i,c; // Banks 00->1F:8000-FFFF if (BSX.MMC[0x07]) { for (c = 0; c < 0x200; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000; BlockIsRAM[i] = FALSE; BlockIsROM[i] = TRUE; } } } // Banks 80->9F:8000-FFFF if (BSX.MMC[0x08]) { for (c = 0; c < 0x200; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i + 0x800] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000; BlockIsRAM[i + 0x800] = FALSE; BlockIsROM[i + 0x800] = TRUE; } } } } static void BSX_Map_RAM (void) { int c; // Banks 7E->7F for (c = 0; c < 16; c++) { Map[c + 0x7E0] = RAM; Map[c + 0x7F0] = RAM + 0x10000; BlockIsRAM[c + 0x7E0] = TRUE; BlockIsRAM[c + 0x7F0] = TRUE; BlockIsROM[c + 0x7E0] = FALSE; BlockIsROM[c + 0x7F0] = FALSE; } } static void BSX_Map_Dirty (void) { // for the quick bank change int i, c; // Banks 00->1F and 80->9F:8000-FFFF if (BSX.MMC[0x02]) { for (c = 0; c < 0x200; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize]; BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; } } } else { for (c = 0; c < 0x200; c += 16) { for (i = c + 8; i < c + 16; i++) { Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000; BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; } } } } static void BSX_Map (void) { #ifdef BSX_DEBUG printf("BS: Remapping\n"); for (int i = 0; i < 32; i++) printf("BS: MMC %02X: %d\n", i, BSX.MMC[i]); #endif memcpy(BSX.prevMMC, BSX.MMC, sizeof(BSX.MMC)); // Do a quick bank change if (BSX.dirty2 && !BSX.dirty) { BSX_Map_Dirty(); BSX_Map_BIOS(); BSX.dirty2 = FALSE; Memory.map_WriteProtectROM(); return; } if (BSX.MMC[0x01]) { MapROM = PSRAM; FlashSize = PSRAM_SIZE; } else { MapROM = FlashROM; FlashSize = FLASH_SIZE; } BSX_Map_SNES(); if (BSX.MMC[0x02]) BSX_Map_HiROM(); else BSX_Map_LoROM(); BSX_Map_PSRAM(); BSX_Map_SRAM(); BSX_Map_RAM(); BSX_Map_BIOS(); BSX_Map_FlashIO(); BSX_Map_MMC(); // Monitor new register changes BSX.dirty = FALSE; BSX.dirty2 = FALSE; Memory.map_WriteProtectROM(); } static uint8 BSX_Get_Bypass_FlashIO (uint16 offset) { if (BSX.MMC[0x02]) return (MapROM[offset]); else { if (offset < 0x8000) return (MapROM[offset]); else return (MapROM[offset - 0x8000]); } } static void BSX_Set_Bypass_FlashIO (uint16 offset, uint8 byte) { if (BSX.MMC[0x02]) MapROM[offset] = byte; else { if (offset < 0x8000) MapROM[offset] = byte; else MapROM[offset - 0x8000] = byte; } } uint8 S9xGetBSX (uint32 address) { uint8 bank = (address >> 16) & 0xFF; uint16 offset = address & 0xFFFF; uint8 t = 0; // MMC if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) return (BSX.MMC[bank]); // Flash IO if (bank == 0xC0) { // default: read-through mode t = BSX_Get_Bypass_FlashIO(offset); // note: may be more registers, purposes unknown switch (offset) { case 0x0002: if (BSX.flash_enable) t = 0x80; // status register? break; case 0x5555: if (BSX.flash_enable) t = 0x80; // ??? break; case 0xFF00: case 0xFF02: case 0xFF04: case 0xFF06: case 0xFF08: case 0xFF0A: case 0xFF0C: case 0xFF0E: case 0xFF10: case 0xFF12: // return flash vendor information if (BSX.read_enable) t = flashcard[offset - 0xFF00]; break; } } return (t); } void S9xSetBSX (uint8 byte, uint32 address) { uint8 bank = (address >> 16) & 0xFF; uint16 offset = address & 0xFFFF; // MMC if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) { switch (bank) { case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: if (BSX.MMC[bank] != byte) { BSX.MMC[bank] = byte; BSX.dirty = TRUE; } break; case 0x07: case 0x08: if (BSX.MMC[bank] != byte) { BSX.MMC[bank] = byte; BSX.dirty2 = TRUE; } break; case 0x0E: BSX.MMC[bank] = byte; if (byte && (BSX.dirty || BSX.dirty2)) BSX_Map(); break; } } // Flash IO if (bank == 0xC0) { BSX.old_write = BSX.new_write; BSX.new_write = address; // ???: double writes to the desired address will bypass // flash registers if (BSX.old_write == BSX.new_write && BSX.write_enable) { BSX_Set_Bypass_FlashIO(offset, byte); return; } // flash command handling // note: incomplete switch (offset) { case 0x0000: BSX.flash_command <<= 8; BSX.flash_command |= byte; if ((BSX.flash_command & 0xFFFF) == 0x38D0) { // retrieve information about the flash card BSX.flash_enable = TRUE; BSX.read_enable = TRUE; } break; case 0x2AAA: BSX.flash_command <<= 8; BSX.flash_command |= byte; break; case 0x5555: BSX.flash_command <<= 8; BSX.flash_command |= byte; switch (BSX.flash_command & 0xFFFFFF) { case 0xAA55F0: // turn off flash i/o BSX.flash_enable = FALSE; BSX.write_enable = FALSE; BSX.read_enable = FALSE; break; case 0xAA55A0: // enable writing to flash BSX.old_write = 0; BSX.new_write = 0; BSX.flash_enable = TRUE; BSX.write_enable = TRUE; BSX_Map(); break; case 0xAA5570: // turn on write-protection BSX.write_enable = FALSE; BSX_Map(); break; case 0xAA5580: case 0xAA5510: // ??? break; } break; } } } uint8 S9xGetBSXPPU (uint16 address) { uint8 t; // known read registers switch (address) { // Test register low? (r/w) case 0x2188: t = BSX.PPU[0x2188 - BSXPPUBASE]; break; // Test register high? (r/w) case 0x2189: t = BSX.PPU[0x2189 - BSXPPUBASE]; break; case 0x218A: t = BSX.PPU[0x218A - BSXPPUBASE]; break; case 0x218C: t = BSX.PPU[0x218C - BSXPPUBASE]; break; // Transmission number low? (r/w) case 0x218E: t = BSX.PPU[0x218E - BSXPPUBASE]; break; // Transmission number high? (r/w) case 0x218F: t = BSX.PPU[0x218F - BSXPPUBASE]; break; // Status register? (r) case 0x2190: t = BSX.PPU[0x2190 - BSXPPUBASE]; break; // Data register? (r/w) case 0x2192: t = BSX.PPU[0x2192 - BSXPPUBASE]; // test t = BSX.test2192[BSX.out_index++]; if (BSX.out_index == 32) BSX.out_index = 0; BSX_RTC.ticks++; if (BSX_RTC.ticks >= 1000) { BSX_RTC.ticks = 0; BSX_RTC.seconds++; } if (BSX_RTC.seconds >= 60) { BSX_RTC.seconds = 0; BSX_RTC.minutes++; } if (BSX_RTC.minutes >= 60) { BSX_RTC.minutes = 0; BSX_RTC.hours++; } if (BSX_RTC.hours >= 24) BSX_RTC.hours = 0; BSX.test2192[10] = BSX_RTC.seconds; BSX.test2192[11] = BSX_RTC.minutes; BSX.test2192[12] = BSX_RTC.hours; break; // Transmission status? (r/w) case 0x2193: // Data ready when bits 2/3 clear? t = BSX.PPU[0x2193 - BSXPPUBASE] & ~0x0C; break; // Reset? (r/w) case 0x2194: t = BSX.PPU[0x2194 - BSXPPUBASE]; break; // Unknown (r) case 0x2196: t = BSX.PPU[0x2196 - BSXPPUBASE]; break; // Unknown (r/w) case 0x2197: t = BSX.PPU[0x2197 - BSXPPUBASE]; break; // Modem protocol? (r/w) case 0x2199: t = BSX.PPU[0x2199 - BSXPPUBASE]; break; default: t = OpenBus; break; } return (t); } void S9xSetBSXPPU (uint8 byte, uint16 address) { // known write registers switch (address) { // Test register low? (r/w) case 0x2188: BSX.PPU[0x2188 - BSXPPUBASE] = byte; break; // Test register high? (r/w) case 0x2189: BSX.PPU[0x2189 - BSXPPUBASE] = byte; break; case 0x218A: BSX.PPU[0x218A - BSXPPUBASE] = byte; break; case 0x218B: BSX.PPU[0x218B - BSXPPUBASE] = byte; break; case 0x218C: BSX.PPU[0x218C - BSXPPUBASE] = byte; break; // Transmission number low? (r/w) case 0x218E: BSX.PPU[0x218E - BSXPPUBASE] = byte; break; // Transmission number high? (r/w) case 0x218F: BSX.PPU[0x218F - BSXPPUBASE] = byte; // ? BSX.PPU[0x218E - BSXPPUBASE] >>= 1; BSX.PPU[0x218E - BSXPPUBASE] = BSX.PPU[0x218F - BSXPPUBASE] - BSX.PPU[0x218E - BSXPPUBASE]; BSX.PPU[0x218F - BSXPPUBASE] >>= 1; BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? break; // Strobe assert? (w) case 0x2191: BSX.PPU[0x2191 - BSXPPUBASE] = byte; BSX.out_index = 0; break; // Data register? (r/w) case 0x2192: BSX.PPU[0x2192 - BSXPPUBASE] = 0x01; // ? BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? break; // Transmission status? (r/w) case 0x2193: BSX.PPU[0x2193 - BSXPPUBASE] = byte; break; // Reset? (r/w) case 0x2194: BSX.PPU[0x2194 - BSXPPUBASE] = byte; break; // Unknown (r/w) case 0x2197: BSX.PPU[0x2197 - BSXPPUBASE] = byte; break; // Modem protocol? (r/w) case 0x2199: // Lots of modem strings written here when // connection is lost or no uplink established BSX.PPU[0x2199 - BSXPPUBASE] = byte; break; } } uint8 * S9xGetBasePointerBSX (uint32 address) { return (MapROM); } static bool8 BSX_LoadBIOS (void) { FILE *fp; char path[PATH_MAX + 1], name[PATH_MAX + 1]; bool8 r = FALSE; strcpy(path, S9xGetDirectory(BIOS_DIR)); strcat(path, SLASH_STR); strcpy(name, path); strcat(name, "BS-X.bin"); fp = fopen(name, "rb"); if (!fp) { strcpy(name, path); strcat(name, "BS-X.bios"); fp = fopen(name, "rb"); } if (fp) { size_t size; size = fread((void *) BIOSROM, 1, BIOS_SIZE, fp); fclose(fp); if (size == BIOS_SIZE) r = TRUE; } #ifdef BSX_DEBUG if (r) printf("BS: BIOS found.\n"); else printf("BS: BIOS not found!\n"); #endif return (r); } static bool8 is_BSX_BIOS (const uint8 *data, uint32 size) { if (size == BIOS_SIZE && strncmp((char *) (data + 0x7FC0), "Satellaview BS-X ", 21) == 0) return (TRUE); else return (FALSE); } void S9xInitBSX (void) { Settings.BS = FALSE; if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize)) { // BS-X itself Settings.BS = TRUE; Settings.BSXItself = TRUE; Memory.LoROM = TRUE; Memory.HiROM = FALSE; memmove(BIOSROM, Memory.ROM, BIOS_SIZE); FlashMode = FALSE; FlashSize = FLASH_SIZE; BSX.bootup = TRUE; } else { Settings.BSXItself = FALSE; int r1, r2; r1 = (is_bsx(Memory.ROM + 0x7FC0) == 1); r2 = (is_bsx(Memory.ROM + 0xFFC0) == 1); Settings.BS = (r1 | r2) ? TRUE : FALSE; if (Settings.BS) { // BS games Memory.LoROM = r1 ? TRUE : FALSE; Memory.HiROM = r2 ? TRUE : FALSE; uint8 *header = r1 ? Memory.ROM + 0x7FC0 : Memory.ROM + 0xFFC0; FlashMode = (header[0x18] & 0xEF) == 0x20 ? FALSE : TRUE; FlashSize = (header[0x19] & 0x20) ? PSRAM_SIZE : FLASH_SIZE; #ifdef BSX_DEBUG for (int i = 0; i <= 0x1F; i++) printf("BS: ROM Header %02X: %02X\n", i, header[i]); printf("BS: FlashMode: %d, FlashSize: %x\n", FlashMode, FlashSize); #endif BSX.bootup = Settings.BSXBootup; if (!BSX_LoadBIOS() && !is_BSX_BIOS(BIOSROM,BIOS_SIZE)) { BSX.bootup = FALSE; memset(BIOSROM, 0, BIOS_SIZE); } } } if (Settings.BS) { MapROM = NULL; FlashROM = Memory.ROM; time_t t; struct tm *tmr; time(&t); tmr = localtime(&t); BSX_RTC.ticks = 0; memcpy(BSX.test2192, init2192, sizeof(init2192)); BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec; BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min; BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour; #ifdef BSX_DEBUG printf("BS: Current Time: %02d:%02d:%02d\n", BSX_RTC.hours, BSX_RTC.minutes, BSX_RTC.seconds); #endif SNESGameFixes.SRAMInitialValue = 0x00; } } void S9xResetBSX (void) { if (Settings.BSXItself) memset(Memory.ROM, 0, FLASH_SIZE); memset(BSX.PPU, 0, sizeof(BSX.PPU)); memset(BSX.MMC, 0, sizeof(BSX.MMC)); memset(BSX.prevMMC, 0, sizeof(BSX.prevMMC)); BSX.dirty = FALSE; BSX.dirty2 = FALSE; BSX.flash_enable = FALSE; BSX.write_enable = FALSE; BSX.read_enable = FALSE; BSX.flash_command = 0; BSX.old_write = 0; BSX.new_write = 0; BSX.out_index = 0; memset(BSX.output, 0, sizeof(BSX.output)); // starting from the bios if (BSX.bootup) BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; else { BSX.MMC[0x02] = FlashMode ? 0x80: 0; // per bios: run from psram or flash card if (FlashSize == PSRAM_SIZE) { memcpy(PSRAM, FlashROM, PSRAM_SIZE); BSX.MMC[0x01] = 0x80; BSX.MMC[0x03] = 0x80; BSX.MMC[0x04] = 0x80; BSX.MMC[0x0C] = 0x80; BSX.MMC[0x0D] = 0x80; } else { BSX.MMC[0x03] = 0x80; BSX.MMC[0x05] = 0x80; BSX.MMC[0x06] = 0x80; } BSX.MMC[0x0E] = 0x80; } BSX_Map(); } void S9xBSXPostLoadState (void) { uint8 temp[16]; bool8 pd1, pd2; pd1 = BSX.dirty; pd2 = BSX.dirty2; memcpy(temp, BSX.MMC, sizeof(BSX.MMC)); memcpy(BSX.MMC, BSX.prevMMC, sizeof(BSX.MMC)); BSX_Map(); memcpy(BSX.MMC, temp, sizeof(BSX.MMC)); BSX.dirty = pd1; BSX.dirty2 = pd2; } static bool valid_normal_bank (unsigned char bankbyte) { switch (bankbyte) { case 32: case 33: case 48: case 49: return (true); break; } return (false); } static int is_bsx (unsigned char *p) { if ((p[26] == 0x33 || p[26] == 0xFF) && (!p[21] || (p[21] & 131) == 128) && valid_normal_bank(p[24])) { unsigned char m = p[22]; if (!m && !p[23]) return (2); if ((m == 0xFF && p[23] == 0xFF) || (!(m & 0xF) && ((m >> 4) - 1 < 12))) return (1); } return (0); } sdd1emu.h000664 001750 001750 00000014211 12720446475 013427 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SDD1EMU_H_ #define _SDD1EMU_H_ void SDD1_decompress (uint8 *, uint8 *, int); #endif apu/bapu/smp/core/oppseudo_pc.cpp000664 001750 001750 00000020425 12720446475 020207 0ustar00sergiosergio000000 000000 case 0x2f: { rd = op_readpc(); if(0){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xf0: { rd = op_readpc(); if(!regs.p.z){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xd0: { rd = op_readpc(); if(regs.p.z){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xb0: { rd = op_readpc(); if(!regs.p.c){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x90: { rd = op_readpc(); if(regs.p.c){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x70: { rd = op_readpc(); if(!regs.p.v){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x50: { rd = op_readpc(); if(regs.p.v){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x30: { rd = op_readpc(); if(!regs.p.n){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x10: { rd = op_readpc(); if(regs.p.n){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x03: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x01) != 0x01){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x13: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x01) == 0x01){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x23: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x02) != 0x02){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x33: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x02) == 0x02){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x43: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x04) != 0x04){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x53: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x04) == 0x04){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x63: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x08) != 0x08){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x73: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x08) == 0x08){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x83: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x10) != 0x10){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x93: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x10) == 0x10){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xa3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x20) != 0x20){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xb3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x20) == 0x20){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xc3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x40) != 0x40){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xd3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x40) == 0x40){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xe3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x80) != 0x80){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xf3: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if((sp & 0x80) == 0x80){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x2e: { dp = op_readpc(); sp = op_readdp(dp); rd = op_readpc(); op_io(); if(regs.B.a == sp){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xde: { dp = op_readpc(); op_io(); sp = op_readdp(dp + regs.x); rd = op_readpc(); op_io(); if(regs.B.a == sp){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x6e: { dp = op_readpc(); wr = op_readdp(dp); op_writedp(dp, --wr); rd = op_readpc(); if(wr == 0x00){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0xfe: { rd = op_readpc(); op_io(); regs.B.y--; op_io(); if(regs.B.y == 0x00){ break; } op_io(2); regs.pc += (int8)rd; break; } case 0x5f: { rd = op_readpc(); rd |= op_readpc() << 8; regs.pc = rd; break; } case 0x1f: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.x; rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; regs.pc = rd; break; } case 0x3f: { rd = op_readpc(); rd |= op_readpc() << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x4f: { rd = op_readpc(); op_io(2); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = 0xff00 | rd; break; } case 0x01: { dp = 0xffde - (0 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x11: { dp = 0xffde - (1 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x21: { dp = 0xffde - (2 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x31: { dp = 0xffde - (3 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x41: { dp = 0xffde - (4 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x51: { dp = 0xffde - (5 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x61: { dp = 0xffde - (6 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x71: { dp = 0xffde - (7 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x81: { dp = 0xffde - (8 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x91: { dp = 0xffde - (9 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xa1: { dp = 0xffde - (10 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xb1: { dp = 0xffde - (11 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xc1: { dp = 0xffde - (12 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xd1: { dp = 0xffde - (13 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xe1: { dp = 0xffde - (14 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0xf1: { dp = 0xffde - (15 << 1); rd = op_readaddr(dp); rd |= op_readaddr(dp + 1) << 8; op_io(3); op_writestack(regs.pc >> 8); op_writestack(regs.pc); regs.pc = rd; break; } case 0x0f: { rd = op_readaddr(0xffde); rd |= op_readaddr(0xffdf) << 8; op_io(2); op_writestack(regs.pc >> 8); op_writestack(regs.pc); op_writestack(regs.p); regs.pc = rd; regs.p.b = 1; regs.p.i = 0; break; } case 0x6f: { rd = op_readstack(); rd |= op_readstack() << 8; op_io(2); regs.pc = rd; break; } case 0x7f: { regs.p = op_readstack(); rd = op_readstack(); rd |= op_readstack() << 8; op_io(2); regs.pc = rd; break; } apu/bapu/smp/debugger/disassembler.cpp000664 001750 001750 00000052131 12720446475 021177 0ustar00sergiosergio000000 000000 uint8 SMP::disassemble_read(uint16 addr) { if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; return smp.apuram[addr]; } uint16 SMP::relb(int8 offset, int op_len) { uint16 pc = regs.pc + op_len; return pc + offset; } void SMP::disassemble_opcode(char *output, uint16 addr) { char *s, t[512]; uint8 op, op0, op1; uint16 opw, opdp0, opdp1; s = output; sprintf(s, "..%.4x ", addr); op = disassemble_read(addr + 0); op0 = disassemble_read(addr + 1); op1 = disassemble_read(addr + 2); opw = (op0) | (op1 << 8); opdp0 = ((unsigned)regs.p.p << 8) + op0; opdp1 = ((unsigned)regs.p.p << 8) + op1; strcpy(t, " "); switch(op) { case 0x00: sprintf(t, "nop"); break; case 0x01: sprintf(t, "tcall 0"); break; case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; case 0x05: sprintf(t, "or a,$%.4x", opw); break; case 0x06: sprintf(t, "or a,(x)"); break; case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; case 0x08: sprintf(t, "or a,#$%.2x", op0); break; case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; case 0x0c: sprintf(t, "asl $%.4x", opw); break; case 0x0d: sprintf(t, "push p"); break; case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; case 0x0f: sprintf(t, "brk"); break; case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; case 0x11: sprintf(t, "tcall 1"); break; case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; case 0x19: sprintf(t, "or (x),(y)"); break; case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; case 0x1c: sprintf(t, "asl a"); break; case 0x1d: sprintf(t, "dec x"); break; case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; case 0x20: sprintf(t, "clrp"); break; case 0x21: sprintf(t, "tcall 2"); break; case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; case 0x25: sprintf(t, "and a,$%.4x", opw); break; case 0x26: sprintf(t, "and a,(x)"); break; case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; case 0x28: sprintf(t, "and a,#$%.2x", op0); break; case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; case 0x2c: sprintf(t, "rol $%.4x", opw); break; case 0x2d: sprintf(t, "push a"); break; case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; case 0x31: sprintf(t, "tcall 3"); break; case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; case 0x39: sprintf(t, "and (x),(y)"); break; case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; case 0x3c: sprintf(t, "rol a"); break; case 0x3d: sprintf(t, "inc x"); break; case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; case 0x3f: sprintf(t, "call $%.4x", opw); break; case 0x40: sprintf(t, "setp"); break; case 0x41: sprintf(t, "tcall 4"); break; case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; case 0x45: sprintf(t, "eor a,$%.4x", opw); break; case 0x46: sprintf(t, "eor a,(x)"); break; case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; case 0x4c: sprintf(t, "lsr $%.4x", opw); break; case 0x4d: sprintf(t, "push x"); break; case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; case 0x51: sprintf(t, "tcall 5"); break; case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; case 0x59: sprintf(t, "eor (x),(y)"); break; case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; case 0x5c: sprintf(t, "lsr a"); break; case 0x5d: sprintf(t, "mov x,a"); break; case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; case 0x5f: sprintf(t, "jmp $%.4x", opw); break; case 0x60: sprintf(t, "clrc"); break; case 0x61: sprintf(t, "tcall 6"); break; case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; case 0x66: sprintf(t, "cmp a,(x)"); break; case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; case 0x6c: sprintf(t, "ror $%.4x", opw); break; case 0x6d: sprintf(t, "push y"); break; case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x6f: sprintf(t, "ret"); break; case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; case 0x71: sprintf(t, "tcall 7"); break; case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; case 0x79: sprintf(t, "cmp (x),(y)"); break; case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; case 0x7c: sprintf(t, "ror a"); break; case 0x7d: sprintf(t, "mov a,x"); break; case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; case 0x7f: sprintf(t, "reti"); break; case 0x80: sprintf(t, "setc"); break; case 0x81: sprintf(t, "tcall 8"); break; case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; case 0x85: sprintf(t, "adc a,$%.4x", opw); break; case 0x86: sprintf(t, "adc a,(x)"); break; case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; case 0x8c: sprintf(t, "dec $%.4x", opw); break; case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; case 0x8e: sprintf(t, "pop p"); break; case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; case 0x91: sprintf(t, "tcall 9"); break; case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; case 0x99: sprintf(t, "adc (x),(y)"); break; case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; case 0x9c: sprintf(t, "dec a"); break; case 0x9d: sprintf(t, "mov x,sp"); break; case 0x9e: sprintf(t, "div ya,x"); break; case 0x9f: sprintf(t, "xcn a"); break; case 0xa0: sprintf(t, "ei"); break; case 0xa1: sprintf(t, "tcall 10"); break; case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; case 0xa6: sprintf(t, "sbc a,(x)"); break; case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0xab: sprintf(t, "inc $%.3x", opdp0); break; case 0xac: sprintf(t, "inc $%.4x", opw); break; case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; case 0xae: sprintf(t, "pop a"); break; case 0xaf: sprintf(t, "mov (x)+,a"); break; case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; case 0xb1: sprintf(t, "tcall 11"); break; case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; case 0xb9: sprintf(t, "sbc (x),(y)"); break; case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; case 0xbc: sprintf(t, "inc a"); break; case 0xbd: sprintf(t, "mov sp,x"); break; case 0xbe: sprintf(t, "das a"); break; case 0xbf: sprintf(t, "mov a,(x)+"); break; case 0xc0: sprintf(t, "di"); break; case 0xc1: sprintf(t, "tcall 12"); break; case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; case 0xc6: sprintf(t, "mov (x),a"); break; case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; case 0xce: sprintf(t, "pop x"); break; case 0xcf: sprintf(t, "mul ya"); break; case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; case 0xd1: sprintf(t, "tcall 13"); break; case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; case 0xdc: sprintf(t, "dec y"); break; case 0xdd: sprintf(t, "mov a,y"); break; case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; case 0xdf: sprintf(t, "daa a"); break; case 0xe0: sprintf(t, "clrv"); break; case 0xe1: sprintf(t, "tcall 14"); break; case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; case 0xe6: sprintf(t, "mov a,(x)"); break; case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; case 0xec: sprintf(t, "mov y,$%.4x", opw); break; case 0xed: sprintf(t, "notc"); break; case 0xee: sprintf(t, "pop y"); break; case 0xef: sprintf(t, "sleep"); break; case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; case 0xf1: sprintf(t, "tcall 15"); break; case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; case 0xfc: sprintf(t, "inc y"); break; case 0xfd: sprintf(t, "mov y,a"); break; case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; case 0xff: sprintf(t, "stop"); break; } t[strlen(t)] = ' '; strcat(s, t); sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); strcat(s, t); sprintf(t, "%c%c%c%c%c%c%c%c", regs.p.n ? 'N' : 'n', regs.p.v ? 'V' : 'v', regs.p.p ? 'P' : 'p', regs.p.b ? 'B' : 'b', regs.p.h ? 'H' : 'h', regs.p.i ? 'I' : 'i', regs.p.z ? 'Z' : 'z', regs.p.c ? 'C' : 'c'); strcat(s, t); } logger.h000664 001750 001750 00000014342 12720446475 013351 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _LOGGER_H_ #define _LOGGER_H_ void S9xResetLogger(void); void S9xCloseLogger(void); void S9xVideoLogger(void *, int, int, int, int); void S9xAudioLogger(void *, int); #endif apu/bapu/smp/timing.cpp000664 001750 001750 00000001151 12720446475 016221 0ustar00sergiosergio000000 000000 template void SMP::Timer::tick() { if(++stage1_ticks < cycle_frequency) return; stage1_ticks = 0; if(enable == false) return; if(++stage2_ticks != target) return; stage2_ticks = 0; stage3_ticks = (stage3_ticks + 1) & 15; } template void SMP::Timer::tick(unsigned clocks) { stage1_ticks += clocks; if(stage1_ticks < cycle_frequency) return; stage1_ticks -= cycle_frequency; if(enable == false) return; if(++stage2_ticks != target) return; stage2_ticks = 0; stage3_ticks = (stage3_ticks + 1) & 15; } libretro/libretro.h000755 001750 001750 00000257402 12720446475 015545 0ustar00sergiosergio000000 000000 /* Copyright (C) 2010-2014 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this libretro API header (libretro.h). * --------------------------------------------------------------------------------------- * * Permission is hereby granted, free of charge, * to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef LIBRETRO_H__ #define LIBRETRO_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif #ifndef __cplusplus #if defined(_MSC_VER) && !defined(SN_TARGET_PS3) /* Hack applied for MSVC when compiling in C89 mode * as it isn't C99-compliant. */ #define bool unsigned char #define true 1 #define false 0 #else #include #endif #endif /* Used for checking API/ABI mismatches that can break libretro * implementations. * It is not incremented for compatible changes to the API. */ #define RETRO_API_VERSION 1 /* * Libretro's fundamental device abstractions. * * Libretro's input system consists of some standardized device types, * such as a joypad (with/without analog), mouse, keyboard, lightgun * and a pointer. * * The functionality of these devices are fixed, and individual cores * map their own concept of a controller to libretro's abstractions. * This makes it possible for frontends to map the abstract types to a * real input device, and not having to worry about binding input * correctly to arbitrary controller layouts. */ #define RETRO_DEVICE_TYPE_SHIFT 8 #define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1) #define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base) /* Input disabled. */ #define RETRO_DEVICE_NONE 0 /* The JOYPAD is called RetroPad. It is essentially a Super Nintendo * controller, but with additional L2/R2/L3/R3 buttons, similar to a * PS1 DualShock. */ #define RETRO_DEVICE_JOYPAD 1 /* The mouse is a simple mouse, similar to Super Nintendo's mouse. * X and Y coordinates are reported relatively to last poll (poll callback). * It is up to the libretro implementation to keep track of where the mouse * pointer is supposed to be on the screen. * The frontend must make sure not to interfere with its own hardware * mouse pointer. */ #define RETRO_DEVICE_MOUSE 2 /* KEYBOARD device lets one poll for raw key pressed. * It is poll based, so input callback will return with the current * pressed state. * For event/text based keyboard input, see * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. */ #define RETRO_DEVICE_KEYBOARD 3 /* Lightgun X/Y coordinates are reported relatively to last poll, * similar to mouse. */ #define RETRO_DEVICE_LIGHTGUN 4 /* The ANALOG device is an extension to JOYPAD (RetroPad). * Similar to DualShock it adds two analog sticks. * This is treated as a separate device type as it returns values in the * full analog range of [-0x8000, 0x7fff]. Positive X axis is right. * Positive Y axis is down. * Only use ANALOG type when polling for analog values of the axes. */ #define RETRO_DEVICE_ANALOG 5 /* Abstracts the concept of a pointing mechanism, e.g. touch. * This allows libretro to query in absolute coordinates where on the * screen a mouse (or something similar) is being placed. * For a touch centric device, coordinates reported are the coordinates * of the press. * * Coordinates in X and Y are reported as: * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen, * and 0x7fff corresponds to the far right/bottom of the screen. * The "screen" is here defined as area that is passed to the frontend and * later displayed on the monitor. * * The frontend is free to scale/resize this screen as it sees fit, however, * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the * game image, etc. * * To check if the pointer coordinates are valid (e.g. a touch display * actually being touched), PRESSED returns 1 or 0. * * If using a mouse on a desktop, PRESSED will usually correspond to the * left mouse button, but this is a frontend decision. * PRESSED will only return 1 if the pointer is inside the game screen. * * For multi-touch, the index variable can be used to successively query * more presses. * If index = 0 returns true for _PRESSED, coordinates can be extracted * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with * index = 1, and so on. * Eventually _PRESSED will return false for an index. No further presses * are registered at this point. */ #define RETRO_DEVICE_POINTER 6 /* Buttons for the RetroPad (JOYPAD). * The placement of these is equivalent to placements on the * Super Nintendo controller. * L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */ #define RETRO_DEVICE_ID_JOYPAD_B 0 #define RETRO_DEVICE_ID_JOYPAD_Y 1 #define RETRO_DEVICE_ID_JOYPAD_SELECT 2 #define RETRO_DEVICE_ID_JOYPAD_START 3 #define RETRO_DEVICE_ID_JOYPAD_UP 4 #define RETRO_DEVICE_ID_JOYPAD_DOWN 5 #define RETRO_DEVICE_ID_JOYPAD_LEFT 6 #define RETRO_DEVICE_ID_JOYPAD_RIGHT 7 #define RETRO_DEVICE_ID_JOYPAD_A 8 #define RETRO_DEVICE_ID_JOYPAD_X 9 #define RETRO_DEVICE_ID_JOYPAD_L 10 #define RETRO_DEVICE_ID_JOYPAD_R 11 #define RETRO_DEVICE_ID_JOYPAD_L2 12 #define RETRO_DEVICE_ID_JOYPAD_R2 13 #define RETRO_DEVICE_ID_JOYPAD_L3 14 #define RETRO_DEVICE_ID_JOYPAD_R3 15 /* Index / Id values for ANALOG device. */ #define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 #define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 #define RETRO_DEVICE_ID_ANALOG_X 0 #define RETRO_DEVICE_ID_ANALOG_Y 1 /* Id values for MOUSE. */ #define RETRO_DEVICE_ID_MOUSE_X 0 #define RETRO_DEVICE_ID_MOUSE_Y 1 #define RETRO_DEVICE_ID_MOUSE_LEFT 2 #define RETRO_DEVICE_ID_MOUSE_RIGHT 3 #define RETRO_DEVICE_ID_MOUSE_WHEELUP 4 #define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5 #define RETRO_DEVICE_ID_MOUSE_MIDDLE 6 /* Id values for LIGHTGUN types. */ #define RETRO_DEVICE_ID_LIGHTGUN_X 0 #define RETRO_DEVICE_ID_LIGHTGUN_Y 1 #define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2 #define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 #define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 #define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 #define RETRO_DEVICE_ID_LIGHTGUN_START 6 /* Id values for POINTER. */ #define RETRO_DEVICE_ID_POINTER_X 0 #define RETRO_DEVICE_ID_POINTER_Y 1 #define RETRO_DEVICE_ID_POINTER_PRESSED 2 /* Returned from retro_get_region(). */ #define RETRO_REGION_NTSC 0 #define RETRO_REGION_PAL 1 /* Id values for LANGUAGE */ enum retro_language { RETRO_LANGUAGE_ENGLISH = 0, RETRO_LANGUAGE_JAPANESE = 1, RETRO_LANGUAGE_FRENCH = 2, RETRO_LANGUAGE_SPANISH = 3, RETRO_LANGUAGE_GERMAN = 4, RETRO_LANGUAGE_ITALIAN = 5, RETRO_LANGUAGE_DUTCH = 6, RETRO_LANGUAGE_PORTUGUESE = 7, RETRO_LANGUAGE_RUSSIAN = 8, RETRO_LANGUAGE_KOREAN = 9, RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10, RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 11, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ RETRO_LANGUAGE_DUMMY = INT_MAX }; /* Passed to retro_get_memory_data/size(). * If the memory type doesn't apply to the * implementation NULL/0 can be returned. */ #define RETRO_MEMORY_MASK 0xff /* Regular save RAM. This RAM is usually found on a game cartridge, * backed up by a battery. * If save game data is too complex for a single memory buffer, * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment * callback can be used. */ #define RETRO_MEMORY_SAVE_RAM 0 /* Some games have a built-in clock to keep track of time. * This memory is usually just a couple of bytes to keep track of time. */ #define RETRO_MEMORY_RTC 1 /* System ram lets a frontend peek into a game systems main RAM. */ #define RETRO_MEMORY_SYSTEM_RAM 2 /* Video ram lets a frontend peek into a game systems video RAM (VRAM). */ #define RETRO_MEMORY_VIDEO_RAM 3 /* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */ enum retro_key { RETROK_UNKNOWN = 0, RETROK_FIRST = 0, RETROK_BACKSPACE = 8, RETROK_TAB = 9, RETROK_CLEAR = 12, RETROK_RETURN = 13, RETROK_PAUSE = 19, RETROK_ESCAPE = 27, RETROK_SPACE = 32, RETROK_EXCLAIM = 33, RETROK_QUOTEDBL = 34, RETROK_HASH = 35, RETROK_DOLLAR = 36, RETROK_AMPERSAND = 38, RETROK_QUOTE = 39, RETROK_LEFTPAREN = 40, RETROK_RIGHTPAREN = 41, RETROK_ASTERISK = 42, RETROK_PLUS = 43, RETROK_COMMA = 44, RETROK_MINUS = 45, RETROK_PERIOD = 46, RETROK_SLASH = 47, RETROK_0 = 48, RETROK_1 = 49, RETROK_2 = 50, RETROK_3 = 51, RETROK_4 = 52, RETROK_5 = 53, RETROK_6 = 54, RETROK_7 = 55, RETROK_8 = 56, RETROK_9 = 57, RETROK_COLON = 58, RETROK_SEMICOLON = 59, RETROK_LESS = 60, RETROK_EQUALS = 61, RETROK_GREATER = 62, RETROK_QUESTION = 63, RETROK_AT = 64, RETROK_LEFTBRACKET = 91, RETROK_BACKSLASH = 92, RETROK_RIGHTBRACKET = 93, RETROK_CARET = 94, RETROK_UNDERSCORE = 95, RETROK_BACKQUOTE = 96, RETROK_a = 97, RETROK_b = 98, RETROK_c = 99, RETROK_d = 100, RETROK_e = 101, RETROK_f = 102, RETROK_g = 103, RETROK_h = 104, RETROK_i = 105, RETROK_j = 106, RETROK_k = 107, RETROK_l = 108, RETROK_m = 109, RETROK_n = 110, RETROK_o = 111, RETROK_p = 112, RETROK_q = 113, RETROK_r = 114, RETROK_s = 115, RETROK_t = 116, RETROK_u = 117, RETROK_v = 118, RETROK_w = 119, RETROK_x = 120, RETROK_y = 121, RETROK_z = 122, RETROK_DELETE = 127, RETROK_KP0 = 256, RETROK_KP1 = 257, RETROK_KP2 = 258, RETROK_KP3 = 259, RETROK_KP4 = 260, RETROK_KP5 = 261, RETROK_KP6 = 262, RETROK_KP7 = 263, RETROK_KP8 = 264, RETROK_KP9 = 265, RETROK_KP_PERIOD = 266, RETROK_KP_DIVIDE = 267, RETROK_KP_MULTIPLY = 268, RETROK_KP_MINUS = 269, RETROK_KP_PLUS = 270, RETROK_KP_ENTER = 271, RETROK_KP_EQUALS = 272, RETROK_UP = 273, RETROK_DOWN = 274, RETROK_RIGHT = 275, RETROK_LEFT = 276, RETROK_INSERT = 277, RETROK_HOME = 278, RETROK_END = 279, RETROK_PAGEUP = 280, RETROK_PAGEDOWN = 281, RETROK_F1 = 282, RETROK_F2 = 283, RETROK_F3 = 284, RETROK_F4 = 285, RETROK_F5 = 286, RETROK_F6 = 287, RETROK_F7 = 288, RETROK_F8 = 289, RETROK_F9 = 290, RETROK_F10 = 291, RETROK_F11 = 292, RETROK_F12 = 293, RETROK_F13 = 294, RETROK_F14 = 295, RETROK_F15 = 296, RETROK_NUMLOCK = 300, RETROK_CAPSLOCK = 301, RETROK_SCROLLOCK = 302, RETROK_RSHIFT = 303, RETROK_LSHIFT = 304, RETROK_RCTRL = 305, RETROK_LCTRL = 306, RETROK_RALT = 307, RETROK_LALT = 308, RETROK_RMETA = 309, RETROK_LMETA = 310, RETROK_LSUPER = 311, RETROK_RSUPER = 312, RETROK_MODE = 313, RETROK_COMPOSE = 314, RETROK_HELP = 315, RETROK_PRINT = 316, RETROK_SYSREQ = 317, RETROK_BREAK = 318, RETROK_MENU = 319, RETROK_POWER = 320, RETROK_EURO = 321, RETROK_UNDO = 322, RETROK_LAST, RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ }; enum retro_mod { RETROKMOD_NONE = 0x0000, RETROKMOD_SHIFT = 0x01, RETROKMOD_CTRL = 0x02, RETROKMOD_ALT = 0x04, RETROKMOD_META = 0x08, RETROKMOD_NUMLOCK = 0x10, RETROKMOD_CAPSLOCK = 0x20, RETROKMOD_SCROLLOCK = 0x40, RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ }; /* If set, this call is not part of the public libretro API yet. It can * change or be removed at any time. */ #define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 /* Environment callback to be used internally in frontend. */ #define RETRO_ENVIRONMENT_PRIVATE 0x20000 /* Environment commands. */ #define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- * Sets screen rotation of graphics. * Is only implemented if rotation can be accelerated by hardware. * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, * 270 degrees counter-clockwise respectively. */ #define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- * Boolean value whether or not the implementation should use overscan, * or crop away overscan. */ #define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 /* bool * -- * Boolean value whether or not frontend supports frame duping, * passing NULL to video frame callback. */ /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), * and reserved to avoid possible ABI clash. */ #define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * -- * Sets a message to be displayed in implementation-specific manner * for a certain amount of 'frames'. * Should not be used for trivial messages, which should simply be * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a * fallback, stderr). */ #define RETRO_ENVIRONMENT_SHUTDOWN 7 /* N/A (NULL) -- * Requests the frontend to shutdown. * Should only be used if game has a specific * way to shutdown the game from a menu item or similar. */ #define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8 /* const unsigned * -- * Gives a hint to the frontend how demanding this implementation * is on a system. E.g. reporting a level of 2 means * this implementation should run decently on all frontends * of level 2 and up. * * It can be used by the frontend to potentially warn * about too demanding implementations. * * The levels are "floating". * * This function can be called on a per-game basis, * as certain games an implementation can play might be * particularly demanding. * If called, it should be called in retro_load_game(). */ #define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9 /* const char ** -- * Returns the "system" directory of the frontend. * This directory can be used to store system specific * content such as BIOSes, configuration data, etc. * The returned value can be NULL. * If so, no such directory is defined, * and it's up to the implementation to find a suitable directory. * * NOTE: Some cores used this folder also for "save" data such as * memory cards, etc, for lack of a better place to put it. * This is now discouraged, and if possible, cores should try to * use the new GET_SAVE_DIRECTORY. */ #define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 /* const enum retro_pixel_format * -- * Sets the internal pixel format used by the implementation. * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555. * This pixel format however, is deprecated (see enum retro_pixel_format). * If the call returns false, the frontend does not support this pixel * format. * * This function should be called inside retro_load_game() or * retro_get_system_av_info(). */ #define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11 /* const struct retro_input_descriptor * -- * Sets an array of retro_input_descriptors. * It is up to the frontend to present this in a usable way. * The array is terminated by retro_input_descriptor::description * being set to NULL. * This function can be called at any time, but it is recommended * to call it as early as possible. */ #define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 /* const struct retro_keyboard_callback * -- * Sets a callback function used to notify core about keyboard events. */ #define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 /* const struct retro_disk_control_callback * -- * Sets an interface which frontend can use to eject and insert * disk images. * This is used for games which consist of multiple images and * must be manually swapped out by the user (e.g. PSX). */ #define RETRO_ENVIRONMENT_SET_HW_RENDER 14 /* struct retro_hw_render_callback * -- * Sets an interface to let a libretro core render with * hardware acceleration. * Should be called in retro_load_game(). * If successful, libretro cores will be able to render to a * frontend-provided framebuffer. * The size of this framebuffer will be at least as large as * max_width/max_height provided in get_av_info(). * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or * NULL to retro_video_refresh_t. */ #define RETRO_ENVIRONMENT_GET_VARIABLE 15 /* struct retro_variable * -- * Interface to acquire user-defined information from environment * that cannot feasibly be supported in a multi-system way. * 'key' should be set to a key which has already been set by * SET_VARIABLES. * 'data' will be set to a value or NULL. */ #define RETRO_ENVIRONMENT_SET_VARIABLES 16 /* const struct retro_variable * -- * Allows an implementation to signal the environment * which variables it might want to check for later using * GET_VARIABLE. * This allows the frontend to present these variables to * a user dynamically. * This should be called as early as possible (ideally in * retro_set_environment). * * 'data' points to an array of retro_variable structs * terminated by a { NULL, NULL } element. * retro_variable::key should be namespaced to not collide * with other implementations' keys. E.g. A core called * 'foo' should use keys named as 'foo_option'. * retro_variable::value should contain a human readable * description of the key as well as a '|' delimited list * of expected values. * * The number of possible options should be very limited, * i.e. it should be feasible to cycle through options * without a keyboard. * * First entry should be treated as a default. * * Example entry: * { "foo_option", "Speed hack coprocessor X; false|true" } * * Text before first ';' is description. This ';' must be * followed by a space, and followed by a list of possible * values split up with '|'. * * Only strings are operated on. The possible values will * generally be displayed and stored as-is by the frontend. */ #define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17 /* bool * -- * Result is set to true if some variables are updated by * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. * Variables should be queried with GET_VARIABLE. */ #define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 /* const bool * -- * If true, the libretro implementation supports calls to * retro_load_game() with NULL as argument. * Used by cores which can run without particular game data. * This should be called within retro_set_environment() only. */ #define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 /* const char ** -- * Retrieves the absolute path from where this libretro * implementation was loaded. * NULL is returned if the libretro was loaded statically * (i.e. linked statically to frontend), or if the path cannot be * determined. * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can * be loaded without ugly hacks. */ /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. * It was not used by any known core at the time, * and was removed from the API. */ #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 /* const struct retro_audio_callback * -- * Sets an interface which is used to notify a libretro core about audio * being available for writing. * The callback can be called from any thread, so a core using this must * have a thread safe audio implementation. * It is intended for games where audio and video are completely * asynchronous and audio can be generated on the fly. * This interface is not recommended for use with emulators which have * highly synchronous audio. * * The callback only notifies about writability; the libretro core still * has to call the normal audio callbacks * to write audio. The audio callbacks must be called from within the * notification callback. * The amount of audio data to write is up to the implementation. * Generally, the audio callback will be called continously in a loop. * * Due to thread safety guarantees and lack of sync between audio and * video, a frontend can selectively disallow this interface based on * internal configuration. A core using this interface must also * implement the "normal" audio interface. * * A libretro core using SET_AUDIO_CALLBACK should also make use of * SET_FRAME_TIME_CALLBACK. */ #define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 /* const struct retro_frame_time_callback * -- * Lets the core know how much time has passed since last * invocation of retro_run(). * The frontend can tamper with the timing to fake fast-forward, * slow-motion, frame stepping, etc. * In this case the delta time will use the reference value * in frame_time_callback.. */ #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 /* struct retro_rumble_interface * -- * Gets an interface which is used by a libretro core to set * state of rumble motors in controllers. * A strong and weak motor is supported, and they can be * controlled indepedently. */ #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 /* uint64_t * -- * Gets a bitmask telling which device type are expected to be * handled properly in a call to retro_input_state_t. * Devices which are not handled or recognized always return * 0 in retro_input_state_t. * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). * Should only be called in retro_run(). */ #define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* struct retro_sensor_interface * -- * Gets access to the sensor interface. * The purpose of this interface is to allow * setting state related to sensors such as polling rate, * enabling/disable it entirely, etc. * Reading sensor state is done via the normal * input_state_callback API. */ #define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* struct retro_camera_callback * -- * Gets an interface to a video camera driver. * A libretro core can use this interface to get access to a * video camera. * New video frames are delivered in a callback in same * thread as retro_run(). * * GET_CAMERA_INTERFACE should be called in retro_load_game(). * * Depending on the camera implementation used, camera frames * will be delivered as a raw framebuffer, * or as an OpenGL texture directly. * * The core has to tell the frontend here which types of * buffers can be handled properly. * An OpenGL texture can only be handled when using a * libretro GL core (SET_HW_RENDER). * It is recommended to use a libretro GL core when * using camera interface. * * The camera is not started automatically. The retrieved start/stop * functions must be used to explicitly * start and stop the camera driver. */ #define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 /* struct retro_log_callback * -- * Gets an interface for logging. This is useful for * logging in a cross-platform way * as certain platforms cannot use use stderr for logging. * It also allows the frontend to * show logging information in a more suitable way. * If this interface is not used, libretro cores should * log to stderr as desired. */ #define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28 /* struct retro_perf_callback * -- * Gets an interface for performance counters. This is useful * for performance logging in a cross-platform way and for detecting * architecture-specific features, such as SIMD support. */ #define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29 /* struct retro_location_callback * -- * Gets access to the location interface. * The purpose of this interface is to be able to retrieve * location-based information from the host device, * such as current latitude / longitude. */ #define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* const char ** -- * Returns the "content" directory of the frontend. * This directory can be used to store specific assets that the * core relies upon, such as art assets, * input data, etc etc. * The returned value can be NULL. * If so, no such directory is defined, * and it's up to the implementation to find a suitable directory. */ #define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 /* const char ** -- * Returns the "save" directory of the frontend. * This directory can be used to store SRAM, memory cards, * high scores, etc, if the libretro core * cannot use the regular memory interface (retro_get_memory_data()). * * NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for * similar things before. * They should still check GET_SYSTEM_DIRECTORY if they want to * be backwards compatible. * The path here can be NULL. It should only be non-NULL if the * frontend user has set a specific save path. */ #define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 /* const struct retro_system_av_info * -- * Sets a new av_info structure. This can only be called from * within retro_run(). * This should *only* be used if the core is completely altering the * internal resolutions, aspect ratios, timings, sampling rate, etc. * Calling this can require a full reinitialization of video/audio * drivers in the frontend, * * so it is important to call it very sparingly, and usually only with * the users explicit consent. * An eventual driver reinitialize will happen so that video and * audio callbacks * happening after this call within the same retro_run() call will * target the newly initialized driver. * * This callback makes it possible to support configurable resolutions * in games, which can be useful to * avoid setting the "worst case" in max_width/max_height. * * ***HIGHLY RECOMMENDED*** Do not call this callback every time * resolution changes in an emulator core if it's * expected to be a temporary change, for the reasons of possible * driver reinitialization. * This call is not a free pass for not trying to provide * correct values in retro_get_system_av_info(). If you need to change * things like aspect ratio or nominal width/height, * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant * of SET_SYSTEM_AV_INFO. * * If this returns false, the frontend does not acknowledge a * changed av_info struct. */ #define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 /* const struct retro_get_proc_address_interface * -- * Allows a libretro core to announce support for the * get_proc_address() interface. * This interface allows for a standard way to extend libretro where * use of environment calls are too indirect, * e.g. for cases where the frontend wants to call directly into the core. * * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK * **MUST** be called from within retro_set_environment(). */ #define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34 /* const struct retro_subsystem_info * -- * This environment call introduces the concept of libretro "subsystems". * A subsystem is a variant of a libretro core which supports * different kinds of games. * The purpose of this is to support e.g. emulators which might * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo. * It can also be used to pick among subsystems in an explicit way * if the libretro implementation is a multi-system emulator itself. * * Loading a game via a subsystem is done with retro_load_game_special(), * and this environment call allows a libretro core to expose which * subsystems are supported for use with retro_load_game_special(). * A core passes an array of retro_game_special_info which is terminated * with a zeroed out retro_game_special_info struct. * * If a core wants to use this functionality, SET_SUBSYSTEM_INFO * **MUST** be called from within retro_set_environment(). */ #define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 /* const struct retro_controller_info * -- * This environment call lets a libretro core tell the frontend * which controller types are recognized in calls to * retro_set_controller_port_device(). * * Some emulators such as Super Nintendo * support multiple lightgun types which must be specifically * selected from. * It is therefore sometimes necessary for a frontend to be able * to tell the core about a special kind of input device which is * not covered by the libretro input API. * * In order for a frontend to understand the workings of an input device, * it must be a specialized type * of the generic device types already defined in the libretro API. * * Which devices are supported can vary per input port. * The core must pass an array of const struct retro_controller_info which * is terminated with a blanked out struct. Each element of the struct * corresponds to an ascending port index to * retro_set_controller_port_device(). * Even if special device types are set in the libretro core, * libretro should only poll input based on the base input device types. */ #define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* const struct retro_memory_map * -- * This environment call lets a libretro core tell the frontend * about the memory maps this core emulates. * This can be used to implement, for example, cheats in a core-agnostic way. * * Should only be used by emulators; it doesn't make much sense for * anything else. * It is recommended to expose all relevant pointers through * retro_get_memory_* as well. * * Can be called from retro_init and retro_load_game. */ #define RETRO_ENVIRONMENT_SET_GEOMETRY 37 /* const struct retro_game_geometry * -- * This environment call is similar to SET_SYSTEM_AV_INFO for changing * video parameters, but provides a guarantee that drivers will not be * reinitialized. * This can only be called from within retro_run(). * * The purpose of this call is to allow a core to alter nominal * width/heights as well as aspect ratios on-the-fly, which can be * useful for some emulators to change in run-time. * * max_width/max_height arguments are ignored and cannot be changed * with this call as this could potentially require a reinitialization or a * non-constant time operation. * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. * * A frontend must guarantee that this environment call completes in * constant time. */ #define RETRO_ENVIRONMENT_GET_USERNAME 38 /* const char ** * Returns the specified username of the frontend, if specified by the user. * This username can be used as a nickname for a core that has online facilities * or any other mode where personalization of the user is desirable. * The returned value can be NULL. * If this environ callback is used by a core that requires a valid username, * a default username should be specified by the core. */ #define RETRO_ENVIRONMENT_GET_LANGUAGE 39 /* unsigned * -- * Returns the specified language of the frontend, if specified by the user. * It can be used by the core for localization purposes. */ #define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ #define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ #define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ #define RETRO_MEMDESC_ALIGN_4 (2 << 16) #define RETRO_MEMDESC_ALIGN_8 (3 << 16) #define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ #define RETRO_MEMDESC_MINSIZE_4 (2 << 24) #define RETRO_MEMDESC_MINSIZE_8 (3 << 24) struct retro_memory_descriptor { uint64_t flags; /* Pointer to the start of the relevant ROM or RAM chip. * It's strongly recommended to use 'offset' if possible, rather than * doing math on the pointer. * * If the same byte is mapped my multiple descriptors, their descriptors * must have the same pointer. * If 'start' does not point to the first byte in the pointer, put the * difference in 'offset' instead. * * May be NULL if there's nothing usable here (e.g. hardware registers and * open bus). No flags should be set if the pointer is NULL. * It's recommended to minimize the number of descriptors if possible, * but not mandatory. */ void *ptr; size_t offset; /* This is the location in the emulated address space * where the mapping starts. */ size_t start; /* Which bits must be same as in 'start' for this mapping to apply. * The first memory descriptor to claim a certain byte is the one * that applies. * A bit which is set in 'start' must also be set in this. * Can be zero, in which case each byte is assumed mapped exactly once. * In this case, 'len' must be a power of two. */ size_t select; /* If this is nonzero, the set bits are assumed not connected to the * memory chip's address pins. */ size_t disconnect; /* This one tells the size of the current memory area. * If, after start+disconnect are applied, the address is higher than * this, the highest bit of the address is cleared. * * If the address is still too high, the next highest bit is cleared. * Can be zero, in which case it's assumed to be infinite (as limited * by 'select' and 'disconnect'). */ size_t len; /* To go from emulated address to physical address, the following * order applies: * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. * * The address space name must consist of only a-zA-Z0-9_-, * should be as short as feasible (maximum length is 8 plus the NUL), * and may not be any other address space plus one or more 0-9A-F * at the end. * However, multiple memory descriptors for the same address space is * allowed, and the address space name can be empty. NULL is treated * as empty. * * Address space names are case sensitive, but avoid lowercase if possible. * The same pointer may exist in multiple address spaces. * * Examples: * blank+blank - valid (multiple things may be mapped in the same namespace) * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace) * 'A'+'B' - valid (neither is a prefix of each other) * 'S'+blank - valid ('S' is not in 0-9A-F) * 'a'+blank - valid ('a' is not in 0-9A-F) * 'a'+'A' - valid (neither is a prefix of each other) * 'AR'+blank - valid ('R' is not in 0-9A-F) * 'ARB'+blank - valid (the B can't be part of the address either, because * there is no namespace 'AR') * blank+'B' - not valid, because it's ambigous which address space B1234 * would refer to. * The length can't be used for that purpose; the frontend may want * to append arbitrary data to an address, without a separator. */ const char *addrspace; }; /* The frontend may use the largest value of 'start'+'select' in a * certain namespace to infer the size of the address space. * * If the address space is larger than that, a mapping with .ptr=NULL * should be at the end of the array, with .select set to all ones for * as long as the address space is big. * * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags): * SNES WRAM: * .start=0x7E0000, .len=0x20000 * (Note that this must be mapped before the ROM in most cases; some of the * ROM mappers * try to claim $7E0000, or at least $7E8000.) * SNES SPC700 RAM: * .addrspace="S", .len=0x10000 * SNES WRAM mirrors: * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000 * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000 * SNES WRAM mirrors, alternate equivalent descriptor: * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF * (Various similar constructions can be created by combining parts of * the above two.) * SNES LoROM (512KB, mirrored a couple of times): * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024 * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024 * SNES HiROM (4MB): * .flags=CONST, .start=0x400000, .select=0x400000, .len=4*1024*1024 * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024 * SNES ExHiROM (8MB): * .flags=CONST, .offset=0, .start=0xC00000, .select=0xC00000, .len=4*1024*1024 * .flags=CONST, .offset=4*1024*1024, .start=0x400000, .select=0xC00000, .len=4*1024*1024 * .flags=CONST, .offset=0x8000, .start=0x808000, .select=0xC08000, .len=4*1024*1024 * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024 * Clarify the size of the address space: * .ptr=NULL, .select=0xFFFFFF * .len can be implied by .select in many of them, but was included for clarity. */ struct retro_memory_map { const struct retro_memory_descriptor *descriptors; unsigned num_descriptors; }; struct retro_controller_description { /* Human-readable description of the controller. Even if using a generic * input device type, this can be set to the particular device type the * core uses. */ const char *desc; /* Device type passed to retro_set_controller_port_device(). If the device * type is a sub-class of a generic input device type, use the * RETRO_DEVICE_SUBCLASS macro to create an ID. * * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */ unsigned id; }; struct retro_controller_info { const struct retro_controller_description *types; unsigned num_types; }; struct retro_subsystem_memory_info { /* The extension associated with a memory type, e.g. "psram". */ const char *extension; /* The memory type for retro_get_memory(). This should be at * least 0x100 to avoid conflict with standardized * libretro memory types. */ unsigned type; }; struct retro_subsystem_rom_info { /* Describes what the content is (SGB BIOS, GB ROM, etc). */ const char *desc; /* Same definition as retro_get_system_info(). */ const char *valid_extensions; /* Same definition as retro_get_system_info(). */ bool need_fullpath; /* Same definition as retro_get_system_info(). */ bool block_extract; /* This is set if the content is required to load a game. * If this is set to false, a zeroed-out retro_game_info can be passed. */ bool required; /* Content can have multiple associated persistent * memory types (retro_get_memory()). */ const struct retro_subsystem_memory_info *memory; unsigned num_memory; }; struct retro_subsystem_info { /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */ const char *desc; /* A computer friendly short string identifier for the subsystem type. * This name must be [a-z]. * E.g. if desc is "Super GameBoy", this can be "sgb". * This identifier can be used for command-line interfaces, etc. */ const char *ident; /* Infos for each content file. The first entry is assumed to be the * "most significant" content for frontend purposes. * E.g. with Super GameBoy, the first content should be the GameBoy ROM, * as it is the most "significant" content to a user. * If a frontend creates new file paths based on the content used * (e.g. savestates), it should use the path for the first ROM to do so. */ const struct retro_subsystem_rom_info *roms; /* Number of content files associated with a subsystem. */ unsigned num_roms; /* The type passed to retro_load_game_special(). */ unsigned id; }; typedef void (*retro_proc_address_t)(void); /* libretro API extension functions: * (None here so far). * * Get a symbol from a libretro core. * Cores should only return symbols which are actual * extensions to the libretro API. * * Frontends should not use this to obtain symbols to standard * libretro entry points (static linking or dlsym). * * The symbol name must be equal to the function name, * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo". * The returned function pointer must be cast to the corresponding type. */ typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym); struct retro_get_proc_address_interface { retro_get_proc_address_t get_proc_address; }; enum retro_log_level { RETRO_LOG_DEBUG = 0, RETRO_LOG_INFO, RETRO_LOG_WARN, RETRO_LOG_ERROR, RETRO_LOG_DUMMY = INT_MAX }; /* Logging function. Takes log level argument as well. */ typedef void (*retro_log_printf_t)(enum retro_log_level level, const char *fmt, ...); struct retro_log_callback { retro_log_printf_t log; }; /* Performance related functions */ /* ID values for SIMD CPU features */ #define RETRO_SIMD_SSE (1 << 0) #define RETRO_SIMD_SSE2 (1 << 1) #define RETRO_SIMD_VMX (1 << 2) #define RETRO_SIMD_VMX128 (1 << 3) #define RETRO_SIMD_AVX (1 << 4) #define RETRO_SIMD_NEON (1 << 5) #define RETRO_SIMD_SSE3 (1 << 6) #define RETRO_SIMD_SSSE3 (1 << 7) #define RETRO_SIMD_MMX (1 << 8) #define RETRO_SIMD_MMXEXT (1 << 9) #define RETRO_SIMD_SSE4 (1 << 10) #define RETRO_SIMD_SSE42 (1 << 11) #define RETRO_SIMD_AVX2 (1 << 12) #define RETRO_SIMD_VFPU (1 << 13) #define RETRO_SIMD_PS (1 << 14) #define RETRO_SIMD_AES (1 << 15) typedef uint64_t retro_perf_tick_t; typedef int64_t retro_time_t; struct retro_perf_counter { const char *ident; retro_perf_tick_t start; retro_perf_tick_t total; retro_perf_tick_t call_cnt; bool registered; }; /* Returns current time in microseconds. * Tries to use the most accurate timer available. */ typedef retro_time_t (*retro_perf_get_time_usec_t)(void); /* A simple counter. Usually nanoseconds, but can also be CPU cycles. * Can be used directly if desired (when creating a more sophisticated * performance counter system). * */ typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void); /* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */ typedef uint64_t (*retro_get_cpu_features_t)(void); /* Asks frontend to log and/or display the state of performance counters. * Performance counters can always be poked into manually as well. */ typedef void (*retro_perf_log_t)(void); /* Register a performance counter. * ident field must be set with a discrete value and other values in * retro_perf_counter must be 0. * Registering can be called multiple times. To avoid calling to * frontend redundantly, you can check registered field first. */ typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter); /* Starts a registered counter. */ typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter); /* Stops a registered counter. */ typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter); /* For convenience it can be useful to wrap register, start and stop in macros. * E.g.: * #ifdef LOG_PERFORMANCE * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name)) * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name)) * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name)) * #else * ... Blank macros ... * #endif * * These can then be used mid-functions around code snippets. * * extern struct retro_perf_callback perf_cb; * Somewhere in the core. * * void do_some_heavy_work(void) * { * RETRO_PERFORMANCE_INIT(cb, work_1; * RETRO_PERFORMANCE_START(cb, work_1); * heavy_work_1(); * RETRO_PERFORMANCE_STOP(cb, work_1); * * RETRO_PERFORMANCE_INIT(cb, work_2); * RETRO_PERFORMANCE_START(cb, work_2); * heavy_work_2(); * RETRO_PERFORMANCE_STOP(cb, work_2); * } * * void retro_deinit(void) * { * perf_cb.perf_log(); * Log all perf counters here for example. * } */ struct retro_perf_callback { retro_perf_get_time_usec_t get_time_usec; retro_get_cpu_features_t get_cpu_features; retro_perf_get_counter_t get_perf_counter; retro_perf_register_t perf_register; retro_perf_start_t perf_start; retro_perf_stop_t perf_stop; retro_perf_log_t perf_log; }; /* FIXME: Document the sensor API and work out behavior. * It will be marked as experimental until then. */ enum retro_sensor_action { RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, RETRO_SENSOR_ACCELEROMETER_DISABLE, RETRO_SENSOR_DUMMY = INT_MAX }; /* Id values for SENSOR types. */ #define RETRO_SENSOR_ACCELEROMETER_X 0 #define RETRO_SENSOR_ACCELEROMETER_Y 1 #define RETRO_SENSOR_ACCELEROMETER_Z 2 typedef bool (*retro_set_sensor_state_t)(unsigned port, enum retro_sensor_action action, unsigned rate); typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id); struct retro_sensor_interface { retro_set_sensor_state_t set_sensor_state; retro_sensor_get_input_t get_sensor_input; }; enum retro_camera_buffer { RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, RETRO_CAMERA_BUFFER_DUMMY = INT_MAX }; /* Starts the camera driver. Can only be called in retro_run(). */ typedef bool (*retro_camera_start_t)(void); /* Stops the camera driver. Can only be called in retro_run(). */ typedef void (*retro_camera_stop_t)(void); /* Callback which signals when the camera driver is initialized * and/or deinitialized. * retro_camera_start_t can be called in initialized callback. */ typedef void (*retro_camera_lifetime_status_t)(void); /* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer. * Width, height and pitch are similar to retro_video_refresh_t. * First pixel is top-left origin. */ typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, unsigned width, unsigned height, size_t pitch); /* A callback for when OpenGL textures are used. * * texture_id is a texture owned by camera driver. * Its state or content should be considered immutable, except for things like * texture filtering and clamping. * * texture_target is the texture target for the GL texture. * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly * more depending on extensions. * * affine points to a packed 3x3 column-major matrix used to apply an affine * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0)) * After transform, normalized texture coord (0, 0) should be bottom-left * and (1, 1) should be top-right (or (width, height) for RECTANGLE). * * GL-specific typedefs are avoided here to avoid relying on gl.h in * the API definition. */ typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id, unsigned texture_target, const float *affine); struct retro_camera_callback { /* Set by libretro core. * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). */ uint64_t caps; unsigned width; /* Desired resolution for camera. Is only used as a hint. */ unsigned height; retro_camera_start_t start; /* Set by frontend. */ retro_camera_stop_t stop; /* Set by frontend. */ /* Set by libretro core if raw framebuffer callbacks will be used. */ retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; /* Set by libretro core if OpenGL texture callbacks will be used. */ retro_camera_frame_opengl_texture_t frame_opengl_texture; /* Set by libretro core. Called after camera driver is initialized and * ready to be started. * Can be NULL, in which this callback is not called. */ retro_camera_lifetime_status_t initialized; /* Set by libretro core. Called right before camera driver is * deinitialized. * Can be NULL, in which this callback is not called. */ retro_camera_lifetime_status_t deinitialized; }; /* Sets the interval of time and/or distance at which to update/poll * location-based data. * * To ensure compatibility with all location-based implementations, * values for both interval_ms and interval_distance should be provided. * * interval_ms is the interval expressed in milliseconds. * interval_distance is the distance interval expressed in meters. */ typedef void (*retro_location_set_interval_t)(unsigned interval_ms, unsigned interval_distance); /* Start location services. The device will start listening for changes to the * current location at regular intervals (which are defined with * retro_location_set_interval_t). */ typedef bool (*retro_location_start_t)(void); /* Stop location services. The device will stop listening for changes * to the current location. */ typedef void (*retro_location_stop_t)(void); /* Get the position of the current location. Will set parameters to * 0 if no new location update has happened since the last time. */ typedef bool (*retro_location_get_position_t)(double *lat, double *lon, double *horiz_accuracy, double *vert_accuracy); /* Callback which signals when the location driver is initialized * and/or deinitialized. * retro_location_start_t can be called in initialized callback. */ typedef void (*retro_location_lifetime_status_t)(void); struct retro_location_callback { retro_location_start_t start; retro_location_stop_t stop; retro_location_get_position_t get_position; retro_location_set_interval_t set_interval; retro_location_lifetime_status_t initialized; retro_location_lifetime_status_t deinitialized; }; enum retro_rumble_effect { RETRO_RUMBLE_STRONG = 0, RETRO_RUMBLE_WEAK = 1, RETRO_RUMBLE_DUMMY = INT_MAX }; /* Sets rumble state for joypad plugged in port 'port'. * Rumble effects are controlled independently, * and setting e.g. strong rumble does not override weak rumble. * Strength has a range of [0, 0xffff]. * * Returns true if rumble state request was honored. * Calling this before first retro_run() is likely to return false. */ typedef bool (*retro_set_rumble_state_t)(unsigned port, enum retro_rumble_effect effect, uint16_t strength); struct retro_rumble_interface { retro_set_rumble_state_t set_rumble_state; }; /* Notifies libretro that audio data should be written. */ typedef void (*retro_audio_callback_t)(void); /* True: Audio driver in frontend is active, and callback is * expected to be called regularily. * False: Audio driver in frontend is paused or inactive. * Audio callback will not be called until set_state has been * called with true. * Initial state is false (inactive). */ typedef void (*retro_audio_set_state_callback_t)(bool enabled); struct retro_audio_callback { retro_audio_callback_t callback; retro_audio_set_state_callback_t set_state; }; /* Notifies a libretro core of time spent since last invocation * of retro_run() in microseconds. * * It will be called right before retro_run() every frame. * The frontend can tamper with timing to support cases like * fast-forward, slow-motion and framestepping. * * In those scenarios the reference frame time value will be used. */ typedef int64_t retro_usec_t; typedef void (*retro_frame_time_callback_t)(retro_usec_t usec); struct retro_frame_time_callback { retro_frame_time_callback_t callback; /* Represents the time of one frame. It is computed as * 1000000 / fps, but the implementation will resolve the * rounding to ensure that framestepping, etc is exact. */ retro_usec_t reference; }; /* Pass this to retro_video_refresh_t if rendering to hardware. * Passing NULL to retro_video_refresh_t is still a frame dupe as normal. * */ #define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1) /* Invalidates the current HW context. * Any GL state is lost, and must not be deinitialized explicitly. * If explicit deinitialization is desired by the libretro core, * it should implement context_destroy callback. * If called, all GPU resources must be reinitialized. * Usually called when frontend reinits video driver. * Also called first time video driver is initialized, * allowing libretro core to initialize resources. */ typedef void (*retro_hw_context_reset_t)(void); /* Gets current framebuffer which is to be rendered to. * Could change every frame potentially. */ typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void); /* Get a symbol from HW context. */ typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym); enum retro_hw_context_type { RETRO_HW_CONTEXT_NONE = 0, /* OpenGL 2.x. Driver can choose to use latest compatibility context. */ RETRO_HW_CONTEXT_OPENGL = 1, /* OpenGL ES 2.0. */ RETRO_HW_CONTEXT_OPENGLES2 = 2, /* Modern desktop core GL context. Use version_major/ * version_minor fields to set GL version. */ RETRO_HW_CONTEXT_OPENGL_CORE = 3, /* OpenGL ES 3.0 */ RETRO_HW_CONTEXT_OPENGLES3 = 4, /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, * use the corresponding enums directly. */ RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, RETRO_HW_CONTEXT_DUMMY = INT_MAX }; struct retro_hw_render_callback { /* Which API to use. Set by libretro core. */ enum retro_hw_context_type context_type; /* Called when a context has been created or when it has been reset. * An OpenGL context is only valid after context_reset() has been called. * * When context_reset is called, OpenGL resources in the libretro * implementation are guaranteed to be invalid. * * It is possible that context_reset is called multiple times during an * application lifecycle. * If context_reset is called without any notification (context_destroy), * the OpenGL context was lost and resources should just be recreated * without any attempt to "free" old resources. */ retro_hw_context_reset_t context_reset; /* Set by frontend. */ retro_hw_get_current_framebuffer_t get_current_framebuffer; /* Set by frontend. */ retro_hw_get_proc_address_t get_proc_address; /* Set if render buffers should have depth component attached. */ bool depth; /* Set if stencil buffers should be attached. */ bool stencil; /* If depth and stencil are true, a packed 24/8 buffer will be added. * Only attaching stencil is invalid and will be ignored. */ /* Use conventional bottom-left origin convention. If false, * standard libretro top-left origin semantics are used. */ bool bottom_left_origin; /* Major version number for core GL context or GLES 3.1+. */ unsigned version_major; /* Minor version number for core GL context or GLES 3.1+. */ unsigned version_minor; /* If this is true, the frontend will go very far to avoid * resetting context in scenarios like toggling fullscreen, etc. */ bool cache_context; /* The reset callback might still be called in extreme situations * such as if the context is lost beyond recovery. * * For optimal stability, set this to false, and allow context to be * reset at any time. */ /* A callback to be called before the context is destroyed in a * controlled way by the frontend. */ retro_hw_context_reset_t context_destroy; /* OpenGL resources can be deinitialized cleanly at this step. * context_destroy can be set to NULL, in which resources will * just be destroyed without any notification. * * Even when context_destroy is non-NULL, it is possible that * context_reset is called without any destroy notification. * This happens if context is lost by external factors (such as * notified by GL_ARB_robustness). * * In this case, the context is assumed to be already dead, * and the libretro implementation must not try to free any OpenGL * resources in the subsequent context_reset. */ /* Creates a debug context. */ bool debug_context; }; /* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. * Called by the frontend in response to keyboard events. * down is set if the key is being pressed, or false if it is being released. * keycode is the RETROK value of the char. * character is the text character of the pressed key. (UTF-32). * key_modifiers is a set of RETROKMOD values or'ed together. * * The pressed/keycode state can be indepedent of the character. * It is also possible that multiple characters are generated from a * single keypress. * Keycode events should be treated separately from character events. * However, when possible, the frontend should try to synchronize these. * If only a character is posted, keycode should be RETROK_UNKNOWN. * * Similarily if only a keycode event is generated with no corresponding * character, character should be 0. */ typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); struct retro_keyboard_callback { retro_keyboard_event_t callback; }; /* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. * Should be set for implementations which can swap out multiple disk * images in runtime. * * If the implementation can do this automatically, it should strive to do so. * However, there are cases where the user must manually do so. * * Overview: To swap a disk image, eject the disk image with * set_eject_state(true). * Set the disk index with set_image_index(index). Insert the disk again * with set_eject_state(false). */ /* If ejected is true, "ejects" the virtual disk tray. * When ejected, the disk image index can be set. */ typedef bool (*retro_set_eject_state_t)(bool ejected); /* Gets current eject state. The initial state is 'not ejected'. */ typedef bool (*retro_get_eject_state_t)(void); /* Gets current disk index. First disk is index 0. * If return value is >= get_num_images(), no disk is currently inserted. */ typedef unsigned (*retro_get_image_index_t)(void); /* Sets image index. Can only be called when disk is ejected. * The implementation supports setting "no disk" by using an * index >= get_num_images(). */ typedef bool (*retro_set_image_index_t)(unsigned index); /* Gets total number of images which are available to use. */ typedef unsigned (*retro_get_num_images_t)(void); struct retro_game_info; /* Replaces the disk image associated with index. * Arguments to pass in info have same requirements as retro_load_game(). * Virtual disk tray must be ejected when calling this. * * Replacing a disk image with info = NULL will remove the disk image * from the internal list. * As a result, calls to get_image_index() can change. * * E.g. replace_image_index(1, NULL), and previous get_image_index() * returned 4 before. * Index 1 will be removed, and the new index is 3. */ typedef bool (*retro_replace_image_index_t)(unsigned index, const struct retro_game_info *info); /* Adds a new valid index (get_num_images()) to the internal disk list. * This will increment subsequent return values from get_num_images() by 1. * This image index cannot be used until a disk image has been set * with replace_image_index. */ typedef bool (*retro_add_image_index_t)(void); struct retro_disk_control_callback { retro_set_eject_state_t set_eject_state; retro_get_eject_state_t get_eject_state; retro_get_image_index_t get_image_index; retro_set_image_index_t set_image_index; retro_get_num_images_t get_num_images; retro_replace_image_index_t replace_image_index; retro_add_image_index_t add_image_index; }; enum retro_pixel_format { /* 0RGB1555, native endian. * 0 bit must be set to 0. * This pixel format is default for compatibility concerns only. * If a 15/16-bit pixel format is desired, consider using RGB565. */ RETRO_PIXEL_FORMAT_0RGB1555 = 0, /* XRGB8888, native endian. * X bits are ignored. */ RETRO_PIXEL_FORMAT_XRGB8888 = 1, /* RGB565, native endian. * This pixel format is the recommended format to use if a 15/16-bit * format is desired as it is the pixel format that is typically * available on a wide range of low-power devices. * * It is also natively supported in APIs like OpenGL ES. */ RETRO_PIXEL_FORMAT_RGB565 = 2, /* Ensure sizeof() == sizeof(int). */ RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX }; struct retro_message { const char *msg; /* Message to be displayed. */ unsigned frames; /* Duration in frames of message. */ }; /* Describes how the libretro implementation maps a libretro input bind * to its internal input system through a human readable string. * This string can be used to better let a user configure input. */ struct retro_input_descriptor { /* Associates given parameters with a description. */ unsigned port; unsigned device; unsigned index; unsigned id; /* Human readable description for parameters. * The pointer must remain valid until * retro_unload_game() is called. */ const char *description; }; struct retro_system_info { /* All pointers are owned by libretro implementation, and pointers must * remain valid until retro_deinit() is called. */ const char *library_name; /* Descriptive name of library. Should not * contain any version numbers, etc. */ const char *library_version; /* Descriptive version of core. */ const char *valid_extensions; /* A string listing probably content * extensions the core will be able to * load, separated with pipe. * I.e. "bin|rom|iso". * Typically used for a GUI to filter * out extensions. */ /* If true, retro_load_game() is guaranteed to provide a valid pathname * in retro_game_info::path. * ::data and ::size are both invalid. * * If false, ::data and ::size are guaranteed to be valid, but ::path * might not be valid. * * This is typically set to true for libretro implementations that must * load from file. * Implementations should strive for setting this to false, as it allows * the frontend to perform patching, etc. */ bool need_fullpath; /* If true, the frontend is not allowed to extract any archives before * loading the real content. * Necessary for certain libretro implementations that load games * from zipped archives. */ bool block_extract; }; struct retro_game_geometry { unsigned base_width; /* Nominal video width of game. */ unsigned base_height; /* Nominal video height of game. */ unsigned max_width; /* Maximum possible width of game. */ unsigned max_height; /* Maximum possible height of game. */ float aspect_ratio; /* Nominal aspect ratio of game. If * aspect_ratio is <= 0.0, an aspect ratio * of base_width / base_height is assumed. * A frontend could override this setting, * if desired. */ }; struct retro_system_timing { double fps; /* FPS of video content. */ double sample_rate; /* Sampling rate of audio. */ }; struct retro_system_av_info { struct retro_game_geometry geometry; struct retro_system_timing timing; }; struct retro_variable { /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. * If NULL, obtains the complete environment string if more * complex parsing is necessary. * The environment string is formatted as key-value pairs * delimited by semicolons as so: * "key1=value1;key2=value2;..." */ const char *key; /* Value to be obtained. If key does not exist, it is set to NULL. */ const char *value; }; struct retro_game_info { const char *path; /* Path to game, UTF-8 encoded. * Usually used as a reference. * May be NULL if rom was loaded from stdin * or similar. * retro_system_info::need_fullpath guaranteed * that this path is valid. */ const void *data; /* Memory buffer of loaded game. Will be NULL * if need_fullpath was set. */ size_t size; /* Size of memory buffer. */ const char *meta; /* String of implementation specific meta-data. */ }; /* Callbacks */ /* Environment callback. Gives implementations a way of performing * uncommon tasks. Extensible. */ typedef bool (*retro_environment_t)(unsigned cmd, void *data); /* Render a frame. Pixel format is 15-bit 0RGB1555 native endian * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT). * * Width and height specify dimensions of buffer. * Pitch specifices length in bytes between two lines in buffer. * * For performance reasons, it is highly recommended to have a frame * that is packed in memory, i.e. pitch == width * byte_per_pixel. * Certain graphic APIs, such as OpenGL ES, do not like textures * that are not packed in memory. */ typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch); /* Renders a single audio frame. Should only be used if implementation * generates a single sample at a time. * Format is signed 16-bit native endian. */ typedef void (*retro_audio_sample_t)(int16_t left, int16_t right); /* Renders multiple audio frames in one go. * * One frame is defined as a sample of left and right channels, interleaved. * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. * Only one of the audio callbacks must ever be used. */ typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames); /* Polls input. */ typedef void (*retro_input_poll_t)(void); /* Queries for input for player 'port'. device will be masked with * RETRO_DEVICE_MASK. * * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that * have been set with retro_set_controller_port_device() * will still use the higher level RETRO_DEVICE_JOYPAD to request input. */ typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id); /* Sets callbacks. retro_set_environment() is guaranteed to be called * before retro_init(). * * The rest of the set_* functions are guaranteed to have been called * before the first call to retro_run() is made. */ void retro_set_environment(retro_environment_t); void retro_set_video_refresh(retro_video_refresh_t); void retro_set_audio_sample(retro_audio_sample_t); void retro_set_audio_sample_batch(retro_audio_sample_batch_t); void retro_set_input_poll(retro_input_poll_t); void retro_set_input_state(retro_input_state_t); /* Library global initialization/deinitialization. */ void retro_init(void); void retro_deinit(void); /* Must return RETRO_API_VERSION. Used to validate ABI compatibility * when the API is revised. */ unsigned retro_api_version(void); /* Gets statically known system info. Pointers provided in *info * must be statically allocated. * Can be called at any time, even before retro_init(). */ void retro_get_system_info(struct retro_system_info *info); /* Gets information about system audio/video timings and geometry. * Can be called only after retro_load_game() has successfully completed. * NOTE: The implementation of this function might not initialize every * variable if needed. * E.g. geom.aspect_ratio might not be initialized if core doesn't * desire a particular aspect ratio. */ void retro_get_system_av_info(struct retro_system_av_info *info); /* Sets device to be used for player 'port'. * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all * available ports. * Setting a particular device type is not a guarantee that libretro cores * will only poll input based on that particular device type. It is only a * hint to the libretro core when a core cannot automatically detect the * appropriate input device type on its own. It is also relevant when a * core can change its behavior depending on device type. */ void retro_set_controller_port_device(unsigned port, unsigned device); /* Resets the current game. */ void retro_reset(void); /* Runs the game for one video frame. * During retro_run(), input_poll callback must be called at least once. * * If a frame is not rendered for reasons where a game "dropped" a frame, * this still counts as a frame, and retro_run() should explicitly dupe * a frame if GET_CAN_DUPE returns true. * In this case, the video callback can take a NULL argument for data. */ void retro_run(void); /* Returns the amount of data the implementation requires to serialize * internal state (save states). * Between calls to retro_load_game() and retro_unload_game(), the * returned size is never allowed to be larger than a previous returned * value, to ensure that the frontend can allocate a save state buffer once. */ size_t retro_serialize_size(void); /* Serializes internal state. If failed, or size is lower than * retro_serialize_size(), it should return false, true otherwise. */ bool retro_serialize(void *data, size_t size); bool retro_unserialize(const void *data, size_t size); void retro_cheat_reset(void); void retro_cheat_set(unsigned index, bool enabled, const char *code); /* Loads a game. */ bool retro_load_game(const struct retro_game_info *game); /* Loads a "special" kind of game. Should not be used, * except in extreme cases. */ bool retro_load_game_special( unsigned game_type, const struct retro_game_info *info, size_t num_info ); /* Unloads a currently loaded game. */ void retro_unload_game(void); /* Gets region of game. */ unsigned retro_get_region(void); /* Gets region of memory. */ void *retro_get_memory_data(unsigned id); size_t retro_get_memory_size(unsigned id); #ifdef __cplusplus } #endif #endif apu/bapu/smp/core/op_misc.cpp000664 001750 001750 00000011012 12720446475 017310 0ustar00sergiosergio000000 000000 case 0x00: { op_io(); break; } case 0xef: { op_io(); op_io(); regs.pc--; break; } case 0xff: { op_io(); op_io(); regs.pc--; break; } case 0x9f: { op_io(); op_io(); op_io(); op_io(); regs.a = (regs.a >> 4) | (regs.a << 4); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xdf: { op_io(); op_io(); if(regs.p.c || (regs.a) > 0x99) { regs.a += 0x60; regs.p.c = 1; } if(regs.p.h || (regs.a & 15) > 0x09) { regs.a += 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xbe: { op_io(); op_io(); if(!regs.p.c || (regs.a) > 0x99) { regs.a -= 0x60; regs.p.c = 0; } if(!regs.p.h || (regs.a & 15) > 0x09) { regs.a -= 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0x60: { op_io(); regs.p.c = 0; break; } case 0x20: { op_io(); regs.p.p = 0; break; } case 0x80: { op_io(); regs.p.c = 1; break; } case 0x40: { op_io(); regs.p.p = 1; break; } case 0xe0: { op_io(); regs.p.v = 0; regs.p.h = 0; break; } case 0xed: { op_io(); op_io(); regs.p.c = !regs.p.c; break; } case 0xa0: { op_io(); op_io(); regs.p.i = 1; break; } case 0xc0: { op_io(); op_io(); regs.p.i = 0; break; } case 0x02: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x01; op_writedp(dp, rd); break; } case 0x12: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x01; op_writedp(dp, rd); break; } case 0x22: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x02; op_writedp(dp, rd); break; } case 0x32: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x02; op_writedp(dp, rd); break; } case 0x42: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x04; op_writedp(dp, rd); break; } case 0x52: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x04; op_writedp(dp, rd); break; } case 0x62: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x08; op_writedp(dp, rd); break; } case 0x72: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x08; op_writedp(dp, rd); break; } case 0x82: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x10; op_writedp(dp, rd); break; } case 0x92: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x10; op_writedp(dp, rd); break; } case 0xa2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x20; op_writedp(dp, rd); break; } case 0xb2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x20; op_writedp(dp, rd); break; } case 0xc2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x40; op_writedp(dp, rd); break; } case 0xd2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x40; op_writedp(dp, rd); break; } case 0xe2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x80; op_writedp(dp, rd); break; } case 0xf2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x80; op_writedp(dp, rd); break; } case 0x2d: { op_io(); op_io(); op_writestack(regs.a); break; } case 0x4d: { op_io(); op_io(); op_writestack(regs.x); break; } case 0x6d: { op_io(); op_io(); op_writestack(regs.y); break; } case 0x0d: { op_io(); op_io(); op_writestack(regs.p); break; } case 0xae: { op_io(); op_io(); regs.a = op_readstack(); break; } case 0xce: { op_io(); op_io(); regs.x = op_readstack(); break; } case 0xee: { op_io(); op_io(); regs.y = op_readstack(); break; } case 0x8e: { op_io(); op_io(); regs.p = op_readstack(); break; } case 0xcf: { op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); ya = regs.y * regs.a; regs.a = ya; regs.y = ya >> 8; //result is set based on y (high-byte) only regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0x9e: { op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); op_io(); ya = regs.ya; //overflow set if quotient >= 256 regs.p.v = !!(regs.y >= regs.x); regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); if(regs.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) regs.a = ya / regs.x; regs.y = ya % regs.x; } else { //otherwise, the quotient won't fit into regs.p.v + regs.a //this emulates the odd behavior of the S-SMP in this case regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } apu/bapu/smp/iplrom.cpp000664 001750 001750 00000003241 12720446475 016236 0ustar00sergiosergio000000 000000 #ifdef SMP_CPP //this is the IPLROM for the S-SMP coprocessor. //the S-SMP does not allow writing to the IPLROM. //all writes are instead mapped to the extended //RAM region, accessible when $f1.d7 is clear. const uint8 SMP::iplrom[64] = { /*ffc0*/ 0xcd, 0xef, //mov x,#$ef /*ffc2*/ 0xbd, //mov sp,x /*ffc3*/ 0xe8, 0x00, //mov a,#$00 /*ffc5*/ 0xc6, //mov (x),a /*ffc6*/ 0x1d, //dec x /*ffc7*/ 0xd0, 0xfc, //bne $ffc5 /*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa /*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb /*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc /*ffd2*/ 0xd0, 0xfb, //bne $ffcf /*ffd4*/ 0x2f, 0x19, //bra $ffef /*ffd6*/ 0xeb, 0xf4, //mov y,$f4 /*ffd8*/ 0xd0, 0xfc, //bne $ffd6 /*ffda*/ 0x7e, 0xf4, //cmp y,$f4 /*ffdc*/ 0xd0, 0x0b, //bne $ffe9 /*ffde*/ 0xe4, 0xf5, //mov a,$f5 /*ffe0*/ 0xcb, 0xf4, //mov $f4,y /*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a /*ffe4*/ 0xfc, //inc y /*ffe5*/ 0xd0, 0xf3, //bne $ffda /*ffe7*/ 0xab, 0x01, //inc $01 /*ffe9*/ 0x10, 0xef, //bpl $ffda /*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 /*ffed*/ 0x10, 0xeb, //bpl $ffda /*ffef*/ 0xba, 0xf6, //movw ya,$f6 /*fff1*/ 0xda, 0x00, //movw $00,ya /*fff3*/ 0xba, 0xf4, //movw ya,$f4 /*fff5*/ 0xc4, 0xf4, //mov $f4,a /*fff7*/ 0xdd, //mov a,y /*fff8*/ 0x5d, //mov x,a /*fff9*/ 0xd0, 0xdb, //bne $ffd6 /*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) /*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) }; #endif snapshot.cpp000664 001750 001750 00000166225 12720446475 014274 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "memmap.h" #include "dma.h" #include "apu/apu.h" #include "fxinst.h" #include "fxemu.h" #include "sdd1.h" #include "srtc.h" #include "snapshot.h" #include "controls.h" #include "movie.h" #include "display.h" #include "language.h" #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif typedef struct { int offset; int offset2; int size; int type; uint16 debuted_in; uint16 deleted_in; const char *name; } FreezeData; enum { INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V, uint8_INDIR_ARRAY_V, uint16_INDIR_ARRAY_V, uint32_INDIR_ARRAY_V, POINTER_V }; #define COUNT(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0])) #define Offset(field, structure) ((int) (((char *) (&(((structure) NULL)->field))) - ((char *) NULL))) #define OFFSET(f) Offset(f, STRUCT *) #define DUMMY(f) Offset(f, struct Obsolete *) #define DELETED(f) (-1) #define INT_ENTRY(save_version_introduced, field) \ { \ OFFSET(field), \ 0, \ sizeof(((STRUCT *) NULL)->field), \ INT_V, \ save_version_introduced, \ 9999, \ #field \ } #define ARRAY_ENTRY(save_version_introduced, field, count, elemType) \ { \ OFFSET(field), \ 0, \ count, \ elemType, \ save_version_introduced, \ 9999, \ #field \ } #define POINTER_ENTRY(save_version_introduced, field, relativeToField) \ { \ OFFSET(field), \ OFFSET(relativeToField), \ 4, \ POINTER_V, \ save_version_introduced, \ 9999, \ #field \ } #define OBSOLETE_INT_ENTRY(save_version_introduced, save_version_removed, field) \ { \ DUMMY(field), \ 0, \ sizeof(((struct Obsolete *) NULL)->field), \ INT_V, \ save_version_introduced, \ save_version_removed, \ #field \ } #define OBSOLETE_ARRAY_ENTRY(save_version_introduced, save_version_removed, field, count, elemType) \ { \ DUMMY(field), \ 0, \ count, \ elemType, \ save_version_introduced, \ save_version_removed, \ #field \ } #define OBSOLETE_POINTER_ENTRY(save_version_introduced, save_version_removed, field, relativeToField) \ { \ DUMMY(field), \ DUMMY(relativeToField), \ 4, \ POINTER_V, \ save_version_introduced, \ save_version_removed, \ #field \ } #define DELETED_INT_ENTRY(save_version_introduced, save_version_removed, field, size) \ { \ DELETED(field), \ 0, \ size, \ INT_V, \ save_version_introduced, \ save_version_removed, \ #field \ } #define DELETED_ARRAY_ENTRY(save_version_introduced, save_version_removed, field, count, elemType) \ { \ DELETED(field), \ 0, \ count, \ elemType, \ save_version_introduced, \ save_version_removed, \ #field \ } #define DELETED_POINTER_ENTRY(save_version_introduced, save_version_removed, field, relativeToField) \ { \ DELETED(field), \ DELETED(relativeToField), \ 4, \ POINTER_V, \ save_version_introduced, \ save_version_removed, \ #field \ } struct SDMASnapshot { struct SDMA dma[8]; }; struct SnapshotMovieInfo { uint32 MovieInputDataSize; }; struct SnapshotScreenshotInfo { uint16 Width; uint16 Height; uint8 Interlaced; uint8 Data[MAX_SNES_WIDTH * MAX_SNES_HEIGHT * 3]; }; static struct Obsolete { uint8 CPU_IRQActive; } Obsolete; #define STRUCT struct SCPUState static FreezeData SnapCPU[] = { INT_ENTRY(6, Cycles), INT_ENTRY(6, PrevCycles), INT_ENTRY(6, V_Counter), INT_ENTRY(6, Flags), OBSOLETE_INT_ENTRY(6, 7, CPU_IRQActive), INT_ENTRY(6, IRQPending), INT_ENTRY(6, MemSpeed), INT_ENTRY(6, MemSpeedx2), INT_ENTRY(6, FastROMSpeed), INT_ENTRY(6, InDMA), INT_ENTRY(6, InHDMA), INT_ENTRY(6, InDMAorHDMA), INT_ENTRY(6, InWRAMDMAorHDMA), INT_ENTRY(6, HDMARanInDMA), INT_ENTRY(6, WhichEvent), INT_ENTRY(6, NextEvent), INT_ENTRY(6, WaitingForInterrupt), DELETED_INT_ENTRY(6, 7, WaitAddress, 4), DELETED_INT_ENTRY(6, 7, WaitCounter, 4), DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4), INT_ENTRY(7, NMILine), INT_ENTRY(7, IRQLine), INT_ENTRY(7, IRQTransition), INT_ENTRY(7, IRQLastState), INT_ENTRY(7, IRQExternal) }; #undef STRUCT #define STRUCT struct SRegisters static FreezeData SnapRegisters[] = { INT_ENTRY(6, PB), INT_ENTRY(6, DB), INT_ENTRY(6, P.W), INT_ENTRY(6, A.W), INT_ENTRY(6, D.W), INT_ENTRY(6, S.W), INT_ENTRY(6, X.W), INT_ENTRY(6, Y.W), INT_ENTRY(6, PCw) }; #undef STRUCT #define STRUCT struct SPPU static FreezeData SnapPPU[] = { INT_ENTRY(6, VMA.High), INT_ENTRY(6, VMA.Increment), INT_ENTRY(6, VMA.Address), INT_ENTRY(6, VMA.Mask1), INT_ENTRY(6, VMA.FullGraphicCount), INT_ENTRY(6, VMA.Shift), INT_ENTRY(6, WRAM), #define O(N) \ INT_ENTRY(6, BG[N].SCBase), \ INT_ENTRY(6, BG[N].HOffset), \ INT_ENTRY(6, BG[N].VOffset), \ INT_ENTRY(6, BG[N].BGSize), \ INT_ENTRY(6, BG[N].NameBase), \ INT_ENTRY(6, BG[N].SCSize) O(0), O(1), O(2), O(3), #undef O INT_ENTRY(6, BGMode), INT_ENTRY(6, BG3Priority), INT_ENTRY(6, CGFLIP), INT_ENTRY(6, CGFLIPRead), INT_ENTRY(6, CGADD), ARRAY_ENTRY(6, CGDATA, 256, uint16_ARRAY_V), #define O(N) \ INT_ENTRY(6, OBJ[N].HPos), \ INT_ENTRY(6, OBJ[N].VPos), \ INT_ENTRY(6, OBJ[N].HFlip), \ INT_ENTRY(6, OBJ[N].VFlip), \ INT_ENTRY(6, OBJ[N].Name), \ INT_ENTRY(6, OBJ[N].Priority), \ INT_ENTRY(6, OBJ[N].Palette), \ INT_ENTRY(6, OBJ[N].Size) O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7), O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15), O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23), O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31), O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39), O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47), O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55), O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63), O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71), O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79), O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87), O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95), O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103), O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111), O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119), O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127), #undef O INT_ENTRY(6, OBJThroughMain), INT_ENTRY(6, OBJThroughSub), INT_ENTRY(6, OBJAddition), INT_ENTRY(6, OBJNameBase), INT_ENTRY(6, OBJNameSelect), INT_ENTRY(6, OBJSizeSelect), INT_ENTRY(6, OAMAddr), INT_ENTRY(6, SavedOAMAddr), INT_ENTRY(6, OAMPriorityRotation), INT_ENTRY(6, OAMFlip), INT_ENTRY(6, OAMReadFlip), INT_ENTRY(6, OAMTileAddress), INT_ENTRY(6, OAMWriteRegister), ARRAY_ENTRY(6, OAMData, 512 + 32, uint8_ARRAY_V), INT_ENTRY(6, FirstSprite), INT_ENTRY(6, LastSprite), INT_ENTRY(6, HTimerEnabled), INT_ENTRY(6, VTimerEnabled), INT_ENTRY(6, HTimerPosition), INT_ENTRY(6, VTimerPosition), INT_ENTRY(6, IRQHBeamPos), INT_ENTRY(6, IRQVBeamPos), INT_ENTRY(6, HBeamFlip), INT_ENTRY(6, VBeamFlip), INT_ENTRY(6, HBeamPosLatched), INT_ENTRY(6, VBeamPosLatched), INT_ENTRY(6, GunHLatch), INT_ENTRY(6, GunVLatch), INT_ENTRY(6, HVBeamCounterLatched), INT_ENTRY(6, Mode7HFlip), INT_ENTRY(6, Mode7VFlip), INT_ENTRY(6, Mode7Repeat), INT_ENTRY(6, MatrixA), INT_ENTRY(6, MatrixB), INT_ENTRY(6, MatrixC), INT_ENTRY(6, MatrixD), INT_ENTRY(6, CentreX), INT_ENTRY(6, CentreY), INT_ENTRY(6, M7HOFS), INT_ENTRY(6, M7VOFS), INT_ENTRY(6, Mosaic), INT_ENTRY(6, MosaicStart), ARRAY_ENTRY(6, BGMosaic, 4, uint8_ARRAY_V), INT_ENTRY(6, Window1Left), INT_ENTRY(6, Window1Right), INT_ENTRY(6, Window2Left), INT_ENTRY(6, Window2Right), INT_ENTRY(6, RecomputeClipWindows), #define O(N) \ INT_ENTRY(6, ClipCounts[N]), \ INT_ENTRY(6, ClipWindowOverlapLogic[N]), \ INT_ENTRY(6, ClipWindow1Enable[N]), \ INT_ENTRY(6, ClipWindow2Enable[N]), \ INT_ENTRY(6, ClipWindow1Inside[N]), \ INT_ENTRY(6, ClipWindow2Inside[N]) O(0), O(1), O(2), O(3), O(4), O(5), #undef O INT_ENTRY(6, ForcedBlanking), INT_ENTRY(6, FixedColourRed), INT_ENTRY(6, FixedColourGreen), INT_ENTRY(6, FixedColourBlue), INT_ENTRY(6, Brightness), INT_ENTRY(6, ScreenHeight), INT_ENTRY(6, Need16x8Mulitply), INT_ENTRY(6, BGnxOFSbyte), INT_ENTRY(6, M7byte), INT_ENTRY(6, HDMA), INT_ENTRY(6, HDMAEnded), INT_ENTRY(6, OpenBus1), INT_ENTRY(6, OpenBus2) }; #undef STRUCT #define STRUCT struct SDMASnapshot static FreezeData SnapDMA[] = { #define O(N) \ INT_ENTRY(6, dma[N].ReverseTransfer), \ INT_ENTRY(6, dma[N].HDMAIndirectAddressing), \ INT_ENTRY(6, dma[N].UnusedBit43x0), \ INT_ENTRY(6, dma[N].AAddressFixed), \ INT_ENTRY(6, dma[N].AAddressDecrement), \ INT_ENTRY(6, dma[N].TransferMode), \ INT_ENTRY(6, dma[N].BAddress), \ INT_ENTRY(6, dma[N].AAddress), \ INT_ENTRY(6, dma[N].ABank), \ INT_ENTRY(6, dma[N].DMACount_Or_HDMAIndirectAddress), \ INT_ENTRY(6, dma[N].IndirectBank), \ INT_ENTRY(6, dma[N].Address), \ INT_ENTRY(6, dma[N].Repeat), \ INT_ENTRY(6, dma[N].LineCount), \ INT_ENTRY(6, dma[N].UnknownByte), \ INT_ENTRY(6, dma[N].DoTransfer) O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7) #undef O }; #undef STRUCT #define STRUCT struct SControlSnapshot static FreezeData SnapControls[] = { INT_ENTRY(6, ver), ARRAY_ENTRY(6, port1_read_idx, 2, uint8_ARRAY_V), ARRAY_ENTRY(6, dummy1, 4, uint8_ARRAY_V), ARRAY_ENTRY(6, port2_read_idx, 2, uint8_ARRAY_V), ARRAY_ENTRY(6, dummy2, 4, uint8_ARRAY_V), ARRAY_ENTRY(6, mouse_speed, 2, uint8_ARRAY_V), INT_ENTRY(6, justifier_select), ARRAY_ENTRY(6, dummy3, 8, uint8_ARRAY_V), INT_ENTRY(6, pad_read), INT_ENTRY(6, pad_read_last), ARRAY_ENTRY(6, internal, 60, uint8_ARRAY_V) }; #undef STRUCT #define STRUCT struct STimings static FreezeData SnapTimings[] = { INT_ENTRY(6, H_Max_Master), INT_ENTRY(6, H_Max), INT_ENTRY(6, V_Max_Master), INT_ENTRY(6, V_Max), INT_ENTRY(6, HBlankStart), INT_ENTRY(6, HBlankEnd), INT_ENTRY(6, HDMAInit), INT_ENTRY(6, HDMAStart), INT_ENTRY(6, NMITriggerPos), INT_ENTRY(6, WRAMRefreshPos), INT_ENTRY(6, RenderPos), INT_ENTRY(6, InterlaceField), INT_ENTRY(6, DMACPUSync), INT_ENTRY(6, NMIDMADelay), INT_ENTRY(6, IRQPendCount), INT_ENTRY(6, APUSpeedup), INT_ENTRY(7, IRQTriggerCycles), INT_ENTRY(7, APUAllowTimeOverflow) }; #undef STRUCT #define STRUCT struct FxRegs_s static FreezeData SnapFX[] = { ARRAY_ENTRY(6, avReg, 16, uint32_ARRAY_V), INT_ENTRY(6, vColorReg), INT_ENTRY(6, vPlotOptionReg), INT_ENTRY(6, vStatusReg), INT_ENTRY(6, vPrgBankReg), INT_ENTRY(6, vRomBankReg), INT_ENTRY(6, vRamBankReg), INT_ENTRY(6, vCacheBaseReg), INT_ENTRY(6, vCacheFlags), INT_ENTRY(6, vLastRamAdr), POINTER_ENTRY(6, pvDreg, avRegAddr), POINTER_ENTRY(6, pvSreg, avRegAddr), INT_ENTRY(6, vRomBuffer), INT_ENTRY(6, vPipe), INT_ENTRY(6, vPipeAdr), INT_ENTRY(6, vSign), INT_ENTRY(6, vZero), INT_ENTRY(6, vCarry), INT_ENTRY(6, vOverflow), INT_ENTRY(6, vErrorCode), INT_ENTRY(6, vIllegalAddress), INT_ENTRY(6, bBreakPoint), INT_ENTRY(6, vBreakPoint), INT_ENTRY(6, vStepPoint), INT_ENTRY(6, nRamBanks), INT_ENTRY(6, nRomBanks), INT_ENTRY(6, vMode), INT_ENTRY(6, vPrevMode), POINTER_ENTRY(6, pvScreenBase, pvRam), #define O(N) \ POINTER_ENTRY(6, apvScreen[N], pvRam) O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7), O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15), O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23), O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31), #undef O ARRAY_ENTRY(6, x, 32, uint32_ARRAY_V), INT_ENTRY(6, vScreenHeight), INT_ENTRY(6, vScreenRealHeight), INT_ENTRY(6, vPrevScreenHeight), INT_ENTRY(6, vScreenSize), POINTER_ENTRY(6, pvRamBank, apvRamBank), POINTER_ENTRY(6, pvRomBank, apvRomBank), POINTER_ENTRY(6, pvPrgBank, apvRomBank), #define O(N) \ POINTER_ENTRY(6, apvRamBank[N], pvRam) O(0), O(1), O(2), O(3), #undef O INT_ENTRY(6, bCacheActive), POINTER_ENTRY(6, pvCache, pvRegisters), ARRAY_ENTRY(6, avCacheBackup, 512, uint8_ARRAY_V), INT_ENTRY(6, vCounter), INT_ENTRY(6, vInstCount), INT_ENTRY(6, vSCBRDirty) }; #undef STRUCT #define STRUCT struct SSA1 static FreezeData SnapSA1[] = { DELETED_INT_ENTRY(6, 7, CPUExecuting, 1), INT_ENTRY(6, ShiftedPB), INT_ENTRY(6, ShiftedDB), INT_ENTRY(6, Flags), DELETED_INT_ENTRY(6, 7, IRQActive, 1), DELETED_INT_ENTRY(6, 7, Waiting, 1), INT_ENTRY(6, WaitingForInterrupt), DELETED_INT_ENTRY(6, 7, WaitAddress, 4), DELETED_INT_ENTRY(6, 7, WaitCounter, 4), DELETED_INT_ENTRY(6, 7, PBPCAtOpcodeStart, 4), DELETED_INT_ENTRY(6, 7, Executing, 1), INT_ENTRY(6, overflow), INT_ENTRY(6, in_char_dma), INT_ENTRY(6, op1), INT_ENTRY(6, op2), INT_ENTRY(6, arithmetic_op), INT_ENTRY(6, sum), INT_ENTRY(6, VirtualBitmapFormat), INT_ENTRY(6, variable_bit_pos), INT_ENTRY(7, Cycles), INT_ENTRY(7, PrevCycles), INT_ENTRY(7, TimerIRQLastState), INT_ENTRY(7, HTimerIRQPos), INT_ENTRY(7, VTimerIRQPos), INT_ENTRY(7, HCounter), INT_ENTRY(7, VCounter), INT_ENTRY(7, PrevHCounter), INT_ENTRY(7, MemSpeed), INT_ENTRY(7, MemSpeedx2) }; #undef STRUCT #define STRUCT struct SSA1Registers static FreezeData SnapSA1Registers[] = { INT_ENTRY(6, PB), INT_ENTRY(6, DB), INT_ENTRY(6, P.W), INT_ENTRY(6, A.W), INT_ENTRY(6, D.W), INT_ENTRY(6, S.W), INT_ENTRY(6, X.W), INT_ENTRY(6, Y.W), INT_ENTRY(6, PCw) }; #undef STRUCT #define STRUCT struct SDSP1 static FreezeData SnapDSP1[] = { INT_ENTRY(6, waiting4command), INT_ENTRY(6, first_parameter), INT_ENTRY(6, command), INT_ENTRY(6, in_count), INT_ENTRY(6, in_index), INT_ENTRY(6, out_count), INT_ENTRY(6, out_index), ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V), ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V), INT_ENTRY(6, CentreX), INT_ENTRY(6, CentreY), INT_ENTRY(6, VOffset), INT_ENTRY(6, VPlane_C), INT_ENTRY(6, VPlane_E), INT_ENTRY(6, SinAas), INT_ENTRY(6, CosAas), INT_ENTRY(6, SinAzs), INT_ENTRY(6, CosAzs), INT_ENTRY(6, SinAZS), INT_ENTRY(6, CosAZS), INT_ENTRY(6, SecAZS_C1), INT_ENTRY(6, SecAZS_E1), INT_ENTRY(6, SecAZS_C2), INT_ENTRY(6, SecAZS_E2), INT_ENTRY(6, Nx), INT_ENTRY(6, Ny), INT_ENTRY(6, Nz), INT_ENTRY(6, Gx), INT_ENTRY(6, Gy), INT_ENTRY(6, Gz), INT_ENTRY(6, C_Les), INT_ENTRY(6, E_Les), INT_ENTRY(6, G_Les), #define O(N) \ ARRAY_ENTRY(6, matrixA[N], 3, uint16_ARRAY_V), \ ARRAY_ENTRY(6, matrixB[N], 3, uint16_ARRAY_V), \ ARRAY_ENTRY(6, matrixC[N], 3, uint16_ARRAY_V) O(0), O(1), O(2), #undef O INT_ENTRY(6, Op00Multiplicand), INT_ENTRY(6, Op00Multiplier), INT_ENTRY(6, Op00Result), INT_ENTRY(6, Op20Multiplicand), INT_ENTRY(6, Op20Multiplier), INT_ENTRY(6, Op20Result), INT_ENTRY(6, Op10Coefficient), INT_ENTRY(6, Op10Exponent), INT_ENTRY(6, Op10CoefficientR), INT_ENTRY(6, Op10ExponentR), INT_ENTRY(6, Op04Angle), INT_ENTRY(6, Op04Radius), INT_ENTRY(6, Op04Sin), INT_ENTRY(6, Op04Cos), INT_ENTRY(6, Op0CA), INT_ENTRY(6, Op0CX1), INT_ENTRY(6, Op0CY1), INT_ENTRY(6, Op0CX2), INT_ENTRY(6, Op0CY2), INT_ENTRY(6, Op02FX), INT_ENTRY(6, Op02FY), INT_ENTRY(6, Op02FZ), INT_ENTRY(6, Op02LFE), INT_ENTRY(6, Op02LES), INT_ENTRY(6, Op02AAS), INT_ENTRY(6, Op02AZS), INT_ENTRY(6, Op02VOF), INT_ENTRY(6, Op02VVA), INT_ENTRY(6, Op02CX), INT_ENTRY(6, Op02CY), INT_ENTRY(6, Op0AVS), INT_ENTRY(6, Op0AA), INT_ENTRY(6, Op0AB), INT_ENTRY(6, Op0AC), INT_ENTRY(6, Op0AD), INT_ENTRY(6, Op06X), INT_ENTRY(6, Op06Y), INT_ENTRY(6, Op06Z), INT_ENTRY(6, Op06H), INT_ENTRY(6, Op06V), INT_ENTRY(6, Op06M), INT_ENTRY(6, Op01m), INT_ENTRY(6, Op01Zr), INT_ENTRY(6, Op01Xr), INT_ENTRY(6, Op01Yr), INT_ENTRY(6, Op11m), INT_ENTRY(6, Op11Zr), INT_ENTRY(6, Op11Xr), INT_ENTRY(6, Op11Yr), INT_ENTRY(6, Op21m), INT_ENTRY(6, Op21Zr), INT_ENTRY(6, Op21Xr), INT_ENTRY(6, Op21Yr), INT_ENTRY(6, Op0DX), INT_ENTRY(6, Op0DY), INT_ENTRY(6, Op0DZ), INT_ENTRY(6, Op0DF), INT_ENTRY(6, Op0DL), INT_ENTRY(6, Op0DU), INT_ENTRY(6, Op1DX), INT_ENTRY(6, Op1DY), INT_ENTRY(6, Op1DZ), INT_ENTRY(6, Op1DF), INT_ENTRY(6, Op1DL), INT_ENTRY(6, Op1DU), INT_ENTRY(6, Op2DX), INT_ENTRY(6, Op2DY), INT_ENTRY(6, Op2DZ), INT_ENTRY(6, Op2DF), INT_ENTRY(6, Op2DL), INT_ENTRY(6, Op2DU), INT_ENTRY(6, Op03F), INT_ENTRY(6, Op03L), INT_ENTRY(6, Op03U), INT_ENTRY(6, Op03X), INT_ENTRY(6, Op03Y), INT_ENTRY(6, Op03Z), INT_ENTRY(6, Op13F), INT_ENTRY(6, Op13L), INT_ENTRY(6, Op13U), INT_ENTRY(6, Op13X), INT_ENTRY(6, Op13Y), INT_ENTRY(6, Op13Z), INT_ENTRY(6, Op23F), INT_ENTRY(6, Op23L), INT_ENTRY(6, Op23U), INT_ENTRY(6, Op23X), INT_ENTRY(6, Op23Y), INT_ENTRY(6, Op23Z), INT_ENTRY(6, Op14Zr), INT_ENTRY(6, Op14Xr), INT_ENTRY(6, Op14Yr), INT_ENTRY(6, Op14U), INT_ENTRY(6, Op14F), INT_ENTRY(6, Op14L), INT_ENTRY(6, Op14Zrr), INT_ENTRY(6, Op14Xrr), INT_ENTRY(6, Op14Yrr), INT_ENTRY(6, Op0EH), INT_ENTRY(6, Op0EV), INT_ENTRY(6, Op0EX), INT_ENTRY(6, Op0EY), INT_ENTRY(6, Op0BX), INT_ENTRY(6, Op0BY), INT_ENTRY(6, Op0BZ), INT_ENTRY(6, Op0BS), INT_ENTRY(6, Op1BX), INT_ENTRY(6, Op1BY), INT_ENTRY(6, Op1BZ), INT_ENTRY(6, Op1BS), INT_ENTRY(6, Op2BX), INT_ENTRY(6, Op2BY), INT_ENTRY(6, Op2BZ), INT_ENTRY(6, Op2BS), INT_ENTRY(6, Op28X), INT_ENTRY(6, Op28Y), INT_ENTRY(6, Op28Z), INT_ENTRY(6, Op28R), INT_ENTRY(6, Op1CX), INT_ENTRY(6, Op1CY), INT_ENTRY(6, Op1CZ), INT_ENTRY(6, Op1CXBR), INT_ENTRY(6, Op1CYBR), INT_ENTRY(6, Op1CZBR), INT_ENTRY(6, Op1CXAR), INT_ENTRY(6, Op1CYAR), INT_ENTRY(6, Op1CZAR), INT_ENTRY(6, Op1CX1), INT_ENTRY(6, Op1CY1), INT_ENTRY(6, Op1CZ1), INT_ENTRY(6, Op1CX2), INT_ENTRY(6, Op1CY2), INT_ENTRY(6, Op1CZ2), INT_ENTRY(6, Op0FRamsize), INT_ENTRY(6, Op0FPass), INT_ENTRY(6, Op2FUnknown), INT_ENTRY(6, Op2FSize), INT_ENTRY(6, Op08X), INT_ENTRY(6, Op08Y), INT_ENTRY(6, Op08Z), INT_ENTRY(6, Op08Ll), INT_ENTRY(6, Op08Lh), INT_ENTRY(6, Op18X), INT_ENTRY(6, Op18Y), INT_ENTRY(6, Op18Z), INT_ENTRY(6, Op18R), INT_ENTRY(6, Op18D), INT_ENTRY(6, Op38X), INT_ENTRY(6, Op38Y), INT_ENTRY(6, Op38Z), INT_ENTRY(6, Op38R), INT_ENTRY(6, Op38D) }; #undef STRUCT #define STRUCT struct SDSP2 static FreezeData SnapDSP2[] = { INT_ENTRY(6, waiting4command), INT_ENTRY(6, command), INT_ENTRY(6, in_count), INT_ENTRY(6, in_index), INT_ENTRY(6, out_count), INT_ENTRY(6, out_index), ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V), ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V), INT_ENTRY(6, Op05HasLen), INT_ENTRY(6, Op05Len), INT_ENTRY(6, Op05Transparent), INT_ENTRY(6, Op06HasLen), INT_ENTRY(6, Op06Len), INT_ENTRY(6, Op09Word1), INT_ENTRY(6, Op09Word2), INT_ENTRY(6, Op0DHasLen), INT_ENTRY(6, Op0DOutLen), INT_ENTRY(6, Op0DInLen) }; #undef STRUCT #define STRUCT struct SDSP4 static FreezeData SnapDSP4[] = { INT_ENTRY(6, waiting4command), INT_ENTRY(6, half_command), INT_ENTRY(6, command), INT_ENTRY(6, in_count), INT_ENTRY(6, in_index), INT_ENTRY(6, out_count), INT_ENTRY(6, out_index), ARRAY_ENTRY(6, parameters, 512, uint8_ARRAY_V), ARRAY_ENTRY(6, output, 512, uint8_ARRAY_V), INT_ENTRY(6, byte), INT_ENTRY(6, address), INT_ENTRY(6, Logic), INT_ENTRY(6, lcv), INT_ENTRY(6, distance), INT_ENTRY(6, raster), INT_ENTRY(6, segments), INT_ENTRY(6, world_x), INT_ENTRY(6, world_y), INT_ENTRY(6, world_dx), INT_ENTRY(6, world_dy), INT_ENTRY(6, world_ddx), INT_ENTRY(6, world_ddy), INT_ENTRY(6, world_xenv), INT_ENTRY(6, world_yofs), INT_ENTRY(6, view_x1), INT_ENTRY(6, view_y1), INT_ENTRY(6, view_x2), INT_ENTRY(6, view_y2), INT_ENTRY(6, view_dx), INT_ENTRY(6, view_dy), INT_ENTRY(6, view_xofs1), INT_ENTRY(6, view_yofs1), INT_ENTRY(6, view_xofs2), INT_ENTRY(6, view_yofs2), INT_ENTRY(6, view_yofsenv), INT_ENTRY(6, view_turnoff_x), INT_ENTRY(6, view_turnoff_dx), INT_ENTRY(6, viewport_cx), INT_ENTRY(6, viewport_cy), INT_ENTRY(6, viewport_left), INT_ENTRY(6, viewport_right), INT_ENTRY(6, viewport_top), INT_ENTRY(6, viewport_bottom), INT_ENTRY(6, sprite_x), INT_ENTRY(6, sprite_y), INT_ENTRY(6, sprite_attr), INT_ENTRY(6, sprite_size), INT_ENTRY(6, sprite_clipy), INT_ENTRY(6, sprite_count), #define O(N) \ ARRAY_ENTRY(6, poly_clipLf[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_clipRt[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_ptr[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_raster[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_top[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_bottom[N], 2, uint16_ARRAY_V), \ ARRAY_ENTRY(6, poly_cx[N], 2, uint16_ARRAY_V) O(0), O(1), #undef O ARRAY_ENTRY(6, poly_start, 2, uint16_ARRAY_V), ARRAY_ENTRY(6, poly_plane, 2, uint16_ARRAY_V), ARRAY_ENTRY(6, OAM_attr, 16, uint16_ARRAY_V), INT_ENTRY(6, OAM_index), INT_ENTRY(6, OAM_bits), INT_ENTRY(6, OAM_RowMax), ARRAY_ENTRY(6, OAM_Row, 32, uint16_ARRAY_V) }; #undef STRUCT #define STRUCT struct SST010 static FreezeData SnapST010[] = { ARRAY_ENTRY(6, input_params, 16, uint8_ARRAY_V), ARRAY_ENTRY(6, output_params, 16, uint8_ARRAY_V), INT_ENTRY(6, op_reg), INT_ENTRY(6, execute), INT_ENTRY(6, control_enable) }; #undef STRUCT #define STRUCT struct SOBC1 static FreezeData SnapOBC1[] = { INT_ENTRY(6, address), INT_ENTRY(6, basePtr), INT_ENTRY(6, shift) }; #undef STRUCT #define STRUCT struct SSPC7110Snapshot static FreezeData SnapSPC7110Snap[] = { INT_ENTRY(6, r4801), INT_ENTRY(6, r4802), INT_ENTRY(6, r4803), INT_ENTRY(6, r4804), INT_ENTRY(6, r4805), INT_ENTRY(6, r4806), INT_ENTRY(6, r4807), INT_ENTRY(6, r4808), INT_ENTRY(6, r4809), INT_ENTRY(6, r480a), INT_ENTRY(6, r480b), INT_ENTRY(6, r480c), INT_ENTRY(6, r4811), INT_ENTRY(6, r4812), INT_ENTRY(6, r4813), INT_ENTRY(6, r4814), INT_ENTRY(6, r4815), INT_ENTRY(6, r4816), INT_ENTRY(6, r4817), INT_ENTRY(6, r4818), INT_ENTRY(6, r481x), INT_ENTRY(6, r4814_latch), INT_ENTRY(6, r4815_latch), INT_ENTRY(6, r4820), INT_ENTRY(6, r4821), INT_ENTRY(6, r4822), INT_ENTRY(6, r4823), INT_ENTRY(6, r4824), INT_ENTRY(6, r4825), INT_ENTRY(6, r4826), INT_ENTRY(6, r4827), INT_ENTRY(6, r4828), INT_ENTRY(6, r4829), INT_ENTRY(6, r482a), INT_ENTRY(6, r482b), INT_ENTRY(6, r482c), INT_ENTRY(6, r482d), INT_ENTRY(6, r482e), INT_ENTRY(6, r482f), INT_ENTRY(6, r4830), INT_ENTRY(6, r4831), INT_ENTRY(6, r4832), INT_ENTRY(6, r4833), INT_ENTRY(6, r4834), INT_ENTRY(6, dx_offset), INT_ENTRY(6, ex_offset), INT_ENTRY(6, fx_offset), INT_ENTRY(6, r4840), INT_ENTRY(6, r4841), INT_ENTRY(6, r4842), INT_ENTRY(6, rtc_state), INT_ENTRY(6, rtc_mode), INT_ENTRY(6, rtc_index), INT_ENTRY(6, decomp_mode), INT_ENTRY(6, decomp_offset), ARRAY_ENTRY(6, decomp_buffer, SPC7110_DECOMP_BUFFER_SIZE, uint8_ARRAY_V), INT_ENTRY(6, decomp_buffer_rdoffset), INT_ENTRY(6, decomp_buffer_wroffset), INT_ENTRY(6, decomp_buffer_length), #define O(N) \ INT_ENTRY(6, context[N].index), \ INT_ENTRY(6, context[N].invert) O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7), O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15), O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23), O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31) #undef O }; #undef STRUCT #define STRUCT struct SSRTCSnapshot static FreezeData SnapSRTCSnap[] = { INT_ENTRY(6, rtc_mode), INT_ENTRY(6, rtc_index) }; #undef STRUCT #define STRUCT struct SBSX static FreezeData SnapBSX[] = { INT_ENTRY(6, dirty), INT_ENTRY(6, dirty2), INT_ENTRY(6, bootup), INT_ENTRY(6, flash_enable), INT_ENTRY(6, write_enable), INT_ENTRY(6, read_enable), INT_ENTRY(6, flash_command), INT_ENTRY(6, old_write), INT_ENTRY(6, new_write), INT_ENTRY(6, out_index), ARRAY_ENTRY(6, output, 32, uint8_ARRAY_V), ARRAY_ENTRY(6, PPU, 32, uint8_ARRAY_V), ARRAY_ENTRY(6, MMC, 16, uint8_ARRAY_V), ARRAY_ENTRY(6, prevMMC, 16, uint8_ARRAY_V), ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V) }; #undef STRUCT #define STRUCT struct SnapshotScreenshotInfo static FreezeData SnapScreenshot[] = { INT_ENTRY(6, Width), INT_ENTRY(6, Height), INT_ENTRY(6, Interlaced), ARRAY_ENTRY(6, Data, MAX_SNES_WIDTH * MAX_SNES_HEIGHT * 3, uint8_ARRAY_V) }; #undef STRUCT #define STRUCT struct SnapshotMovieInfo static FreezeData SnapMovie[] = { INT_ENTRY(6, MovieInputDataSize) }; static int UnfreezeBlock (STREAM, const char *, uint8 *, int); static int UnfreezeBlockCopy (STREAM, const char *, uint8 **, int); static int UnfreezeStruct (STREAM, const char *, void *, FreezeData *, int, int); static int UnfreezeStructCopy (STREAM, const char *, uint8 **, FreezeData *, int, int); static void UnfreezeStructFromCopy (void *, FreezeData *, int, uint8 *, int); static void FreezeBlock (STREAM, const char *, uint8 *, int); static void FreezeStruct (STREAM, const char *, void *, FreezeData *, int); void S9xResetSaveTimer (bool8 dontsave) { static time_t t = -1; if (!Settings.DontSaveOopsSnapshot && !dontsave && t != -1 && time(NULL) - t > 300) { char filename[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; _splitpath(Memory.ROMFilename, drive, dir, def, ext); sprintf(filename, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops"); S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, SAVE_INFO_OOPS); S9xFreezeGame(filename); } t = time(NULL); } uint32 S9xFreezeSize() { nulStream stream; S9xFreezeToStream(&stream); return stream.size(); } bool8 S9xFreezeGameMem (uint8 *buf, uint32 bufSize) { memStream mStream(buf, bufSize); S9xFreezeToStream(&mStream); return (TRUE); } bool8 S9xFreezeGame (const char *filename) { STREAM stream = NULL; if (S9xOpenSnapshotFile(filename, FALSE, &stream)) { S9xFreezeToStream(stream); S9xCloseSnapshotFile(stream); S9xResetSaveTimer(TRUE); const char *base = S9xBasename(filename); if (S9xMovieActive()) sprintf(String, MOVIE_INFO_SNAPSHOT " %s", base); else sprintf(String, SAVE_INFO_SNAPSHOT " %s", base); S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String); return (TRUE); } return (FALSE); } int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize) { memStream stream(buf, bufSize); int result = S9xUnfreezeFromStream(&stream); return result; } bool8 S9xUnfreezeGame (const char *filename) { STREAM stream = NULL; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; const char *base = S9xBasename(filename); _splitpath(filename, drive, dir, def, ext); S9xResetSaveTimer(!strcmp(ext, "oops") || !strcmp(ext, "oop") || !strcmp(ext, ".oops") || !strcmp(ext, ".oop")); if (S9xOpenSnapshotFile(filename, TRUE, &stream)) { int result; result = S9xUnfreezeFromStream(stream); S9xCloseSnapshotFile(stream); if (result != SUCCESS) { switch (result) { case WRONG_FORMAT: S9xMessage(S9X_ERROR, S9X_WRONG_FORMAT, SAVE_ERR_WRONG_FORMAT); break; case WRONG_VERSION: S9xMessage(S9X_ERROR, S9X_WRONG_VERSION, SAVE_ERR_WRONG_VERSION); break; case WRONG_MOVIE_SNAPSHOT: S9xMessage(S9X_ERROR, S9X_WRONG_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_WRONG_MOVIE); break; case NOT_A_MOVIE_SNAPSHOT: S9xMessage(S9X_ERROR, S9X_NOT_A_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_NOT_MOVIE); break; case SNAPSHOT_INCONSISTENT: S9xMessage(S9X_ERROR, S9X_SNAPSHOT_INCONSISTENT, MOVIE_ERR_SNAPSHOT_INCONSISTENT); break; case FILE_NOT_FOUND: default: sprintf(String, SAVE_ERR_ROM_NOT_FOUND, base); S9xMessage(S9X_ERROR, S9X_ROM_NOT_FOUND, String); break; } return (FALSE); } if (S9xMovieActive()) { if (S9xMovieReadOnly()) sprintf(String, MOVIE_INFO_REWIND " %s", base); else sprintf(String, MOVIE_INFO_RERECORD " %s", base); } else sprintf(String, SAVE_INFO_LOAD " %s", base); S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String); return (TRUE); } sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base); S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String); return (FALSE); } void S9xFreezeToStream (STREAM stream) { char buffer[1024]; uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE]; S9xSetSoundMute(TRUE); sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION); WRITE_STREAM(buffer, strlen(buffer), stream); sprintf(buffer, "NAM:%06d:%s%c", (int) strlen(Memory.ROMFilename) + 1, Memory.ROMFilename, 0); WRITE_STREAM(buffer, strlen(buffer) + 1, stream); FreezeStruct(stream, "CPU", &CPU, SnapCPU, COUNT(SnapCPU)); FreezeStruct(stream, "REG", &Registers, SnapRegisters, COUNT(SnapRegisters)); FreezeStruct(stream, "PPU", &PPU, SnapPPU, COUNT(SnapPPU)); struct SDMASnapshot dma_snap; for (int d = 0; d < 8; d++) dma_snap.dma[d] = DMA[d]; FreezeStruct(stream, "DMA", &dma_snap, SnapDMA, COUNT(SnapDMA)); FreezeBlock (stream, "VRA", Memory.VRAM, 0x10000); FreezeBlock (stream, "RAM", Memory.RAM, 0x20000); FreezeBlock (stream, "SRA", Memory.SRAM, 0x20000); FreezeBlock (stream, "FIL", Memory.FillRAM, 0x8000); S9xAPUSaveState(soundsnapshot); FreezeBlock (stream, "SND", soundsnapshot, SPC_SAVE_STATE_BLOCK_SIZE); struct SControlSnapshot ctl_snap; S9xControlPreSaveState(&ctl_snap); FreezeStruct(stream, "CTL", &ctl_snap, SnapControls, COUNT(SnapControls)); FreezeStruct(stream, "TIM", &Timings, SnapTimings, COUNT(SnapTimings)); if (Settings.SuperFX) { GSU.avRegAddr = (uint8 *) &GSU.avReg; FreezeStruct(stream, "SFX", &GSU, SnapFX, COUNT(SnapFX)); } if (Settings.SA1) { S9xSA1PackStatus(); FreezeStruct(stream, "SA1", &SA1, SnapSA1, COUNT(SnapSA1)); FreezeStruct(stream, "SAR", &SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers)); } if (Settings.DSP == 1) FreezeStruct(stream, "DP1", &DSP1, SnapDSP1, COUNT(SnapDSP1)); if (Settings.DSP == 2) FreezeStruct(stream, "DP2", &DSP2, SnapDSP2, COUNT(SnapDSP2)); if (Settings.DSP == 4) FreezeStruct(stream, "DP4", &DSP4, SnapDSP4, COUNT(SnapDSP4)); if (Settings.C4) FreezeBlock (stream, "CX4", Memory.C4RAM, 8192); if (Settings.SETA == ST_010) FreezeStruct(stream, "ST0", &ST010, SnapST010, COUNT(SnapST010)); if (Settings.OBC1) { FreezeStruct(stream, "OBC", &OBC1, SnapOBC1, COUNT(SnapOBC1)); FreezeBlock (stream, "OBM", Memory.OBC1RAM, 8192); } if (Settings.SPC7110) { S9xSPC7110PreSaveState(); FreezeStruct(stream, "S71", &s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap)); } if (Settings.SRTC) { S9xSRTCPreSaveState(); FreezeStruct(stream, "SRT", &srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap)); } if (Settings.SRTC || Settings.SPC7110RTC) FreezeBlock (stream, "CLK", RTCData.reg, 20); if (Settings.BS) FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX)); if (Settings.SnapshotScreenshots) { SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; ssi->Width = min(IPPU.RenderedScreenWidth, MAX_SNES_WIDTH); ssi->Height = min(IPPU.RenderedScreenHeight, MAX_SNES_HEIGHT); ssi->Interlaced = GFX.DoInterlace; uint8 *rowpix = ssi->Data; uint16 *screen = GFX.Screen; for (int y = 0; y < ssi->Height; y++, screen += GFX.RealPPL) { for (int x = 0; x < ssi->Width; x++) { uint32 r, g, b; DECOMPOSE_PIXEL(screen[x], r, g, b); *(rowpix++) = r; *(rowpix++) = g; *(rowpix++) = b; } } memset(rowpix, 0, sizeof(ssi->Data) + ssi->Data - rowpix); FreezeStruct(stream, "SHO", ssi, SnapScreenshot, COUNT(SnapScreenshot)); delete ssi; } if (S9xMovieActive()) { uint8 *movie_freeze_buf; uint32 movie_freeze_size; S9xMovieFreeze(&movie_freeze_buf, &movie_freeze_size); if (movie_freeze_buf) { struct SnapshotMovieInfo mi; mi.MovieInputDataSize = movie_freeze_size; FreezeStruct(stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie)); FreezeBlock (stream, "MID", movie_freeze_buf, movie_freeze_size); delete [] movie_freeze_buf; } } S9xSetSoundMute(FALSE); delete [] soundsnapshot; } int S9xUnfreezeFromStream (STREAM stream) { int result = SUCCESS; int version, len; char buffer[PATH_MAX + 1]; len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; if (READ_STREAM(buffer, len, stream) != len) return (WRONG_FORMAT); if (strncmp(buffer, SNAPSHOT_MAGIC, strlen(SNAPSHOT_MAGIC)) != 0) return (WRONG_FORMAT); version = atoi(&buffer[strlen(SNAPSHOT_MAGIC) + 1]); if (version > SNAPSHOT_VERSION) return (WRONG_VERSION); result = UnfreezeBlock(stream, "NAM", (uint8 *) buffer, PATH_MAX); if (result != SUCCESS) return (result); uint8 *local_cpu = NULL; uint8 *local_registers = NULL; uint8 *local_ppu = NULL; uint8 *local_dma = NULL; uint8 *local_vram = NULL; uint8 *local_ram = NULL; uint8 *local_sram = NULL; uint8 *local_fillram = NULL; uint8 *local_apu_sound = NULL; uint8 *local_control_data = NULL; uint8 *local_timing_data = NULL; uint8 *local_superfx = NULL; uint8 *local_sa1 = NULL; uint8 *local_sa1_registers = NULL; uint8 *local_dsp1 = NULL; uint8 *local_dsp2 = NULL; uint8 *local_dsp4 = NULL; uint8 *local_cx4_data = NULL; uint8 *local_st010 = NULL; uint8 *local_obc1 = NULL; uint8 *local_obc1_data = NULL; uint8 *local_spc7110 = NULL; uint8 *local_srtc = NULL; uint8 *local_rtc_data = NULL; uint8 *local_bsx_data = NULL; uint8 *local_screenshot = NULL; uint8 *local_movie_data = NULL; do { result = UnfreezeStructCopy(stream, "CPU", &local_cpu, SnapCPU, COUNT(SnapCPU), version); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "REG", &local_registers, SnapRegisters, COUNT(SnapRegisters), version); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "PPU", &local_ppu, SnapPPU, COUNT(SnapPPU), version); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "DMA", &local_dma, SnapDMA, COUNT(SnapDMA), version); if (result != SUCCESS) break; result = UnfreezeBlockCopy (stream, "VRA", &local_vram, 0x10000); if (result != SUCCESS) break; result = UnfreezeBlockCopy (stream, "RAM", &local_ram, 0x20000); if (result != SUCCESS) break; result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000); if (result != SUCCESS) break; result = UnfreezeBlockCopy (stream, "FIL", &local_fillram, 0x8000); if (result != SUCCESS) break; result = UnfreezeBlockCopy (stream, "SND", &local_apu_sound, SPC_SAVE_STATE_BLOCK_SIZE); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "CTL", &local_control_data, SnapControls, COUNT(SnapControls), version); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "TIM", &local_timing_data, SnapTimings, COUNT(SnapTimings), version); if (result != SUCCESS) break; result = UnfreezeStructCopy(stream, "SFX", &local_superfx, SnapFX, COUNT(SnapFX), version); if (result != SUCCESS && Settings.SuperFX) break; result = UnfreezeStructCopy(stream, "SA1", &local_sa1, SnapSA1, COUNT(SnapSA1), version); if (result != SUCCESS && Settings.SA1) break; result = UnfreezeStructCopy(stream, "SAR", &local_sa1_registers, SnapSA1Registers, COUNT(SnapSA1Registers), version); if (result != SUCCESS && Settings.SA1) break; result = UnfreezeStructCopy(stream, "DP1", &local_dsp1, SnapDSP1, COUNT(SnapDSP1), version); if (result != SUCCESS && Settings.DSP == 1) break; result = UnfreezeStructCopy(stream, "DP2", &local_dsp2, SnapDSP2, COUNT(SnapDSP2), version); if (result != SUCCESS && Settings.DSP == 2) break; result = UnfreezeStructCopy(stream, "DP4", &local_dsp4, SnapDSP4, COUNT(SnapDSP4), version); if (result != SUCCESS && Settings.DSP == 4) break; result = UnfreezeBlockCopy (stream, "CX4", &local_cx4_data, 8192); if (result != SUCCESS && Settings.C4) break; result = UnfreezeStructCopy(stream, "ST0", &local_st010, SnapST010, COUNT(SnapST010), version); if (result != SUCCESS && Settings.SETA == ST_010) break; result = UnfreezeStructCopy(stream, "OBC", &local_obc1, SnapOBC1, COUNT(SnapOBC1), version); if (result != SUCCESS && Settings.OBC1) break; result = UnfreezeBlockCopy (stream, "OBM", &local_obc1_data, 8192); if (result != SUCCESS && Settings.OBC1) break; result = UnfreezeStructCopy(stream, "S71", &local_spc7110, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), version); if (result != SUCCESS && Settings.SPC7110) break; result = UnfreezeStructCopy(stream, "SRT", &local_srtc, SnapSRTCSnap, COUNT(SnapSRTCSnap), version); if (result != SUCCESS && Settings.SRTC) break; result = UnfreezeBlockCopy (stream, "CLK", &local_rtc_data, 20); if (result != SUCCESS && (Settings.SRTC || Settings.SPC7110RTC)) break; result = UnfreezeStructCopy(stream, "BSX", &local_bsx_data, SnapBSX, COUNT(SnapBSX), version); if (result != SUCCESS && Settings.BS) break; result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version); SnapshotMovieInfo mi; result = UnfreezeStruct(stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie), version); if (result != SUCCESS) { if (S9xMovieActive()) { result = NOT_A_MOVIE_SNAPSHOT; break; } } else { result = UnfreezeBlockCopy(stream, "MID", &local_movie_data, mi.MovieInputDataSize); if (result != SUCCESS) { if (S9xMovieActive()) { result = NOT_A_MOVIE_SNAPSHOT; break; } } if (S9xMovieActive()) { result = S9xMovieUnfreeze(local_movie_data, mi.MovieInputDataSize); if (result != SUCCESS) break; } } result = SUCCESS; } while (false); if (result == SUCCESS) { uint32 old_flags = CPU.Flags; uint32 sa1_old_flags = SA1.Flags; S9xSetSoundMute(TRUE); S9xReset(); UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version); UnfreezeStructFromCopy(&Registers, SnapRegisters, COUNT(SnapRegisters), local_registers, version); UnfreezeStructFromCopy(&PPU, SnapPPU, COUNT(SnapPPU), local_ppu, version); struct SDMASnapshot dma_snap; UnfreezeStructFromCopy(&dma_snap, SnapDMA, COUNT(SnapDMA), local_dma, version); memcpy(Memory.VRAM, local_vram, 0x10000); memcpy(Memory.RAM, local_ram, 0x20000); memcpy(Memory.SRAM, local_sram, 0x20000); memcpy(Memory.FillRAM, local_fillram, 0x8000); if(version < SNAPSHOT_VERSION_BAPU) { printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION); S9xAPULoadBlarggState(local_apu_sound); } else S9xAPULoadState(local_apu_sound); struct SControlSnapshot ctl_snap; UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version); UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version); if (local_superfx) { GSU.avRegAddr = (uint8 *) &GSU.avReg; UnfreezeStructFromCopy(&GSU, SnapFX, COUNT(SnapFX), local_superfx, version); } if (local_sa1) UnfreezeStructFromCopy(&SA1, SnapSA1, COUNT(SnapSA1), local_sa1, version); if (local_sa1_registers) UnfreezeStructFromCopy(&SA1Registers, SnapSA1Registers, COUNT(SnapSA1Registers), local_sa1_registers, version); if (local_dsp1) UnfreezeStructFromCopy(&DSP1, SnapDSP1, COUNT(SnapDSP1), local_dsp1, version); if (local_dsp2) UnfreezeStructFromCopy(&DSP2, SnapDSP2, COUNT(SnapDSP2), local_dsp2, version); if (local_dsp4) UnfreezeStructFromCopy(&DSP4, SnapDSP4, COUNT(SnapDSP4), local_dsp4, version); if (local_cx4_data) memcpy(Memory.C4RAM, local_cx4_data, 8192); if (local_st010) UnfreezeStructFromCopy(&ST010, SnapST010, COUNT(SnapST010), local_st010, version); if (local_obc1) UnfreezeStructFromCopy(&OBC1, SnapOBC1, COUNT(SnapOBC1), local_obc1, version); if (local_obc1_data) memcpy(Memory.OBC1RAM, local_obc1_data, 8192); if (local_spc7110) UnfreezeStructFromCopy(&s7snap, SnapSPC7110Snap, COUNT(SnapSPC7110Snap), local_spc7110, version); if (local_srtc) UnfreezeStructFromCopy(&srtcsnap, SnapSRTCSnap, COUNT(SnapSRTCSnap), local_srtc, version); if (local_rtc_data) memcpy(RTCData.reg, local_rtc_data, 20); if (local_bsx_data) UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version); if (version < SNAPSHOT_VERSION_IRQ) { printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION); CPU.NMILine = (CPU.Flags & (1 << 7)) ? TRUE : FALSE; CPU.IRQLine = (CPU.Flags & (1 << 11)) ? TRUE : FALSE; CPU.IRQTransition = FALSE; CPU.IRQLastState = FALSE; CPU.IRQExternal = (Obsolete.CPU_IRQActive & ~(1 << 1)) ? TRUE : FALSE; switch (CPU.WhichEvent) { case 12: case 1: CPU.WhichEvent = 1; break; case 2: case 3: CPU.WhichEvent = 2; break; case 4: case 5: CPU.WhichEvent = 3; break; case 6: case 7: CPU.WhichEvent = 4; break; case 8: case 9: CPU.WhichEvent = 5; break; case 10: case 11: CPU.WhichEvent = 6; break; } if (local_sa1) // FIXME { SA1.Cycles = SA1.PrevCycles = 0; SA1.TimerIRQLastState = FALSE; SA1.HTimerIRQPos = Memory.FillRAM[0x2212] | (Memory.FillRAM[0x2213] << 8); SA1.VTimerIRQPos = Memory.FillRAM[0x2214] | (Memory.FillRAM[0x2215] << 8); SA1.HCounter = 0; SA1.VCounter = 0; SA1.PrevHCounter = 0; SA1.MemSpeed = SLOW_ONE_CYCLE; SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2; } } CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase(Registers.PBPC); S9xUnpackStatus(); S9xFixCycles(); for (int d = 0; d < 8; d++) DMA[d] = dma_snap.dma[d]; CPU.InDMA = CPU.InHDMA = FALSE; CPU.InDMAorHDMA = CPU.InWRAMDMAorHDMA = FALSE; CPU.HDMARanInDMA = 0; S9xFixColourBrightness(); IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; IPPU.RenderThisFrame = TRUE; uint8 hdma_byte = Memory.FillRAM[0x420c]; S9xSetCPU(hdma_byte, 0x420c); S9xControlPostLoadState(&ctl_snap); if (local_superfx) { GSU.pfPlot = fx_PlotTable[GSU.vMode]; GSU.pfRpix = fx_PlotTable[GSU.vMode + 5]; } if (local_sa1 && local_sa1_registers) { SA1.Flags |= sa1_old_flags & TRACE_FLAG; S9xSA1PostLoadState(); } if (Settings.SDD1) S9xSDD1PostLoadState(); if (local_spc7110) S9xSPC7110PostLoadState(version); if (local_srtc) S9xSRTCPostLoadState(version); if (local_bsx_data) S9xBSXPostLoadState(); if (local_movie_data) { // restore last displayed pad_read status extern bool8 pad_read, pad_read_last; bool8 pad_read_temp = pad_read; pad_read = pad_read_last; S9xUpdateFrameCounter(-1); pad_read = pad_read_temp; } if (local_screenshot) { SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version); IPPU.RenderedScreenWidth = min(ssi->Width, IMAGE_WIDTH); IPPU.RenderedScreenHeight = min(ssi->Height, IMAGE_HEIGHT); const bool8 scaleDownX = IPPU.RenderedScreenWidth < ssi->Width; const bool8 scaleDownY = IPPU.RenderedScreenHeight < ssi->Height && ssi->Height > SNES_HEIGHT_EXTENDED; GFX.DoInterlace = Settings.SupportHiRes ? ssi->Interlaced : 0; uint8 *rowpix = ssi->Data; uint16 *screen = GFX.Screen; for (int y = 0; y < IPPU.RenderedScreenHeight; y++, screen += GFX.RealPPL) { for (int x = 0; x < IPPU.RenderedScreenWidth; x++) { uint32 r, g, b; r = *(rowpix++); g = *(rowpix++); b = *(rowpix++); if (scaleDownX) { r = (r + *(rowpix++)) >> 1; g = (g + *(rowpix++)) >> 1; b = (b + *(rowpix++)) >> 1; if (x + x + 1 >= ssi->Width) break; } screen[x] = BUILD_PIXEL(r, g, b); } if (scaleDownY) { rowpix += 3 * ssi->Width; if (y + y + 1 >= ssi->Height) break; } } // black out what we might have missed for (uint32 y = IPPU.RenderedScreenHeight; y < (uint32) (IMAGE_HEIGHT); y++) memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2); delete ssi; } else { // couldn't load graphics, so black out the screen instead for (uint32 y = 0; y < (uint32) (IMAGE_HEIGHT); y++) memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2); } S9xSetSoundMute(FALSE); } if (local_cpu) delete [] local_cpu; if (local_registers) delete [] local_registers; if (local_ppu) delete [] local_ppu; if (local_dma) delete [] local_dma; if (local_vram) delete [] local_vram; if (local_ram) delete [] local_ram; if (local_sram) delete [] local_sram; if (local_fillram) delete [] local_fillram; if (local_apu_sound) delete [] local_apu_sound; if (local_control_data) delete [] local_control_data; if (local_timing_data) delete [] local_timing_data; if (local_superfx) delete [] local_superfx; if (local_sa1) delete [] local_sa1; if (local_sa1_registers) delete [] local_sa1_registers; if (local_dsp1) delete [] local_dsp1; if (local_dsp2) delete [] local_dsp2; if (local_dsp4) delete [] local_dsp4; if (local_cx4_data) delete [] local_cx4_data; if (local_st010) delete [] local_st010; if (local_obc1) delete [] local_obc1; if (local_obc1_data) delete [] local_obc1_data; if (local_spc7110) delete [] local_spc7110; if (local_srtc) delete [] local_srtc; if (local_rtc_data) delete [] local_rtc_data; if (local_bsx_data) delete [] local_bsx_data; if (local_screenshot) delete [] local_screenshot; if (local_movie_data) delete [] local_movie_data; return (result); } static int FreezeSize (int size, int type) { switch (type) { case uint32_ARRAY_V: case uint32_INDIR_ARRAY_V: return (size * 4); case uint16_ARRAY_V: case uint16_INDIR_ARRAY_V: return (size * 2); default: return (size); } } static void FreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields, int num_fields) { int len = 0; int i, j; for (i = 0; i < num_fields; i++) { if (SNAPSHOT_VERSION < fields[i].debuted_in) { fprintf(stderr, "%s[%p]: field has bad debuted_in value %d, > %d.", name, (void *) fields, fields[i].debuted_in, SNAPSHOT_VERSION); continue; } if (SNAPSHOT_VERSION < fields[i].deleted_in) len += FreezeSize(fields[i].size, fields[i].type); } uint8 *block = new uint8[len]; uint8 *ptr = block; uint8 *addr; uint16 word; uint32 dword; int64 qaword; int relativeAddr; for (i = 0; i < num_fields; i++) { if (SNAPSHOT_VERSION >= fields[i].deleted_in || SNAPSHOT_VERSION < fields[i].debuted_in) continue; addr = (uint8 *) base + fields[i].offset; // determine real address of indirect-type fields // (where the structure contains a pointer to an array rather than the array itself) if (fields[i].type == uint8_INDIR_ARRAY_V || fields[i].type == uint16_INDIR_ARRAY_V || fields[i].type == uint32_INDIR_ARRAY_V) addr = (uint8 *) (*((pint *) addr)); // convert pointer-type saves from absolute to relative pointers if (fields[i].type == POINTER_V) { uint8 *pointer = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset)); uint8 *relativeTo = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset2)); relativeAddr = pointer - relativeTo; addr = (uint8 *) &relativeAddr; } switch (fields[i].type) { case INT_V: case POINTER_V: switch (fields[i].size) { case 1: *ptr++ = *(addr); break; case 2: word = *((uint16 *) (addr)); *ptr++ = (uint8) (word >> 8); *ptr++ = (uint8) word; break; case 4: dword = *((uint32 *) (addr)); *ptr++ = (uint8) (dword >> 24); *ptr++ = (uint8) (dword >> 16); *ptr++ = (uint8) (dword >> 8); *ptr++ = (uint8) dword; break; case 8: qaword = *((int64 *) (addr)); *ptr++ = (uint8) (qaword >> 56); *ptr++ = (uint8) (qaword >> 48); *ptr++ = (uint8) (qaword >> 40); *ptr++ = (uint8) (qaword >> 32); *ptr++ = (uint8) (qaword >> 24); *ptr++ = (uint8) (qaword >> 16); *ptr++ = (uint8) (qaword >> 8); *ptr++ = (uint8) qaword; break; } break; case uint8_ARRAY_V: case uint8_INDIR_ARRAY_V: memmove(ptr, addr, fields[i].size); ptr += fields[i].size; break; case uint16_ARRAY_V: case uint16_INDIR_ARRAY_V: for (j = 0; j < fields[i].size; j++) { word = *((uint16 *) (addr + j * 2)); *ptr++ = (uint8) (word >> 8); *ptr++ = (uint8) word; } break; case uint32_ARRAY_V: case uint32_INDIR_ARRAY_V: for (j = 0; j < fields[i].size; j++) { dword = *((uint32 *) (addr + j * 4)); *ptr++ = (uint8) (dword >> 24); *ptr++ = (uint8) (dword >> 16); *ptr++ = (uint8) (dword >> 8); *ptr++ = (uint8) dword; } break; } } FreezeBlock(stream, name, block, len); delete [] block; } static void FreezeBlock (STREAM stream, const char *name, uint8 *block, int size) { char buffer[20]; // check if it fits in 6 digits. (letting it go over and using strlen isn't safe) if (size <= 999999) sprintf(buffer, "%s:%06d:", name, size); else { // to make it fit, pack it in the bytes instead of as digits sprintf(buffer, "%s:------:", name); buffer[6] = (unsigned char) ((unsigned) size >> 24); buffer[7] = (unsigned char) ((unsigned) size >> 16); buffer[8] = (unsigned char) ((unsigned) size >> 8); buffer[9] = (unsigned char) ((unsigned) size >> 0); } buffer[11] = 0; WRITE_STREAM(buffer, 11, stream); WRITE_STREAM(block, size, stream); } static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int size) { char buffer[20]; int len = 0, rem = 0; long rewind = FIND_STREAM(stream); size_t l = READ_STREAM(buffer, 11, stream); buffer[l] = 0; if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':') { err: #ifdef DEBUGGER fprintf(stdout, "absent: %s(%d); next: '%.11s'\n", name, size, buffer); #endif REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0); return (WRONG_FORMAT); } if (buffer[4] == '-') { len = (((unsigned char) buffer[6]) << 24) | (((unsigned char) buffer[7]) << 16) | (((unsigned char) buffer[8]) << 8) | (((unsigned char) buffer[9]) << 0); } else len = atoi(buffer + 4); if (len <= 0) goto err; if (len > size) { rem = len - size; len = size; } memset(block, 0, size); if (READ_STREAM(block, len, stream) != len) { REVERT_STREAM(stream, rewind, 0); return (WRONG_FORMAT); } if (rem) { char *junk = new char[rem]; len = READ_STREAM(junk, rem, stream); delete [] junk; if (len != rem) { REVERT_STREAM(stream, rewind, 0); return (WRONG_FORMAT); } } return (SUCCESS); } static int UnfreezeBlockCopy (STREAM stream, const char *name, uint8 **block, int size) { int result; *block = new uint8[size]; result = UnfreezeBlock(stream, name, *block, size); if (result != SUCCESS) { delete [] (*block); *block = NULL; return (result); } return (SUCCESS); } static int UnfreezeStruct (STREAM stream, const char *name, void *base, FreezeData *fields, int num_fields, int version) { int result; uint8 *block = NULL; result = UnfreezeStructCopy(stream, name, &block, fields, num_fields, version); if (result != SUCCESS) { if (block != NULL) delete [] block; return (result); } UnfreezeStructFromCopy(base, fields, num_fields, block, version); delete [] block; return (SUCCESS); } static int UnfreezeStructCopy (STREAM stream, const char *name, uint8 **block, FreezeData *fields, int num_fields, int version) { int len = 0; for (int i = 0; i < num_fields; i++) { if (version >= fields[i].debuted_in && version < fields[i].deleted_in) len += FreezeSize(fields[i].size, fields[i].type); } return (UnfreezeBlockCopy(stream, name, block, len)); } static void UnfreezeStructFromCopy (void *sbase, FreezeData *fields, int num_fields, uint8 *block, int version) { uint8 *ptr = block; uint16 word; uint32 dword; int64 qaword; uint8 *addr; void *base; int relativeAddr; int i, j; for (i = 0; i < num_fields; i++) { if (version < fields[i].debuted_in || version >= fields[i].deleted_in) continue; base = (SNAPSHOT_VERSION >= fields[i].deleted_in) ? ((void *) &Obsolete) : sbase; addr = (uint8 *) base + fields[i].offset; if (fields[i].type == uint8_INDIR_ARRAY_V || fields[i].type == uint16_INDIR_ARRAY_V || fields[i].type == uint32_INDIR_ARRAY_V) addr = (uint8 *) (*((pint *) addr)); switch (fields[i].type) { case INT_V: case POINTER_V: switch (fields[i].size) { case 1: if (fields[i].offset < 0) { ptr++; break; } *(addr) = *ptr++; break; case 2: if (fields[i].offset < 0) { ptr += 2; break; } word = *ptr++ << 8; word |= *ptr++; *((uint16 *) (addr)) = word; break; case 4: if (fields[i].offset < 0) { ptr += 4; break; } dword = *ptr++ << 24; dword |= *ptr++ << 16; dword |= *ptr++ << 8; dword |= *ptr++; *((uint32 *) (addr)) = dword; break; case 8: if (fields[i].offset < 0) { ptr += 8; break; } qaword = (int64) *ptr++ << 56; qaword |= (int64) *ptr++ << 48; qaword |= (int64) *ptr++ << 40; qaword |= (int64) *ptr++ << 32; qaword |= (int64) *ptr++ << 24; qaword |= (int64) *ptr++ << 16; qaword |= (int64) *ptr++ << 8; qaword |= (int64) *ptr++; *((int64 *) (addr)) = qaword; break; default: assert(0); break; } break; case uint8_ARRAY_V: case uint8_INDIR_ARRAY_V: if (fields[i].offset >= 0) memmove(addr, ptr, fields[i].size); ptr += fields[i].size; break; case uint16_ARRAY_V: case uint16_INDIR_ARRAY_V: if (fields[i].offset < 0) { ptr += fields[i].size * 2; break; } for (j = 0; j < fields[i].size; j++) { word = *ptr++ << 8; word |= *ptr++; *((uint16 *) (addr + j * 2)) = word; } break; case uint32_ARRAY_V: case uint32_INDIR_ARRAY_V: if (fields[i].offset < 0) { ptr += fields[i].size * 4; break; } for (j = 0; j < fields[i].size; j++) { dword = *ptr++ << 24; dword |= *ptr++ << 16; dword |= *ptr++ << 8; dword |= *ptr++; *((uint32 *) (addr + j * 4)) = dword; } break; } if (fields[i].type == POINTER_V) { relativeAddr = (int) *((pint *) ((uint8 *) base + fields[i].offset)); uint8 *relativeTo = (uint8 *) *((pint *) ((uint8 *) base + fields[i].offset2)); *((pint *) (addr)) = (pint) (relativeTo + relativeAddr); } } } getset.h000664 001750 001750 00000065600 12720446475 013370 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _GETSET_H_ #define _GETSET_H_ #include "cpuexec.h" #include "dsp.h" #include "sa1.h" #include "spc7110.h" #include "c4.h" #include "obc1.h" #include "seta.h" #include "bsx.h" #define addCyclesInMemoryAccess \ if (!CPU.InDMAorHDMA) \ { \ CPU.PrevCycles = CPU.Cycles; \ CPU.Cycles += speed; \ S9xCheckInterrupts(); \ while (CPU.Cycles >= CPU.NextEvent) \ S9xDoHEventProcessing(); \ } #define addCyclesInMemoryAccess_x2 \ if (!CPU.InDMAorHDMA) \ { \ CPU.PrevCycles = CPU.Cycles; \ CPU.Cycles += speed << 1; \ S9xCheckInterrupts(); \ while (CPU.Cycles >= CPU.NextEvent) \ S9xDoHEventProcessing(); \ } extern uint8 OpenBus; static inline int32 memory_speed (uint32 address) { if (address & 0x408000) { if (address & 0x800000) return (CPU.FastROMSpeed); return (SLOW_ONE_CYCLE); } if ((address + 0x6000) & 0x4000) return (SLOW_ONE_CYCLE); if ((address - 0x4000) & 0x7e00) return (ONE_CYCLE); return (TWO_CYCLES); } inline uint8 S9xGetByte (uint32 Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *GetAddress = Memory.Map[block]; int32 speed = memory_speed(Address); uint8 byte; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { byte = *(GetAddress + (Address & 0xffff)); addCyclesInMemoryAccess; return (byte); } switch ((pint) GetAddress) { case CMemory::MAP_CPU: byte = S9xGetCPU(Address & 0xffff); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_PPU: if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) return (OpenBus); byte = S9xGetPPU(Address & 0xffff); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: // Address & 0x7fff : offset into bank // Address & 0xff0000 : bank // bank >> 1 | offset : SRAM address, unbound // unbound & SRAMMask : SRAM offset byte = *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_LOROM_SRAM_B: byte = *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_HIROM_SRAM: case CMemory::MAP_RONLY_SRAM: byte = *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_BWRAM: byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_DSP: byte = S9xGetDSP(Address & 0xffff); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_SPC7110_ROM: byte = S9xGetSPC7110Byte(Address); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_SPC7110_DRAM: byte = S9xGetSPC7110(0x4800); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_C4: byte = S9xGetC4(Address & 0xffff); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_OBC_RAM: byte = S9xGetOBC1(Address & 0xffff); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_SETA_DSP: byte = S9xGetSetaDSP(Address); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_SETA_RISC: byte = S9xGetST018(Address); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_BSX: byte = S9xGetBSX(Address); addCyclesInMemoryAccess; return (byte); case CMemory::MAP_NONE: default: byte = OpenBus; addCyclesInMemoryAccess; return (byte); } } inline uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w = WRAP_NONE) { uint32 mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); if ((Address & mask) == mask) { PC_t a; OpenBus = S9xGetByte(Address); switch (w) { case WRAP_PAGE: a.xPBPC = Address; a.B.xPCl++; return (OpenBus | (S9xGetByte(a.xPBPC) << 8)); case WRAP_BANK: a.xPBPC = Address; a.W.xPC++; return (OpenBus | (S9xGetByte(a.xPBPC) << 8)); case WRAP_NONE: default: return (OpenBus | (S9xGetByte(Address + 1) << 8)); } } int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *GetAddress = Memory.Map[block]; int32 speed = memory_speed(Address); uint16 word; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { word = READ_WORD(GetAddress + (Address & 0xffff)); addCyclesInMemoryAccess_x2; return (word); } switch ((pint) GetAddress) { case CMemory::MAP_CPU: word = S9xGetCPU(Address & 0xffff); addCyclesInMemoryAccess; word |= S9xGetCPU((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_PPU: if (CPU.InDMAorHDMA) { OpenBus = S9xGetByte(Address); return (OpenBus | (S9xGetByte(Address + 1) << 8)); } word = S9xGetPPU(Address & 0xffff); addCyclesInMemoryAccess; word |= S9xGetPPU((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: if (Memory.SRAMMask >= MEMMAP_MASK) word = READ_WORD(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)); else word = (*(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask))) | ((*(Memory.SRAM + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask))) << 8); addCyclesInMemoryAccess_x2; return (word); case CMemory::MAP_LOROM_SRAM_B: if (Multi.sramMaskB >= MEMMAP_MASK) word = READ_WORD(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)); else word = (*(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB))) | ((*(Multi.sramB + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Multi.sramMaskB))) << 8); addCyclesInMemoryAccess_x2; return (word); case CMemory::MAP_HIROM_SRAM: case CMemory::MAP_RONLY_SRAM: if (Memory.SRAMMask >= MEMMAP_MASK) word = READ_WORD(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); else word = (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) | (*(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask)) << 8)); addCyclesInMemoryAccess_x2; return (word); case CMemory::MAP_BWRAM: word = READ_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); addCyclesInMemoryAccess_x2; return (word); case CMemory::MAP_DSP: word = S9xGetDSP(Address & 0xffff); addCyclesInMemoryAccess; word |= S9xGetDSP((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_SPC7110_ROM: word = S9xGetSPC7110Byte(Address); addCyclesInMemoryAccess; word |= S9xGetSPC7110Byte(Address + 1) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_SPC7110_DRAM: word = S9xGetSPC7110(0x4800); addCyclesInMemoryAccess; word |= S9xGetSPC7110(0x4800) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_C4: word = S9xGetC4(Address & 0xffff); addCyclesInMemoryAccess; word |= S9xGetC4((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_OBC_RAM: word = S9xGetOBC1(Address & 0xffff); addCyclesInMemoryAccess; word |= S9xGetOBC1((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_SETA_DSP: word = S9xGetSetaDSP(Address); addCyclesInMemoryAccess; word |= S9xGetSetaDSP(Address + 1) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_SETA_RISC: word = S9xGetST018(Address); addCyclesInMemoryAccess; word |= S9xGetST018(Address + 1) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_BSX: word = S9xGetBSX(Address); addCyclesInMemoryAccess; word |= S9xGetBSX(Address + 1) << 8; addCyclesInMemoryAccess; return (word); case CMemory::MAP_NONE: default: word = OpenBus | (OpenBus << 8); addCyclesInMemoryAccess_x2; return (word); } } inline void S9xSetByte (uint8 Byte, uint32 Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *SetAddress = Memory.WriteMap[block]; int32 speed = memory_speed(Address); if (SetAddress >= (uint8 *) CMemory::MAP_LAST) { *(SetAddress + (Address & 0xffff)) = Byte; addCyclesInMemoryAccess; return; } switch ((pint) SetAddress) { case CMemory::MAP_CPU: S9xSetCPU(Byte, Address & 0xffff); addCyclesInMemoryAccess; return; case CMemory::MAP_PPU: if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) return; S9xSetPPU(Byte, Address & 0xffff); addCyclesInMemoryAccess; return; case CMemory::MAP_LOROM_SRAM: if (Memory.SRAMMask) { *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = Byte; CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess; return; case CMemory::MAP_LOROM_SRAM_B: if (Multi.sramMaskB) { *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = Byte; CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess; return; case CMemory::MAP_HIROM_SRAM: if (Memory.SRAMMask) { *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = Byte; CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess; return; case CMemory::MAP_BWRAM: *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte; CPU.SRAMModified = TRUE; addCyclesInMemoryAccess; return; case CMemory::MAP_SA1RAM: *(Memory.SRAM + (Address & 0xffff)) = Byte; addCyclesInMemoryAccess; return; case CMemory::MAP_DSP: S9xSetDSP(Byte, Address & 0xffff); addCyclesInMemoryAccess; return; case CMemory::MAP_C4: S9xSetC4(Byte, Address & 0xffff); addCyclesInMemoryAccess; return; case CMemory::MAP_OBC_RAM: S9xSetOBC1(Byte, Address & 0xffff); addCyclesInMemoryAccess; return; case CMemory::MAP_SETA_DSP: S9xSetSetaDSP(Byte, Address); addCyclesInMemoryAccess; return; case CMemory::MAP_SETA_RISC: S9xSetST018(Byte, Address); addCyclesInMemoryAccess; return; case CMemory::MAP_BSX: S9xSetBSX(Byte, Address); addCyclesInMemoryAccess; return; case CMemory::MAP_NONE: default: addCyclesInMemoryAccess; return; } } inline void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w = WRAP_NONE, enum s9xwriteorder_t o = WRITE_01) { uint32 mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); if ((Address & mask) == mask) { PC_t a; if (!o) S9xSetByte((uint8) Word, Address); switch (w) { case WRAP_PAGE: a.xPBPC = Address; a.B.xPCl++; S9xSetByte(Word >> 8, a.xPBPC); break; case WRAP_BANK: a.xPBPC = Address; a.W.xPC++; S9xSetByte(Word >> 8, a.xPBPC); break; case WRAP_NONE: default: S9xSetByte(Word >> 8, Address + 1); break; } if (o) S9xSetByte((uint8) Word, Address); return; } int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *SetAddress = Memory.WriteMap[block]; int32 speed = memory_speed(Address); if (SetAddress >= (uint8 *) CMemory::MAP_LAST) { WRITE_WORD(SetAddress + (Address & 0xffff), Word); addCyclesInMemoryAccess_x2; return; } switch ((pint) SetAddress) { case CMemory::MAP_CPU: if (o) { S9xSetCPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; S9xSetCPU((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; return; } else { S9xSetCPU((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; S9xSetCPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; return; } case CMemory::MAP_PPU: if (CPU.InDMAorHDMA) { if ((Address & 0xff00) != 0x2100) S9xSetPPU((uint8) Word, Address & 0xffff); if (((Address + 1) & 0xff00) != 0x2100) S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); return; } if (o) { S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; S9xSetPPU((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; return; } else { S9xSetPPU((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; return; } case CMemory::MAP_LOROM_SRAM: if (Memory.SRAMMask) { if (Memory.SRAMMask >= MEMMAP_MASK) WRITE_WORD(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask), Word); else { *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = (uint8) Word; *(Memory.SRAM + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask)) = Word >> 8; } CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess_x2; return; case CMemory::MAP_LOROM_SRAM_B: if (Multi.sramMaskB) { if (Multi.sramMaskB >= MEMMAP_MASK) WRITE_WORD(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB), Word); else { *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = (uint8) Word; *(Multi.sramB + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Multi.sramMaskB)) = Word >> 8; } CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess_x2; return; case CMemory::MAP_HIROM_SRAM: if (Memory.SRAMMask) { if (Memory.SRAMMask >= MEMMAP_MASK) WRITE_WORD(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask), Word); else { *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = (uint8) Word; *(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask)) = Word >> 8; } CPU.SRAMModified = TRUE; } addCyclesInMemoryAccess_x2; return; case CMemory::MAP_BWRAM: WRITE_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000), Word); CPU.SRAMModified = TRUE; addCyclesInMemoryAccess_x2; return; case CMemory::MAP_SA1RAM: WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word); addCyclesInMemoryAccess_x2; return; case CMemory::MAP_DSP: if (o) { S9xSetDSP(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; S9xSetDSP((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; return; } else { S9xSetDSP((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; S9xSetDSP(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; return; } case CMemory::MAP_C4: if (o) { S9xSetC4(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; S9xSetC4((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; return; } else { S9xSetC4((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; S9xSetC4(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; return; } case CMemory::MAP_OBC_RAM: if (o) { S9xSetOBC1(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; S9xSetOBC1((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; return; } else { S9xSetOBC1((uint8) Word, Address & 0xffff); addCyclesInMemoryAccess; S9xSetOBC1(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess; return; } case CMemory::MAP_SETA_DSP: if (o) { S9xSetSetaDSP(Word >> 8, Address + 1); addCyclesInMemoryAccess; S9xSetSetaDSP((uint8) Word, Address); addCyclesInMemoryAccess; return; } else { S9xSetSetaDSP((uint8) Word, Address); addCyclesInMemoryAccess; S9xSetSetaDSP(Word >> 8, Address + 1); addCyclesInMemoryAccess; return; } case CMemory::MAP_SETA_RISC: if (o) { S9xSetST018(Word >> 8, Address + 1); addCyclesInMemoryAccess; S9xSetST018((uint8) Word, Address); addCyclesInMemoryAccess; return; } else { S9xSetST018((uint8) Word, Address); addCyclesInMemoryAccess; S9xSetST018(Word >> 8, Address + 1); addCyclesInMemoryAccess; return; } case CMemory::MAP_BSX: if (o) { S9xSetBSX(Word >> 8, Address + 1); addCyclesInMemoryAccess; S9xSetBSX((uint8) Word, Address); addCyclesInMemoryAccess; return; } else { S9xSetBSX((uint8) Word, Address); addCyclesInMemoryAccess; S9xSetBSX(Word >> 8, Address + 1); addCyclesInMemoryAccess; return; } case CMemory::MAP_NONE: default: addCyclesInMemoryAccess_x2; return; } } inline void S9xSetPCBase (uint32 Address) { Registers.PBPC = Address & 0xffffff; ICPU.ShiftedPB = Address & 0xff0000; int block; uint8 *GetAddress = Memory.Map[block = ((Address & 0xffffff) >> MEMMAP_SHIFT)]; CPU.MemSpeed = memory_speed(Address); CPU.MemSpeedx2 = CPU.MemSpeed << 1; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { CPU.PCBase = GetAddress; return; } switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) CPU.PCBase = NULL; else CPU.PCBase = Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff); return; case CMemory::MAP_LOROM_SRAM_B: if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK) CPU.PCBase = NULL; else CPU.PCBase = Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB) - (Address & 0xffff); return; case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) CPU.PCBase = NULL; else CPU.PCBase = Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff); return; case CMemory::MAP_BWRAM: CPU.PCBase = Memory.BWRAM - 0x6000 - (Address & 0x8000); return; case CMemory::MAP_SA1RAM: CPU.PCBase = Memory.SRAM; return; case CMemory::MAP_SPC7110_ROM: CPU.PCBase = S9xGetBasePointerSPC7110(Address); return; case CMemory::MAP_C4: CPU.PCBase = S9xGetBasePointerC4(Address & 0xffff); return; case CMemory::MAP_OBC_RAM: CPU.PCBase = S9xGetBasePointerOBC1(Address & 0xffff); return; case CMemory::MAP_BSX: CPU.PCBase = S9xGetBasePointerBSX(Address); return; case CMemory::MAP_NONE: default: CPU.PCBase = NULL; return; } } inline uint8 * S9xGetBasePointer (uint32 Address) { uint8 *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) return (GetAddress); switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff)); case CMemory::MAP_LOROM_SRAM_B: if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB) - (Address & 0xffff)); case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff)); case CMemory::MAP_BWRAM: return (Memory.BWRAM - 0x6000 - (Address & 0x8000)); case CMemory::MAP_SA1RAM: return (Memory.SRAM); case CMemory::MAP_SPC7110_ROM: return (S9xGetBasePointerSPC7110(Address)); case CMemory::MAP_C4: return (S9xGetBasePointerC4(Address & 0xffff)); case CMemory::MAP_OBC_RAM: return (S9xGetBasePointerOBC1(Address & 0xffff)); case CMemory::MAP_NONE: default: return (NULL); } } inline uint8 * S9xGetMemPointer (uint32 Address) { uint8 *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) return (GetAddress + (Address & 0xffff)); switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)); case CMemory::MAP_LOROM_SRAM_B: if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)); case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return (NULL); return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); case CMemory::MAP_BWRAM: return (Memory.BWRAM - 0x6000 + (Address & 0x7fff)); case CMemory::MAP_SA1RAM: return (Memory.SRAM + (Address & 0xffff)); case CMemory::MAP_SPC7110_ROM: return (S9xGetBasePointerSPC7110(Address) + (Address & 0xffff)); case CMemory::MAP_C4: return (S9xGetMemPointerC4(Address & 0xffff)); case CMemory::MAP_OBC_RAM: return (S9xGetMemPointerOBC1(Address & 0xffff)); case CMemory::MAP_NONE: default: return (NULL); } } #endif libretro/jni/Android.mk000664 001750 001750 00000001050 12720446475 016224 0ustar00sergiosergio000000 000000 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -DANDROID_ARM LOCAL_ARM_MODE := arm endif ifeq ($(TARGET_ARCH),x86) LOCAL_CFLAGS += -DANDROID_X86 endif ifeq ($(TARGET_ARCH),mips) LOCAL_CFLAGS += -DANDROID_MIPS endif CORE_DIR := ../.. LOCAL_MODULE := libretro include ../Makefile.common LOCAL_SRC_FILES = $(SOURCES_CXX) LOCAL_CXXFLAGS = -DANDROID -D__LIBRETRO__ -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR $(INCFLAGS) LOCAL_C_INCLUDES = $(INCFLAGS) include $(BUILD_SHARED_LIBRARY) libretro/msvc/msvc-2010/libretro.def000664 001750 001750 00000001011 12720446475 020332 0ustar00sergiosergio000000 000000 LIBRARY "msvc-2010" EXPORTS retro_set_environment retro_set_video_refresh retro_set_audio_sample retro_set_audio_sample_batch retro_set_input_poll retro_set_input_state retro_init retro_deinit retro_api_version retro_get_system_info retro_get_system_av_info retro_set_controller_port_device retro_reset retro_run retro_serialize_size retro_serialize retro_unserialize retro_cheat_reset retro_cheat_set retro_load_game retro_load_game_special retro_unload_game retro_get_region retro_get_memory_data retro_get_memory_size spc7110emu.cpp000664 001750 001750 00000042276 12720446475 014241 0ustar00sergiosergio000000 000000 /***** * SPC7110 emulator - version 0.03 (2008-08-10) * Copyright (c) 2008, byuu and neviksti * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * The software is provided "as is" and the author disclaims all warranties * with regard to this software including all implied warranties of * merchantibility and fitness, in no event shall the author be liable for * any special, direct, indirect, or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an * action of contract, negligence or other tortious action, arising out of * or in connection with the use or performance of this software. *****/ #define _SPC7110EMU_CPP_ #include "spc7110dec.cpp" const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; void SPC7110::power() { reset(); } void SPC7110::reset() { r4801 = 0x00; r4802 = 0x00; r4803 = 0x00; r4804 = 0x00; r4805 = 0x00; r4806 = 0x00; r4807 = 0x00; r4808 = 0x00; r4809 = 0x00; r480a = 0x00; r480b = 0x00; r480c = 0x00; decomp.reset(); r4811 = 0x00; r4812 = 0x00; r4813 = 0x00; r4814 = 0x00; r4815 = 0x00; r4816 = 0x00; r4817 = 0x00; r4818 = 0x00; r481x = 0x00; r4814_latch = false; r4815_latch = false; r4820 = 0x00; r4821 = 0x00; r4822 = 0x00; r4823 = 0x00; r4824 = 0x00; r4825 = 0x00; r4826 = 0x00; r4827 = 0x00; r4828 = 0x00; r4829 = 0x00; r482a = 0x00; r482b = 0x00; r482c = 0x00; r482d = 0x00; r482e = 0x00; r482f = 0x00; r4830 = 0x00; mmio_write(0x4831, 0); mmio_write(0x4832, 1); mmio_write(0x4833, 2); r4834 = 0x00; r4840 = 0x00; r4841 = 0x00; r4842 = 0x00; if(cartridge_info_spc7110rtc) { rtc_state = RTCS_Inactive; rtc_mode = RTCM_Linear; rtc_index = 0; } } unsigned SPC7110::datarom_addr(unsigned addr) { unsigned size = memory_cartrom_size() - 0x100000; while(addr >= size) addr -= size; return addr + 0x100000; } unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); } unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); } unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); } void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; } void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; } void SPC7110::update_time(int offset) { time_t rtc_time = (memory_cartrtc_read(16) << 0) | (memory_cartrtc_read(17) << 8) | (memory_cartrtc_read(18) << 16) | (memory_cartrtc_read(19) << 24); time_t current_time = time(0) - offset; //sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic. //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow //memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if //time_t overflows. calculation should be valid regardless of number representation, time_t size, //or whether time_t is signed or unsigned. time_t diff = (current_time >= rtc_time) ? (current_time - rtc_time) : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow bool update = true; if(memory_cartrtc_read(13) & 1) update = false; //do not update if CR0 timer disable flag is set if(memory_cartrtc_read(15) & 3) update = false; //do not update if CR2 timer disable flags are set if(diff > 0 && update == true) { unsigned second = memory_cartrtc_read( 0) + memory_cartrtc_read( 1) * 10; unsigned minute = memory_cartrtc_read( 2) + memory_cartrtc_read( 3) * 10; unsigned hour = memory_cartrtc_read( 4) + memory_cartrtc_read( 5) * 10; unsigned day = memory_cartrtc_read( 6) + memory_cartrtc_read( 7) * 10; unsigned month = memory_cartrtc_read( 8) + memory_cartrtc_read( 9) * 10; unsigned year = memory_cartrtc_read(10) + memory_cartrtc_read(11) * 10; unsigned weekday = memory_cartrtc_read(12); day--; month--; year += (year >= 90) ? 1900 : 2000; //range = 1990-2089 second += diff; while(second >= 60) { second -= 60; minute++; if(minute < 60) continue; minute = 0; hour++; if(hour < 24) continue; hour = 0; day++; weekday = (weekday + 1) % 7; unsigned days = months[month % 12]; if(days == 28) { bool leapyear = false; if((year % 4) == 0) { leapyear = true; if((year % 100) == 0 && (year % 400) != 0) leapyear = false; } if(leapyear) days++; } if(day < days) continue; day = 0; month++; if(month < 12) continue; month = 0; year++; } day++; month++; year %= 100; memory_cartrtc_write( 0, second % 10); memory_cartrtc_write( 1, second / 10); memory_cartrtc_write( 2, minute % 10); memory_cartrtc_write( 3, minute / 10); memory_cartrtc_write( 4, hour % 10); memory_cartrtc_write( 5, hour / 10); memory_cartrtc_write( 6, day % 10); memory_cartrtc_write( 7, day / 10); memory_cartrtc_write( 8, month % 10); memory_cartrtc_write( 9, month / 10); memory_cartrtc_write(10, year % 10); memory_cartrtc_write(11, (year / 10) % 10); memory_cartrtc_write(12, weekday % 7); } memory_cartrtc_write(16, current_time >> 0); memory_cartrtc_write(17, current_time >> 8); memory_cartrtc_write(18, current_time >> 16); memory_cartrtc_write(19, current_time >> 24); } uint8 SPC7110::mmio_read(unsigned addr) { addr &= 0xffff; switch(addr) { //================== //decompression unit //================== case 0x4800: { uint16 counter = (r4809 + (r480a << 8)); counter--; r4809 = counter; r480a = counter >> 8; return decomp.read(); } case 0x4801: return r4801; case 0x4802: return r4802; case 0x4803: return r4803; case 0x4804: return r4804; case 0x4805: return r4805; case 0x4806: return r4806; case 0x4807: return r4807; case 0x4808: return r4808; case 0x4809: return r4809; case 0x480a: return r480a; case 0x480b: return r480b; case 0x480c: { uint8 status = r480c; r480c &= 0x7f; return status; } //============== //data port unit //============== case 0x4810: { if(r481x != 0x07) return 0x00; unsigned addr = data_pointer(); unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend unsigned adjustaddr = addr; if(r4818 & 2) { adjustaddr += adjust; set_data_adjust(adjust + 1); } uint8 data = memory_cartrom_read(datarom_addr(adjustaddr)); if(!(r4818 & 2)) { unsigned increment = (r4818 & 1) ? data_increment() : 1; if(r4818 & 4) increment = (int16)increment; //16-bit sign extend if((r4818 & 16) == 0) { set_data_pointer(addr + increment); } else { set_data_adjust(adjust + increment); } } return data; } case 0x4811: return r4811; case 0x4812: return r4812; case 0x4813: return r4813; case 0x4814: return r4814; case 0x4815: return r4815; case 0x4816: return r4816; case 0x4817: return r4817; case 0x4818: return r4818; case 0x481a: { if(r481x != 0x07) return 0x00; unsigned addr = data_pointer(); unsigned adjust = data_adjust(); if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend uint8 data = memory_cartrom_read(datarom_addr(addr + adjust)); if((r4818 & 0x60) == 0x60) { if((r4818 & 16) == 0) { set_data_pointer(addr + adjust); } else { set_data_adjust(adjust + adjust); } } return data; } //========= //math unit //========= case 0x4820: return r4820; case 0x4821: return r4821; case 0x4822: return r4822; case 0x4823: return r4823; case 0x4824: return r4824; case 0x4825: return r4825; case 0x4826: return r4826; case 0x4827: return r4827; case 0x4828: return r4828; case 0x4829: return r4829; case 0x482a: return r482a; case 0x482b: return r482b; case 0x482c: return r482c; case 0x482d: return r482d; case 0x482e: return r482e; case 0x482f: { uint8 status = r482f; r482f &= 0x7f; return status; } //=================== //memory mapping unit //=================== case 0x4830: return r4830; case 0x4831: return r4831; case 0x4832: return r4832; case 0x4833: return r4833; case 0x4834: return r4834; //==================== //real-time clock unit //==================== case 0x4840: return r4840; case 0x4841: { if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00; r4842 = 0x80; uint8 data = memory_cartrtc_read(rtc_index); rtc_index = (rtc_index + 1) & 15; return data; } case 0x4842: { uint8 status = r4842; r4842 &= 0x7f; return status; } } return cpu_regs_mdr; } void SPC7110::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; switch(addr) { //================== //decompression unit //================== case 0x4801: r4801 = data; break; case 0x4802: r4802 = data; break; case 0x4803: r4803 = data; break; case 0x4804: r4804 = data; break; case 0x4805: r4805 = data; break; case 0x4806: { r4806 = data; unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16)); unsigned index = (r4804 << 2); //unsigned length = (r4809 + (r480a << 8)); unsigned addr = datarom_addr(table + index); unsigned mode = (memory_cartrom_read(addr + 0)); unsigned offset = (memory_cartrom_read(addr + 1) << 16) + (memory_cartrom_read(addr + 2) << 8) + (memory_cartrom_read(addr + 3) << 0); decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode); r480c = 0x80; } break; case 0x4807: r4807 = data; break; case 0x4808: r4808 = data; break; case 0x4809: r4809 = data; break; case 0x480a: r480a = data; break; case 0x480b: r480b = data; break; //============== //data port unit //============== case 0x4811: r4811 = data; r481x |= 0x01; break; case 0x4812: r4812 = data; r481x |= 0x02; break; case 0x4813: r4813 = data; r481x |= 0x04; break; case 0x4814: { r4814 = data; r4814_latch = true; if(!r4815_latch) break; if(!(r4818 & 2)) break; if(r4818 & 0x10) break; if((r4818 & 0x60) == 0x20) { unsigned increment = data_adjust() & 0xff; if(r4818 & 8) increment = (int8)increment; //8-bit sign extend set_data_pointer(data_pointer() + increment); } else if((r4818 & 0x60) == 0x40) { unsigned increment = data_adjust(); if(r4818 & 8) increment = (int16)increment; //16-bit sign extend set_data_pointer(data_pointer() + increment); } } break; case 0x4815: { r4815 = data; r4815_latch = true; if(!r4814_latch) break; if(!(r4818 & 2)) break; if(r4818 & 0x10) break; if((r4818 & 0x60) == 0x20) { unsigned increment = data_adjust() & 0xff; if(r4818 & 8) increment = (int8)increment; //8-bit sign extend set_data_pointer(data_pointer() + increment); } else if((r4818 & 0x60) == 0x40) { unsigned increment = data_adjust(); if(r4818 & 8) increment = (int16)increment; //16-bit sign extend set_data_pointer(data_pointer() + increment); } } break; case 0x4816: r4816 = data; break; case 0x4817: r4817 = data; break; case 0x4818: { if(r481x != 0x07) break; r4818 = data; r4814_latch = r4815_latch = false; } break; //========= //math unit //========= case 0x4820: r4820 = data; break; case 0x4821: r4821 = data; break; case 0x4822: r4822 = data; break; case 0x4823: r4823 = data; break; case 0x4824: r4824 = data; break; case 0x4825: { r4825 = data; if(r482e & 1) { //signed 16-bit x 16-bit multiplication int16 r0 = (int16)(r4824 + (r4825 << 8)); int16 r1 = (int16)(r4820 + (r4821 << 8)); signed result = r0 * r1; r4828 = result; r4829 = result >> 8; r482a = result >> 16; r482b = result >> 24; } else { //unsigned 16-bit x 16-bit multiplication uint16 r0 = (uint16)(r4824 + (r4825 << 8)); uint16 r1 = (uint16)(r4820 + (r4821 << 8)); unsigned result = r0 * r1; r4828 = result; r4829 = result >> 8; r482a = result >> 16; r482b = result >> 24; } r482f = 0x80; } break; case 0x4826: r4826 = data; break; case 0x4827: { r4827 = data; if(r482e & 1) { //signed 32-bit x 16-bit division int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24)); int16 divisor = (int16)(r4826 + (r4827 << 8)); int32 quotient; int16 remainder; if(divisor) { quotient = (int32)(dividend / divisor); remainder = (int32)(dividend % divisor); } else { //illegal division by zero quotient = 0; remainder = dividend & 0xffff; } r4828 = quotient; r4829 = quotient >> 8; r482a = quotient >> 16; r482b = quotient >> 24; r482c = remainder; r482d = remainder >> 8; } else { //unsigned 32-bit x 16-bit division uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24)); uint16 divisor = (uint16)(r4826 + (r4827 << 8)); uint32 quotient; uint16 remainder; if(divisor) { quotient = (uint32)(dividend / divisor); remainder = (uint16)(dividend % divisor); } else { //illegal division by zero quotient = 0; remainder = dividend & 0xffff; } r4828 = quotient; r4829 = quotient >> 8; r482a = quotient >> 16; r482b = quotient >> 24; r482c = remainder; r482d = remainder >> 8; } r482f = 0x80; } break; case 0x482e: { //reset math unit r4820 = r4821 = r4822 = r4823 = 0; r4824 = r4825 = r4826 = r4827 = 0; r4828 = r4829 = r482a = r482b = 0; r482c = r482d = 0; r482e = data; } break; //=================== //memory mapping unit //=================== case 0x4830: r4830 = data; break; case 0x4831: { r4831 = data; dx_offset = datarom_addr((data & 7) * 0x100000); } break; case 0x4832: { r4832 = data; ex_offset = datarom_addr((data & 7) * 0x100000); } break; case 0x4833: { r4833 = data; fx_offset = datarom_addr((data & 7) * 0x100000); } break; case 0x4834: r4834 = data; break; //==================== //real-time clock unit //==================== case 0x4840: { r4840 = data; if(!(r4840 & 1)) { //disable RTC rtc_state = RTCS_Inactive; update_time(); } else { //enable RTC r4842 = 0x80; rtc_state = RTCS_ModeSelect; } } break; case 0x4841: { r4841 = data; switch(rtc_state) { case RTCS_ModeSelect: { if(data == RTCM_Linear || data == RTCM_Indexed) { r4842 = 0x80; rtc_state = RTCS_IndexSelect; rtc_mode = (RTC_Mode)data; rtc_index = 0; } } break; case RTCS_IndexSelect: { r4842 = 0x80; rtc_index = data & 15; if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write; } break; case RTCS_Write: { r4842 = 0x80; //control register 0 if(rtc_index == 13) { //increment second counter if(data & 2) update_time(+1); //round minute counter if(data & 8) { update_time(); unsigned second = memory_cartrtc_read( 0) + memory_cartrtc_read( 1) * 10; //clear seconds memory_cartrtc_write(0, 0); memory_cartrtc_write(1, 0); if(second >= 30) update_time(+60); } } //control register 2 if(rtc_index == 15) { //disable timer and clear second counter if((data & 1) && !(memory_cartrtc_read(15) & 1)) { update_time(); //clear seconds memory_cartrtc_write(0, 0); memory_cartrtc_write(1, 0); } //disable timer if((data & 2) && !(memory_cartrtc_read(15) & 2)) { update_time(); } } memory_cartrtc_write(rtc_index, data & 15); rtc_index = (rtc_index + 1) & 15; } break; case RTCS_Inactive: { } break; } //switch(rtc_state) } break; } } SPC7110::SPC7110() { } c4emu.cpp000664 001750 001750 00000116375 12720446475 013453 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "memmap.h" #include "sar.h" static int16 C4SinTable[512] = { 0, 402, 804, 1206, 1607, 2009, 2410, 2811, 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, 0, -402, -804, -1206, -1607, -2009, -2410, -2811, -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 }; static int16 C4CosTable[512] = { 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, 0, -402, -804, -1206, -1607, -2009, -2410, -2811, -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, 0, 402, 804, 1206, 1607, 2009, 2410, 2811, 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 }; static uint8 C4TestPattern[12 * 4] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00 }; static void C4ConvOAM (void); static void C4DoScaleRotate (int); static void C4DrawLine (int32, int32, int16, int32, int32, int16, uint8); static void C4DrawWireFrame (void); static void C4TransformLines (void); static void C4BitPlaneWave (void); static void C4SprDisintegrate (void); static void C4ProcessSprites (void); static void C4ConvOAM (void) { uint8 *OAMptr = Memory.C4RAM + (Memory.C4RAM[0x626] << 2); for (uint8 *i = Memory.C4RAM + 0x1fd; i > OAMptr; i -= 4) *i = 0xe0; // Clear OAM-to-be uint8 *OAMptr2; uint16 globalX, globalY; int16 SprX, SprY; uint8 SprName, SprAttr; uint8 SprCount; globalX = READ_WORD(Memory.C4RAM + 0x0621); globalY = READ_WORD(Memory.C4RAM + 0x0623); OAMptr2 = Memory.C4RAM + 0x200 + (Memory.C4RAM[0x626] >> 2); #ifdef DEBUGGER if (Memory.C4RAM[0x625] != 0) printf("$6625=%02x, expected 00\n", Memory.C4RAM[0x625]); if ((Memory.C4RAM[0x626] >> 2) != Memory.C4RAM[0x629]) printf("$6629=%02x, expected %02x\n", Memory.C4RAM[0x629], (Memory.C4RAM[0x626] >> 2)); if (((uint16) Memory.C4RAM[0x626] << 2) != READ_WORD(Memory.C4RAM + 0x627)) printf("$6627=%04x, expected %04x\n", READ_WORD(Memory.C4RAM + 0x627), ((uint16) Memory.C4RAM[0x626] << 2)); #endif if (Memory.C4RAM[0x0620] != 0) { SprCount = 128 - Memory.C4RAM[0x626]; uint8 offset = (Memory.C4RAM[0x626] & 3) * 2; uint8 *srcptr = Memory.C4RAM + 0x220; for (int i = Memory.C4RAM[0x0620]; i > 0 && SprCount > 0; i--, srcptr += 16) { SprX = READ_WORD(srcptr) - globalX; SprY = READ_WORD(srcptr + 2) - globalY; SprName = srcptr[5]; SprAttr = srcptr[4] | srcptr[0x06]; // XXX: mask bits? uint8 *sprptr = C4GetMemPointer(READ_3WORD(srcptr + 7)); if (*sprptr != 0) { int16 X, Y; for (int SprCnt = *sprptr++; SprCnt > 0 && SprCount > 0; SprCnt--, sprptr += 4) { X = (int8) sprptr[1]; if (SprAttr & 0x40) X = -X - ((sprptr[0] & 0x20) ? 16 : 8); // flip X X += SprX; if (X >= -16 && X <= 272) { Y = (int8) sprptr[2]; if (SprAttr & 0x80) Y = -Y - ((sprptr[0] & 0x20) ? 16 : 8); Y += SprY; if (Y >= -16 && Y <= 224) { OAMptr[0] = X & 0xff; OAMptr[1] = (uint8) Y; OAMptr[2] = SprName + sprptr[3]; OAMptr[3] = SprAttr ^ (sprptr[0] & 0xc0); // XXX: Carry from SprName addition? *OAMptr2 &= ~(3 << offset); if (X & 0x100) *OAMptr2 |= 1 << offset; if (sprptr[0] & 0x20) *OAMptr2 |= 2 << offset; OAMptr += 4; SprCount--; offset = (offset + 2) & 6; if (offset == 0) OAMptr2++; } } } } else if (SprCount > 0) { // XXX: Should we be testing -16<=SprX<=272 and -16<=SprY<=224? OAMptr[0] = (uint8) SprX; OAMptr[1] = (uint8) SprY; OAMptr[2] = SprName; OAMptr[3] = SprAttr; *OAMptr2 &= ~(3 << offset); if (SprX & 0x100) *OAMptr2 |= 3 << offset; else *OAMptr2 |= 2 << offset; OAMptr += 4; SprCount--; offset = (offset + 2) & 6; if (offset == 0) OAMptr2++; } } } } static void C4DoScaleRotate (int row_padding) { int16 A, B, C, D; // Calculate matrix int32 XScale = READ_WORD(Memory.C4RAM + 0x1f8f); if (XScale & 0x8000) XScale = 0x7fff; int32 YScale = READ_WORD(Memory.C4RAM + 0x1f92); if (YScale & 0x8000) YScale = 0x7fff; if (READ_WORD(Memory.C4RAM + 0x1f80) == 0) // no rotation { // XXX: only do this for C and D? // XXX: and then only when YScale is 0x1000? A = (int16) XScale; B = 0; C = 0; D = (int16) YScale; } else if (READ_WORD(Memory.C4RAM + 0x1f80) == 128) // 90 degree rotation { // XXX: Really do this? A = 0; B = (int16) (-YScale); C = (int16) XScale; D = 0; } else if (READ_WORD(Memory.C4RAM + 0x1f80) == 256) // 180 degree rotation { // XXX: Really do this? A = (int16) (-XScale); B = 0; C = 0; D = (int16) (-YScale); } else if (READ_WORD(Memory.C4RAM + 0x1f80) == 384) // 270 degree rotation { // XXX: Really do this? A = 0; B = (int16) YScale; C = (int16) (-XScale); D = 0; } else { A = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15); B = (int16) (-SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15)); C = (int16) SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15); D = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15); } // Calculate Pixel Resolution uint8 w = Memory.C4RAM[0x1f89] & ~7; uint8 h = Memory.C4RAM[0x1f8c] & ~7; //printf("%dx%d XScale=%04x YScale=%04x angle=%03x\n", w, h, XScale, YScale, READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff); //printf("Matrix: [%10g %10g] [%04x %04x]\n", A / 4096.0, B / 4096.0, A & 0xffff, B & 0xffff); //printf(" [%10g %10g] [%04x %04x]\n", C / 4096.0, D / 4096.0, C & 0xffff, D & 0xffff); // Clear the output RAM memset(Memory.C4RAM, 0, (w + row_padding / 4) * h / 2); int32 Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f83); int32 Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f86); #ifdef DEBUGGER if (Memory.C4RAM[0x1f97] != 0) printf("$7f97=%02x, expected 00\n", Memory.C4RAM[0x1f97]); if ((Cx & ~1) != w / 2 || (Cy & ~1) != h / 2) printf("Center is not middle of image! (%d, %d) != (%d, %d)\n", Cx, Cy, w / 2, h / 2); #endif // Calculate start position (i.e. (Ox, Oy) = (0, 0)) // The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in the function. // We do Cx*A etc normally because the matrix parameters already have the fractional parts. int32 LineX = (Cx << 12) - Cx * A - Cx * B; int32 LineY = (Cy << 12) - Cy * C - Cy * D; // Start loop uint32 X, Y; uint8 byte; int outidx = 0; uint8 bit = 0x80; for (int y = 0; y < h; y++) { X = LineX; Y = LineY; for (int x = 0; x < w; x++) { if ((X >> 12) >= w || (Y >> 12) >= h) byte = 0; else { uint32 addr = (Y >> 12) * w + (X >> 12); byte = Memory.C4RAM[0x600 + (addr >> 1)]; if (addr & 1) byte >>= 4; } // De-bitplanify if (byte & 1) Memory.C4RAM[outidx] |= bit; if (byte & 2) Memory.C4RAM[outidx + 1] |= bit; if (byte & 4) Memory.C4RAM[outidx + 16] |= bit; if (byte & 8) Memory.C4RAM[outidx + 17] |= bit; bit >>= 1; if (bit == 0) { bit = 0x80; outidx += 32; } X += A; // Add 1 to output x => add an A and a C Y += C; } outidx += 2 + row_padding; if (outidx & 0x10) outidx &= ~0x10; else outidx -= w * 4 + row_padding; LineX += B; // Add 1 to output y => add a B and a D LineY += D; } } static void C4DrawLine (int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color) { // Transform coordinates C4WFXVal = (int16) X1; C4WFYVal = (int16) Y1; C4WFZVal = Z1; C4WFScale = Memory.C4RAM[0x1f90]; C4WFX2Val = Memory.C4RAM[0x1f86]; C4WFY2Val = Memory.C4RAM[0x1f87]; C4WFDist = Memory.C4RAM[0x1f88]; C4TransfWireFrame2(); X1 = (C4WFXVal + 48) << 8; Y1 = (C4WFYVal + 48) << 8; C4WFXVal = (int16) X2; C4WFYVal = (int16) Y2; C4WFZVal = Z2; C4TransfWireFrame2(); X2 = (C4WFXVal + 48) << 8; Y2 = (C4WFYVal + 48) << 8; // Get line info C4WFXVal = (int16) (X1 >> 8); C4WFYVal = (int16) (Y1 >> 8); C4WFX2Val = (int16) (X2 >> 8); C4WFY2Val = (int16) (Y2 >> 8); C4CalcWireFrame(); X2 = (int16) C4WFXVal; Y2 = (int16) C4WFYVal; // Render line for (int i = C4WFDist ? C4WFDist : 1; i > 0; i--) { if (X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) { uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2; uint8 bit = 0x80 >> ((X1 >> 8) & 7); Memory.C4RAM[addr + 0x300] &= ~bit; Memory.C4RAM[addr + 0x301] &= ~bit; if (Color & 1) Memory.C4RAM[addr + 0x300] |= bit; if (Color & 2) Memory.C4RAM[addr + 0x301] |= bit; } X1 += X2; Y1 += Y2; } } static void C4DrawWireFrame (void) { uint8 *line = C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f80)); uint8 *point1, *point2; int16 X1, Y1, Z1; int16 X2, Y2, Z2; uint8 Color; #ifdef DEBUGGER if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff) printf("wireframe: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8f)); if (READ_3WORD(Memory.C4RAM + 0x1fa4) != 0x001000) printf("wireframe: Unexpected value in $7fa4: %06x\n", READ_3WORD(Memory.C4RAM + 0x1fa4)); #endif for (int i = Memory.C4RAM[0x0295]; i > 0; i--, line += 5) { if (line[0] == 0xff && line[1] == 0xff) { uint8 *tmp = line - 5; while (tmp[2] == 0xff && tmp[3] == 0xff) tmp -= 5; point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (tmp[2] << 8) | tmp[3]); } else point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[0] << 8) | line[1]); point2 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[2] << 8) | line[3]); X1 = (point1[0] << 8) | point1[1]; Y1 = (point1[2] << 8) | point1[3]; Z1 = (point1[4] << 8) | point1[5]; X2 = (point2[0] << 8) | point2[1]; Y2 = (point2[2] << 8) | point2[3]; Z2 = (point2[4] << 8) | point2[5]; Color = line[4]; C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); } } static void C4TransformLines (void) { C4WFX2Val = Memory.C4RAM[0x1f83]; C4WFY2Val = Memory.C4RAM[0x1f86]; C4WFDist = Memory.C4RAM[0x1f89]; C4WFScale = Memory.C4RAM[0x1f8c]; #ifdef DEBUGGER if (Memory.C4RAM[0x1f8a] != 0x90) printf("lines: $7f8a = %02x, expected 90\n", READ_WORD(Memory.C4RAM + 0x1f8a)); #endif // Transform vertices uint8 *ptr = Memory.C4RAM; for (int i = READ_WORD(Memory.C4RAM + 0x1f80); i > 0; i--, ptr += 0x10) { C4WFXVal = READ_WORD(ptr + 1); C4WFYVal = READ_WORD(ptr + 5); C4WFZVal = READ_WORD(ptr + 9); C4TransfWireFrame(); // Displace WRITE_WORD(ptr + 1, C4WFXVal + 0x80); WRITE_WORD(ptr + 5, C4WFYVal + 0x50); } WRITE_WORD(Memory.C4RAM + 0x600, 23); WRITE_WORD(Memory.C4RAM + 0x602, 0x60); WRITE_WORD(Memory.C4RAM + 0x605, 0x40); WRITE_WORD(Memory.C4RAM + 0x600 + 8, 23); WRITE_WORD(Memory.C4RAM + 0x602 + 8, 0x60); WRITE_WORD(Memory.C4RAM + 0x605 + 8, 0x40); ptr = Memory.C4RAM + 0xb02; uint8 *ptr2 = Memory.C4RAM; for (int i = READ_WORD(Memory.C4RAM + 0xb00); i > 0; i--, ptr += 2, ptr2 += 8) { C4WFXVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 1); C4WFYVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 5); C4WFX2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 1); C4WFY2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 5); C4CalcWireFrame(); WRITE_WORD(ptr2 + 0x600, C4WFDist ? C4WFDist : 1); WRITE_WORD(ptr2 + 0x602, C4WFXVal); WRITE_WORD(ptr2 + 0x605, C4WFYVal); } } static void C4BitPlaneWave (void) { static uint16 bmpdata[] = { 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E, 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, 0x020E, 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E, 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060A, 0x060C, 0x060E, 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080A, 0x080C, 0x080E }; uint8 *dst = Memory.C4RAM; uint32 waveptr = Memory.C4RAM[0x1f83]; uint16 mask1 = 0xc0c0; uint16 mask2 = 0x3f3f; #ifdef DEBUGGER if (READ_3WORD(Memory.C4RAM + 0x1f80) != Memory.C4RAM[waveptr + 0xb00]) printf("$7f80=%06x, expected %02x\n", READ_3WORD(Memory.C4RAM + 0x1f80), Memory.C4RAM[waveptr + 0xb00]); #endif for (int j = 0; j < 0x10; j++) { do { int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16; for (int i = 0; i < 40; i++) { uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2; if (height >= 0) { if (height < 8) tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa00 + height * 2); else tmp |= mask1 & 0xff00; } WRITE_WORD(dst + bmpdata[i], tmp); height++; } waveptr = (waveptr + 1) & 0x7f; mask1 = (mask1 >> 2) | (mask1 << 6); mask2 = (mask2 >> 2) | (mask2 << 6); } while (mask1 != 0xc0c0); dst += 16; do { int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16; for (int i = 0; i < 40; i++) { uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2; if (height >= 0) { if (height < 8) tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa10 + height * 2); else tmp |= mask1 & 0xff00; } WRITE_WORD(dst + bmpdata[i], tmp); height++; } waveptr = (waveptr + 1) & 0x7f; mask1 = (mask1 >> 2) | (mask1 << 6); mask2 = (mask2 >> 2) | (mask2 << 6); } while (mask1 != 0xc0c0); dst += 16; } } static void C4SprDisintegrate (void) { uint8 *src; uint8 width, height; uint32 StartX, StartY; int32 scaleX, scaleY; int32 Cx, Cy; width = Memory.C4RAM[0x1f89]; height = Memory.C4RAM[0x1f8c]; Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f80); Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f83); #ifdef DEBUGGER if ((Cx & ~1) != width / 2 || (Cy & ~1) != height / 2) printf("Center is not middle of image for disintegrate! (%d, %d) != (%d, %d)\n", Cx, Cy, width / 2, height / 2); #endif scaleX = (int16) READ_WORD(Memory.C4RAM + 0x1f86); scaleY = (int16) READ_WORD(Memory.C4RAM + 0x1f8f); StartX = -Cx * scaleX + (Cx << 8); StartY = -Cy * scaleY + (Cy << 8); src = Memory.C4RAM + 0x600; memset(Memory.C4RAM, 0, width * height / 2); for (uint32 y = StartY, i = 0; i < height; i++, y += scaleY) { for (uint32 x = StartX, j = 0; j < width; j++, x += scaleX) { if ((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000) { uint8 pixel = (j & 1) ? (*src >> 4) : *src; int idx = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2; uint8 mask = 0x80 >> ((x >> 8) & 7); if (pixel & 1) Memory.C4RAM[idx] |= mask; if (pixel & 2) Memory.C4RAM[idx + 1] |= mask; if (pixel & 4) Memory.C4RAM[idx + 16] |= mask; if (pixel & 8) Memory.C4RAM[idx + 17] |= mask; } if (j & 1) src++; } } } static void C4ProcessSprites (void) { switch (Memory.C4RAM[0x1f4d]) { case 0x00: // Build OAM #ifdef DEBUGGER //printf("00 00 Build OAM!\n"); #endif C4ConvOAM(); break; case 0x03: // Scale/Rotate #ifdef DEBUGGER //printf("00 03 Scale/Rotate!\n"); #endif C4DoScaleRotate(0); break; case 0x05: // Transform Lines #ifdef DEBUGGER //printf("00 05 Transform Lines!\n"); #endif C4TransformLines(); break; case 0x07: // Scale/Rotate #ifdef DEBUGGER //printf("00 07 Scale/Rotate!\n"); #endif C4DoScaleRotate(64); break; case 0x08: // Draw wireframe #ifdef DEBUGGER //printf("00 08 Draw wireframe!\n"); #endif C4DrawWireFrame(); break; case 0x0b: // Disintegrate #ifdef DEBUGGER //printf("00 0b Disintegrate!\n"); #endif C4SprDisintegrate(); break; case 0x0c: // Wave #ifdef DEBUGGER //printf("00 0b Wave!\n"); #endif C4BitPlaneWave(); break; default: #ifdef DEBUGGER printf("Unknown C4 sprite command (%02x)\n", Memory.C4RAM[0x1f4d]); #endif break; } } void S9xInitC4 (void) { // Stupid zsnes code, we can't do the logical thing without breaking savestates // Memory.C4RAM = &Memory.FillRAM [0x6000]; memset(Memory.C4RAM, 0, 0x2000); } uint8 S9xGetC4 (uint16 Address) { if (Address == 0x7f5e) return (0); return (Memory.C4RAM[Address - 0x6000]); } void S9xSetC4 (uint8 byte, uint16 Address) { Memory.C4RAM[Address - 0x6000] = byte; if (Address == 0x7f4f) { if (Memory.C4RAM[0x1f4d] == 0x0e && byte < 0x40 && (byte & 3) == 0) { #ifdef DEBUGGER printf("Test command %02x 0e used!\n", byte); #endif Memory.C4RAM[0x1f80] = byte >> 2; } else { switch (byte) { case 0x00: // Sprite #ifdef DEBUGGER //printf("00 Sprite!\n"); #endif C4ProcessSprites(); break; case 0x01: // Draw wireframe #ifdef DEBUGGER //printf("01 Draw wireframe!\n"); if (Memory.C4RAM[0x1f4d] != 8) printf("$7f4d=%02x, expected 08 for command 01 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif memset(Memory.C4RAM + 0x300, 0, 16 * 12 * 3 * 4); C4DrawWireFrame(); break; case 0x05: // Propulsion (?) { #ifdef DEBUGGER //printf("05 Propulsion (?)!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 05 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int32 tmp = 0x10000; if (READ_WORD(Memory.C4RAM + 0x1f83)) tmp = SAR((tmp / READ_WORD(Memory.C4RAM + 0x1f83)) * READ_WORD(Memory.C4RAM + 0x1f81), 8); WRITE_WORD(Memory.C4RAM + 0x1f80, (uint16) tmp); break; } case 0x0d: // Set vector length #ifdef DEBUGGER //printf("0d Set vector length!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 0d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); C41FDistVal = READ_WORD(Memory.C4RAM + 0x1f86); C4Op0D(); WRITE_WORD(Memory.C4RAM + 0x1f89, C41FXVal); WRITE_WORD(Memory.C4RAM + 0x1f8c, C41FYVal); break; case 0x10: // Polar to rectangluar { #ifdef DEBUGGER //printf("10 Polar->Rect!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 10 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int32 tmp; int32 r1; r1 = READ_WORD(Memory.C4RAM + 0x1f83); if (r1 & 0x8000) r1 |= ~0x7fff; else r1 &= 0x7fff; tmp = SAR(r1 * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16); WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp); tmp = SAR(r1 * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16); WRITE_3WORD(Memory.C4RAM + 0x1f89, (tmp - SAR(tmp, 6))); break; } case 0x13: // Polar to rectangluar { #ifdef DEBUGGER //printf("13 Polar->Rect!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 13 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int32 tmp; tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8); WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp); tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8); WRITE_3WORD(Memory.C4RAM + 0x1f89, tmp); break; } case 0x15: // Pythagorean #ifdef DEBUGGER //printf("15 Pythagorean!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 15 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); //C4Op15(); // optimized to: C41FDist = (int16) sqrt((double) C41FXVal * C41FXVal + (double) C41FYVal * C41FYVal); WRITE_WORD(Memory.C4RAM + 0x1f80, C41FDist); break; case 0x1f: // atan #ifdef DEBUGGER //printf("1f atan!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 1f %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80); C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83); C4Op1F(); WRITE_WORD(Memory.C4RAM + 0x1f86, C41FAngleRes); break; case 0x22: // Trapezoid { #ifdef DEBUGGER //printf("22 Trapezoid!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 22 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int16 angle1 = READ_WORD(Memory.C4RAM + 0x1f8c) & 0x1ff; int16 angle2 = READ_WORD(Memory.C4RAM + 0x1f8f) & 0x1ff; #ifdef DEBUGGER if (C4CosTable[angle1] == 0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle1=%d\n", angle1); if (C4CosTable[angle2] == 0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle2=%d\n", angle2); #endif int32 tan1 = (C4CosTable[angle1] != 0) ? ((((int32) C4SinTable[angle1]) << 16) / C4CosTable[angle1]) : 0x80000000; int32 tan2 = (C4CosTable[angle2] != 0) ? ((((int32) C4SinTable[angle2]) << 16) / C4CosTable[angle2]) : 0x80000000; int16 y = READ_WORD(Memory.C4RAM + 0x1f83) - READ_WORD(Memory.C4RAM + 0x1f89); int16 left, right; for (int j = 0; j < 225; j++) { if (y >= 0) { left = SAR((int32) tan1 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86); right = SAR((int32) tan2 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86) + READ_WORD(Memory.C4RAM + 0x1f93); if (left < 0 && right < 0) { left = 1; right = 0; } else if (left < 0) left = 0; else if (right < 0) right = 0; if (left > 255 && right > 255) { left = 255; right = 254; } else if (left > 255) left = 255; else if (right > 255) right = 255; } else { left = 1; right = 0; } Memory.C4RAM[j + 0x800] = (uint8) left; Memory.C4RAM[j + 0x900] = (uint8) right; y++; } break; } case 0x25: // Multiply { #ifdef DEBUGGER //printf("25 Multiply!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 25 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int32 foo = READ_3WORD(Memory.C4RAM + 0x1f80); int32 bar = READ_3WORD(Memory.C4RAM + 0x1f83); foo *= bar; WRITE_3WORD(Memory.C4RAM + 0x1f80, foo); break; } case 0x2d: // Transform Coords #ifdef DEBUGGER //printf("2d Transform Coords!\n"); if (Memory.C4RAM[0x1f4d] != 2) printf("$7f4d=%02x, expected 02 for command 2d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff) printf("2d transform coords: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8f)); if (READ_3WORD(Memory.C4RAM + 0x1f8c) != 0x001000) printf("0d transform coords: Unexpected value in $7f8c: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8c)); #endif C4WFXVal = READ_WORD(Memory.C4RAM + 0x1f81); C4WFYVal = READ_WORD(Memory.C4RAM + 0x1f84); C4WFZVal = READ_WORD(Memory.C4RAM + 0x1f87); C4WFX2Val = Memory.C4RAM[0x1f89]; C4WFY2Val = Memory.C4RAM[0x1f8a]; C4WFDist = Memory.C4RAM[0x1f8b]; C4WFScale = READ_WORD(Memory.C4RAM + 0x1f90); C4TransfWireFrame2(); WRITE_WORD(Memory.C4RAM + 0x1f80, C4WFXVal); WRITE_WORD(Memory.C4RAM + 0x1f83, C4WFYVal); break; case 0x40: // Sum { #ifdef DEBUGGER //printf("40 Sum!\n"); if (Memory.C4RAM[0x1f4d] != 0x0e) printf("$7f4d=%02x, expected 0e for command 40 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif uint16 sum = 0; for (int i = 0; i < 0x800; sum += Memory.C4RAM[i++]) ; WRITE_WORD(Memory.C4RAM + 0x1f80, sum); break; } case 0x54: // Square { #ifdef DEBUGGER //printf("54 Square!\n"); if (Memory.C4RAM[0x1f4d] != 0x0e) printf("$7f4d=%02x, expected 0e for command 54 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif int64 a = SAR((int64) READ_3WORD(Memory.C4RAM + 0x1f80) << 40, 40); //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF)); a *= a; //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF)); WRITE_3WORD(Memory.C4RAM + 0x1f83, a); WRITE_3WORD(Memory.C4RAM + 0x1f86, (a >> 24)); break; } case 0x5c: // Immediate Reg #ifdef DEBUGGER //printf("5c Immediate Reg!\n"); if (Memory.C4RAM[0x1f4d] != 0x0e) printf("$7f4d=%02x, expected 0e for command 5c %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif for (int i = 0; i < 12 * 4; i++) Memory.C4RAM[i] = C4TestPattern[i]; break; case 0x89: // Immediate ROM #ifdef DEBUGGER //printf("89 Immediate ROM!\n"); if (Memory.C4RAM[0x1f4d] != 0x0e) printf("$7f4d=%02x, expected 0e for command 89 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); #endif Memory.C4RAM[0x1f80] = 0x36; Memory.C4RAM[0x1f81] = 0x43; Memory.C4RAM[0x1f82] = 0x05; break; default: #ifdef DEBUGGER printf("Unknown C4 command (%02x)\n", byte); #endif break; } } } else if (Address == 0x7f47) { #ifdef DEBUGGER //printf("C4 load memory %06x => %04x, %04x bytes\n", READ_3WORD(Memory.C4RAM + 0x1f40), READ_WORD(Memory.C4RAM + 0x1f45), READ_WORD(Memory.C4RAM + 0x1f43)); if (byte != 0) printf("C4 load: non-0 written to $7f47! Wrote %02x\n", byte); if (READ_WORD(Memory.C4RAM + 0x1f45) < 0x6000 || (READ_WORD(Memory.C4RAM + 0x1f45) + READ_WORD(Memory.C4RAM + 0x1f43)) > 0x6c00) printf("C4 load: Dest unusual! It's %04x\n", READ_WORD(Memory.C4RAM + 0x1f45)); #endif memmove(Memory.C4RAM + (READ_WORD(Memory.C4RAM + 0x1f45) & 0x1fff), C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f40)), READ_WORD(Memory.C4RAM + 0x1f43)); } } docs/porting.html000664 001750 001750 00000070126 12720446475 015223 0ustar00sergiosergio000000 000000 Porting Snes9x

How to Port Snes9x to a New Platform

Version: 1.53
(c) Copyright 1998 Gary Henderson

Introduction

This is brief description of the steps to port Snes9x to the new platform. It describes what code you have to write and what functions exist that you can make use of. It also gives some insights as to how Snes9x actually works, although that will be subject of another document yet to be written.

System Requirements

A C++ compiler. For the most part Snes9x really isn't written in C++, it just uses the C++ compiler as a “better C” compiler to get inline functions and so on. GCC is good for compiling Snes9x (http://gcc.gnu.org/).

A fast CPU. SNES emulation is very compute intensive; two, or sometimes three CPUs to emulate, an 8-channel 16-bit stereo sound digital signal processor with real-time sample decompression, filter and echo effects, two custom graphics processor chips that can produce transparency, scaling, rotation and window effects in 32768 colors, and finally hardware DMA all take their toll on the host CPU.

Enough RAM. Snes9x uses 8MB to load SNES ROM images and several MB for emulating sound, graphics, custom chips, and so on.

A 16-bit color (two bytes per pixel) or deeper display, at least 512*478 pixels in resolution. Pixel format conversion may be required before you place the rendered SNES screen on to the display.

Sound output requires spooling 8-bit or 16-bit, mono or stereo digital sound data to the host sound system. Some ports can use interrupts or callbacks from the sound system to know when more sound data is required, most other ports have to periodically poll the host sound system to see if more data is required; if it is then the sound mixing code is called to fill the sound buffer with SNES sound data, which then can be passed on to the host sound system. Sound data is generated as an array of bytes (uint8) for 8-bit sound or shorts (int16) for 16-bit data. Stereo sound data generates twice as many samples, with each channel's samples interleaved, first left's then right's.

For the user to be able to control and play SNES games, some form of input device is required, a joypad or keyboard, for example. The real SNES can have 2 eight-button digital joypads connected to it or 5 joypads when an optional multi-player adaptor is connected, although most games only require a single joypad. Access to all eight buttons and the direction pad, of course, are usually required by most games. Snes9x does emulate the multi-player adaptor hardware, if you were wondering, but its still up to you to provide the emulation of the individual joypads.

The real SNES also has a SNES mouse, Super Scope and Justifier (light-gun) available as optional extras. Snes9x can emulate all of these using some form of pointing device, usually the host system's mouse.

Some SNES game cartridges contains a small amount of extra RAM and a battery, so ROMs could save a player's progress through a game for games that takes many hours to play from start to finish. Snes9x simulates this S-RAM by saving the contents of the area of memory occupied by the S-RAM into a file then automatically restoring it again the next time the user plays the same game. If the hardware you're porting to doesn't have a storage media available then you could be in trouble.

Snes9x also implements freeze-game files which can record the state of the SNES hardware and RAM at a particular point in time and can restore it to that exact state at a later date - the result is that users can save a game at any point, not just at save-game or password points provided by the original game coders. Each freeze file is over 400k in size. To help save disk space, Snes9x can be compiled with zlib (http://www.zlib.net/), which is used to GZIP compress the freeze files, reducing the size to typically below 100k. zlib is also used to load GZIP or ZIP compressed ROM images. Additionally, Snes9x supports JMA archives compressed with NSRT (http://nsrt.edgeemu.com/).

Compile-Time Options

DEBUGGER

Enables extra code to assist you in debugging SNES ROMs. The debugger has only ever been a quick-hack and user-interface to debugger facilities is virtually non-existent. Most of the debugger information is output via stdout and enabling the debugger slows the whole emulator down slightly. However, the debugger options available are very powerful; you could use it to help get your port working. You probably still want to ship the finished version with the debugger disabled, it will only confuse non-technical users.

RIGHTSHIFT_IS_SAR

Define this if your compiler uses shift right arithmetic for signed values. For example, GCC and Visual C++ use shift right arithmetic.

ZLIB / UNZIP_SUPPORT / JMA_SUPPORT

Define these if you want to support GZIP/ZIP/JMA compressed ROM images and GZIP compressed freeze-game files.

USE_OPENGL

Define this and set Settings.OpenGLEnable to true, then you'll get the rendered SNES image as one OpenGL texture.

Typical Options Common for Most Platforms

ZLIB
UNZIP_SUPPORT
JMA_SUPPORT
RIGHTSHIFT_IS_SAR

Editing port.h

You may need to edit port.h to fit Snes9x to your system.

If the byte ordering of your system is least significant byte first, make sure LSB_FIRST is defined, otherwise make sure it's not defined.

You'll need to make sure what pixel format your system uses for 16-bit colors (RGB565, RGB555, BGR565 or BGR555), and if it's not RGB565, define PIXEL_FORMAT to it so that Snes9x will use it to render the SNES screen. For example, Windows uses RGB565, Mac OS X uses RGB555. If your system supports more than one pixel format, you can define GFX_MULTI_FORMAT and change Snes9x's pixel format dynamically by calling S9xSetRenderPixelFormat function. If your system is 24 or 32-bit only, then don't define anything; instead write a conversion routine that will take a complete rendered 16-bit SNES screen in RGB565 format and convert to the format required to be displayed on your system.

port.h also typedefs some types; uint8 for an unsigned 8-bit quantity, uint16 for an unsigned 16-bit quantity, uint32 for a 32-bit unsigned quantity and bool8 for a true/false type. Signed versions are also typedef'ed.

Controllers Management

Read controls.h, crosshair.h, controls.txt and control-inputs.txt for details. This section is the minimal explanation to get the SNES controls workable.

The real SNES allows several different types of devices to be plugged into the game controller ports. The devices Snes9x emulates are a joypad, multi-player adaptor known as the Multi Player 5 or Multi Tap (allowing a further 4 joypads to be plugged in), a 2-button mouse, a light gun known as the Super Scope, and a light gun known as the Justifier.

In your initialization code, call S9xUnmapAllControl function.

Map any IDs to each SNES controller's buttons and pointers. (ID 249-255 are reserved).

Typically, use S9xMapPointer function for the pointer of the SNES mouse, Super Scope and Justifier, S9xMapButton function for other buttons. Set poll to false for the joypad buttons, true for the other buttons and pointers.

S9xMapButton(k1P_A_Button, s9xcommand_t cmd = S9xGetCommandT("Joypad1 A"), false);

In your main emulation loop, after S9xMainLoop function is called, check your system's keyboard/joypad, and call S9xReportButton function to report the states of the SNES joypad buttons to Snes9x.

void MyMainLoop (void)
{
    S9xMainLoop();
    MyReportButttons();
}

void MyReportButtons (void)
{
    S9xReportButton(k1P_A_Button, (key_is_pressed ? true : false));
}

Prepare your S9xPollButton and S9xPollPointer function to reply Snes9x's request for other buttons/cursors states.

Call S9xSetController function. It connects each input device to each SNES input port.
Here's typical controller settings that is used by the real SNES games:

Joypad
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);

Mouse (port 1)
S9xSetController(0, CTL_MOUSE, 0, 0, 0, 0);
S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0);

Mouse (port 2)
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_MOUSE, 1, 0, 0, 0);

Super Scope
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_SUPERSCOPE, 0, 0, 0, 0);

Multi Player 5
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_MP5, 1, 2, 3, 4);

Justifier
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_JUSTIFIER, 0, 0, 0, 0);

Justifier (2 players)
S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0);
S9xSetController(1, CTL_JUSTIFIER, 1, 0, 0, 0);

Existing Interface Functions

bool8 Memory.Init (void)

Allocates and initializes several major lumps of memory, for example the SNES ROM and RAM arrays, tile cache arrays, etc. Returns false if memory allocation fails.

void Memory.Deinit (void)

Deallocates the memory allocations made by Memory.Init function.

bool8 S9xGraphicsInit (void)

Allocates and initializes several lookup tables used to speed up SNES graphics rendering. Call after you have initialized the GFX.Screen and GFX.Pitch values. Returns false if memory allocation fails.

void S9xGraphicsDeinit (void)

Deallocates the memory allocations made by S9xGraphicsInit function.

bool8 S9xInitAPU (void)

Allocates and initializes several arrays used by the sound CPU and sound generation code. Returns false if memory allocation fails.

void S9xDeinitAPU (void)

Deallocates the allocations made by S9xInitAPU function.

bool8 S9xInitSound (int buffer_ms, int lag_ms)

Allocates memory for mixing and queueing SNES sound data, does more sound code initialization and opens the host system's sound device by calling S9xOpenSoundDevice, a function you must provide. Before calling this function you must set up Settings.SoundSync, Settings.SixteenBitSound, Settings.SoundPlaybackRate, Settings.SoundInputRate (see section below) and Settings.Stereo.
buffer_ms, given in milliseconds, is the memory buffer size for queueing sound data. lag_ms is allowable latency between when a sample is queued and when it is pulled in S9xMixSamples. Set lag_ms to zero if you have your own latency handling code in your port.

void S9xReset (void)

Resets the SNES emulated hardware back to the state it was in at “switch-on” except the S-RAM area is preserved (“hardware reset”). The effect is it resets the current game back to the start. This function is automatically called by Memory.LoadROM function.

void S9xSoftReset (void)

Similar to S9xReset function, but “software reset” as you press the SNES reset button.

bool8 Memory.LoadROM (const char *filepath)

Attempts to load the specified ROM image filename into the emulated ROM area. There are many different SNES ROM image formats and the code attempts to auto-detect as many different types as it can and in a vast majority of the cases gets it right.
There are several ROM image options in the Settingsstructure; allow the user to set them before calling Memory.LoadROM function, or make sure they are all reset to default values before each call to Memory.LoadROM function. See Settings.ForceXXX in snes9x.h.

bool8 Memory.LoadMultiCart (const char *cartApath, const char *cartBpath)

Attempts to load multiple ROM images into the emulated ROM area, for the multiple cartridge systems such as Sufami Turbo, Same Game, etc.

bool8 Memory.LoadSRAM (const char *filepath)

Call this function to load the associated S-RAM save file (if any). The filename should be based on the ROM image name to allow easy linkage. The current ports change the directory and the filename extension of the ROM filename to derive the S-RAM filename.

bool8 Memory.SaveSRAM (const char *filepath)

Call this function to save the emulated S-RAM area into a file so it can be restored again the next time the user wants to play the game. Remember to call this when just before the emulator exits or when the user has been playing a game and is about to load another one.

void S9xMainLoop (void)

The emulator main loop. Call this from your own main loop that calls this function (if a ROM image is loaded and the game is not paused), processes any pending host system events, then goes back around the loop again until the emulator exits. S9xMainLoop function normally returns control to your main loop once every emulated frame, when it reaches the start of scan-line zero. However it may take a few frames when a huge memory transfer is being emulated. The function can return more often if the DEBUGGER compile-time flag is defined and the CPU has hit a break point, or the DEBUG_MODE_FLAG bit is set in CPU.Flags or instruction single-stepping is enabled.

void S9xMixSamples (uint8 *buffer, int sample_count)

Call this function from your host sound system handling code to fill buffer with ready-mixed SNES sound data. If 16-bit sound mode is chosen, then the buffer will be filled with an array of sample_count int16, otherwise an array of sample_count uint8. If stereo sound generation is selected the buffer is filled with the same number of samples, but in pairs, first a left channel sample followed by the right channel sample.
If there are less queued samples than you request by sample_count, the function fills buffer with silent sound data and returns false. To avoid this shortage of queued samples, request larger buffer size when calling S9xInitSound, and handle sound latency safely.

int S9xGetSampleCount (void)

Returns the number of sound samples available in the buffer for your configured playback settings.

void S9xSetSamplesAvailableCallback (void (*) samples_available (void *), void *data)

Call this function to set up a callback that is run when sound samples are made available. samples_available is a function you provide that returns void and takes a pointer as an argument. data is a pointer that you may wish to pass to your callback or can be NULL. If you choose to provide a callback, you must call the provided S9xFinalizeSamples function inside it to actually buffer the samples. If you are using a callback-oriented sound API, it is recommended to set up a function that locks a common mutex during the calls to S9xFinalizeSamples and S9xMixSamples to prevent them from running at the same time and corrupting the sound buffer.
If you wish to disable a callback you have set up or need to temporarily shut down your sound system, you may pass NULL for both arguments to revert to the built-in version.

bool8 S9xSyncSound (void)

Call this function to synchronize the sound buffers to the game state. If Snes9x is generating too much sound data, or a buffer-overrun is likely, this function will return false. In this case, you may wish to wait until your host sound system uses the available samples, and S9xSyncSound returns true before continuing to execute S9xMainLoop.

bool8 S9xSetSoundMute (bool8 mute)

Call with a true parameter to prevent S9xMixSamples function from processing SNES sample data and instead just filling the return buffer with silent sound data. Useful if your sound system is interrupt or callback driven and the game has been paused either directly or indirectly because the user interacting with the emulator's user interface in some way.

bool8 S9xFreezeGame (const char *filepath)

Call this function to record the current SNES hardware state into a file, the file can be loaded back using S9xUnfreezeGame function at a later date effectively restoring the current game to exact same spot. Call this function while you're processing any pending system events when S9xMainLoop function has returned control to you in your main loop.

bool8 S9xUnfreezeGame (const char *filepath)

Restore the SNES hardware back to the exactly the state it was in when S9xFreezeGame function was used to generate the file specified. You have to arrange the correct ROM is already loaded using Memory.LoadROM function, an easy way to arrange this is to base freeze-game filenames on the ROM image name. The UNIX/Linux ports load freeze-game files when the user presses a function key, with the names romfilename.000 for F1, romfilename.001 for F2, etc. Games are frozen in the first place when the user presses Shift-function key. You could choose some other scheme.

void S9xDumpSPCSnapshot (void)

Call this funtion to make a so-called SPC file, a snapshot of SNES sound state. Actual dump occurs at the first key-on event after this function is called.

void S9xSetInfoString (const char *string)

Call this function if you want to show a message onto the SNES screen.

Other Available Functions

See movie.h and movie.cpp to support the Snes9x movie feature.
See cheats.h, cheats.cpp and cheats2.cpp to support the cheat feature.

Interface Functions You Need to Implement

bool8 S9xOpenSnapshotFile (const char *filepath, bool8 read_only, STREAM *file)

This function opens a freeze-game file. STREAM is defined as a gzFile if ZLIB is defined else it's defined as FILE *. The read_only parameter is set to true when reading a freeze-game file and false when writing a freeze-game file. Open the file filepath and return its pointer file.

void S9xCloseSnapshotFile (STREAM file)

This function closes the freeze-game file opened by S9xOpenSnapshotFile function.

void S9xExit (void)

Called when some fatal error situation arises or when the “q” debugger command is used.

bool8 S9xInitUpdate (void)

Called just before Snes9x begins to render an SNES screen. Use this function if you should prepare before drawing, otherwise let it empty.

bool8 S9xDeinitUpdate (int width, int height)

Called once a complete SNES screen has been rendered into the GFX.Screen memory buffer, now is your chance to copy the SNES rendered screen to the host computer's screen memory. The problem is that you have to cope with different sized SNES rendered screens: 256*224, 256*239, 512*224, 512*239, 512*448 and 512*478.

void S9xMessage (int type, int number, const char *message)

When Snes9x wants to display an error, information or warning message, it calls this function. Check in messages.h for the types and individual message numbers that Snes9x currently passes as parameters.
The idea is display the message string so the user can see it, but you choose not to display anything at all, or change the message based on the message number or message type.
Eventually all debug output will also go via this function, trace information already does.

bool8 S9xOpenSoundDevice (void)

S9xInitSound function calls this function to actually open the host sound device.

const char *S9xGetFilename (const char *extension, enum s9x_getdirtype dirtype)

When Snes9x needs to know the name of the cheat/IPS file and so on, this function is called. Check extension and dirtype, and return the appropriate filename. The current ports return the ROM file path with the given extension.

const char *S9xGetFilenameInc (const char *extension, enum s9x_getdirtype dirtype)

Almost the same as S9xGetFilename function, but used for saving SPC files etc. So you have to take care not to delete the previously saved file, by increasing the number of the filename; romname.000.spc, romname.001.spc, ...

const char *S9xGetDirectory (enum s9x_getdirtype dirtype)

Called when Snes9x wants to know the directory dirtype.

const char *S9xChooseFilename (bool8 read_only)

If your port can match Snes9x's built-in LoadFreezeFile/SaveFreezeFile command (see controls.cpp), you may choose to use this function. Otherwise return NULL.

const char *S9xChooseMovieFilename (bool8 read_only)

If your port can match Snes9x's built-in BeginRecordingMovie/LoadMovie command (see controls.cpp), you may choose to use this function. Otherwise return NULL.

const char *S9xBasename (const char *path)

Called when Snes9x wants to know the name of the ROM image. Typically, extract the filename from path and return it.

void S9xAutoSaveSRAM (void)

If Settings.AutoSaveDelay is not zero, Snes9x calls this function when the contents of the S-RAM has been changed. Typically, call Memory.SaveSRAM function from this function.

void S9xToggleSoundChannel (int c)

If your port can match Snes9x's built-in SoundChannelXXX command (see controls.cpp), you may choose to use this function. Otherwise return NULL. Basically, turn on/off the sound channel c (0-7), and turn on all channels if c is 8.

void S9xSetPalette (void)

Called when the SNES color palette has changed. Use this function if your system should change its color palette to match the SNES's. Otherwise let it empty.

void S9xSyncSpeed (void)

Called at the end of S9xMainLoop function, when emulating one frame has been done. You should adjust the frame rate in this function.

Global Variables

uint16 *GFX.Screen

A uint16 array pointer to (at least) 2*512*478 bytes buffer where Snes9x puts the rendered SNES screen. However, if your port will not support hires mode (Settings.SupportHiRes = false), then a 2*256*239 bytes buffer is allowed. You should allocate the space by yourself. As well you can change the GFX.Screen value after S9xDeinitUpdate function is called so that double-buffering will be easy.

uint32 GFX.Pitch

Bytes per line (not pixels per line) of the GFX.Screen buffer. Typically set it to 1024. When the SNES screen is 256 pixels width and Settings.OpenGLEnable is false, last half 512 bytes per line are unused. When Settings.OpenGLEnable is true, GFX.Pitch is ignored.

Settings structure

There are various switches in the Settings structure. See snes9x.h for details. At least the settings below are required for good emulation.

memset(&Settings, 0, sizeof(Settings));
Settings.MouseMaster = true;
Settings.SuperScopeMaster = true;
Settings.JustifierMaster = true;
Settings.MultiPlayer5Master = true;
Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667;
Settings.SixteenBitSound = true;
Settings.Stereo = true;
Settings.SoundPlaybackRate = 32000;
Settings.SoundInputRate = 32000;
Settings.SupportHiRes = true;
Settings.Transparency = true;
Settings.AutoDisplayMessages = true;
Settings.InitialInfoStringTimeout = 120;
Settings.HDMATimingHack = 100;
Settings.BlockInvalidVRAMAccessMaster = true;

Settings.SoundInputRate

Adjusts the sound rate through resampling. For every Settings.SoundInputRate samples generated by the SNES, Settings.SoundPlaybackRate samples will be produced.
The sound generation rate on a SNES is directly proportional to the video output rate. Displays that synchronize with the vertical refresh but have a slightly lower refresh-rate than the emulated system can experience sound drop-outs. It may be beneficial to provide an option for users to configure Settings.SoundInputRate to suit their own systems. Setting Settings.SoundInputRate to a value that matches the actual output rate (i.e. 31977hz for 59.96hz) or lower will allow the users to eliminate crackling. A range of 31000hz to 33000hz should be inclusive enough for all displays. Use of this setting paired with the S9xSyncSound function can eliminate sound discontinuity.

Updated most recently by: 2011/1/16 zones
libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters000664 001750 001750 00000015120 12720446475 022452 0ustar00sergiosergio000000 000000  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {7722f8be-0c98-4fd5-a919-d642e2bae1ce} {effa9675-f3f1-4f4e-a39c-171182a225b8} {e6d15138-760b-4651-ac48-7eaab1f67fec} {57cbef14-a9d6-45dd-9d6b-338d7b63a520} {161f54ee-3443-4972-afe1-b1931c65570b} Source Files\libretro Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files apu/bapu/dsp/SPC_DSP.h000664 001750 001750 00000017464 12720446475 015537 0ustar00sergiosergio000000 000000 // Highly accurate SNES SPC-700 DSP emulator // snes_spc 0.9.0 #ifndef SPC_DSP_H #define SPC_DSP_H #include "blargg_common.h" extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); } class SPC_DSP { public: typedef BOOST::uint8_t uint8_t; // Setup // Initializes DSP and has it use the 64K RAM provided void init( void* ram_64k ); // Sets destination for output samples. If out is NULL or out_size is 0, // doesn't generate any. typedef short sample_t; void set_output( sample_t* out, int out_size ); // Number of samples written to output since it was last set, always // a multiple of 2. Undefined if more samples were generated than // output buffer could hold. int sample_count() const; // Emulation // Resets DSP to power-on state void reset(); // Emulates pressing reset switch on SNES void soft_reset(); // Reads/writes DSP registers. For accuracy, you must first call run() // to catch the DSP up to present. int read ( int addr ) const; void write( int addr, int data ); // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks // a pair of samples is be generated. void run( int clock_count ); // Sound control // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). // Reduces emulation accuracy. enum { voice_count = 8 }; void mute_voices( int mask ); // State // Resets DSP and uses supplied values to initialize registers enum { register_count = 128 }; void load( uint8_t const regs [register_count] ); // Saves/loads exact emulator state enum { state_size = 640 }; // maximum space needed when saving typedef dsp_copy_func_t copy_func_t; void copy_state( unsigned char** io, copy_func_t ); // Returns non-zero if new key-on events occurred since last call bool check_kon(); // Snes9x Accessor int stereo_switch; int take_spc_snapshot; void (*spc_snapshot_callback) (void); void set_spc_snapshot_callback( void (*callback) (void) ); void dump_spc_snapshot( void ); void set_stereo_switch( int ); uint8_t reg_value( int, int ); int envx_value( int ); // DSP register addresses // Global registers enum { r_mvoll = 0x0C, r_mvolr = 0x1C, r_evoll = 0x2C, r_evolr = 0x3C, r_kon = 0x4C, r_koff = 0x5C, r_flg = 0x6C, r_endx = 0x7C, r_efb = 0x0D, r_pmon = 0x2D, r_non = 0x3D, r_eon = 0x4D, r_dir = 0x5D, r_esa = 0x6D, r_edl = 0x7D, r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F }; // Voice registers enum { v_voll = 0x00, v_volr = 0x01, v_pitchl = 0x02, v_pitchh = 0x03, v_srcn = 0x04, v_adsr0 = 0x05, v_adsr1 = 0x06, v_gain = 0x07, v_envx = 0x08, v_outx = 0x09 }; public: enum { extra_size = 16 }; sample_t* extra() { return m.extra; } sample_t const* out_pos() const { return m.out; } void disable_surround( bool ) { } // not supported public: BLARGG_DISABLE_NOTHROW typedef BOOST::int8_t int8_t; typedef BOOST::int16_t int16_t; enum { echo_hist_size = 8 }; enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; enum { brr_buf_size = 12 }; struct voice_t { int buf [brr_buf_size*2];// decoded samples (twice the size to simplify wrap handling) int buf_pos; // place in buffer where next samples will be decoded int interp_pos; // relative fractional position in sample (0x1000 = 1.0) int brr_addr; // address of current BRR block int brr_offset; // current decoding offset in BRR block uint8_t* regs; // pointer to voice's DSP registers int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc. int kon_delay; // KON delay/current setup phase env_mode_t env_mode; int env; // current envelope level int hidden_env; // used by GAIN mode 7, very obscure quirk uint8_t t_envx_out; int voice_number; }; private: enum { brr_block_size = 9 }; struct state_t { uint8_t regs [register_count]; // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) int echo_hist [echo_hist_size * 2] [2]; int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] int every_other_sample; // toggles every sample int kon; // KON value when last checked int noise; int counter; int echo_offset; // offset from ESA in echo buffer int echo_length; // number of bytes that echo_offset will stop at int phase; // next clock cycle to run (0-31) bool kon_check; // set when a new KON occurs // Hidden registers also written to when main register is written to int new_kon; uint8_t endx_buf; uint8_t envx_buf; uint8_t outx_buf; // Temporary state between clocks // read once per sample int t_pmon; int t_non; int t_eon; int t_dir; int t_koff; // read a few clocks ahead then used int t_brr_next_addr; int t_adsr0; int t_brr_header; int t_brr_byte; int t_srcn; int t_esa; int t_echo_enabled; // internal state that is recalculated every sample int t_dir_addr; int t_pitch; int t_output; int t_looped; int t_echo_ptr; // left/right sums int t_main_out [2]; int t_echo_out [2]; int t_echo_in [2]; voice_t voices [voice_count]; // non-emulation state uint8_t* ram; // 64K shared RAM between DSP and SMP int mute_mask; sample_t* out; sample_t* out_end; sample_t* out_begin; sample_t extra [extra_size]; }; state_t m; void init_counter(); void run_counters(); unsigned read_counter( int rate ); int interpolate( voice_t const* v ); void run_envelope( voice_t* const v ); void decode_brr( voice_t* v ); void misc_27(); void misc_28(); void misc_29(); void misc_30(); void voice_output( voice_t const* v, int ch ); void voice_V1( voice_t* const ); void voice_V2( voice_t* const ); void voice_V3( voice_t* const ); void voice_V3a( voice_t* const ); void voice_V3b( voice_t* const ); void voice_V3c( voice_t* const ); void voice_V4( voice_t* const ); void voice_V5( voice_t* const ); void voice_V6( voice_t* const ); void voice_V7( voice_t* const ); void voice_V8( voice_t* const ); void voice_V9( voice_t* const ); void voice_V7_V4_V1( voice_t* const ); void voice_V8_V5_V2( voice_t* const ); void voice_V9_V6_V3( voice_t* const ); void echo_read( int ch ); int echo_output( int ch ); void echo_write( int ch ); void echo_22(); void echo_23(); void echo_24(); void echo_25(); void echo_26(); void echo_27(); void echo_28(); void echo_29(); void echo_30(); void soft_reset_common(); }; #include inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; } inline int SPC_DSP::read( int addr ) const { assert( (unsigned) addr < register_count ); return m.regs [addr]; } inline void SPC_DSP::write( int addr, int data ) { assert( (unsigned) addr < register_count ); m.regs [addr] = (uint8_t) data; switch ( addr & 0x0F ) { case v_envx: m.envx_buf = (uint8_t) data; break; case v_outx: m.outx_buf = (uint8_t) data; break; case 0x0C: if ( addr == r_kon ) m.new_kon = (uint8_t) data; if ( addr == r_endx ) // always cleared, regardless of data written { m.endx_buf = 0; m.regs [r_endx] = 0; } break; } } inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; } inline bool SPC_DSP::check_kon() { bool old = m.kon_check; m.kon_check = 0; return old; } #if !SPC_NO_COPY_STATE_FUNCS class SPC_State_Copier { SPC_DSP::copy_func_t func; unsigned char** buf; public: SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; } void copy( void* state, size_t size ); int copy_int( int state, int size ); void skip( int count ); void extra(); }; #define SPC_COPY( type, state )\ {\ state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\ assert( (BOOST::type) state == state );\ } #endif #endif ppu.cpp000664 001750 001750 00000140142 12720446475 013227 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "dma.h" #include "apu/apu.h" #include "fxemu.h" #include "sdd1.h" #include "srtc.h" #include "controls.h" #include "movie.h" #include "display.h" #ifdef NETPLAY_SUPPORT #include "netplay.h" #endif #ifdef DEBUGGER #include "debug.h" #include "missing.h" #endif extern uint8 *HDMAMemPointers[8]; static inline void S9xLatchCounters (bool force) { if (force || (Memory.FillRAM[0x4213] & 0x80)) { // Latch h and v counters, like the gun #ifdef DEBUGGER missing.h_v_latch = 1; #endif PPU.HVBeamCounterLatched = 1; PPU.VBeamPosLatched = (uint16) CPU.V_Counter; // From byuu: // All dots are 4 cycles long, except dots 322 and 326. dots 322 and 326 are 6 cycles long. // This holds true for all scanlines except scanline 240 on non-interlace odd frames. // The reason for this is because this scanline is only 1360 cycles long, // instead of 1364 like all other scanlines. // This makes the effective range of hscan_pos 0-339 at all times. int32 hc = CPU.Cycles; if (Timings.H_Max == Timings.H_Max_Master) // 1364 { if (hc >= 1292) hc -= (ONE_DOT_CYCLE / 2); if (hc >= 1308) hc -= (ONE_DOT_CYCLE / 2); } PPU.HBeamPosLatched = (uint16) (hc / ONE_DOT_CYCLE); Memory.FillRAM[0x213f] |= 0x40; } if (CPU.V_Counter > PPU.GunVLatch || (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE)) PPU.GunVLatch = 1000; } static inline void S9xTryGunLatch (bool force) { if (CPU.V_Counter > PPU.GunVLatch || (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE)) { if (force || (Memory.FillRAM[0x4213] & 0x80)) { #ifdef DEBUGGER missing.h_v_latch = 1; #endif PPU.HVBeamCounterLatched = 1; PPU.VBeamPosLatched = (uint16) PPU.GunVLatch; PPU.HBeamPosLatched = (uint16) PPU.GunHLatch; Memory.FillRAM[0x213f] |= 0x40; } PPU.GunVLatch = 1000; } } void S9xUpdateHVTimerPosition (void) { PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles; if (Timings.H_Max == Timings.H_Max_Master) // 1364 { if (PPU.IRQHBeamPos > 322) PPU.HTimerPosition += (ONE_DOT_CYCLE / 2); if (PPU.IRQHBeamPos > 326) PPU.HTimerPosition += (ONE_DOT_CYCLE / 2); } PPU.VTimerPosition = PPU.IRQVBeamPos; if ((PPU.HTimerPosition >= Timings.H_Max) && (PPU.IRQHBeamPos < 340)) { PPU.HTimerPosition -= Timings.H_Max; PPU.VTimerPosition++; // FIXME if (PPU.VTimerPosition >= Timings.V_Max) PPU.VTimerPosition = 0; } #ifdef DEBUGGER S9xTraceFormattedMessage("--- IRQ Timer set HTimer:%d Pos:%04d VTimer:%d Pos:%03d", PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); #endif } void S9xFixColourBrightness (void) { IPPU.XB = mul_brightness[PPU.Brightness]; for (int i = 0; i < 256; i++) { IPPU.Red[i] = IPPU.XB[(PPU.CGDATA[i]) & 0x1f]; IPPU.Green[i] = IPPU.XB[(PPU.CGDATA[i] >> 5) & 0x1f]; IPPU.Blue[i] = IPPU.XB[(PPU.CGDATA[i] >> 10) & 0x1f]; IPPU.ScreenColors[i] = BUILD_PIXEL(IPPU.Red[i], IPPU.Green[i], IPPU.Blue[i]); } } void S9xSetPPU (uint8 Byte, uint16 Address) { // MAP_PPU: $2000-$3FFF if (CPU.InDMAorHDMA) { if (CPU.CurrentDMAorHDMAChannel >= 0 && DMA[CPU.CurrentDMAorHDMAChannel].ReverseTransfer) { // S9xSetPPU() is called to write to DMA[].AAddress if ((Address & 0xff00) == 0x2100) { // Cannot access to Address Bus B ($2100-$21ff) via (H)DMA return; } else { // 0x2000-0x3FFF is connected to Address Bus A // SA1, SuperFX and SRTC are mapped here // I don't bother for now... return; } } else { // S9xSetPPU() is called to read from $21xx // Take care of DMA wrapping if (Address > 0x21ff) Address = 0x2100 + (Address & 0xff); } } #ifdef DEBUGGER if (CPU.InHDMA) S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte); #endif if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3 // write_port will run the APU until given clock before writing value S9xAPUWritePort(Address & 3, Byte); else if (Address <= 0x2183) { switch (Address) { case 0x2100: // INIDISP if (Byte != Memory.FillRAM[0x2100]) { FLUSH_REDRAW(); if (PPU.Brightness != (Byte & 0xf)) { IPPU.ColorsChanged = TRUE; IPPU.DirectColourMapsNeedRebuild = TRUE; PPU.Brightness = Byte & 0xf; S9xFixColourBrightness(); if (PPU.Brightness > IPPU.MaxBrightness) IPPU.MaxBrightness = PPU.Brightness; } if ((Memory.FillRAM[0x2100] & 0x80) != (Byte & 0x80)) { IPPU.ColorsChanged = TRUE; PPU.ForcedBlanking = (Byte >> 7) & 1; } } if ((Memory.FillRAM[0x2100] & 0x80) && CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) { PPU.OAMAddr = PPU.SavedOAMAddr; uint8 tmp = 0; if (PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr & 0xfe) >> 1; if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) { PPU.FirstSprite = tmp; IPPU.OBJChanged = TRUE; } PPU.OAMFlip = 0; } break; case 0x2101: // OBSEL if (Byte != Memory.FillRAM[0x2101]) { FLUSH_REDRAW(); PPU.OBJNameBase = (Byte & 3) << 14; PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13; PPU.OBJSizeSelect = (Byte >> 5) & 7; IPPU.OBJChanged = TRUE; } break; case 0x2102: // OAMADDL PPU.OAMAddr = ((Memory.FillRAM[0x2103] & 1) << 8) | Byte; PPU.OAMFlip = 2; PPU.OAMReadFlip = 0; PPU.SavedOAMAddr = PPU.OAMAddr; if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; #ifdef DEBUGGER missing.sprite_priority_rotation = 1; #endif } break; case 0x2103: // OAMADDH PPU.OAMAddr = ((Byte & 1) << 8) | Memory.FillRAM[0x2102]; PPU.OAMPriorityRotation = (Byte & 0x80) ? 1 : 0; if (PPU.OAMPriorityRotation) { if (PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; #ifdef DEBUGGER missing.sprite_priority_rotation = 1; #endif } } else { if (PPU.FirstSprite != 0) { PPU.FirstSprite = 0; IPPU.OBJChanged = TRUE; #ifdef DEBUGGER missing.sprite_priority_rotation = 1; #endif } } PPU.OAMFlip = 0; PPU.OAMReadFlip = 0; PPU.SavedOAMAddr = PPU.OAMAddr; break; case 0x2104: // OAMDATA REGISTER_2104(Byte); break; case 0x2105: // BGMODE if (Byte != Memory.FillRAM[0x2105]) { FLUSH_REDRAW(); PPU.BG[0].BGSize = (Byte >> 4) & 1; PPU.BG[1].BGSize = (Byte >> 5) & 1; PPU.BG[2].BGSize = (Byte >> 6) & 1; PPU.BG[3].BGSize = (Byte >> 7) & 1; PPU.BGMode = Byte & 7; // BJ: BG3Priority only takes effect if BGMode == 1 and the bit is set PPU.BG3Priority = ((Byte & 0x0f) == 0x09); IPPU.Interlace = Memory.FillRAM[0x2133] & 1; #ifdef DEBUGGER missing.modes[PPU.BGMode] = 1; #endif } break; case 0x2106: // MOSAIC if (Byte != Memory.FillRAM[0x2106]) { FLUSH_REDRAW(); PPU.MosaicStart = CPU.V_Counter; if (PPU.MosaicStart > PPU.ScreenHeight) PPU.MosaicStart = 0; PPU.Mosaic = (Byte >> 4) + 1; PPU.BGMosaic[0] = (Byte & 1); PPU.BGMosaic[1] = (Byte & 2); PPU.BGMosaic[2] = (Byte & 4); PPU.BGMosaic[3] = (Byte & 8); #ifdef DEBUGGER if ((Byte & 0xf0) && (Byte & 0x0f)) missing.mosaic = 1; #endif } break; case 0x2107: // BG1SC if (Byte != Memory.FillRAM[0x2107]) { FLUSH_REDRAW(); PPU.BG[0].SCSize = Byte & 3; PPU.BG[0].SCBase = (Byte & 0x7c) << 8; } break; case 0x2108: // BG2SC if (Byte != Memory.FillRAM[0x2108]) { FLUSH_REDRAW(); PPU.BG[1].SCSize = Byte & 3; PPU.BG[1].SCBase = (Byte & 0x7c) << 8; } break; case 0x2109: // BG3SC if (Byte != Memory.FillRAM[0x2109]) { FLUSH_REDRAW(); PPU.BG[2].SCSize = Byte & 3; PPU.BG[2].SCBase = (Byte & 0x7c) << 8; } break; case 0x210a: // BG4SC if (Byte != Memory.FillRAM[0x210a]) { FLUSH_REDRAW(); PPU.BG[3].SCSize = Byte & 3; PPU.BG[3].SCBase = (Byte & 0x7c) << 8; } break; case 0x210b: // BG12NBA if (Byte != Memory.FillRAM[0x210b]) { FLUSH_REDRAW(); PPU.BG[0].NameBase = (Byte & 7) << 12; PPU.BG[1].NameBase = ((Byte >> 4) & 7) << 12; } break; case 0x210c: // BG34NBA if (Byte != Memory.FillRAM[0x210c]) { FLUSH_REDRAW(); PPU.BG[2].NameBase = (Byte & 7) << 12; PPU.BG[3].NameBase = ((Byte >> 4) & 7) << 12; } break; case 0x210d: // BG1HOFS, M7HOFS PPU.BG[0].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[0].HOffset >> 8) & 7); PPU.M7HOFS = (Byte << 8) | PPU.M7byte; PPU.BGnxOFSbyte = Byte; PPU.M7byte = Byte; break; case 0x210e: // BG1VOFS, M7VOFS PPU.BG[0].VOffset = (Byte << 8) | PPU.BGnxOFSbyte; PPU.M7VOFS = (Byte << 8) | PPU.M7byte; PPU.BGnxOFSbyte = Byte; PPU.M7byte = Byte; break; case 0x210f: // BG2HOFS PPU.BG[1].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[1].HOffset >> 8) & 7); PPU.BGnxOFSbyte = Byte; break; case 0x2110: // BG2VOFS PPU.BG[1].VOffset = (Byte << 8) | PPU.BGnxOFSbyte; PPU.BGnxOFSbyte = Byte; break; case 0x2111: // BG3HOFS PPU.BG[2].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[2].HOffset >> 8) & 7); PPU.BGnxOFSbyte = Byte; break; case 0x2112: // BG3VOFS PPU.BG[2].VOffset = (Byte << 8) | PPU.BGnxOFSbyte; PPU.BGnxOFSbyte = Byte; break; case 0x2113: // BG4HOFS PPU.BG[3].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[3].HOffset >> 8) & 7); PPU.BGnxOFSbyte = Byte; break; case 0x2114: // BG4VOFS PPU.BG[3].VOffset = (Byte << 8) | PPU.BGnxOFSbyte; PPU.BGnxOFSbyte = Byte; break; case 0x2115: // VMAIN PPU.VMA.High = (Byte & 0x80) == 0 ? FALSE : TRUE; switch (Byte & 3) { case 0: PPU.VMA.Increment = 1; break; case 1: PPU.VMA.Increment = 32; break; case 2: PPU.VMA.Increment = 128; break; case 3: PPU.VMA.Increment = 128; break; } if (Byte & 0x0c) { static uint16 Shift[4] = { 0, 5, 6, 7 }; static uint16 IncCount[4] = { 0, 32, 64, 128 }; uint8 i = (Byte & 0x0c) >> 2; PPU.VMA.FullGraphicCount = IncCount[i]; PPU.VMA.Mask1 = IncCount[i] * 8 - 1; PPU.VMA.Shift = Shift[i]; #ifdef DEBUGGER missing.vram_full_graphic_inc = (Byte & 0x0c) >> 2; #endif } else PPU.VMA.FullGraphicCount = 0; #ifdef DEBUGGER if (Byte & 3) missing.vram_inc = Byte & 3; #endif break; case 0x2116: // VMADDL PPU.VMA.Address &= 0xff00; PPU.VMA.Address |= Byte; if (PPU.VMA.FullGraphicCount) { uint32 addr = PPU.VMA.Address; uint32 rem = addr & PPU.VMA.Mask1; uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((address << 1) & 0xffff)); } else IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); break; case 0x2117: // VMADDH PPU.VMA.Address &= 0x00ff; PPU.VMA.Address |= Byte << 8; if (PPU.VMA.FullGraphicCount) { uint32 addr = PPU.VMA.Address; uint32 rem = addr & PPU.VMA.Mask1; uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((address << 1) & 0xffff)); } else IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); break; case 0x2118: // VMDATAL REGISTER_2118(Byte); break; case 0x2119: // VMDATAH REGISTER_2119(Byte); break; case 0x211a: // M7SEL if (Byte != Memory.FillRAM[0x211a]) { FLUSH_REDRAW(); PPU.Mode7Repeat = Byte >> 6; if (PPU.Mode7Repeat == 1) PPU.Mode7Repeat = 0; PPU.Mode7VFlip = (Byte & 2) >> 1; PPU.Mode7HFlip = Byte & 1; } break; case 0x211b: // M7A PPU.MatrixA = PPU.M7byte | (Byte << 8); PPU.Need16x8Mulitply = TRUE; PPU.M7byte = Byte; break; case 0x211c: // M7B PPU.MatrixB = PPU.M7byte | (Byte << 8); PPU.Need16x8Mulitply = TRUE; PPU.M7byte = Byte; break; case 0x211d: // M7C PPU.MatrixC = PPU.M7byte | (Byte << 8); PPU.M7byte = Byte; break; case 0x211e: // M7D PPU.MatrixD = PPU.M7byte | (Byte << 8); PPU.M7byte = Byte; break; case 0x211f: // M7X PPU.CentreX = PPU.M7byte | (Byte << 8); PPU.M7byte = Byte; break; case 0x2120: // M7Y PPU.CentreY = PPU.M7byte | (Byte << 8); PPU.M7byte = Byte; break; case 0x2121: // CGADD PPU.CGFLIP = 0; PPU.CGFLIPRead = 0; PPU.CGADD = Byte; break; case 0x2122: // CGDATA REGISTER_2122(Byte); break; case 0x2123: // W12SEL if (Byte != Memory.FillRAM[0x2123]) { FLUSH_REDRAW(); PPU.ClipWindow1Enable[0] = !!(Byte & 0x02); PPU.ClipWindow1Enable[1] = !!(Byte & 0x20); PPU.ClipWindow2Enable[0] = !!(Byte & 0x08); PPU.ClipWindow2Enable[1] = !!(Byte & 0x80); PPU.ClipWindow1Inside[0] = !(Byte & 0x01); PPU.ClipWindow1Inside[1] = !(Byte & 0x10); PPU.ClipWindow2Inside[0] = !(Byte & 0x04); PPU.ClipWindow2Inside[1] = !(Byte & 0x40); PPU.RecomputeClipWindows = TRUE; #ifdef DEBUGGER if (Byte & 0x80) missing.window2[1] = 1; if (Byte & 0x20) missing.window1[1] = 1; if (Byte & 0x08) missing.window2[0] = 1; if (Byte & 0x02) missing.window1[0] = 1; #endif } break; case 0x2124: // W34SEL if (Byte != Memory.FillRAM[0x2124]) { FLUSH_REDRAW(); PPU.ClipWindow1Enable[2] = !!(Byte & 0x02); PPU.ClipWindow1Enable[3] = !!(Byte & 0x20); PPU.ClipWindow2Enable[2] = !!(Byte & 0x08); PPU.ClipWindow2Enable[3] = !!(Byte & 0x80); PPU.ClipWindow1Inside[2] = !(Byte & 0x01); PPU.ClipWindow1Inside[3] = !(Byte & 0x10); PPU.ClipWindow2Inside[2] = !(Byte & 0x04); PPU.ClipWindow2Inside[3] = !(Byte & 0x40); PPU.RecomputeClipWindows = TRUE; #ifdef DEBUGGER if (Byte & 0x80) missing.window2[3] = 1; if (Byte & 0x20) missing.window1[3] = 1; if (Byte & 0x08) missing.window2[2] = 1; if (Byte & 0x02) missing.window1[2] = 1; #endif } break; case 0x2125: // WOBJSEL if (Byte != Memory.FillRAM[0x2125]) { FLUSH_REDRAW(); PPU.ClipWindow1Enable[4] = !!(Byte & 0x02); PPU.ClipWindow1Enable[5] = !!(Byte & 0x20); PPU.ClipWindow2Enable[4] = !!(Byte & 0x08); PPU.ClipWindow2Enable[5] = !!(Byte & 0x80); PPU.ClipWindow1Inside[4] = !(Byte & 0x01); PPU.ClipWindow1Inside[5] = !(Byte & 0x10); PPU.ClipWindow2Inside[4] = !(Byte & 0x04); PPU.ClipWindow2Inside[5] = !(Byte & 0x40); PPU.RecomputeClipWindows = TRUE; #ifdef DEBUGGER if (Byte & 0x80) missing.window2[5] = 1; if (Byte & 0x20) missing.window1[5] = 1; if (Byte & 0x08) missing.window2[4] = 1; if (Byte & 0x02) missing.window1[4] = 1; #endif } break; case 0x2126: // WH0 if (Byte != Memory.FillRAM[0x2126]) { FLUSH_REDRAW(); PPU.Window1Left = Byte; PPU.RecomputeClipWindows = TRUE; } break; case 0x2127: // WH1 if (Byte != Memory.FillRAM[0x2127]) { FLUSH_REDRAW(); PPU.Window1Right = Byte; PPU.RecomputeClipWindows = TRUE; } break; case 0x2128: // WH2 if (Byte != Memory.FillRAM[0x2128]) { FLUSH_REDRAW(); PPU.Window2Left = Byte; PPU.RecomputeClipWindows = TRUE; } break; case 0x2129: // WH3 if (Byte != Memory.FillRAM[0x2129]) { FLUSH_REDRAW(); PPU.Window2Right = Byte; PPU.RecomputeClipWindows = TRUE; } break; case 0x212a: // WBGLOG if (Byte != Memory.FillRAM[0x212a]) { FLUSH_REDRAW(); PPU.ClipWindowOverlapLogic[0] = (Byte & 0x03); PPU.ClipWindowOverlapLogic[1] = (Byte & 0x0c) >> 2; PPU.ClipWindowOverlapLogic[2] = (Byte & 0x30) >> 4; PPU.ClipWindowOverlapLogic[3] = (Byte & 0xc0) >> 6; PPU.RecomputeClipWindows = TRUE; } break; case 0x212b: // WOBJLOG if (Byte != Memory.FillRAM[0x212b]) { FLUSH_REDRAW(); PPU.ClipWindowOverlapLogic[4] = (Byte & 0x03); PPU.ClipWindowOverlapLogic[5] = (Byte & 0x0c) >> 2; PPU.RecomputeClipWindows = TRUE; } break; case 0x212c: // TM if (Byte != Memory.FillRAM[0x212c]) { FLUSH_REDRAW(); PPU.RecomputeClipWindows = TRUE; } break; case 0x212d: // TS if (Byte != Memory.FillRAM[0x212d]) { FLUSH_REDRAW(); PPU.RecomputeClipWindows = TRUE; #ifdef DEBUGGER if (Byte & 0x1f) missing.subscreen = 1; #endif } break; case 0x212e: // TMW if (Byte != Memory.FillRAM[0x212e]) { FLUSH_REDRAW(); PPU.RecomputeClipWindows = TRUE; } break; case 0x212f: // TSW if (Byte != Memory.FillRAM[0x212f]) { FLUSH_REDRAW(); PPU.RecomputeClipWindows = TRUE; } break; case 0x2130: // CGWSEL if (Byte != Memory.FillRAM[0x2130]) { FLUSH_REDRAW(); PPU.RecomputeClipWindows = TRUE; #ifdef DEBUGGER if ((Byte & 1) && (PPU.BGMode == 3 || PPU.BGMode == 4 || PPU.BGMode == 7)) missing.direct = 1; #endif } break; case 0x2131: // CGADSUB if (Byte != Memory.FillRAM[0x2131]) { FLUSH_REDRAW(); #ifdef DEBUGGER if (Byte & 0x80) { if (Memory.FillRAM[0x2130] & 0x02) missing.subscreen_sub = 1; else missing.fixed_colour_sub = 1; } else { if (Memory.FillRAM[0x2130] & 0x02) missing.subscreen_add = 1; else missing.fixed_colour_add = 1; } #endif } break; case 0x2132: // COLDATA if (Byte != Memory.FillRAM[0x2132]) { FLUSH_REDRAW(); if (Byte & 0x80) PPU.FixedColourBlue = Byte & 0x1f; if (Byte & 0x40) PPU.FixedColourGreen = Byte & 0x1f; if (Byte & 0x20) PPU.FixedColourRed = Byte & 0x1f; } break; case 0x2133: // SETINI if (Byte != Memory.FillRAM[0x2133]) { if ((Memory.FillRAM[0x2133] ^ Byte) & 8) { FLUSH_REDRAW(); IPPU.PseudoHires = Byte & 8; } if (Byte & 0x04) { PPU.ScreenHeight = SNES_HEIGHT_EXTENDED; if (IPPU.DoubleHeightPixels) IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; else IPPU.RenderedScreenHeight = PPU.ScreenHeight; #ifdef DEBUGGER missing.lines_239 = 1; #endif } else PPU.ScreenHeight = SNES_HEIGHT; if ((Memory.FillRAM[0x2133] ^ Byte) & 3) { FLUSH_REDRAW(); if ((Memory.FillRAM[0x2133] ^ Byte) & 2) IPPU.OBJChanged = TRUE; IPPU.Interlace = Byte & 1; IPPU.InterlaceOBJ = Byte & 2; } #ifdef DEBUGGER if (Byte & 0x40) missing.mode7_bgmode = 1; if (Byte & 0x08) missing.pseudo_512 = 1; if (Byte & 0x02) missing.sprite_double_height = 1; if (Byte & 0x01) missing.interlace = 1; #endif } break; case 0x2134: // MPYL case 0x2135: // MPYM case 0x2136: // MPYH case 0x2137: // SLHV case 0x2138: // OAMDATAREAD case 0x2139: // VMDATALREAD case 0x213a: // VMDATAHREAD case 0x213b: // CGDATAREAD case 0x213c: // OPHCT case 0x213d: // OPVCT case 0x213e: // STAT77 case 0x213f: // STAT78 return; case 0x2180: // WMDATA if (!CPU.InWRAMDMAorHDMA) REGISTER_2180(Byte); break; case 0x2181: // WMADDL if (!CPU.InWRAMDMAorHDMA) { PPU.WRAM &= 0x1ff00; PPU.WRAM |= Byte; } break; case 0x2182: // WMADDM if (!CPU.InWRAMDMAorHDMA) { PPU.WRAM &= 0x100ff; PPU.WRAM |= Byte << 8; } break; case 0x2183: // WMADDH if (!CPU.InWRAMDMAorHDMA) { PPU.WRAM &= 0x0ffff; PPU.WRAM |= Byte << 16; PPU.WRAM &= 0x1ffff; } break; } } else { if (Settings.SuperFX && Address >= 0x3000 && Address <= 0x32ff) { S9xSetSuperFX(Byte, Address); return; } else if (Settings.SA1 && Address >= 0x2200) { if (Address <= 0x23ff) S9xSetSA1(Byte, Address); else Memory.FillRAM[Address] = Byte; return; } else if (Settings.BS && Address >= 0x2188 && Address <= 0x219f) S9xSetBSXPPU(Byte, Address); else if (Settings.SRTC && Address == 0x2801) S9xSetSRTC(Byte, Address); #ifdef DEBUGGER else { missing.unknownppu_write = Address; if (Settings.TraceUnknownRegisters) { sprintf(String, "Unknown register write: $%02X->$%04X\n", Byte, Address); S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String); } } #endif } Memory.FillRAM[Address] = Byte; } uint8 S9xGetPPU (uint16 Address) { // MAP_PPU: $2000-$3FFF if (Address < 0x2100) return (OpenBus); if (CPU.InDMAorHDMA) { if (CPU.CurrentDMAorHDMAChannel >= 0 && !DMA[CPU.CurrentDMAorHDMAChannel].ReverseTransfer) { // S9xGetPPU() is called to read from DMA[].AAddress if ((Address & 0xff00) == 0x2100) // Cannot access to Address Bus B ($2100-$21FF) via (H)DMA return (OpenBus); else // $2200-$3FFF are connected to Address Bus A // SA1, SuperFX and SRTC are mapped here // I don't bother for now... return (OpenBus); } else { // S9xGetPPU() is called to write to $21xx // Take care of DMA wrapping if (Address > 0x21ff) Address = 0x2100 + (Address & 0xff); } } if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3 // read_port will run the APU until given APU time before reading value return (S9xAPUReadPort(Address & 3)); else if (Address <= 0x2183) { uint8 byte; switch (Address) { case 0x2104: // OAMDATA case 0x2105: // BGMODE case 0x2106: // MOSAIC case 0x2108: // BG2SC case 0x2109: // BG3SC case 0x210a: // BG4SC case 0x2114: // BG4VOFS case 0x2115: // VMAIN case 0x2116: // VMADDL case 0x2118: // VMDATAL case 0x2119: // VMDATAH case 0x211a: // M7SEL case 0x2124: // W34SEL case 0x2125: // WOBJSEL case 0x2126: // WH0 case 0x2128: // WH2 case 0x2129: // WH3 case 0x212a: // WBGLOG return (PPU.OpenBus1); case 0x2134: // MPYL case 0x2135: // MPYM case 0x2136: // MPYH if (PPU.Need16x8Mulitply) { int32 r = (int32) PPU.MatrixA * (int32) (PPU.MatrixB >> 8); Memory.FillRAM[0x2134] = (uint8) r; Memory.FillRAM[0x2135] = (uint8) (r >> 8); Memory.FillRAM[0x2136] = (uint8) (r >> 16); PPU.Need16x8Mulitply = FALSE; } #ifdef DEBUGGER missing.matrix_multiply = 1; #endif return (PPU.OpenBus1 = Memory.FillRAM[Address]); case 0x2137: // SLHV S9xLatchCounters(0); return (OpenBus); case 0x2138: // OAMDATAREAD if (PPU.OAMAddr & 0x100) { if (!(PPU.OAMFlip & 1)) byte = PPU.OAMData[(PPU.OAMAddr & 0x10f) << 1]; else { byte = PPU.OAMData[((PPU.OAMAddr & 0x10f) << 1) + 1]; PPU.OAMAddr = (PPU.OAMAddr + 1) & 0x1ff; if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; #ifdef DEBUGGER missing.sprite_priority_rotation = 1; #endif } } } else { if (!(PPU.OAMFlip & 1)) byte = PPU.OAMData[PPU.OAMAddr << 1]; else { byte = PPU.OAMData[(PPU.OAMAddr << 1) + 1]; ++PPU.OAMAddr; if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; #ifdef DEBUGGER missing.sprite_priority_rotation = 1; #endif } } } PPU.OAMFlip ^= 1; #ifdef DEBUGGER missing.oam_read = 1; #endif return (PPU.OpenBus1 = byte); case 0x2139: // VMDATALREAD byte = IPPU.VRAMReadBuffer & 0xff; if (!PPU.VMA.High) { if (PPU.VMA.FullGraphicCount) { uint32 addr = PPU.VMA.Address; uint32 rem = addr & PPU.VMA.Mask1; uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((address << 1) & 0xffff)); } else IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); PPU.VMA.Address += PPU.VMA.Increment; } #ifdef DEBUGGER missing.vram_read = 1; #endif return (PPU.OpenBus1 = byte); case 0x213a: // VMDATAHREAD byte = (IPPU.VRAMReadBuffer >> 8) & 0xff; if (PPU.VMA.High) { if (PPU.VMA.FullGraphicCount) { uint32 addr = PPU.VMA.Address; uint32 rem = addr & PPU.VMA.Mask1; uint32 address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((address << 1) & 0xffff)); } else IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); PPU.VMA.Address += PPU.VMA.Increment; } #ifdef DEBUGGER missing.vram_read = 1; #endif return (PPU.OpenBus1 = byte); case 0x213b: // CGDATAREAD if (PPU.CGFLIPRead) byte = (PPU.OpenBus2 & 0x80) | ((PPU.CGDATA[PPU.CGADD++] >> 8) & 0x7f); else byte = PPU.CGDATA[PPU.CGADD] & 0xff; PPU.CGFLIPRead ^= 1; #ifdef DEBUGGER missing.cgram_read = 1; #endif return (PPU.OpenBus2 = byte); case 0x213c: // OPHCT S9xTryGunLatch(false); if (PPU.HBeamFlip) byte = (PPU.OpenBus2 & 0xfe) | ((PPU.HBeamPosLatched >> 8) & 0x01); else byte = (uint8) PPU.HBeamPosLatched; PPU.HBeamFlip ^= 1; #ifdef DEBUGGER missing.h_counter_read = 1; #endif return (PPU.OpenBus2 = byte); case 0x213d: // OPVCT S9xTryGunLatch(false); if (PPU.VBeamFlip) byte = (PPU.OpenBus2 & 0xfe) | ((PPU.VBeamPosLatched >> 8) & 0x01); else byte = (uint8) PPU.VBeamPosLatched; PPU.VBeamFlip ^= 1; #ifdef DEBUGGER missing.v_counter_read = 1; #endif return (PPU.OpenBus2 = byte); case 0x213e: // STAT77 FLUSH_REDRAW(); byte = (PPU.OpenBus1 & 0x10) | PPU.RangeTimeOver | Model->_5C77; return (PPU.OpenBus1 = byte); case 0x213f: // STAT78 S9xTryGunLatch(false); PPU.VBeamFlip = PPU.HBeamFlip = 0; byte = (PPU.OpenBus2 & 0x20) | (Memory.FillRAM[0x213f] & 0xc0) | (Settings.PAL ? 0x10 : 0) | Model->_5C78; Memory.FillRAM[0x213f] &= ~0x40; return (PPU.OpenBus2 = byte); case 0x2180: // WMDATA if (!CPU.InWRAMDMAorHDMA) { byte = Memory.RAM[PPU.WRAM++]; PPU.WRAM &= 0x1ffff; } else byte = OpenBus; #ifdef DEBUGGER missing.wram_read = 1; #endif return (byte); default: return (OpenBus); } } else { if (Settings.SuperFX && Address >= 0x3000 && Address <= 0x32ff) return (S9xGetSuperFX(Address)); else if (Settings.SA1 && Address >= 0x2200) return (S9xGetSA1(Address)); else if (Settings.BS && Address >= 0x2188 && Address <= 0x219f) return (S9xGetBSXPPU(Address)); else if (Settings.SRTC && Address == 0x2800) return (S9xGetSRTC(Address)); else switch (Address) { case 0x21c2: if (Model->_5C77 == 2) return (0x20); return (OpenBus); case 0x21c3: if (Model->_5C77 == 2) return (0); return (OpenBus); default: return (OpenBus); } } } void S9xSetCPU (uint8 Byte, uint16 Address) { if (Address < 0x4200) { switch (Address) { case 0x4016: // JOYSER0 S9xSetJoypadLatch(Byte & 1); break; case 0x4017: // JOYSER1 return; default: break; } } else if ((Address & 0xff80) == 0x4300) { if (CPU.InDMAorHDMA) return; int d = (Address >> 4) & 0x7; switch (Address & 0xf) { case 0x0: // 0x43x0: DMAPx DMA[d].ReverseTransfer = (Byte & 0x80) ? TRUE : FALSE; DMA[d].HDMAIndirectAddressing = (Byte & 0x40) ? TRUE : FALSE; DMA[d].UnusedBit43x0 = (Byte & 0x20) ? TRUE : FALSE; DMA[d].AAddressDecrement = (Byte & 0x10) ? TRUE : FALSE; DMA[d].AAddressFixed = (Byte & 0x08) ? TRUE : FALSE; DMA[d].TransferMode = (Byte & 7); return; case 0x1: // 0x43x1: BBADx DMA[d].BAddress = Byte; return; case 0x2: // 0x43x2: A1TxL DMA[d].AAddress &= 0xff00; DMA[d].AAddress |= Byte; return; case 0x3: // 0x43x3: A1TxH DMA[d].AAddress &= 0xff; DMA[d].AAddress |= Byte << 8; return; case 0x4: // 0x43x4: A1Bx DMA[d].ABank = Byte; HDMAMemPointers[d] = NULL; return; case 0x5: // 0x43x5: DASxL DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff00; DMA[d].DMACount_Or_HDMAIndirectAddress |= Byte; HDMAMemPointers[d] = NULL; return; case 0x6: // 0x43x6: DASxH DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff; DMA[d].DMACount_Or_HDMAIndirectAddress |= Byte << 8; HDMAMemPointers[d] = NULL; return; case 0x7: // 0x43x7: DASBx DMA[d].IndirectBank = Byte; HDMAMemPointers[d] = NULL; return; case 0x8: // 0x43x8: A2AxL DMA[d].Address &= 0xff00; DMA[d].Address |= Byte; HDMAMemPointers[d] = NULL; return; case 0x9: // 0x43x9: A2AxH DMA[d].Address &= 0xff; DMA[d].Address |= Byte << 8; HDMAMemPointers[d] = NULL; return; case 0xa: // 0x43xa: NLTRx if (Byte & 0x7f) { DMA[d].LineCount = Byte & 0x7f; DMA[d].Repeat = !(Byte & 0x80); } else { DMA[d].LineCount = 128; DMA[d].Repeat = !!(Byte & 0x80); } return; case 0xb: // 0x43xb: ????x case 0xf: // 0x43xf: mirror of 0x43xb DMA[d].UnknownByte = Byte; return; default: break; } } else { uint16 pos; switch (Address) { case 0x4200: // NMITIMEN if (Byte & 0x20) { PPU.VTimerEnabled = TRUE; #ifdef DEBUGGER missing.virq = 1; missing.virq_pos = PPU.IRQVBeamPos; #endif } else PPU.VTimerEnabled = FALSE; if (Byte & 0x10) { PPU.HTimerEnabled = TRUE; #ifdef DEBUGGER missing.hirq = 1; missing.hirq_pos = PPU.IRQHBeamPos; #endif } else PPU.HTimerEnabled = FALSE; if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled) CPU.IRQTransition = TRUE; if (!PPU.HTimerEnabled && !PPU.VTimerEnabled) { CPU.IRQLine = FALSE; CPU.IRQTransition = FALSE; } // NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard. if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) && (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE) && (Memory.FillRAM[0x4210] & 0x80)) { // FIXME: triggered at HC+=6, checked just before the final CPU cycle, // then, when to call S9xOpcode_NMI()? CPU.NMILine = TRUE; Timings.NMITriggerPos = CPU.Cycles + 6 + 6; } #ifdef DEBUGGER S9xTraceFormattedMessage("--- IRQ Timer Enable HTimer:%d Pos:%04d VTimer:%d Pos:%03d", PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); #endif break; case 0x4201: // WRIO if ((Byte & 0x80) == 0 && (Memory.FillRAM[0x4213] & 0x80) == 0x80) S9xLatchCounters(1); else S9xTryGunLatch((Byte & 0x80) ? true : false); Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = Byte; break; case 0x4202: // WRMPYA break; case 0x4203: // WRMPYB { uint32 res = Memory.FillRAM[0x4202] * Byte; // FIXME: The update occurs 8 machine cycles after $4203 is set. Memory.FillRAM[0x4216] = (uint8) res; Memory.FillRAM[0x4217] = (uint8) (res >> 8); break; } case 0x4204: // WRDIVL case 0x4205: // WRDIVH break; case 0x4206: // WRDIVB { uint16 a = Memory.FillRAM[0x4204] + (Memory.FillRAM[0x4205] << 8); uint16 div = Byte ? a / Byte : 0xffff; uint16 rem = Byte ? a % Byte : a; // FIXME: The update occurs 16 machine cycles after $4206 is set. Memory.FillRAM[0x4214] = (uint8) div; Memory.FillRAM[0x4215] = div >> 8; Memory.FillRAM[0x4216] = (uint8) rem; Memory.FillRAM[0x4217] = rem >> 8; break; } case 0x4207: // HTIMEL pos = PPU.IRQHBeamPos; PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte; if (PPU.IRQHBeamPos != pos) S9xUpdateHVTimerPosition(); #ifdef DEBUGGER missing.hirq_pos = PPU.IRQHBeamPos; #endif break; case 0x4208: // HTIMEH pos = PPU.IRQHBeamPos; PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8); if (PPU.IRQHBeamPos != pos) S9xUpdateHVTimerPosition(); #ifdef DEBUGGER missing.hirq_pos = PPU.IRQHBeamPos; #endif break; case 0x4209: // VTIMEL pos = PPU.IRQVBeamPos; PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte; if (PPU.IRQVBeamPos != pos) S9xUpdateHVTimerPosition(); #ifdef DEBUGGER missing.virq_pos = PPU.IRQVBeamPos; #endif break; case 0x420a: // VTIMEH pos = PPU.IRQVBeamPos; PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8); if (PPU.IRQVBeamPos != pos) S9xUpdateHVTimerPosition(); #ifdef DEBUGGER missing.virq_pos = PPU.IRQVBeamPos; #endif break; case 0x420b: // MDMAEN if (CPU.InDMAorHDMA) return; // XXX: Not quite right... if (Byte) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += Timings.DMACPUSync; S9xCheckInterrupts(); } if (Byte & 0x01) S9xDoDMA(0); if (Byte & 0x02) S9xDoDMA(1); if (Byte & 0x04) S9xDoDMA(2); if (Byte & 0x08) S9xDoDMA(3); if (Byte & 0x10) S9xDoDMA(4); if (Byte & 0x20) S9xDoDMA(5); if (Byte & 0x40) S9xDoDMA(6); if (Byte & 0x80) S9xDoDMA(7); #ifdef DEBUGGER missing.dma_this_frame = Byte; missing.dma_channels = Byte; #endif break; case 0x420c: // HDMAEN if (CPU.InDMAorHDMA) return; Memory.FillRAM[0x420c] = Byte; // Yoshi's Island, Genjyu Ryodan, Mortal Kombat, Tales of Phantasia PPU.HDMA = Byte & ~PPU.HDMAEnded; #ifdef DEBUGGER missing.hdma_this_frame |= Byte; missing.hdma_channels |= Byte; #endif break; case 0x420d: // MEMSEL if ((Byte & 1) != (Memory.FillRAM[0x420d] & 1)) { if (Byte & 1) { CPU.FastROMSpeed = ONE_CYCLE; #ifdef DEBUGGER missing.fast_rom = 1; #endif } else CPU.FastROMSpeed = SLOW_ONE_CYCLE; } break; case 0x4210: // RDNMI case 0x4211: // TIMEUP case 0x4212: // HVBJOY case 0x4213: // RDIO case 0x4214: // RDDIVL case 0x4215: // RDDIVH case 0x4216: // RDMPYL case 0x4217: // RDMPYH case 0x4218: // JOY1L case 0x4219: // JOY1H case 0x421a: // JOY2L case 0x421b: // JOY2H case 0x421c: // JOY3L case 0x421d: // JOY3H case 0x421e: // JOY4L case 0x421f: // JOY4H return; default: if (Settings.SPC7110 && Address >= 0x4800) S9xSetSPC7110(Byte, Address); else if (Settings.SDD1 && Address >= 0x4804 && Address <= 0x4807) S9xSetSDD1MemoryMap(Address - 0x4804, Byte & 7); break; } } Memory.FillRAM[Address] = Byte; } uint8 S9xGetCPU (uint16 Address) { if (Address < 0x4200) { #ifdef SNES_JOY_READ_CALLBACKS extern bool8 pad_read; if (Address == 0x4016 || Address == 0x4017) { S9xOnSNESPadRead(); pad_read = TRUE; } #endif switch (Address) { case 0x4016: // JOYSER0 case 0x4017: // JOYSER1 return (S9xReadJOYSERn(Address)); default: return (OpenBus); } } else if ((Address & 0xff80) == 0x4300) { if (CPU.InDMAorHDMA) return (OpenBus); int d = (Address >> 4) & 0x7; switch (Address & 0xf) { case 0x0: // 0x43x0: DMAPx return ((DMA[d].ReverseTransfer ? 0x80 : 0) | (DMA[d].HDMAIndirectAddressing ? 0x40 : 0) | (DMA[d].UnusedBit43x0 ? 0x20 : 0) | (DMA[d].AAddressDecrement ? 0x10 : 0) | (DMA[d].AAddressFixed ? 0x08 : 0) | (DMA[d].TransferMode & 7)); case 0x1: // 0x43x1: BBADx return (DMA[d].BAddress); case 0x2: // 0x43x2: A1TxL return (DMA[d].AAddress & 0xff); case 0x3: // 0x43x3: A1TxH return (DMA[d].AAddress >> 8); case 0x4: // 0x43x4: A1Bx return (DMA[d].ABank); case 0x5: // 0x43x5: DASxL return (DMA[d].DMACount_Or_HDMAIndirectAddress & 0xff); case 0x6: // 0x43x6: DASxH return (DMA[d].DMACount_Or_HDMAIndirectAddress >> 8); case 0x7: // 0x43x7: DASBx return (DMA[d].IndirectBank); case 0x8: // 0x43x8: A2AxL return (DMA[d].Address & 0xff); case 0x9: // 0x43x9: A2AxH return (DMA[d].Address >> 8); case 0xa: // 0x43xa: NLTRx return (DMA[d].LineCount ^ (DMA[d].Repeat ? 0x00 : 0x80)); case 0xb: // 0x43xb: ????x case 0xf: // 0x43xf: mirror of 0x43xb return (DMA[d].UnknownByte); default: return (OpenBus); } } else { uint8 byte; switch (Address) { case 0x4210: // RDNMI byte = Memory.FillRAM[0x4210]; Memory.FillRAM[0x4210] = Model->_5A22; return ((byte & 0x80) | (OpenBus & 0x70) | Model->_5A22); case 0x4211: // TIMEUP byte = CPU.IRQLine ? 0x80 : 0; CPU.IRQLine = FALSE; CPU.IRQTransition = FALSE; return (byte | (OpenBus & 0x7f)); case 0x4212: // HVBJOY return (REGISTER_4212() | (OpenBus & 0x3e)); case 0x4213: // RDIO return (Memory.FillRAM[0x4213]); case 0x4214: // RDDIVL case 0x4215: // RDDIVH case 0x4216: // RDMPYL case 0x4217: // RDMPYH return (Memory.FillRAM[Address]); case 0x4218: // JOY1L case 0x4219: // JOY1H case 0x421a: // JOY2L case 0x421b: // JOY2H case 0x421c: // JOY3L case 0x421d: // JOY3H case 0x421e: // JOY4L case 0x421f: // JOY4H #ifdef SNES_JOY_READ_CALLBACKS extern bool8 pad_read; if (Memory.FillRAM[0x4200] & 1) { S9xOnSNESPadRead(); pad_read = TRUE; } #endif return (Memory.FillRAM[Address]); default: if (Settings.SPC7110 && Address >= 0x4800) return (S9xGetSPC7110(Address)); if (Settings.SDD1 && Address >= 0x4800 && Address <= 0x4807) return (Memory.FillRAM[Address]); return (OpenBus); } } } void S9xResetPPU (void) { S9xSoftResetPPU(); S9xControlsReset(); PPU.M7HOFS = 0; PPU.M7VOFS = 0; PPU.M7byte = 0; } void S9xSoftResetPPU (void) { S9xControlsSoftReset(); PPU.VMA.High = 0; PPU.VMA.Increment = 1; PPU.VMA.Address = 0; PPU.VMA.FullGraphicCount = 0; PPU.VMA.Shift = 0; PPU.WRAM = 0; for (int c = 0; c < 4; c++) { PPU.BG[c].SCBase = 0; PPU.BG[c].HOffset = 0; PPU.BG[c].VOffset = 0; PPU.BG[c].BGSize = 0; PPU.BG[c].NameBase = 0; PPU.BG[c].SCSize = 0; } PPU.BGMode = 0; PPU.BG3Priority = 0; PPU.CGFLIP = 0; PPU.CGFLIPRead = 0; PPU.CGADD = 0; for (int c = 0; c < 256; c++) { IPPU.Red[c] = (c & 7) << 2; IPPU.Green[c] = ((c >> 3) & 7) << 2; IPPU.Blue[c] = ((c >> 6) & 2) << 3; PPU.CGDATA[c] = IPPU.Red[c] | (IPPU.Green[c] << 5) | (IPPU.Blue[c] << 10); } for (int c = 0; c < 128; c++) { PPU.OBJ[c].HPos = 0; PPU.OBJ[c].VPos = 0; PPU.OBJ[c].HFlip = 0; PPU.OBJ[c].VFlip = 0; PPU.OBJ[c].Name = 0; PPU.OBJ[c].Priority = 0; PPU.OBJ[c].Palette = 0; PPU.OBJ[c].Size = 0; } PPU.OBJThroughMain = FALSE; PPU.OBJThroughSub = FALSE; PPU.OBJAddition = FALSE; PPU.OBJNameBase = 0; PPU.OBJNameSelect = 0; PPU.OBJSizeSelect = 0; PPU.OAMAddr = 0; PPU.SavedOAMAddr = 0; PPU.OAMPriorityRotation = 0; PPU.OAMFlip = 0; PPU.OAMReadFlip = 0; PPU.OAMTileAddress = 0; PPU.OAMWriteRegister = 0; memset(PPU.OAMData, 0, 512 + 32); PPU.FirstSprite = 0; PPU.LastSprite = 127; PPU.RangeTimeOver = 0; PPU.HTimerEnabled = FALSE; PPU.VTimerEnabled = FALSE; PPU.HTimerPosition = Timings.H_Max + 1; PPU.VTimerPosition = Timings.V_Max + 1; PPU.IRQHBeamPos = 0x1ff; PPU.IRQVBeamPos = 0x1ff; PPU.HBeamFlip = 0; PPU.VBeamFlip = 0; PPU.HBeamPosLatched = 0; PPU.VBeamPosLatched = 0; PPU.GunHLatch = 0; PPU.GunVLatch = 1000; PPU.HVBeamCounterLatched = 0; PPU.Mode7HFlip = FALSE; PPU.Mode7VFlip = FALSE; PPU.Mode7Repeat = 0; PPU.MatrixA = 0; PPU.MatrixB = 0; PPU.MatrixC = 0; PPU.MatrixD = 0; PPU.CentreX = 0; PPU.CentreY = 0; PPU.Mosaic = 0; PPU.BGMosaic[0] = FALSE; PPU.BGMosaic[1] = FALSE; PPU.BGMosaic[2] = FALSE; PPU.BGMosaic[3] = FALSE; PPU.Window1Left = 1; PPU.Window1Right = 0; PPU.Window2Left = 1; PPU.Window2Right = 0; PPU.RecomputeClipWindows = TRUE; for (int c = 0; c < 6; c++) { PPU.ClipCounts[c] = 0; PPU.ClipWindowOverlapLogic[c] = CLIP_OR; PPU.ClipWindow1Enable[c] = FALSE; PPU.ClipWindow2Enable[c] = FALSE; PPU.ClipWindow1Inside[c] = TRUE; PPU.ClipWindow2Inside[c] = TRUE; } PPU.ForcedBlanking = TRUE; PPU.FixedColourRed = 0; PPU.FixedColourGreen = 0; PPU.FixedColourBlue = 0; PPU.Brightness = 0; PPU.ScreenHeight = SNES_HEIGHT; PPU.Need16x8Mulitply = FALSE; PPU.BGnxOFSbyte = 0; PPU.HDMA = 0; PPU.HDMAEnded = 0; PPU.OpenBus1 = 0; PPU.OpenBus2 = 0; for (int c = 0; c < 2; c++) memset(&IPPU.Clip[c], 0, sizeof(struct ClipData)); IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; IPPU.DirectColourMapsNeedRebuild = TRUE; memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES); IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better? IPPU.Interlace = FALSE; IPPU.InterlaceOBJ = FALSE; IPPU.DoubleWidthPixels = FALSE; IPPU.DoubleHeightPixels = FALSE; IPPU.CurrentLine = 0; IPPU.PreviousLine = 0; IPPU.XB = NULL; for (int c = 0; c < 256; c++) IPPU.ScreenColors[c] = c; IPPU.MaxBrightness = 0; IPPU.RenderThisFrame = TRUE; IPPU.RenderedScreenWidth = SNES_WIDTH; IPPU.RenderedScreenHeight = SNES_HEIGHT; IPPU.FrameCount = 0; IPPU.RenderedFramesCount = 0; IPPU.DisplayedRenderedFrameCount = 0; IPPU.SkippedFrames = 0; IPPU.FrameSkip = 0; S9xFixColourBrightness(); for (int c = 0; c < 0x8000; c += 0x100) memset(&Memory.FillRAM[c], c >> 8, 0x100); memset(&Memory.FillRAM[0x2100], 0, 0x100); memset(&Memory.FillRAM[0x4200], 0, 0x100); memset(&Memory.FillRAM[0x4000], 0, 0x100); // For BS Suttehakkun 2... memset(&Memory.FillRAM[0x1000], 0, 0x1000); Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff; } sdd1.h000664 001750 001750 00000014274 12720446475 012731 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SDD1_H_ #define _SDD1_H_ void S9xSetSDD1MemoryMap (uint32, uint32); void S9xResetSDD1 (void); void S9xSDD1PostLoadState (void); #endif spc7110dec.cpp000664 001750 001750 00000034526 12720446475 014205 0ustar00sergiosergio000000 000000 /***** * SPC7110 emulator - version 0.03 (2008-08-10) * Copyright (c) 2008, byuu and neviksti * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * The software is provided "as is" and the author disclaims all warranties * with regard to this software including all implied warranties of * merchantibility and fitness, in no event shall the author be liable for * any special, direct, indirect, or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an * action of contract, negligence or other tortious action, arising out of * or in connection with the use or performance of this software. *****/ #ifdef _SPC7110EMU_CPP_ uint8 SPC7110Decomp::read() { if(decomp_buffer_length == 0) { //decompress at least (decomp_buffer_size / 2) bytes to the buffer switch(decomp_mode) { case 0: mode0(false); break; case 1: mode1(false); break; case 2: mode2(false); break; default: return 0x00; } } uint8 data = decomp_buffer[decomp_buffer_rdoffset++]; decomp_buffer_rdoffset &= decomp_buffer_size - 1; decomp_buffer_length--; return data; } void SPC7110Decomp::write(uint8 data) { decomp_buffer[decomp_buffer_wroffset++] = data; decomp_buffer_wroffset &= decomp_buffer_size - 1; decomp_buffer_length++; } uint8 SPC7110Decomp::dataread() { unsigned size = memory_cartrom_size() - 0x100000; while(decomp_offset >= size) decomp_offset -= size; return memory_cartrom_read(0x100000 + decomp_offset++); } void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) { decomp_mode = mode; decomp_offset = offset; decomp_buffer_rdoffset = 0; decomp_buffer_wroffset = 0; decomp_buffer_length = 0; //reset context states for(unsigned i = 0; i < 32; i++) { context[i].index = 0; context[i].invert = 0; } switch(decomp_mode) { case 0: mode0(true); break; case 1: mode1(true); break; case 2: mode2(true); break; } //decompress up to requested output data index while(index--) read(); } // void SPC7110Decomp::mode0(bool init) { static uint8 val, in, span; static int out, inverts, lps, in_count; if(init == true) { out = inverts = lps = 0; span = 0xff; val = dataread(); in = dataread(); in_count = 8; return; } while(decomp_buffer_length < (decomp_buffer_size >> 1)) { for(unsigned bit = 0; bit < 8; bit++) { //get context uint8 mask = (1 << (bit & 3)) - 1; uint8 con = mask + ((inverts & mask) ^ (lps & mask)); if(bit > 3) con += 15; //get prob and mps unsigned prob = probability(con); unsigned mps = (((out >> 15) & 1) ^ context[con].invert); //get bit unsigned flag_lps; if(val <= span - prob) { //mps span = span - prob; out = (out << 1) + mps; flag_lps = 0; } else { //lps val = val - (span - (prob - 1)); span = prob - 1; out = (out << 1) + 1 - mps; flag_lps = 1; } //renormalize unsigned shift = 0; while(span < 0x7f) { shift++; span = (span << 1) + 1; val = (val << 1) + (in >> 7); in <<= 1; if(--in_count == 0) { in = dataread(); in_count = 8; } } //update processing info lps = (lps << 1) + flag_lps; inverts = (inverts << 1) + context[con].invert; //update context state if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; if(flag_lps) context[con].index = next_lps(con); else if(shift) context[con].index = next_mps(con); } //save byte write(out); } } void SPC7110Decomp::mode1(bool init) { static unsigned pixelorder[4], realorder[4]; static uint8 in, val, span; static int out, inverts, lps, in_count; if(init == true) { for(unsigned i = 0; i < 4; i++) pixelorder[i] = i; out = inverts = lps = 0; span = 0xff; val = dataread(); in = dataread(); in_count = 8; return; } while(decomp_buffer_length < (decomp_buffer_size >> 1)) { for(unsigned pixel = 0; pixel < 8; pixel++) { //get first symbol context unsigned a = ((out >> (1 * 2)) & 3); unsigned b = ((out >> (7 * 2)) & 3); unsigned c = ((out >> (8 * 2)) & 3); unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); //update pixel order unsigned m, n; for(m = 0; m < 4; m++) if(pixelorder[m] == a) break; for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; pixelorder[0] = a; //calculate the real pixel order for(m = 0; m < 4; m++) realorder[m] = pixelorder[m]; //rotate reference pixel c value to top for(m = 0; m < 4; m++) if(realorder[m] == c) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = c; //rotate reference pixel b value to top for(m = 0; m < 4; m++) if(realorder[m] == b) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = b; //rotate reference pixel a value to top for(m = 0; m < 4; m++) if(realorder[m] == a) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = a; //get 2 symbols for(unsigned bit = 0; bit < 2; bit++) { //get prob unsigned prob = probability(con); //get symbol unsigned flag_lps; if(val <= span - prob) { //mps span = span - prob; flag_lps = 0; } else { //lps val = val - (span - (prob - 1)); span = prob - 1; flag_lps = 1; } //renormalize unsigned shift = 0; while(span < 0x7f) { shift++; span = (span << 1) + 1; val = (val << 1) + (in >> 7); in <<= 1; if(--in_count == 0) { in = dataread(); in_count = 8; } } //update processing info lps = (lps << 1) + flag_lps; inverts = (inverts << 1) + context[con].invert; //update context state if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; if(flag_lps) context[con].index = next_lps(con); else if(shift) context[con].index = next_mps(con); //get next context con = 5 + (con << 1) + ((lps ^ inverts) & 1); } //get pixel b = realorder[(lps ^ inverts) & 3]; out = (out << 2) + b; } //turn pixel data into bitplanes unsigned data = morton_2x8(out); write(data >> 8); write(data >> 0); } } void SPC7110Decomp::mode2(bool init) { static unsigned pixelorder[16], realorder[16]; static uint8 bitplanebuffer[16], buffer_index; static uint8 in, val, span; static int out0, out1, inverts, lps, in_count; if(init == true) { for(unsigned i = 0; i < 16; i++) pixelorder[i] = i; buffer_index = 0; out0 = out1 = inverts = lps = 0; span = 0xff; val = dataread(); in = dataread(); in_count = 8; return; } while(decomp_buffer_length < (decomp_buffer_size >> 1)) { for(unsigned pixel = 0; pixel < 8; pixel++) { //get first symbol context unsigned a = ((out0 >> (0 * 4)) & 15); unsigned b = ((out0 >> (7 * 4)) & 15); unsigned c = ((out1 >> (0 * 4)) & 15); unsigned con = 0; unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); //update pixel order unsigned m, n; for(m = 0; m < 16; m++) if(pixelorder[m] == a) break; for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1]; pixelorder[0] = a; //calculate the real pixel order for(m = 0; m < 16; m++) realorder[m] = pixelorder[m]; //rotate reference pixel c value to top for(m = 0; m < 16; m++) if(realorder[m] == c) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = c; //rotate reference pixel b value to top for(m = 0; m < 16; m++) if(realorder[m] == b) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = b; //rotate reference pixel a value to top for(m = 0; m < 16; m++) if(realorder[m] == a) break; for(n = m; n > 0; n--) realorder[n] = realorder[n - 1]; realorder[0] = a; //get 4 symbols for(unsigned bit = 0; bit < 4; bit++) { //get prob unsigned prob = probability(con); //get symbol unsigned flag_lps; if(val <= span - prob) { //mps span = span - prob; flag_lps = 0; } else { //lps val = val - (span - (prob - 1)); span = prob - 1; flag_lps = 1; } //renormalize unsigned shift = 0; while(span < 0x7f) { shift++; span = (span << 1) + 1; val = (val << 1) + (in >> 7); in <<= 1; if(--in_count == 0) { in = dataread(); in_count = 8; } } //update processing info lps = (lps << 1) + flag_lps; unsigned invertbit = context[con].invert; inverts = (inverts << 1) + invertbit; //update context state if(flag_lps & toggle_invert(con)) context[con].invert ^= 1; if(flag_lps) context[con].index = next_lps(con); else if(shift) context[con].index = next_mps(con); //get next context con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); } //get pixel b = realorder[(lps ^ inverts) & 0x0f]; out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); out0 = (out0 << 4) + b; } //convert pixel data into bitplanes unsigned data = morton_4x8(out0); write(data >> 24); write(data >> 16); bitplanebuffer[buffer_index++] = data >> 8; bitplanebuffer[buffer_index++] = data >> 0; if(buffer_index == 16) { for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]); buffer_index = 0; } } } // const uint8 SPC7110Decomp::evolution_table[53][4] = { //{ prob, nextlps, nextmps, toggle invert }, { 0x5a, 1, 1, 1 }, { 0x25, 6, 2, 0 }, { 0x11, 8, 3, 0 }, { 0x08, 10, 4, 0 }, { 0x03, 12, 5, 0 }, { 0x01, 15, 5, 0 }, { 0x5a, 7, 7, 1 }, { 0x3f, 19, 8, 0 }, { 0x2c, 21, 9, 0 }, { 0x20, 22, 10, 0 }, { 0x17, 23, 11, 0 }, { 0x11, 25, 12, 0 }, { 0x0c, 26, 13, 0 }, { 0x09, 28, 14, 0 }, { 0x07, 29, 15, 0 }, { 0x05, 31, 16, 0 }, { 0x04, 32, 17, 0 }, { 0x03, 34, 18, 0 }, { 0x02, 35, 5, 0 }, { 0x5a, 20, 20, 1 }, { 0x48, 39, 21, 0 }, { 0x3a, 40, 22, 0 }, { 0x2e, 42, 23, 0 }, { 0x26, 44, 24, 0 }, { 0x1f, 45, 25, 0 }, { 0x19, 46, 26, 0 }, { 0x15, 25, 27, 0 }, { 0x11, 26, 28, 0 }, { 0x0e, 26, 29, 0 }, { 0x0b, 27, 30, 0 }, { 0x09, 28, 31, 0 }, { 0x08, 29, 32, 0 }, { 0x07, 30, 33, 0 }, { 0x05, 31, 34, 0 }, { 0x04, 33, 35, 0 }, { 0x04, 33, 36, 0 }, { 0x03, 34, 37, 0 }, { 0x02, 35, 38, 0 }, { 0x02, 36, 5, 0 }, { 0x58, 39, 40, 1 }, { 0x4d, 47, 41, 0 }, { 0x43, 48, 42, 0 }, { 0x3b, 49, 43, 0 }, { 0x34, 50, 44, 0 }, { 0x2e, 51, 45, 0 }, { 0x29, 44, 46, 0 }, { 0x25, 45, 24, 0 }, { 0x56, 47, 48, 1 }, { 0x4f, 47, 49, 0 }, { 0x47, 48, 50, 0 }, { 0x41, 49, 51, 0 }, { 0x3c, 50, 52, 0 }, { 0x37, 51, 43, 0 }, }; const uint8 SPC7110Decomp::mode2_context_table[32][2] = { //{ next 0, next 1 }, { 1, 2 }, { 3, 8 }, { 13, 14 }, { 15, 16 }, { 17, 18 }, { 19, 20 }, { 21, 22 }, { 23, 24 }, { 25, 26 }, { 25, 26 }, { 25, 26 }, { 25, 26 }, { 25, 26 }, { 27, 28 }, { 29, 30 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, { 31, 31 }, }; uint8 SPC7110Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; } uint8 SPC7110Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; } uint8 SPC7110Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; } bool SPC7110Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; } unsigned SPC7110Decomp::morton_2x8(unsigned data) { //reverse morton lookup: de-interleave two 8-bit values //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 return morton16[0][(data >> 0) & 255] + morton16[1][(data >> 8) & 255]; } unsigned SPC7110Decomp::morton_4x8(unsigned data) { //reverse morton lookup: de-interleave four 8-bit values //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 return morton32[0][(data >> 0) & 255] + morton32[1][(data >> 8) & 255] + morton32[2][(data >> 16) & 255] + morton32[3][(data >> 24) & 255]; } // void SPC7110Decomp::reset() { //mode 3 is invalid; this is treated as a special case to always return 0x00 //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 decomp_mode = 3; decomp_buffer_rdoffset = 0; decomp_buffer_wroffset = 0; decomp_buffer_length = 0; } SPC7110Decomp::SPC7110Decomp() { decomp_buffer = new uint8_t[decomp_buffer_size]; reset(); //initialize reverse morton lookup tables for(unsigned i = 0; i < 256; i++) { #define map(x, y) (((i >> x) & 1) << y) //2x8-bit morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4); morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0); //4x8-bit morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6); morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4); morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2); morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0); #undef map } } SPC7110Decomp::~SPC7110Decomp() { delete[] decomp_buffer; } #endif docs/changes.txt000664 001750 001750 00000447153 12720446475 015034 0ustar00sergiosergio000000 000000 Snes9x 1.53 - Rebuilt IRQ handling. (zones) - Improved overall timings, now Snes9x can handle events in a opcode a little. (zones) - Improved screen interlace and sprite interlace supports. (OV2, zones) - Fixed Hi-Res pixel plotter. (BearOso, zones, OV2) - Fixed C4 for Mega Man X2's "weapon get" screen. (Jonas Quinn) - Fixed Super Buster Bros. graphics after reset. (Jonas Quinn) - Improved SA-1 support. (zones) - Added SA-1 CC2 support. (Jonas Quinn, byuu) - Fixed SA-1 NMI override mode. (zones) - Fixed Dual Orb 2 sound glitch. (byuu) - New APU timing hack, fixes various games that exhibit problems with Blargg's SNES_SPC library. (OV2) - Fixed the problem that echo buffer breaks IPL ROM. (zones, OV2) - Fixed movie snapshot unfreeze inconsistency. (gocha) - Faster config file saving. (OV2) - Fixed BlockInvalidVRAMAccess config file option. (windows port, unix port and gtk legacy config) (Jonas Quinn) - Remove POSIX dup and access calls, and rename qword to fix compilation with Cell SDK. (BearOso) - Fixed PS3 version save state crash by using heap allocation for soundsnapshot. (danieldematteis) - Fixed crash relating to double-closed descriptor. (BearOso) - Removed CPUShutdown speedhack, DisableHDMA and DisableIRQ options. (zones) - Removed remaining outdated asm code. (zones) - JMA 64 bit support. (kode54, Nach, friedrich.goepel) - GTK+, Win32, Mac: Added optional Hi-Res blending. (BearOso, OV2, zones) - GTK+, Win32: Support for bsnes-style XML shaders. (BearOso, OV2) - Win32: Full unicode support. (OV2) - Win32: Restored OpenGL mode. (OV2) - Win32: x64 version. (OV2) - Win32: HLSL shader support. (mudlord) - Win32: Win7 jumplist synchronizes with recent roms list. (OV2) - Win32: Updated menu structure. (OV2) - Win32: Drag&Drop support for ROMs. (gocha, OV2) - Win32: Reworked movie-recording with size selection. (gocha, OV2) - Win32: Restored SPC save option. (OV2) - Win32: Fixed vsync in DirectDraw. (OV2) - Win32: Improved window position saving. (OV2) - Win32: Restored compile with DEBUGGER. (gocha) - Win32: Fixed various edge-case errors and/or possible leaks. (Brian Friesen) - Win32: Config file option to always center image. (OV2) - Win32: Fixed "Turbo Down mode" hotkey assignment. (gocha) - Win32: Added and fixed Autofire for D-pad. (gocha) - Win32: Fixed aggressive soundsync wait. (OV2) - Win32: Added window size presets. (OV2) - Mac : Added pause and frame advance functions. (zones) - Mac : Now you can choose any folder for saving files. (zones) - Mac : Updated Music Box (mostly internally). (zones) - Mac : Fixed gliches in open/save dialogs on 10.6. (zones) - Mac : Fixed display configuration in windowed mode. (zones) - Unix : Fixed segfault and hang-up with -DNOSOUND. (zones) - GTK+ : Added ability to set specific folders for SRAM, patches, snapshots, etc. (BearOso) - GTK+ : Fixed many permissions issues with config folders. (BearOso) - GTK+ : Updated compatibility with latest GTK+ and GtkBuilder. Added experimental support for GTK+ 3.x. (BearOso) - GTK+ : Updated software output to use cairo and added the ability to use bilinear-filtering with it. (BearOso) - GTK+ : Fixed issues where cheats wouldn't stay enabled. (BearOso) - GTK+ : Fixed focus issue when there is no window manager. (BearOso) - GTK+ : Fixed X Visual incompatibilities and expose problems in the Xv and OpenGL outputs. (BearOso) - GTK+ : Fixed vsync with new X Server and NVIDIA drivers. (BearOso) - GTK+ : Added "Reduce input lag" option to OpenGL output. (BearOso) - GTK+ : Added a visual indication of the expected video refresh rate for the currently selected sound input rate. (BearOso) Snes9x 1.52 - IMPORTANT NOTICE: The structure of savestates (also known as snapshots / freeze files) is incompatible with older versions! Snes9x 1.52 cannot read the savestates created by 1.51 or older. (zones) - Highly acculate SPC700 and S-DSP emulation. (Blargg) - Replaced APU emulation cores (SPC700 and S-DSP) with ones provided by Blargg's SNES_SPC library. This renders savestates incompatible with older versions. (BearOso, zones) - SPC7110 emulation. (byuu, neviksti) - Merged bsnes' SPC7110 emulation code. Note that the .rtc file of Far East of Eden Zero is incompatible with older versions. (zones) - Removed graphics pack support. It's no more necessary. (zones) - Replaced S-RTC emulation code with bsnes' one to keep the good compatibility of .rtc files between the two emulators. As a result, Daikaijuu Monogatari 2 now outputs the .rtc file, and its .srm file is incompatible with older versions. (zones) - Added savestate supports for DSP-2, DSP-4, ST-010 and OBC1. (zones) - Added UPS support. (byuu) - Fixed DSP-4 AI problem. (Jonas Quinn) - Fixed invalid memory accesses in C4 and OBC1 codes. (zones) - Fixed invalid memory accesses in BSX codes. My mistake. (zones) - Fixed the read value of $213e, $4210 and $4211. (zones) - Fixed the writing of word values at the memory boundary. (zones) - Fixed the bug that the unnecessary SA-1 emulation continues once any SA-1 games are launched. (zones) - Removed old color blending codes. (zones) - Removed too-old Snes96 and ZSNES snapshot support. (zones) - Updated command-line options. (zones) - Code cleaning. (zones) - GTK+ : Added a port of Snes9x to the GTK+ toolkit. (BearOso) - Unix : Reconstructed and simplified all the contents. Some features have been removed to be simple, and many options have changed. GTK+ port is recommended for most of Linux users. (zones) - Win32: Now uses snes9x.conf to prevent problems with modified meaning of settings. (OV2) - Win32: Removed broken OpenGL mode. (OV2) - Win32: Removed support for 8bit output. (OV2) - Win32: Reworked settings dialogues to accomodate the new APU core and display settings. (OV2) - Win32: Updated defaults to use D3D and XA2 (better Vista and Win7 support). (OV2) - Win32: Direct3D and XAudio2 support. (OV2) - Win32: Added Blargg's ntsc filter (three presets). (OV2) - Mac : Fixed corrupted screenshot on Intel Mac. (zones) - Mac : Fixed sudden abort in QuickTime movie export on Intel Mac. (zones) - Mac : Changed sound settings for the new APU core. (zones) - Mac : Changed the default folder which Snes9x looks for to 'Application Support' folder. (zones) - Mac : Changed folder names: 'IPSs' -> 'Patches', 'BIOSs' -> 'BIOSes'. (zones) - Mac : Added Blargg's ntsc filter. (zones) - Mac : Internal changes for Leopard and Snow Leopard. (zones) Snes9x 1.51 - Added DSP1 and SuperFX savestate support. (nitsuja) - Added screen state GFX to save states. (optional) (nitsuja) - Fixed desync when loading inconsistent state in playback. (nitsuja) - When playback reaches a movie's end, recording continues instead of the movie suddenly closing. (after recording) (nitsuja) - can now record resets and mouse/superscope/justifier(s) (nitsuja) - Added same-line-comment support for config files. (nitsuja) - input display for all controllers (including peripherals) (nitsuja) - Win32: Now uses .cfg file instead of Windows registry. (nitsuja) - Win32: open ROM dialog bugfixes and speedup and facelift (nitsuja) - Win32: option to use standard file open dialog for ROMs (nitsuja) - Win32: maintain aspect ratio and bilinear filter stretch (nitsuja) - Win32: optional removal of the dreaded "black bar" (nitsuja) - Win32: Added EPX,EPX2,EPX3,HQ2X,HQ3X,TV3X,DM3X filters. (nitsuja) - Win32: Added hires support for Interlace and TV Mode. (nitsuja) - Win32: text removed from .avi output (optional) (nitsuja) - Win32: better directory management, customizeable (nitsuja) - Win32: Screenshot support is back. (nitsuja) - Win32: Netplay is back (but still not very good). (nitsuja) - Win32: Made OpenGL Bi-linear an advanced .cfg option. (nitsuja) - Win32: cheat search improvements (address, watch, SuperFX)(nitsuja) - Win32: Added non-modal ("active") cheat search option. (nitsuja) - Win32: new hotkey-config dialog and configurable hotkeys (nitsuja) - Win32: Fixed joystick config in input dialog. (nitsuja) - Win32: Fixed hires and extended height .avi output. (nitsuja) - Win32: various small GUI improvements (nitsuja) - Win32: Netplay fixes. (nitsuja) - "Fake Mute" desync workaround option for movies, until all ports have deterministic sound. (Bisqwit, nitsuja) - Fix for save state blocks > 999999 bytes. (Bisqwit) - C4 games now save C4 data in save states. (DeHackEd) - Unix: Framework for high-speed seeking. Specify a frame number in a movie, and the emulator will run at maximum speed to that frame. Untested. (DeHackEd) - X11: Support for window exposure. When a window is damaged due to overlay, being iconified, etc. it will be repainted correctly. (DeHackEd) - Unix: parameter: -autodemo loads a movie for playback on startup. Only the x11 code handles this right now. (DeHackEd) - Unix: parameter: -oldturbo, the turbo button renders all frames when fast-forwarding. (DeHackEd) - Unix: parameter: -upanddown, override U+D and L+R protection. (DeHackEd) - Unix: parameter: -mute, currently linux only, blocks out audio output from your speakers while still emulating sound. Not fully tested. (DeHackEd) - Unix: parameter: -maxframes during movie playback, snes9x will exit when the target is hit. (DeHackEd) - Unix: parameter: -keypress shows to stderr and on-screen the currently pressed buttons on joypad 1. (DeHackEd) - Unix: Stream dumping (NOT COMPLETE). With -dumpstreams, raw video and raw audio are dumped to videostream%d.dat and audiostream%d.dat, where %d increments on each CPU reset, starting at zero. (DeHackEd) - Unix: Non-blocking sound on Linux. It makes seeking nicer.(DeHackEd) - Unix: Configurable sound device. (pierredavidbelanger) - configure.in now requires a sufficiently new version of autoconf. (anomie) - Fixed slow versions of branch opcodes. (anomie) - Fixed the mosaic offset bug. (anomie) - No sorting by priority in C4 command 00 00. MegaMan X2 can go behind the legs of the intro stage boss. (anomie) - New RTO discovery, fixes Super Conflict: The Mideast title screen. (anomie, byuu) - A 1->0 transition on $2100.7 causes OAM Address Reset. (anomie, byuu) - The final HDMA Indirect Address load is only weird on the last channel of the scanline. Touge Densetsu Saisoku Battle problem solved. (anomie, byuu) - Fixed BGnVOFS bug. Only HOFS needs ~&7 update. (byuu) - Fixed superfluous VIRQ triggers. (zones) - Fixed missing IRQ trigger just after the previous one. (zones) - Fixed missing IRQ while writing to $4200. (zones) - Fixed IRQ timing after WRAM refresh. (zones) - Fixed NMA timing after DMA transfer. (zones) - Fixed superfluous auto-joypad-reading. (zones) - Fixed missing WRAM refresh during DMA transfer. (zones) - Fixed DMA so that HDMA and any HC triggered events can run during DMA transfer. (zones) - Roughly fixed the case that HDMA and DMA use the same channel at the same time. HDMA kills DMA. Thanks byuu. (zones) - Changed initial DMA registers values. (zones) - Slightly modified APU execute timings. (zones) - Fixed APU I/O registers to get/set the proper value. (zones) - Blocked invalid VRAM writings, though you can turn off this option due to Snes9x's inaccurate timings. (zones) - Omitted SPCTOOL, no one uses it. (zones) - Added Sufami Turbo support. (zones) - Added Same Game add-on cart support. (zones) - Fixed HiROM SRAM and DSP1-4 memory maps a little. (zones) - Improved mirroring. (Nach, grinvader, byuu) - CRC32 on BS dumps now follows uCONSRT standard. (Nach) - BS dumps now always run in NTSC mode. (Nach) - Unknown regions (generally betas) default to NTSC. (Nach) - Now support NSRT headers for setting up controllers. (Nach, nitsuja) - Unix: Fixed command line help output. (Nach) - Unix: Sound now defaults to 32KHz, Stereo, Interpolation so Snes9x finally sounds like a real SNES by default. (Nach) - Win32: Saner defaults for movie record. (Nach) - Unix: Fixed crashing with mouse or super scope. (Nach) - Removed some weird code which was crashing Korean League and its varients. (Nach) - Win32: Can now compile with MinGW. (Jonas Quinn, Nach) - Win32: Can now cross compile Snes9xw. (Nach) - Unix: SSnes9x compiles again. (Nach) - Win32: ZSNES C4 and SuperFX compiles once again. (Jonas Quinn) - Unix: Netplay Fixes. (Nach) - Unix: Netplay Improvements. (Fabianx) Snes9x 1.5 - Pseudo-hires rendering flush, Old 2xsai endian fix (anomie) - Added 'oops' auto-snapshot support (anomie) - Fixed usage messages (Unix) (anomie) - Old split-ROM-in-zip bugfix (anomie) - ./configure fix for detecting libpng (anomie) - Fix "no PNG support" error message (anomie) - Anomie's control remapping patch (anomie) - Support for IPS patches in the zip file (anomie) - OBC1 savestate fix (Overload) - Fix turbo frameskip, X11 keyboard auto-repeat, VRAM reads (anomie) - Add some missing ifdefs (UNZIP_SUPPORT and ZLIB), from AaronOneal (anomie) - Config file for Unix/X11 and Unix/SVGA (anomie) - CPU instruction fixes (mostly emulation mode & timing) (anomie) - Mode 7 fixes (anomie) - Rewrote the renderer. Enjoy! (anomie) - Correct-ish memmap boundary testing. (anomie) - Add support for saner directory structures under Unix (anomie) - Unix: Fixed detection of newer libpng (spotted by vapier) (PBortas) - Added 4-point gaussian interpolation and proper envelopes many thanks to Brad Martin and TRAC. (zones) - Fixed several sound problems. (zones) - Fixed the memory access problem in C++ Super FX core. (zones) - Speed adjustment of C++ Super FX emulation. (zones) - Various timing fixes: NMI, IRQ, WRAM refresh, cycles per line, HBlank start, etc. Many thanks to byuu for much information. (zones) - Removed some game specific hacks. (zones) - Added partial Satellaview (BS) emulation. (Dreamer Nom, zones) - Added the Katakana font for onscreen messages. (107) - Updated JMA to v1 (Nach) - Unix: Fixed JMA options in config (Nach) - Unix: Removed --with(out)-asmcpu option in config because the i386 assembler CPU core is out of date. (zones) - Unix: Changed the default settings in config. (zones) - Updated porting.html (porting.txt) in sync with 1.5. (zones) - Fixed buffer over/under flow due to incorrect logical operator in S-RTC code (byuu) - Fixed HDMA flags bug. (byuu, anomie) - Fixed bugs causing crashing in Unix. (Nach) - Ported Snes9x to AMD64. (John Weidman, Nach, zones) - Completed DSP-1 code. (Andreas Naive, Overload, Nach) - Updated DSP-3 code. (Nach, z80 gaiden) - Updated DSP-4 code. (Dreamer Nom, Nach, z80 gaiden) - Overhauled BS detection. (Nach) - Improved Unix portability. (Nach, zones) - Fixed infiniti loop and invalid read bug in C++ C4 core. (Nach) Snes9x 1.43 - Win32: Disabled Netplay (funkyass) - Win32: Various fixes, including ROM dialog (funkyass) - Win32: New Input Config Dialog (funkyass) - Win32: added .avi output feature (blip) - Win32: fixed frame timings >100ms, added frame advance (blip) - Rewrote Unfreeze, renamed it S9xUnfreezeFromStream, failing to load a freeze file no longer resets emulation (blip) - Fixed Unfreeze to restore IPPU.HDMA properly (blip) - Rewrote OBC1 code to match the real chip (Overload) - More updates the to DSP-1 code, fixes to projection (Overload, Andreas Naive) - Unix/X11: Rewrote keyboard setup code (Bisqwit) - Added movie recording+rerecording support (blip, Bisqwit) - Added -hidemenu CLI switch (funkyass) - fixed broken Win32 filters (lantus) - Added internal support for emulating the new-style SNES (MKendora) - Cleaned up many quirks of the cheat search engine (MKendora, Don Vincenzo) - Fix mosaic in hires SNES modes (Tokimeki Memorial) (MKendora, zones) - Rewrote Legend's hack, added another game to it (MKendora) - Optimized the Open ROM dialog (MKendora) - Rewrote the Seta DSP map (The Dumper, MKendora) - Began string isolation for the UI, eases translation (funkyass) - added -nopatch -nocheat, and -cheat CLI items (MKendora) - fixed a UI typo (funkyass) - fixed several C core stack ops in emulation mode (MKendora) - split emulation mode ops from native mode ops (MKendora) - Seta special chip emulation enhancements (Feather, The Dumper, Overload, MKendora) - code tweaks to the ST010 (Nach, pagefault) - fix some C/asm quirks and HDMA quirks (all my fault) (MKendora) - several timing hacks to fix games (lantus) - improved checksumming for odd mirrorings (MKendora) - Snes9x uses a standard zlib instead of a packaged one (PBortas) - Exhaust Heat 2 and regional ports are playable (Feather, The Dumper, Overload, MKendora) - Game Doctor dumps that are 24 Mbit are now supported by a force option (MKendora, Nach) - SuperFx interleave format is now considered deprecated. Support will be removed in future versions (Team decision) - made SuperFx interleave detection a compile option (MKendora) - added memory maps for slotted games (MKendora) - fixed a typo in the usage messages (MKendora) - fixed the bug that had nuked optimizations (The Dumper) - restored full speed optimizations in release builds (funkyass) - Added non-speed-hack version of color subtraction. (zones) - OpenGL info message font fix (zones) - APU timer fix (zones, Nach) - Fixed mouse offset in resized X11 window. (PhaethonH) - Fixed a (presumably) long-standing bug: Mode 6's BG is depth 4, not depth 8! (anomie) - Unix: unmap all joystick buttons before applying -joymapX (anomie) - Win32: added a define to disable pausing when focus is lost, NOPAUSE (funkyass) - Win32: Changed the default for Auto-save SRAM to 15 sec (funkyass) - Dreamcast: Added SH4 assembler (PBortas, Marcus Comstedt, Per Hedbor) - C90 and aclocal 1.8 warning fixes (thanks Ville Skytt) (PBortas) - Unix: AMD64 compilation fixes. (PBortas) - Added support for NSRT Team's JMA format (Nach, NSRT Team, funkyass) - Unix: Loading a zip file on binaries without zip support will give an appropriate error message (Nach) - Unix: Added install target with proper --prefix handling. (PBortas) Snes9x 1.42 - Added 8-bit rendering filters (funkyass) - Added Sanity Checks for the Display Dialog (funkyass) - New Layout for the Joypad Dialog, (funkyass) - Fixed that anoying Joypad dialog bug. Now check to see if the axis exists before asking for the info form it (funkyass) - Added full POV support. (funkyass) - Fixed sram sizes for SuperFx games (Nach, MKendora) - Stopped saving sram for games with no battery (Nach, Mkendora) - Killed the gray line and slightly optimized Win32 GL (MKendora) - stack wrapping fix in C core (MKendora) - removed some dead hacks (Oda Nobunaga and Dezaemon) (MKendora) - fixed some DMA and HDMA modes (anomie, MKendora) - improved HDMA timing (anomie) - cleaned up load and deinterleave code (MKendora) - removed old UI DLL (MKendora) - new cheat dialogs (MKendora) - started Unicode preparation in Win32 UI (MKendora) - Implement odd sprite sizes, sprite priority rotation. (anomie) - RTO code that hopefully works. MK's #define is "MK_DEBUG_RTO" to try to debug the RTO code. (anomie) - SDD1 decompression support for Linux. Also added a new command line option -sdd1-pack. (anomie) - Added correct VRAM read logic. #define CORRECT_VRAM_READS if you want it. (anomie) - removed the non-VAR_CYCLES path (MKendora) - changed access timing map to be address-based. (MKendora, anomie) - DSP-1 updates (Overload, Andreas Naive) - S-DD1 decompression support (Andreas Naive) - optimized S-DD1 code (anomie) - S-DD1 can use packs or decompression (MKendora) - More work on Exhaust Heat 2 (MKendora, Overload, The Dumper) - separated ROM detection from file reading (lantus) - fixed a mirroring bug in LoROMs (MKendora) - cleaned up some mapping issues (MKendora) - ST018 games now boot before locking up (Mkendora, Overload) - SA-1 state was not completely reset, crashed Marvelous (zones) - Removed sample caching. It caused problems, and was not noticably faster. (MKendora) - Fixed interlace without breaking the displays for MK (anomie) - Fixed a PPU OpenBus hack (anomie) - Moved SPC7110 and S-DD1 regs to speed up the general case of reading the $4xxx registers (MKendora) - altered Hi/Lo ROM detection to fix a few misdetects. (MKendora) - Implemented RTO flags. With MK's implementation of $213F's interlace bit, we now pass the SNES Test Cart's Electronics Test (anomie) - Fix sprite windowing bug (anomie) - Way back in 1.40 MK changed the Windows port to default to a plain old joypad instead of the MP5. And then we removed the hacks for games that dislike the MP5. So we need to change the defaults elsewhere too... (anomie) - cleaned up the hacks section somewhat (MKendora) - removed some interleave hacks (MKendora) - fixed a bug in KartContents (MKendora) - transparency fix for Jurassic Park (lantus) - A hidden Win32 feature (MKendora) - Kludged Mark Davis until I get stable APU timing (MKendora) - Win32 renders overscan always, fixes some jumpy games (MKendora, lantus) - Fixed an FMOD bug (MKendora) - cosmetic tweaks (Everyone) - Fixed 2 special chip bugs in the C core (zones) - Added some sanity fixes to the C core, fixes MLBPA Baseball for C core users (zones) - updated zlib source (includes 1.1.4-1 patch) (MKendora) - compiler warning fixes (PBortas) - Updated the SuperFx asm core (pagefault) - Kludged Unix compilation to produce working SuperFx (PBortas) with the asm core. - Kludged VC to deal with optimization weirdness (MKendora) - Hacked Robocop vs. Terminator using Daffy Duck hack. Stops flashing. (MKendora) - Added some defines to the asm core (MKendora) - Added possibility to take screenshots on Unix (PBortas) - Initialize the C SuperFx core better (PBortas) - Kludge a Japanese golf game until the APU timing is fixed (MKendora) Snes9x 1.41-1 - Oops, in the asm CPU core i was stomping on %eax too early, so register $4210 wasn't getting set properly. (anomie) Snes9x 1.41 - Win32 controllers now stay the same between games (MKendora) - Win 32 Open ROM dialog fixes (MKendora) - Win32 Display dialog fixes (funkyass) - Win32 OpenGL ratio tweaking. (Reduces the gray line) (kode54) - Fixed Win32 superscope for those having issues (MKendora) - Generic accuracy fix in main SUperscope emulation (MKendora) - sprite bug fixed (gah! How'd we miss that) (anomie) - SPC saving compatibility fix (Caz and zones) - Window clipping update (anomie) - Mode 7 clipping fix (TRAC) - latching fix (anomie) - BS BIOS checksum and mapping fix (MKendora) - Working Uniracers hack (dma.cpp) (anomie) - HDMA Indirect Address fix for Romancing Saga 2 (anomie) - Better savestate hack, does it break anything? (anomie) - C4 C core fixes. Mostly Trapezoid (thanks Nach), some s/short/int16/, some indentation. (anomie) - Damn, but the indentation in ppu.cpp was screwed up. Killed some dead code too (twas commented forevermore). (anomie) - fixed a potential crash in S-DD1 logging (MKendora) - Improved accuracy of Hi/LoROM detection (~500 ROM test) (MKendora) - Hack for Moryou Senki Madara 2, don't call SelectTileRenderer from DrawOBJS if BGMode is 5 or 6. A real fix requires at least rewriting SelectTileRenderer, or inlining a special version in DrawOBJS. (anomie) - DMA traces: add additional address info to reads too. (anomie) - Killed the old Borland Joypad dialog (funkyass) - Fixed issues with Dezaemon and CT, maybe others (anomie, MKendora) - Changed the internal snapshot key from \ to VK_F12 (funkyass) Fixes issues with non-US keyboard layouts. - Fixed OAM reset to not occur during forced blank. (anomie) - Killed some dead OAM reset code that doesn't need saving. (anomie) - Unix/X11: Fixed screen jumping. CT enables overscan mid- frame for only one frame, and we now update the rendered screen height accordingly. Other ports are still broken. (anomie) - Unix/X11: Fixed possible TV mode crash. (anomie) - Fixed OAM reset timing (beginning of V-Blank rather than end) for R-TYPE 3 (J). (anomie) - Unix/X11: Fixed OpenGL target (PBortas) - Unix/OSS: Fixed big endian sound (PBortas/ernstp) - Tweaked the About Dialog so its read-only and no scroll (funkyass) Snes9x 1.40 - cleaned up a sound skipping code issue. Same as the RTC issue (lantus) - re-fixed the invalid BRR header behavior twice (Lord Nightmare, FatlXception, Mkendora) - More BS mapping fixes. (The Dumper, MKendora) - Fixed Ranma Bun no 1 - Chonai Gekitou Hen (J) and Street Combat (U). Interlace is not supported in the non-Hi-res modes, as far as I can tell. (MKendora) - Also fixes Maka Maka (J). Frank Yang's report, and anomie's code both provided clues to this one. - Removed special casing on setting 5c77 version to one. This seems to be true for U and J units always. I need it checked out on PAL... (neviksti) - Using SNEeSe's values for 5c78 and 5A22. Note we know that the 5c78 version can also be 1 or 2, instead of 3. (TRAC, neviksti) - Added turbo buttons. Credit/blame for the design goes to slack, Nave, Gogo, and myself. (MKendora) - fixed a bug in turbo (slack, MKendora) - Tried merging the behavior of Old $4200 with new $4200 (MKendora) - Made $4200's return value match what VSMC Explorer showed on Fancia's SNES (MKendora) - Fixed a matrix multiplcation bug in ZSNES state loads (MKendora) - Fixed Dezaemon and Ys3 mode 7 (lantus) - Fixed H-DMA modes 5-7. Thanks to The Dumper for the extra motivation needed. GunForce and Genocide 2 work. (The Dumper, MKendora) - Fixed BG3 Priority. I'm stupid. anomie had fixed it, but lantus fixed it again, because I didn't use it. (anomie, lantus) - Added a Star Fox 2 hack, and an interleave skip (The Dumper, lantus, MKendora) - Cleared BS setting on load (lantus) - Fix for Mode 7 priorities. fixes F-1 Grand Prix (all 3) (anomie) - JANJYU GAKUEN 2 needs Multi-tap 5 off. (Frank Yang, MKendora) - HONKAKUHA IGO GOSEI: No multi-tap 5, allow mouse (lantus, MKendora) - Added a few missed conditional compiles (Nach) - disabled multitap 5 by default, added menu to enable (MKendora) - special thanks to anomie and lantus. One of them is responsible for a bug fix I forgot already. (anomie, lantus) - Removed several Multitap5 disable hacks. (MKendora) - Added an SPC dumping upgrade from kode54 (kode54) - cleaned up some resource leaks (MKendora) - I forgot this since 1.39mk, but SPC700 flag fixes (anomie) - Mode 7 interpolation screen flip fix (anomie) - Updated SPC7110 code a bit, for compatibility (Daniel, anomie) - Changed RTC saving. (Byte exact to old format on Win32) The submitted patch for "safety" doubled the file size, so I had to write it in explicitly little-endian. (MKendora) - Removed the old hidden cursor (MKendora) - Applied a WAI correction from anomie. (anomie) - Added a patch for Pseudo hi-res (anomie) - Hacked around Word writes to $7F:FFFF. Thanks to lantus and The Dumper for verification. (MKendora) - PPC compile fix? and debugger reversion (anomie) - Set defaults differently to improve sound quality. (MKendora) - Clear Force load settings after Init (lantus) - Made menu reset a soft reset. Fixed BL Sound Test & more (CaitSith2) - Fixed word writes to block bounds in asm core. (MKendora) - redone version of my bounds fix, only this one WORKS! (TRAC) - Thanks to TRAC for the AT&T syntax refresher! (TRAC) - Fixed screen saver disable (kode54) - Fixed OAM and sprite priority in the asm core (anomie) - Proper Interlace fix for mid-frame changes (anomie) - Fixed OpenGL to accomodate previous patch (MKendora) - Ported the "Settings" dialog to VC (MKendora) - Fixed ROM Info bugs (_pentium_five, MKendora) - Fixed non-stretched interlacing, but it's s.l.o.w. (anomie) - Superscope and Mouse need to be enabled by the menu. (MKendora) - Fixed HiROM sram reads in asm and C cores (anomie, MKendora) - Added Company 48 to the list. Thanks to _pentium_five_ (StatMat) - Set Super Drift Out's S-ram correctly. (Snes9xppSE Team) - Fixed NTSC timing. Helps ToP Intro greatly (kode54) - Added several entries to the company list, from uCON64 (Nach) - Lots more companies (StatMat, Nach) - Fixed Win32 Superscope support (NT kernel only?) (MKendora) - Added ZSNES OBC1 code ported from asm to C (sanmaiwashi) - Implemented Justifier emulation (neviksti, MKendora) - Fixed Rudora no Hihou's clip window bug (anomie) - Fixed Flintstones sprite issue (lantus) - Fixed sram mappings for Big Sky Troopers and Taikyoku - IGO Goliath. Both map in bank F0 (MKendora) - Fixed a possible crash when switching audio settings (MKendora) - Added per-pack gfx pack configuration (MKendora) - Fixed glitches in DSP-1 games (Flintstones fix) (lantus) - Added delay to Superscope latching. Fixes X-Zone. (neviksti, MKendora, zones) - Added DSP-2 support (Overload, The Dumper, Lord Nightmare, MKendora, neviksti) - Fixed Super Bases Loaded 2 (and J/K ports) DSP-1 seems to ignore the A15 line in LoROM maps (MKendora) - Corrected $4200 again (The Dumper) - Corrected $2100, $2102, and $2102 read behavior (anomie) - Fixed Cancel on the Sound Options dialog. (MKendora) - Fixed the sound options dialog (Thanks, Quattro) (MKendora) - updated DSP-1 support to match chip better (Overload, neviksti, The Dumper) - added a few Ops to the DSP-4 routine (Nothing plays yet) (neviksti, The Dumper, Overload, MKendora) - added screenshot support (anomie, sanmaiwashi) - stubbed the ST010 chip in Exhaust Heat 2 (Overload, MKendora) - hacked around War 2410's lockup (pagefault, _Demo_, MKendora) - updated tests for type 1 ROMs (based on reset vector) (MKendora) - Emulation mode CPU fix (The Dumper) - Open Bus fixes (anomie) - Better Expansion port emulation (anomie) - More Open Bus fixes (Overload, anomie) - HDMA fixes (fix colors only in Full Throttle Racing) (anomie) - Migrated DKJM2 onto the Tales map (MKendora) - Tried to remove Dragon Knight 4 hack (LoROM sram fix) (MKendora) - Fixed ROM Mirroring for LoROMs (<= 32 Mbit) (MKendora, TRAC) - blocked wram to wram DMAs (neviksti) - fixed HiROM mirroring, too. Thanks TRAC! (MKendora, TRAC) - fixed C core RMW and Push ops to write in the correct order, fixes Michael Jordan gfx. (anomie, Overload, MKendora) - set RDIO to start as 0xFF, fixes SuperFx games. (anomie, Overload) - New connect dialog (funkyass) - better conditional compile of FMOD (funkyass) - fixed screenshot code when libpng is not used (funkyass) - added portability fixes (zones) - fixed asm Pushes (anomie) - fixed asm LoROM s-ram decode (MKendora) - migrated DEZAEMON to standard LoROM map (MKendora) - fixed the Madara 2 OpenGL bug (key found in Rudra) (MKendora) - fixed asm RMW instructions (MKendora) - fixed ADC opcode (The Dumper) - added DSP-2 Op09 (The Dumper) - updated C4 C code (anomie) - updated C4 asm code (Nach) - Keep OpenGL in ratio (kode54) - Replaced many more Borland dialogs (funkyass, MKendora, Nach) - Added CRC32 to displayed ROM Info (Nach, MKendora) - Fix cheat support (The Dumper) - improved DMA timing (MKendora, Overload, The Dumper) - Fixed Mode 7 math, removed Dezaemon, Gaia, Ys 3 hacks (TRAC, MKendora) - Mode 7 flip fix (TRAC) - Multiple safety and initialization fixes (zones) - Platform safety fixes (PBortas) - Memmap cleanups (MKendora) - More preliminary work on special chips (The Dumper, Overload, MKendora) - Added color coding (MKendora) - Another HDMA fix (anomie) - added another known hack to the hacked games list (Nach) - ToP memmap changes (MKendora) - Checksum calculation changes (MKendora) - Special cased a few games for OAM issues (MKendora) - Reverted OAM reset to 1.39 timing (MKendora) - Reworked vram wrapping (zones, Mkendora) - Fixed $4210 and Super Professional Baseball 2 (Overload, MKendora) - Fixed APU RAM init (Overload, MKendora) - More support for Exhaust Heat 2 (not playable) (The Dumper, Overload, neviksti) - removed some debris from save states (MKendora) - fixed? Doom's save state bug (MKendora) - simple overdump detection warning (MKendora) 1.39mk3b - Fixed the RTC detection. FINALLY done correctly (lantus, MKendora) 1.39mk3a - neatened up the company table. (MKendora) - fixed a mistake in the ROM Info box (MKendora) - Added a Calulcated Size field to ROM INfo. (MKendora) - Added 3 more companies to the ROM Info table (MKendora) - Fixed BS detection (The Dumper) - Added a Legend-specific hack to get sound. I remembered it being mentioned in the changelog. (Gary Henderson) - Unbroke the Star Ocean special cases (Trigger of Time, MKendora) - Company 255 is not Hudson-ZFE detects all Hudson games without it, except a corrupt dump (StatMat, MKendora) - fixed a bug in the redone detection for the SPC7110 (CaitSith2) - 44Khz sound should be 44.1Kz. Changed, though you'll need to re-set 44.1Khz to make it take effect. Not sure if this affects non-Windows ports. (MKendora) - Added 32Khz playback (MKendora) - Inproved BS ROM mapping (_Demo_, The Dumper, MKendora) 1.39mk3 - Honkaku Syogi Fuunji Ryuou (J) fixed (force no multitap) (Frank Yang) Also Fixed Super Castles (j). Also fixed a bunch more. This dude e-mailed like 100 bugs to my hosts, some already fixed in Snes9x1.39mk2, but about 7 were clearly multi-tap5. - also fixed Dekitate High School. Error was in Japanese (Frank Yang, Tomato) - fixed 2 memory leaks (Aaron) - Dai Kaiju Monogotari 2 works as a 40 Mbit ROM. (MKendora, The Dumper) - Fixed the Flashback bug. Lots of info led to this. (neviksti, MKendora) Thanks neviksti, The Dumper, TRAC, and FatlXception for clarifying the behavior. - Fixed Sailor Moon Fuwa Fuwa Panic 2 to work with (neviksti, MKendora) previous fix. It's a total hack, but it should sound just like the old Snes9x did. neviksti strikes again! - Dirty hack to make 3 games deinterleave properly: (MKendora) Wizardry 4, Mark Davis, and Honkakuha Igo Gosei(FX) all work as well as the deinterleaved counterparts. (The last is a hacked game, and you should get the non-FX version) - Fixed Seima Jyuden Beasts and Blades. Another Multitap, (Frank Yang) but for some reason, the hack requires the C cpu core. Thanks to Tomato for taking a stab at the error message, as well. It was too vague to be of use, he said. I just tried it because it worked on other games. - Res Arcana fixed. Another Frank Yang report, another J (Frank Yang, MKendora) error, but I can read kana well enough with a table! - Removed a Terranigma specific hack. Not sure, but the (anomie) new behavior might have fixed Tin-Tin in Tibet's colors. - Dirty hack to work around a dirty hack. Both Yoshi's (MKendora) Island (E) dumps should work now - Added the JumboLoROM memory map, Extends LoROM support (The Dumper, neviksti, MKendora) to 48+ Megabits. - added an EXTBG fix, since iirc, TRAC is using it as well (anomie) Does it actually fix anything? - Fixed crash in DSP Op06 (The Dumper) - Fixed a GUI error on my part (Trigger of Time) - Cleaned up some of the SPC7110 detection/size code. (MKendora) - Merged in XBox port changes to SPC7110 code (lantus) - Added a call to Memory.Deinit when exiting. (lantus, MKendora) - Many memory leaks fixed while chatting with lantus (lantus, MKendora) - Fixed that stubborn open/close leak (lantus) 1.39mk2 - hacked in Shien's Revenge (anomie) - fixed Orge Battle's green lines. (CPU source for DMA) (anomie) - Looks interesting, and might apply to other DMA cases? - maybe "fixed" DKC's barrels? by treating $2001 as unmapped. The game worked before with a hack. (MKendora) - optimized SPC7110 slightly by removing extra setup work (MKendora) - Fixed DBZ 3 (Korean). S. Korea is, in fact, NTSC. (MKendora) - Fixed a hard-coded value in the SPC7110 (MKendora) - Added a Win port ROM Info dialog (MKendora) - some companies aren't in the table I used. If you encounter an Unimplemented company, report it the the Snes9x development forum, with the correct company and the number. 1.39mk - SPC7110 support based on Dark Force's docs. (Dark Force, zsKnight, The Dumper, MKendora) Trust me when I say those guys deserve the credit more than me. From what I'm told, Dark Force is the man behind most of the reverse engineering, but they all did a much harder bunch of work than I did following their specs. It's plain and simple that these three are the masterminds behind all SPC7110 support. Dark Force for reverse engineering the chip (Extremely tough work!) zsKnight for the original core, and probably other things The Dumper for dumping the packs and doing hardware tests. Also thanks to CaitSith2 for numerous bug reports and a lot of bug fixes. - Theme Park hack removed, fixed via PPU latching (anomie, MKendora, TRAC) - WWF Wrestlemania hack removed (anomie, TRAC) - Strike Gunner hack fixed (anomie, MKendora, TRAC) - FF:MQ text fixed. May help other sprite issues. (TRAC) - Umi Hara Kawa Se timing corrected. (anomie) - S-DD1 packs load by the same rules as ZSNES (MKendora) - SPC7110 code builds in linux (Lord Nightmare, zinx) - Added The Dumper's DSP-1 updates (The Dumper) - SPC7110 is correctly displayed on load, RTC also noted. (MKendora) - Fixed a potential graphics problem (TRAC) no known games fixed, but who knows? - Fixed Ballz3D (pagefault) - Re-fixed Ballz3D, via DSP op 0F (The Dumper) - included some of anomie's fixes. Many caused me grief, so only Marko's Magic Football is intentionally fixed. (anomie) - finished zsnes save support, though I don't know how well it will work with SPC7110 games (MKendora) - Added a new soundux.cpp again to fix some noise. (Fixes the GW "fart track") (Lord Nightmare, info from Anti-Res) - Added 3 cache modes for SPC7110 games (MKendora) - Added new BRR decoder. Requires sample caching and the Anti-Res decoder be disabled. (FatlXception, port by Lord Nightmare) - Added CaitSith2's RTC debugger. define RTC_DEBUGGER in project settings to enable it. (CaitSith2) - SPC7110 per-game cumulative logging (MKendora) - other fixes that I've forgotten (sanma iwashi, TRAC, anomie, ????) - "I'm not worthy" thanks to the original SPC7110 crew (DF, zsKnight, and the Dumper) - Thanks again to the same people, because they deserve it! - thanks to The Dumper, Dejap, TRAC, and all the ZSNES crew for technical assistance - Thanks to most of the Snes9x mods for testing (no thanks to you, Raptor ;) - and thanks to TRAC and #mkendora for letting me vent at you. 1.39 - Added SDD-1 unknown graphics data logging at the dumper's request. A bit late but might help with Street Fighter 2 Alpha's data dumping. Creates a romname.dat file in the freeze file folder. - Implemented 16-bit texture support for OpenGL modes in Windows and Linux. Had to support a new pixel format type to do it - RGB5551 (one bit of alpha) which caused me some major problems - black was no longer always pixel value zero! - Removed the Bump map OpenGL mode from the Windows port (didn't look so good anyway and was slow). - Added a hidden novelty OpenGL mode (clue: a keyboard shortcut activates it) - Reverted back to FMod version 3.20 after reports that version 3.33 broke AD3 support. - Implemented a better work-around for the broken select system call in the Linux kernel - the original work-around was long-winded and stopped working when I implemented OpenGL support under Linux. - Added the same speed-up hack to the OpenGL code that the Glide code already supported. Basically, if your OpenGL implementation supports 16-bit textures then OpenGL mode should be as fast, or faster than the 3dfx Glide mode. - Hopefully fixed Glide support. - Reverted back to the original colour blending code. The newer code, although more accurate in most cases, had too many glitches and was slower. - Included multiple Japanese games fixes from Iswashi San. - Fixed a timing problem caused by a speed up hack that was affecting Top Gear 300. No the game still isn't playable yet, but I noticed the problem while investigating the DSP-4 chip used by the game. 1.38 - Added support for Star Ocean and Street Fighter 2 Alpha decompressed graphics packs from dejap. Used a binary chop search rather than a linear search to locate correct decompressed graphics more quickly - should help emulation speed during later stages of the game. - Included OpenGL support into the Linux port and speeded up the Windows OpenGL implementation slightly. The real speed up would occur if I could figure out how/if 16-bit textures are supported in OpenGL because at the moment the 16-bit software rendered SNES image must be converted to 24-bit before being uploaded as a texture... - Included the latest ZSNES DSP-1 code. Now Pilotwings, SD Racer and Suzuka 8 Hours are playable. Aim For The Ace, Super Air Diver 1 & 2 and Syutoko Battle 94 are also playable, but with bugs. Thanks to zsKnight, _demo_, et al for all their hard work. - Another Daffy Duck: Marvin Missions screen flicker problem worked around - writing to the IRQ enable register shouldn't clear any pending IRQs, but Sieken 3 seems to require this or else the game hangs. Special-cased Daffy Duck for now. - An NMI emulation bug was triggering a Panic Bomberman World game bug, crashing it. Basically, if a game enables NMIs after the normal trigger point, the NMI should not trigger if the game has already read the NMI clear register. - Panic Bomberman World requires SPC700 memory to be initialised to zero on reset otherwise the game hangs when a tune finishes and another one should start. - Added mouse pointer auto-hide to the Windows port. Much better than the turn the mouse pointer into a black dot method I was using before. - Included the latest ZSNES Super FX code. Not sure if it fixes actually fixes any games. - Added an offset hack for Strike Gunner to get the scrolling ground layer to line up correctly - another offset-per-tile bug hacked around for now. - Arrr! Left in some debugging code in the last release that prevented all games that need the slower SPC700 timing from working. Removed it. - Hmm. The broken cut-scenes in Deep Space 9 seem to indicate that I haven't got the emulated clock speed of the 65c816 CPU correct yet. And not by a little bit - a 9% too slow error. Hacked special timing for the game for now. - Added triple-buffering to Windows port - enabling double-buffering actually enables triple-buffering if you have enough free video RAM, defaulting to double-buffering if you don't. - Fixed another crash bug in the interpolated mode 7 code - if no scaling was being used (either up or down) and screen repeat was enabled and the screen was flipped horizontally, the routine would crash Snes9x. Was causing Snes9x to crash during rock monster boss stage of Castlevania 4. - Oops. Got the initialisation of the default SNES screen width and height round the wrong way - could cause a X Windows System error message on the UNIX port after loading a ZSNES freeze file. - Included the unofficial Windows port emulation fixes for several games including Kentouou World championship and TKO Super Championship. - Included Iwashi San's improved Anti Res. sound sample decoding routine and updated the C version to match. - Included Anti Res. improved sample decompression code he sent me ages ago, but for some reason I didn't include. Sorry. This version seems good enough to leave enabled all the time. 1.37 - Added fix for Captain America's corrupt graphics - a ROM bug causes it to read from what I thought should be an unmapped memory area, but it expects the value returned to be zero. - Added code to support games that switch to the hi-res. SNES screen mode part way down the screen while using the 3dfx bi-linear filter mode. The code basically has to back out of the speed up hack it was using when the game switches resolutions. - Fixed support for games that have mixed lo-res. (256x224), medium res. (512x224) and hi-res. (512x448) all on the same screen - corrects the display of Majin Tensei 2. - Added support for games that use sub-screen addition to the back-drop layer while displaying hi-res. graphics - something I thought the SNES couldn't do but the game Marvelous uses this. - Reworked the UNIX/Linux output image handling code: the image doesn't always have to be scaled when hi-res. support is enabled, the PutImage operation only updates the area of the screen it has to, the SNES image is now always centred in the window/full-screen area and if the SNES image changes size between frames, the old screen areas are now correctly cleared. - Fixed the corrupt graphics problem during the battle scene of Last Bible 3 - it requires that previously unknown DMA mode 5 should just act the same as DMA mode 1. - Fixed a nasty bug when H-IRQs were being reused on the same scanline - a logic bug could cause H-DMA processing for that line to be skipped. Was causing the bridge and the start banners to be the wrong colours in Top Gear 2. - Added Kreed's display processing modes to the Linux port, including his new asm version of the Super2xSaI mode and the new software bi-linear filtering mode. - Think I might have figured out the odd Mode 7 glitch problems the games Illusion and Gaia and Chase HQ were having. My original fix was to mod the centre X & Y values with 1024, but looks like the true fix is to mod X + horizontal offset and Y + vertical offset with 1024 when screen wrapping is enabled. - Disabled H-DMA'ing into V-RAM via registers 2118/2119. The game Hook deliberately does this causing graphic corruption while dialog boxes are displayed. Maybe the real SNES disallowed this and it was left in the game by mistake? Not sure what effect the game was trying to produce because disabling the emulation of this feature doesn't seem to affect the game at all, other than stopping the corruption. + Also fixes graphics junk problem on first screen of Bugs Bunny. - Added a 'region-free' timing hack for Power Rangers Fight - without it the NTSC version was displaying badly glitching graphics; I'd already fixed the PAL version. - Added true priority-per-pixel mode 7 support (the previous support was just a hack to get the colours correct) - level 2 of Contra 3 used this feature. - The Japanese, German, French and Spanish version of Illusion of Gaia needs the slow SPC700 timing. - Deleted the Breath of Fire 2 S-RAM hack for the hacker intro version - according to reports it was causing problems for the non-hacked version. - Legend, the PAL version, never sets the sound master volume control - Snes9x was defaulting this to off, I guess the real SNES must default it to full volume; changed Snes9x. The NTSC version of Legend does set the master volume level, but sets it to off just after the title screen. Hmm. The -nmv command-line switch allows you to hear sound in this version. - Panic Bomber World was tripping an SA-1 emulation bug - the WAI instruction emulation code was setting the 'waiting for interrupt' flag on the wrong CPU causing the main SNES to skip an instruction when the next interrupt occurred. - Panic Bomber World, Bomberman 4 and UFO Kamen Yakisoban all need the slower SPC700 timing. - Oops! The Super Formation Soccer 95 fix was causing Aero 2 to lock up. This means I have no no idea what value the DMA in progress register should represent. I've hacked it and made it toggle between 0 and $ff on each read which gets both games working, for now... - The ROM de-interleaving code always assumed the blocks were rearranged based on a power of two, but Francois found a copy of Soldiers of Fortune where this was not the case. Corrected the code. 1.36 - Finally worked out why the menu items weren't being highlighted in several ROMs, including Battletoads, U.N. Squadron and All Japan Pro Wrestling. Two problems: its seems the SNES does halve the colour value result when blending colours when only the fixed colour addition/subtraction is enabled, but doesn't halve the result when sub-screen is being blended and its a clear part of the sub-screen. The second problem was that I had an optimisation that prevented the time consuming colour blending code from being called if the colour being added/subtracted was black - adding zero to a number doesn't affect the result, but not performing the side-effect of halving the result does affect the final value... - Super Formation Soccer 95 requires that the DMA enabled register doesn't always return zero, otherwise the game locks up. - Thanks to several people reporting a screen flickering problem in the pseudo 3-d section of Jurassic Park 2 I've fixed a nasty problem in H-IRQ handling code which could cause double-triggers or skip IRQs altogether. With this fix I can now remove the special hacks for Ninja Warriors Again, Chuck Rock and F-1 Grand Prix. - More games needing the slow SPC700 timing: Zennihon Puroresu 2, Soulblazer and Robotrek. - The CPU idle time skipping code was skipping cycles during a software delay loop in Itchy and Scratchy, causing screen flicker. - Looks like reading the value of register $2137 shouldn't clear a pending IRQ - was causing screen flicker on Yoshi's Island. - Actraiser 1 & 2 both need the slow SPC700 timing. - Terranigma reads a sound channel's current sample output value and waits for it to be zero before preceeding. I forgot to always return zero when a channel was silent. This mistake was causing the game to lock up. + Itchy and Scratchy and was causing the music to stop and samples to be cut short in the Mario Early Years series. - Added a hack for Secret of the Evermore - at several points in the game, just as the plane is about to land, it reads from unknown registers $4000 and $4001 and, if it doesn't get the value its looking for, the game hangs or displays corrupt graphics. - Silva Saga 2 was accidentally triggering a colour blending hack I put in place Kirby Dreamland 3 and Kirby Superstar. - The ZSNES freeze-file loading code could leave a file open if the file wasn't a valid ZSNES freeze file. - Super Punch-out requires certain DMA registers to be updated after the DMA completes. Snes9x used to do that, but I must have accidentally left the code commented out whilst investigating a different problem in another game. 1.35 - Added a recently played game list to the Windows port File menu so you can quickly load up your favourite games. - Included IPS patching support based on code from Neill Corlett - just rename the patch file to match your ROM image name but with a .ips extension and copy it into your ROM or freeze-file folder. - Added John Weidman's and Darkforce's S-RTC, (Real Time Clock) emulation code. The only game that seems to use it is Dai Kaijyu Monogatari II. - Included code from Nose000 for games with 128Kbytes of S-RAM. Now Sound Novel-Tcool, Thoroughbred Breeder 3, RPG-Tcool 2 and Dezaemon are supported. - The Windows port now has an option to make the 'turbo speed' button a toggle button. - The optimised fixed colour addition/subtraction code was ignoring the colour window. Thanks to John Weidman for pointing this out. - Added mode 7 and hi-res. hack for Dezaemon from Nose000 - the mode 7 hack looks interesting (to me); I wonder if some other games would benefit? - Both Tales of Phantasia and Star Ocean need custom sound CPU timing. Hmm. That's 4 ROMs now, there will be more... That means I still haven't discovered all the major SNES timing quirks. :-( - Windows port now has an option to save the S-RAM data at any time. - Windows port saving SPC dumps now auto-increments the filename. - Added work-around for a Super Robot Wars Ex ROM bug - the game was checking the wrong PPU register for end of h-blank. The game must have only worked by chance rather than by design on a real SNES. 1.34 - Corrected the colour addition/subtraction and halve the result code not to halve the result when only the fixed colour is used, i.e. the sub-screen is clear. Discovered and fixed this awhile ago, but I accidentally reintroduced the bug when adding some optimisations a few versions back. - Finally cleared the last of the offset per tile background mode bugs. There was something odd about the tile at the left-hand edge of the screen that I couldn't figure out - well now I have. Yoshi's Island level 6 boss screen, Mario RPG mine cart screen and Jim Power title screen now all display correctly. - Made reading blank areas of the SNES memory map return the middle byte of the address - fixes Home Alone which tries to execute code in an empty part of its memory map but only works because the real SNES seems to return the middle byte of the address - $60 in this case, which corresponds to the ReTurn from Subroutine instruction. - Added auto-cycle skipping disable for Earth Worm Jim 2 and several other games that spool sample data using H-DMA as the sample is being played. Improves some sound effects in these games. - Fixed joy-pad routines to only report up or left if down or right are also pressed respectively. Works around a game bug in Empire Strikes Back in the asteroid stage where the game crashes if both left and right are pressed - something impossible to do on the original SNES game-pad. - Added custom SPC700 timing for Rendering Ranger R2 - the game now works with full sound. No idea why it needs custom SPC700 timing. - The ROM type detection was broken for Treasure Hunter G and Test Drive 2 - fixed the code so type 2 ROMs can be LoROM. - Adjusted the main CPU cycles per scan-line from 341 to 342 to give an exact match for the timing required for Earth Worm Jim 2. All EWJ2 needs now for perfect sound emulation is a method of synchronising the emulation speed to the host hardware's sound card playback rate, oh, and a fast CPU! The Linux port already has this but seems to be broken because games play at double-speed when this option is enabled. - Some SPC700 code in Earth Worm Jim 2 seemed to prove that I had guessed the clock speed of the SPC700 sound CPU incorrectly - out by almost a factor of two, in fact. Changed the relative emulated clock speed of SPC700. Now Chrono Trigger doesn't lock up at certain points anymore, the special SPC700 timing for games written by the Human Software company isn't required and you can hear some more of the sound samples in Earth Worm Jim 2, etc. - H-IRQ triggering code was broken - if a ROM turned on H-IRQ but later turned it off, Snes9x could continued to generate H-IRQs, crashing some games. - Added a generic test for Human Entertainment games - they need special sound CPU timing to work. Gets Taekwon-Do working. - Disabled offset-per-tile mode for Theme Park; the world map screen is corrupt with it enabled. - Yet more changes to the offset-per-tile backgrounds modes 2 and 4. Added 64 tile wide screen support for Mario RPG's mine cart ride and fixed multiple bugs with the handling of horizontal offset-per-tile used in Chrono Trigger's fade in of the space ship. - New feature: Snes9x can now load ZSNES freeze state files! Just copy them into the freeze file folder and Snes9x will load them when you load a freeze file, but only if the corresponding native format Snes9x freeze file doesn't exist. - Added memory map hack for Batman - Revenge of the Joker: its ROM header block is in the wrong location and Snes9x incorrectly detected its ROM type. - Fixed an off-by-one-pixel clip window 2 bug when the window was set to clip outside the window area; clip window 1 was already correct. Removed the bright line bug at the left edge when the combat screen is appearing in Starfox and the clip problem when text boxes zoom-out in Yoshi's Island. - Jim Power's title screen seems to prove that the per-tile offset data on mode 2 isn't ignored for the left most tile as I originally thought. Modified the code. - The recent timing changes highlighted another problem with Daffy Duck - changed IRQ enable register to only clear pending IRQs if one has been pending for several microseconds. - Speeded up the sprite data register handling slightly. - Finally got Aero the AcroBat 2 working, after many hours of investigation, spread over several years - literally! Two problems. The SNES doesn't seem to consider scan-line line zero to be part of the v-blank period even though the line is never drawn and V-IRQs at the start of the scan-line have to be delayed until a few microseconds into the line - Traverse: Starlight & Prairie required this as well, so I removed the original, Traverse specific hack. There's a problem with the in-game music that I'll investigate at a later date. - The in-game music problem just required ENVX emulation to be switched on, off by default on the Linux port, on by default on the Windows port. - Fixed the mode 7 corruption problem on the title screen of Chase HQ using the same trick as Illusion of Gaia - i.e. mod the mode 7 centre X & Y values with 1024. - Fixed another crash bug in the interpolated mode 7 code - a portion of the code was ignoring the screen flip value and the fact that X render direction reversed if the screen was flipped horizontally. Was causing a crash on the whale boss screen of Kirby Superstar. - Mortal Kombat 3 now auto-adjusts emulated cycles per scan-line work-around a speech sample being cut short. - Added sample data register reading support to the sound DSP - somehow I seem to have missed implementing this. Not sure if any ROM actually reads the value. - Followed Sumire Kinoshita's suggestion and stopped clearing the ENDX flags when the value is read, against my better judgement, and it does actually improve speech samples in several games. Ooops! The Mortal Kombat series, Magical Drop 2 and Metal Combat are the ones I've discovered so far. - WWF Arcade now auto-adjusts the cycles per scan-line value to work-around a sound sample repeat problem. - Hmm. There's something about offset-per-tile mode I don't understand - WWF Wrestlemania Arcade is getting corrupt graphics; not sure what effect the ROM is trying to produce. Disabled offset-per-tile mode for the game for now. - Fixed Street Racer player 1 wobble problem during the soccer game by auto- adjusting the cycles per scan-line value slightly. - Made Power Rangers Fight auto-adjust emulated cycles per scan-line to work around a slight timing problem that causes an NMI to corrupt register values that an IRQ handler is trying to update. Without it the scrolling back-drop and fighter graphics are corrupt. - Illusion of Gaia seems to need the mode 7 centre X & Y values to be mod 1024 if the screen repeat flag is set. Fixes the island fly-over bug right at the end of the intro but breaks a few other games. Hmm. Made it auto-switch on for this game only. - Added memory map support for Radical Dreamers. Thanks to satellite hut master for the information. - Made updates to the top bit of the sprite write address register be ignored unless the low byte had been written to first. A ROM coding bug in James Pond II requires this, otherwise it writes a junk byte value into the main character's X position and Robocod wobbles around all over the place. - Reverted back to pre 1.31 way of initialising unknown register values - Rock and Roll Racing was reading a junk register value and using the value to set up DMA, which in turn was causing corruption on the player select screen. - Added Star Ocean memory map - thanks zsKnight! The original ROM I was testing was corrupt, no wonder I couldn't figure out the memory map myself! The game still isn't playable, though, due to missing S-DD1 graphics decompression (+ encryption?) emulation. - Started to dump some compressed data values from Street Fighter 2 Alpha in the hope that one day someone will be able to crack the S-DD1's compression algorithm. 1.33a - C4 emulation wasn't being automatically enabled for Rockman X2 / X3 - the Japanese versions of Megaman X2 / X3. - Fixed the Super FX plot table pointer that I accidentally broke while saving 1Mb of workspace RAM - it was stopping all Super FX games from working. 1.33 - Noticed another problem with the CPU_SHUTDOWN code - Chrono Trigger locked up during the intro but only when using the asm code CPU core. Found the algorithm difference between the code and made the CPU match what the C version was doing. Still not sure why it caused a problem in the first place. - Changed colour subtraction code to use Lindsey Dubb's newer version he sent me some time ago but I 'forgot' to include. I say forgot, but I really put off including it because, although it improves most games that use the effect, it does result in one or two slight visual glitches. - Hacked in zsKnight's C4 emulation asm code - now both Megaman X2 and X3 are playable. Still got to complete the reverse engineering of the i386 asm code to C so other, non-Intel ports can have C4 emulation. - Shuffled the keyboard mapping a bit on the Linux port so now Tab key acts as an emulation speed turbo button, `, # and ~ act as superscope turbo and / acts as the superscope pause button. - Fixed asm CPU_SHUTDOWN code that I accidentally broke while trying to optimise it! Thanks to all the people who noticed Snes9x's frame skipping had changed between releases. Frames rates should be improved again for more than 50% of games. - Re-enabled in-lining of the C SNES memory access routines, improves frame rate by one or two on slower machines. - Optimised the asm 65c816 addressing mode emulation code a little. - Included some code changes making life easier for the Mac porter, John Stiles. - Added memory map support for Sufami Turbo using information supplied by Nose0000. No idea if it works because I don't have the ROM. - Spent a few minutes trying to figure out the Star Ocean memory map so at least the sound effects could be heard. But gave up after a couple of hours due to laziness. If anyone knows the memory map details, let me know please! 1.32a - The delay loading of the OpenGL DLLs on the Windows port was causing the OpenGL initialisation code to fail. Reverted back to normal DDL loading but with the side effect that Windows 95 users must visit the Microsoft web site and download the OpenGL add-on before Snes9x will work for them. - Corrected the OpenGL bump-map display option - my attempt to get the bi-linear OpenGL display option to work with Voodoo card's limited texture size had broken the bump-map mode. 1.32 - Changed the Windows port to delay load the two OpenGL DLLs, so now they're only loaded if you switch to OpenGL mode. The original version of Windows 95 didn't include the OpenGL DDLs, so Snes9x wouldn't even start on that platform; now it should. - Added yet another sound buffer option to the Windows port - this time the block size of sound data to mix. Some DirectSound sound card drivers only report the play position moving in steps rather than continuous amounts and Snes9x's default mix block size turned out to be smaller than this step value on several cards. Snes9x couldn't work out out where the true play position was accurately enough resulting in broken, noisy sound output. - Modified the Windows frame timer code to use semaphores rather than events - they should make Snes9x more reliable at not missing frame sync pulses when Windows is busy doing background tasks. - Added SA-1 shutdown code - basically, Snes9x now stops emulating SA-1 CPU instructions when the SA-1 enters an idle loop waiting for the main SNES CPU to give it something to do. All SA-1 run much faster and smoother now. - Added multi-axis joystick/game controller support to the Windows port and tweaked the dead-zone threshold position a little. - It looks like the SNES PPU was designed to support 128K of V-RAM but only 64K was fitted; Snes9x wasn't wrapping all V-RAM address to stay within the 64K limit causing a corrupt title screen on ReX Ronan - there will be others. - Added amend functionality to the Windows Cheat Entry dialog and added extra text boxes for direct address and cheat value input rather than only being able to type in a Game Genie or Pro-Action Reply code. - BS Suttehakkun2 was crashing just before start of play - the ROM was performing a junk DMA that was corrupting RAM, crashing the game when it went searching for a particular value. - F-1 Grand Prix requires IRQ triggering when IRQ scan-line register set to current scan line, but Chuck Rock objects. Hmm. Chuck Rock seems to indicate the CPU emulation is running too fast, but I can't see where the mistake is. Special-cased Chuck Rock for now. - Optimised SNES DMA handling slightly - copying data to SNES V-RAM is now significantly faster. - Windows Cheat search dialog was ignoring data type parameter in various places which was causing problems when larger numbers were being searched for. - Forced unknown PPU register reads to always return 0 - a coding bug in Equinox shows that this is required. An earlier fix didn't work. - Puya Puya 2 & remix were objecting to an NMI being triggered when enabling NMIs after scan-line 226, but Ys 5 seems to require this. Hmm. Added a hack to support both games. 1.31 - Snes9x DirectSound code modified - the mixing block size is now always 10ms for Windows 95/98/2000 and 20ms for NT 4.x, now there should be no need to enable Sync Sound when a large sound buffer is required (helps emulation speed). The maximum sound buffer length values have been updated to reflect the smaller mixing block size. - Changed the DirectSound code back to use an offset from the play position as the place to write new sample data into the sound buffer - on NT 4.x the write position seems to vary randomly rather than being a fixed distance in front of the play position as documented. Now I know why I used the play position originally! - Changed the DirectSound code to fill the sound buffer at the write position supplied by DirectSound, rather than just before the current play position - should help reduce latency. - Added an auto-detect method for interleaved mode 2 Super FX ROM images - well, not really auto-detect: if the game crashes and its a Super FX game, Snes9x assumes its in interleaved mode 2, de-mangles the ROM image and tries to run the game again. - Had to update the Snes9x Windows registry version number as the additional diagonal settings make old registry settings incompatible. - Added diagonal keyboard controls to the Windows port, as requested by several users. - Changed PPU code to return zero when reading non-existent registers - the game Equinox relies on this due to an original game coding bug. - Included FMOD sound driver support to Windows port - people experiencing broken sound or delayed sound, etc, might want to give it a try. - Tales of Phantasia - un-interleaved format ROM memory map changes to match odd ZSNES format, now the hacked ROM works. - Changed NMI again. Made reading or writing to PPU register 0x4210 clear NMI pending flag again, without this Super Tennis does not work. - Changed NMI timing back to be the same as several versions ago and just special cased Cacoma Knight instead - although kept the code to prevent the re-triggering of an NNI more than once in the same frame. 1.30 - Forgot to force GUI surface to be displayed when some dialogs where popped up - problem only happened on full-screen mode with triple or double buffering enabled, or when using 3dfx mode. It appeared as if Snes9x had locked up, but pressing Esc would pop down the hidden dialog. - Added a couple of options to the Settings dialog. Now its possible to disable S-RAM auto-save which was causing Snes9x to write to the hard disk every 30 seconds on some games, causing the occasional skipped frame. - Fixed Reset option which was accidentally broken when Netplay support was added. - Added support for Dirt Racer - it leaves the Super FX chip running all the time, so the default CPU emulation method never allocated any time to other CPUs and the emulation seemed to lock up. - NMI timing changed again. Now an NMI can only be triggered once per frame and enabling an NMI after the normal trigger scan line triggers an NMI immediately. This fixes display glitches in Ys 5, Stargate and Daffy Duck. - Fixed the WAI instruction to only 'wake up' once an actual NMI has triggered, rather than just waking up when it should have triggered. This fixes Battletoads, broken since version 1.29(ish). - Changed NMI again. Made reading or writing to PPU register 0x4210 not clear NMI pending flag. Seems to allow all the NMI timing sensitive ROMs I had on my list to now work without any special hacks. Illusion of Gaia now works again. - Another NMI fix - cleared the CPU pending NMI flag at start of frame; Battletoads intro was crashing without this. A long DMA was stopping the SNES CPU so it couldn't and shouldn't respond to the NMI signal from the PPU. - Fixed Netplay problem when game didn't have any S-RAM and Sync Using Reset was being used. An error dialog was displayed and the client would disconnect from the server. 1.30b#1 - The Windows auto-frame skip code was broken - badly. It didn't re-sync a timer value with timer events being generated, causing Snes9x to deliberately stop and wait for an event when it didn't need to, slowing down the overall emulation speed and increasing the number of frames skipped. - Improved the Windows cheat search dialog - its now possible to compare against a value and more comparison functions are available. - Finally worked out why Voodoo 3 support was so buggy in Snes9x - the Voodoo 3 card generates a WM_DISPLAYCHANGE message when switching to Voodoo mode (the Voodoo 1 and 2 cards don't); Snes9x thought that some other application had changed the screen depth or resolution and tried to adjust its window to match - triggering another WM_DISPLAYCHANGE message. No idea how the code worked at all; it must have been only by chance and very dependant on the driver version you were using! - Implemented Netplay on the Windows port - but its buggy as hell. I seem to be having major Windows multi-threading problems. Comments I've seen seem to suggest that Windows 95/98 don't implement true multi-threading; hmm... - Not happy with the current Netplay, so I scrapped it and tried again; the protocol is much improved and not using select to control game timing seems to have removed lots of the threading-type problems I was having. - Attempted to switch to just using Borland's C++ Builder to build the Windows port - and failed, again. Although C++ Builder can build Snes9x from sources, it can't then link in the asm CPU cores. I had hoped Borland might have fixed this with their latest release - they haven't. - Several attempts to get Anti Resonance's super-fast sound CPU and sound DSP code working in Snes9x, but all failed. Part of the problem was his code was written using TASM and the object files it generated would only work under Windows - but all my SNES debugging code was in the Linux port. Anti' fixed that, and I then had some success getting his code working, but its just too unstable at the moment for a main-stream release. - Included an option to use Anti Resonance's alternate sample decoding routine; it can approximate the wind and noise sound effects heard in several Square Soft games. - Thanks to Lindsey Dubb for the mode 7 bi-linear filtering code - it generates a nice smooth image when a game scales the screen using the SNES' mode 7, but you'll a fast machine if you don't want the frame rate to drop. - Thanks again to Lindsey Dubb, he improved the colour addition/subtraction subtraction routines - they are just a little slower but now mostly perform full 15-bit precision addition and subtraction rather than the previous 13-bits of precision. Many more colour shades can be seen - look at the improved shading on the Mario Kart or F-Zero track for example. - Added a reverse stereo option, for people with sound cards that swap the two channels. - Added a sound config dialog to the Windows port - now you can access extra sound options that have always been there, but just no GUI interface to access them. - Fixed the 32-bit windowed support on the Windows port. - Adjusted the NMI timing by a few microseconds to get Metal Warriors working again. - Added a few more sound playback rate choices. Most modern sound cards allow any value to be used from a large range, rather than just a select few, may be I ought to add text field so you could just type a value in? - Used Factory Setup 4 to build a new installer package for the Windows port - just shipping a zip file was confusing novice users and many (mostly AOL users) seemed to have an odd program mapped to .zip files, further confusing the issue. 1.29 - Disabled the SPC700 noise feature simulation used by Chrono Trigger and Final Fantasy 3 until I work out why its being triggered by sound effects that don't use it. - Rewrote/reorganised the DirectX and 3D/fx handling code, now both are never enabled at the same time in Snes9X. It might fix the crashing problems some Window port users are seeing. Changing between DirectX and Voodoo 3D/fx modes now requires Snes9X to be restarted. - Tracked down and fixed the Chrono Trigger black screen problem on the Windows port: a rogue asm instruction was left in by mistake after some code edits - it was only by chance that the code worked on the Linux port. - Added some SNES debug options to the Windows port, but disabled by default, on the shipped version. - Clicking on the column headings in the OpenROM dialog in the Windows port now sorts by that column; plus added some slight screen update optimisations. - Added an optimisation to graphics rendering: don't add or subtract sub-screen from background layers, or clear the sub-screen, if SNES fixed colour is black and no background layers are enabled on sub-screen, even if ROM tries to enable translucency effects for every background layer. Discovered Sonic was doing this, there will be others. - Forgot to enable auto S-RAM save on Windows port, oops! 1.28 - Warning dialog added to the Windows port - if a ROM is loaded from a read-only directory, e.g. a CD, and the freeze file folder is set to be the same as the ROM image folder, then a warning is displayed when the game first starts. - The Windows port now supports 5 joy-pads - Snes9x always did support 5 but the Windows port lacked the GUI option to enable and configure it. - Added an about dialog to the Windows port. - The Windows port now has a simple settings dialog, only one option so far - changing the freeze file and S-RAM save directory; much better than having to use regedit at least. - Added a new cheat search dialog, you can use it to find where games are storing life counters, health levels, etc. and then add cheats that stop the values from changing. - Added a cheat code entry dialog to the Windows port; now Game Genie, Pro-Action Replay and Gold Finger codes can be graphically entered and edited. - Added a master cheat codes on/off toggle, available from the Cheats menu on the Windows port. - Extended the number of cheats per game from 10 to 75. - Changed cheat code to reapply cheat every emulated frame so if RAM is being patched the cheat value is continuously applied. - Wrote some new cheat search code, the code won't be useful until I get around to writing a cheat search dialog. - Added automatic cheat code loading and saving using the same file format as ZSNES. - Rewrote large parts of the Snes9x cheat handling code ready for adding cheat dialogs to the Windows port. 1.27 - Added a flag to only enable SPC700 noise 'feature' when Chrono Trigger or Final Fantasy 3 are loaded - the conditions that I thought were necessary to trigger the feature where sometimes being met by other games. - Added a simulation of the SPC700 noise 'feature' where some games, notably Chrono Trigger and Final Fantasy 3, play samples that deliberately overrun outside a 16-bit value, the SPC700 sound DSP then for some reason starts to generate a type of noise sound which the games use to generate wind and swish type sound effects. Thanks to ZSNES for some of the information. - Fixed another sound interpolation problem, thanks to Mikael Bouillot - the initial value of the sample byte being played was not being set correctly when processing fractional offsets. - Added auto S-RAM save option; S-RAM is automatically written to a .srm file a few seconds (30 by default) after a ROM writes to it - useful for people who were playing games long into to night, only to lose their progress after a power cut or machine crash. - NMI delay code changed again - the fix for Cacoma Knight was breaking Tuff E Nuff; it would seem delaying NMI until the start of h-blank to too long, added a cycle counter instead. - Fixed yet another clip window bug - clip window was being incorrectly set at no range if colour window was enabled but background layer clip window was disabled (meaning layer should not be clipped). Fixes the sunken ship level on FF5. - Worked out (by example) how to add keyboard accelerators to the Windows port, now toggling full screen using ALT+Return works. - Added mouse-warp to the Windows port so the the cursor doesn't wonder off the Window while SNES mouse emulation is enabled. - Improved 3dfx support on Windows port - load dialog doesn't drop out of bi-linear mode and underlying window zooms to full-screen so its easy to find and click on the menu bar with the mouse. - Added Mouse and Superscope SNES emulation support to the Windows port, use '7' on the keyboard to select. - Windows cursor now hidden unless super scope emulation is enabled. - Windows port now has command line parsing - cheapo way of adding Game Genie, Pro Action Replay cheat codes, disabling sound CPU emulation for the corrupt copy of Star Fox 2, etc. Also allows ROM images to be dropped onto the Snes9x icon. - Cacoma Knight seems to provide proof that Snes9x triggers the SNES non-maskable interrupt (NMI) too early. Changed interrupt to trigger at the start of the next horizontal blank period. Will have to watch for it causing problems for other ROMs. - Added a translucency hack - when a ROM tries to create a stipple background pattern by enabling pseudo hi-res. and not enabling a background layer on one of the screens, Snes9x changes the effect to use transparency effects instead (the real SNES can't do transparency effects with pseudo hi-res. enabled). Now the water in Kirby 3 is translucent. - SA-1 CPU reset bug fixed, now Jumpin' Derby boots and plays but with major graphics problems. - Fixed nasty asm SA-1 custom hardware read/write bug that was causing the course map not to be displayed on Augusta Masters and Pebble Beach. - Added SA-1 character conversion DMA support for all SNES depths, now Augusta Masters and Pebble Beach work. - Merged in minor code changes for Linux running on the Alpha processor. Thanks to Sadruddin Rejeb for the changes. - Added four more auto-multi-player-adaptor-emulation-off presets based on code from Mystagogus. - Added DirectX3D output image processing support to the Windows port... and removed it again because it causes my desktop machine to lock up. Back to the drawing board... 1.26 - Fixed memory leak that crept in when SA-1 support was added when loading a game freeze file. - Added SPC dumping option based on code from Cyber Warrior X that he sent me ages ago but I've just found again while looking for something else! - Merged in most of the Amiga PPC port source code changes into the main source code tree. - Keying on a sound channel seems to clear its last-sound-sample-block-just- played flag. Chaos Engine/Soldiers of Fortune needs this. - Add multi-thread support to the UNIX ports for sound playing - required in the Linux port to work around a Sound Blaster Live driver bug and useful if you have multiple CPUs in your machine to help spread the emulation workload. 1.25 - Added BS 24Mbit ROM memory map, for Derby Stallion 96 and Sound Novel-TCool. No idea if it works. Thanks to Nose0000 for the info and code. - Corrected unzip code not to loop forever if an encrypted zip file is loaded - an error is generated instead. - Changed relative SPC700 cycle length for Mortal Kombat 3 to fix sample repeat problems - I wish I knew exactly how fast the SPC700 is clocked. Maybe I should write a test ROM and run it on a real SNES? 1.24 - 3dfx speed hack back again, only disabled when Seiken 3 is loaded. - Some minor SA-1 speed ups added - the SA-1 instruction skipping code will have to wait until I have more time. 1.23 - Corrected a SA-1 reset bug that reset the SA-1 RAM bank pointer back to block zero but didn't clear the RAM bank register. Was causing Kirby 3 to crash. - Fixed a wave clipping problem with interpolated sound that was causing noise on sound output when certain sound samples were played. - Fixed a bug in the sync-sound code that could overrun the sound buffer by a few bytes causing clicks on the sound output. - The sound sample repeat bug that has plagued Snes9x ever since is was called Snes96 finally bit the dust - Snes9x continued to play sample loops even if the game dynamically updated the sample not to loop. Fixes the stutter in the Mortal Kombat series and improves the sound from several games that download sound samples in real-time as they are played. - Rewrote the code the handled the SPC700's 64 byte shadow RAM area to fix a possible sample corruption problem with ROMs that stored samples that cross the 64 byte start area. - Added code to allow ROMs to change the sample being played the next time the channel loops or is keyed on - not sure if it fixes anything but seems more correct. - Added a zero-frequency fix to the stereo sound mixing code that I'd already added to the mono code some time ago. - Changed the code to set the end-of-sample flag just before the last block is played, rather than just after. Seems to help improve the sound on some games. - Sound sample start code now doesn't reset the channel's envelope volume level to zero before starting the sample - helps reduce the clicks being heard when a channel envelope volume level hadn't reached zero before being keyed on again. - Changed initialisation of sample-end-register to 0 rather than 255 - seems more logical now I've thought about it. Not sure if it helps anything. 1.22 - Finally fixed the corrupt copy of Donkey Kong Country not working problem - Snes9x thought the ROM used the same memory map as Street Fighter Alpha 2. - Added explode, un-shrink and un-reduce decompression modes support to the unzip code. - Fixed offset per tile bug that crept in after me trying to fix the Starfox on-tilt bug. - Made some fixes to the C Super FX emulation code, enough to get most 'FX games playable on the Mac port. 1.21 - Finally worked out how character DMA worked on the SA-1 and implemented a hacky, slow version, but its enough to get the level up screens displaying correctly on Mario RPG. - Incorporated ZSNES' new optimised Super FX asm code - had to track down and fix a nasty memory overwrite bug in the code first to get it to work. - Changed sample mixing code to not automatically wrap offsets to keep inside the sound buffer, external port code is now expected to do that. Helped me fix a problem in the Windows port that prevented very large sound buffers from working, which are required for some badly written sound card drivers. - Corrected a bug in the SA-1 C code where incorrect processor emulation functions where called if the code was compiled with in-lining turned off. - Fixed crash bug in Super Mario RPG on the level up screen - forgot to mask the enable bit from the RAM bank register. Thanks to Christian Wolf for sending me a freeze file which made it easy to find the problem. - Fixed a lockup bug in the window clipping code, if the ROM ever turned off the sub-screen completely the clipping code would enter an infinite loop. Fixes The Cartoon Addams. - Made the Daffy Duck NMI fix only enable when Daffy Duck is loaded - fix was causing problems for Breath Of Fire 1 and 2. 1.20 - Windows port no longer sets DirectSound to exclusive mode, so its now possible to hear sound output from Windows apps while Snes9x has focus. - Fixed the freeze file loading and saving on the Windows port. - More GUI settings are saved in the registry on the Windows port now. - Added 3D/FX image scaling/filtering support to the Windows port. - Added the TV mode from the Mac/Linux ports to the Windows port. - Incorporated Kreed's new output image routines into the Windows port that fixes RGB555 display colour problems. Many thanks to Kreed. - New auto-frame rate timing code on the Windows port, stops the silly speed up problems when the old code tried to 'catch up' after the emulator had been paused. - Increased the DirectSound secondary buffer length on the Windows port to hopefully fix all the static/broken sound output problems some people were experiencing. - Altered the ZSNES Super FX asm code so the Windows port could use it - all previous versions of the Windows port were shipped using the C Super FX emulation code which is a lot slower. - Implemented interpolated and sync-sound options on the Windows port. - Added an image stretch option to the Windows port - stretches the SNES image to fill the whole screen or the Window. Looks really good on my TNT card since that chips seems to filter the image as it scales it. - Implemented Windowed mode on the Windows port. - Added special SPC700 cycle timing for Empire Strikes Back. - Fixed the missing polygon problem for Super FX games - thanks to zsknight for the information. - Implemented SA-1 support required for Mario RPG, Kirby Superstar, Paradius 3, etc. but since only a good image of Mario RPG exists, I could only test that game. - Fixed a graphics clip window bug: inverting the area of a clip area that only consisted of empty bands should become the full width of the screen; Mario Kart's rear-view mirror display needs it. - Fixed mode 7 render code to use correct z-buffer when rendering onto the sub-screen. Fixes Final Fantasy V title screen. - Added horizontal offset per tile support in the offset per tile modes 2 and 6, and switchable horizontal/vertical offset in mode 4. Fixes Chrono Trigger in several places and Mario All Stars title screens. - Changed SPC700 relative cycle length to 14, needed for Stunt Car Racer. - Enabled immediate triggering of NMI if NMI enable flag set while scan-line was on first line of v-blank. Needed to fix a background jitter bug in Daffy Duck: The Marvin Missions. - Altered ROM load code to ignore corrupt ROM map type byte in ROM header, preventing the code erroneously detecting what it thinks are interleaved ROMs. Fixes EEK! The cat, Formation Soccer, the corrupt copy of Donkey Kong Country, ... - Disabled IRQ re-triggering if V-IRQ registers set to the current line. Fixes Chuck Rock. - Fixed missing sprites in Andre Agassi Tennis - writing to low byte only of the sprite write address register seems to also clear the hi-byte. 1.19 - Games written by the Japanese software company Human seem to need special SPC700 sound CPU timing, so the ROM load and reset routines now check the software author company and adjust the CPU cycle length accordingly. It gets Clock Tower, Super Fire Pro-wrestling Premium, etc working. - Added ROM check sum calculation and testing code - Snes9x can now detect pure, corrupt or hacked ROMs. - Noticed a fast way to implement the SNES 4096 colour mode, so I implemented it. Now the colours in ActRaiser 2 look correct. - Corrected a noise frequency error thanks to information from Takehiro. - Added a 'start in full screen mode' flag to the Linux port. - While debugging the new graphics code I thought of a fast way to implement the SNES direct colour mode, tried it out and now the colours in Actraiser 2 are correct. - Blast, forgot about the colour window and fixed colour effects. The separate sub-screen is back again, but all the other graphics speed ups are there. - Now I've got a z-buffer I keep finding other ways to optimise the SNES graphics rendering - no need for a separate sub-screen, no need to clear the sub-screen to the fixed colour, no need to waste CPU time on translucency effects on hidden pixels, no need to completely clear the main-screen to the back drop colour, etc., etc. - Implemented a software z-buffer and changed the SNES graphics rendering to use it (required change for future 3D card support). Finally fixes the sprite-to-sprite priority bug that some games suffer from. Also a big speed increasing for some games (10 fps+), others are slight losers. - Added code to skip the rendering of completely transparent graphic tiles rather than comparing each pixel to see if it is transparent; helps the frame rate a bit on some games. - Added a fixed for Tetris & Dr. Mario - the game didn't like a multi-player 5 adaptor plugged in to the real SNES when being played, so turned off the adaptor emulation for this game. - Added hack for Final Fantasy II - if sync sound isn't on, make attack rate of 1ms actually 0ms (old v1.16 behaviour). Causes a slight click but its better than samples being cut short. - Fixed a clip window area invert bug if the colour window was enabled on on one window and the other window was being used to clip a background layer. Fixes the finial (I hope) display problem with Gun Hazard. - Added code to intersect the clip window areas if both a colour window and a background layer clip window were enabled at the same time. Required by Gun Hazard. - Forgot to mark graphic clip windows as needing recomputing when the master colour window inside/outside/on/off/main-screen/sub-screen PPU register was updated. Was causing display problems for Gun Hazard. - Internal H-DMA execution accelerator pointer variables where not always being recomputed when started H-DMA part way into a frame. Was causing display problems for Gun Hazard. - Made H-DMA continue for one extra scan-line to fix a disappearing monster problem in Dragon Quest 5. Thanks to Alex Jackson for the bug report. - Zoop seems to require volume envelope height reading by the sound CPU to always return 0 when the channel is in gain mode. - The sound code was ignoring updates to the ADSR volume envelope rates while one was in progress. Fixed that and now the bird song at the start of Chrono Trigger sounds correct. - Had to disable the CPU shutdown code for loops reading the horizontal beam position, it was causing problems for Star Fox. Still no polygons though. - Oops, sound DSP noise output was broken - accidentally deleted an important line while removing debug code ready for the last release. - Added initial 3Dfx support to the Linux port - basically using the Voodoo card as a bi-linear filtering, scaling blitter. Actually slightly slower than TV mode, for non-scrolling images due to poor texture upload speeds to the card, but the full-screen feature is nice and the speed doesn't drop as more of the screen changes. 1.18 - Implemented a sync-sound mode where sound data gets generated in sync with SPC700 instructions being executed. Finally the sound Williams Arcade classics can be heard. Also helps slight sound timing problems in many other games but doesn't fix Mortal Kombat 2 like I thought it would - its sound routine programmers must have been on drugs or something! - Added interpolated sound - gives low frequency sounds much more bass similar to a real SNES especially with the playback rate ramped up to 44KHz. - Added on-screen messages as various emulation options are toggled on and off using the in-game keys. - Fixed a PPU register read bug with the sprite register write position. Thanks to Takehiro TOMINAGA for the bug report. - Altered the auto-frame skip timing code to only wait and re-sync to the end of frame when frames haven't been skipped. Again thanks to Takehiro. - Speeded up the colour addition and subtraction code using ideas from Takehiro. 1.17 - Linux and UNIX sound code now driven directly from signal timer handler rather than the timer handler just setting a flag which had to be polled in the main emulation code. Slightly faster execution. - Fixed the crash bug in the ZSNES Super FX asm code with Vortex - the game's polygons still aren't visible though. - Implemented bent-line increase and exponential decay and sustain volume envelopes - they should match, or at least be very similar to the real SNES sound DSP chip now. - It would seem ROMs can key on sound channels even if the channel hasn't been keyed-off, Pac-In-Time requires it. Changed code to allow it. - Quick mod to ZSNES Super FX code to get Winter Gold working - it was already working with the C Super FX code. - Added emulation of the extra 1/2 scan-line per frame on PAL and NTSC - should help improve music speed emulation. - Worked around the click sound heard when ROMs use 0 volume envelope attack rate. - Removed the 'check for IRQ already happened' H-IRQ position register setting code - it was causing problems for Ninja Warriors and was not required by F1 Grand Prix. - Fixed a bug in the new sound code - the sustain part of the attack-decay-sustain-release volume envelope was being skipped if the sustain level wasn't at 100%. The fix has helped some music notes from being cut off early in a few games. - Added fix to Pro Action Reply support (again). Thanks to Paul Shoener III for the original fix and Gil Pedersen for reminding me to apply it! - Finally fixed the Tales of Phantasia 'bum note' problem! The ROM set its sample directory to the upper-most page and I forget to code for the hidden 64 bytes of RAM, that appear when the boot ROM is switched off, when fetching sample addresses. - Adjusted the relative cycle length between the 65c816 and the SPC700 slightly to get Terranigma working again. - Oops, the emulated joypads 3 and 4 via the emulated Multi-player 5 interface weren't working. Thanks to Steffen Schwenke for the bug report. - Optimised the echo sound code - by-passed the the FIR filter code if only a pass-through FIR filter was defined by the ROM. - Modified V and H-IRQ register changing code to trigger an IRQ immediately if V-IRQ is enabled and the scan-lines match and either H-IRQ is not enabled or the electron beam position has already gone past the trigger point. Fixes the screen flicker in F1 Grand Prix. - Modified the priority-per-pixel mode 7 code to use BG#1's clipping data if the top bit of the mode 7 pixel is set. Fixes initial track drive-through display in F1 Grand Prix. - Modified the sprite priority levels for the priority-per-pixel mode 7 display. Now the car can be seen in F1 Grand Prix. - Wrote a sound DSP register recording scheme which 'plays back' the register changes in sync with the sound generation code. I'm bit disappointed, it only improves the sound in a very few games... Scrapped the code, it actually causes more problems than it fixes. Oh, well, another 3 weeks work wasted... - Fixed a SPC700 wake up problem for Lufia I - made the SPC700 also wake up when the 65c816 read from one of the four comm ports. - Included lots of sound code speed ups and sound quality improvements from Takehiro TOMINAGA - many thanks go to him. 1.16 - Fixed a case where the -forcelorom option didn't work - the case was required for Formation Soccer which claims in its ROM header to use the same memory map as Super FX ROM, it doesn't. - Pulled apart a real SNES using a crowbar (great fun), just to look at what speed the SPC700 is actually clocked at for more accurate relative emulation speed. - Implemented SPC700 cycle counting in the hope the improved timing would fix Tales'; no such luck but at least the -ratio option is obsolete now. - Implemented executing SPC700 instructions during DMA, fixes BSZelda and Goal lock up at start and music pausing briefly when ROMs do lots of DMA, usually between game screens. - Scrapped the i386 asm SPC700 code - it was the cause of the music not restarting after a battle in Chrono Trigger and FF3 and I didn't realise because the bug had already occurred in the test freeze-file I had. Thanks to John Stiles for pointing out that the Mac port didn't have the missing music problem. - Fixed RGB subtraction bug on displays with only 5 bits for green, e.g. RGB555 displays. The GREEN_HI_BIT variable was always set to a value for 6 bit green displays. - Added the SA-1 memory map, still a long way to go before any SA-1 game will run. 1.15 - Jumped versions to keep in sync with the DOS port release. 1.14 - Improved 8-bit sound generation slightly, but it still sounds very poor compared to 16-bit sound. 1.13 - Implemented the Tales of Phantasia memory map using the information supplied by zsKnight. Had to also implement a de-interleave routine to work around a ROM feature and Snes9x CPU instruction fetching implementation detail. - Added a frames-per-second on-screen display option. - Fixed the final glitch bug with the Mario Kart track display - the byte code for the termination of the DSP1 raster command wasn't been recognised. - Disabled a NMI/DMA hack for Rise of the Robots, was causing problems for Mario Kart and 'Robots wasn't working correctly anyway. - Optimised the mode 7 rendering a little. - Changed tile rendering code to use offsets into screen buffer rather than direct pointers ready for z-buffer implementation. 1.12 - Changed V-blank NMI to occur immediately after a WAI instruction, Toy Story required this. - Fixed reading of H-DMA line counter register, Top Gear 3000 needed this. - Ripped off large parts of ZSNES's DSP1 code (with _Demo_'s and zsKnight's approval). Now Mario Kart works almost 100%. - Added a check to see if a vertical scan-line IRQ register change will cause a H-IRQ later on the current scan-line. Pilot Wings needed this. - Fixed possible crash bug in clip window code when both windows had two spans. Could actually cause Chrono Trigger to crash the emulator. - Fixed a lock-up problem with the C Super FX code, Star Fox and executing a few 'FX instructions per scan-line (required for Winter Gold). 1.11 - Partially fixed the DOS netplay server - the server timer is running too slowly and it doesn't deal with disconnects correctly yet. - Corrected the sound echo delay - it was varying with the sound playback rate chosen by the user - it shouldn't have been. - Implemented DOS netplay code - DOS server code still not working though. - Removed all floating point calculations from the sound generation code. - Fiddled with the pitch modulation code - my guess is the output of a channel that is used to modulate the frequency of another channel is automatically muted by the SPC700 chip. Just a guess, but the wind from FF3 sounds 'better' but far from perfect. - Optimised the tile palette index calculation. - Optimised the planar to chunky tile conversion code. - Fixed X11 port to always scale SNES image if hi-res. only (no interpolation) support is enabled. - Added zipped ROM image support using Gilles Vollant unzip code and some code that Ivar (Lestat) sent me a long time ago. - 65c816 asm RTI instruction was destroying the program bank in emulation mode, the C code was already correct. Caused C64E to break. 1.10 - Finished NetPlay v1 - allows up to five networked machines to play multi-player SNES games, one player on each machine. - Switchable full-screen mode added to Linux X11 port, some code and ideas nicked from Maciej Babinski's original Snes9x XFree86 DGA Linux port, the UAE Amiga emulator, plus lots of my own code. 1.08 - Bug fixes to C Super FX emulation - now Winter Gold works correctly again. 1.07 - More DSP1 work. Mario Kart is now playable! The character projection code is still broken so the opponents and obstacles aren't always positioned correctly on screen and you keep bumping into them, but I can still keep coming first! - Started work on NetPlay support. - Decreased sound card DMA buffer size on DOS port to improve sound generation and sound CPU synchronisation in some games. - Included Linux joystick driver patches from Vojtech Pavlik so the port can use the new v1.x joystick drivers, again written by Vojtech Pavlik. Allows use of Micro$oft Sidewinder pads, NES and SNES pads, PlayStation pads, Gamepad Pros, etc. - Added halve-the-result colour subtraction. 1.06 - Extended code to allow support for multiple 16-bit screen formats, switchable at run-time, rather just supporting one, selectable at compile time. - Added XFree86 DGA Linux port - code from Maciej Babinski. - More fixes to the X11 image format conversion and setup code. - The asm SetByte routine wasn't wrapping writes to S-RAM correctly, allowing some ROMs to think they were running on a copier and put up an error screen. Thanks to Nu of #rom for the report. - Added 'TV-Mode' support (interpolation and scan-lines) to the DOS and UNIX ports from code based on John Stiles work. - Added v-sync option to the DOS port. - Added fix to Pro Action Reply support, thanks to Paul Shoener III. - Added ggi support (untested) to Linux port using patches from Alexander Larsson (alla@lysator.liu.se). - Added 16 to 24/32 bit image conversion routines to the UNIX X11 code. - The SPC700 OR1 instruction was broken. Thanks to Pyrgopolinices for the report. - DOS port was having trouble splitting and joining path names - caused problems when specifying the full path name of a ROM when the ROM image was on another drive. - If a ROM reset the sound DSP and then turned on echo effects but kept the same echo delay setting, then the echo effects could not be heard. Thanks to madec@mclink.it for the bug report and freeze file that made it easy to find the problem. - DOS port was always using stereo sound setting, if sound card supported it, regardless of the user preference. - Linux port X11 port could crash if window was resized while transparency effects were enabled. - The colour subtraction accelerator look-up table was slightly wrong, causing one bit of red, green blue values to 'spill' into the next field. - Allowed colour window to cut a hole in the main-screen and show the sub- screen underneath. The effect is used by Illusion of Gaia. - Added support for colour subtraction, with the halve-the-result flag set. - Included DSP1 code from _Demo_. Now you can see the track in Mario Kart and the ground in Pilot Wings - still can't play the games though due to other missing commands. - Added an NMI hack to work around a code bug in Battle Toads: BATTLEMANIACS, its only by chance that the game works on a real SNES - And disabled it again because it causes problems for Chrono Trigger. - A frame skip of zero was actually still skipping one frame. Thanks to Marius Fodor for the info. - And yet more X-OR window bug fixes - now the effects during some of the more 'posh' spells look correct in Chrono Trigger. - Yet another window area inversion bug - off by one pixel on right-hand edge. - Forgot to put dummy start and end points for XOR window combination modes - now Uniracers looks correct and Sailor Moon looks like it does on a real SNES. - Window clip code was using wrong index into a 2-dimensional array when the whole of the main or sub-screens were clipped. 1.05 - The master volume disable code was looking that the wrong variable! - Fixed crash bug in newer sound code if a ROM tried to start a sample playing who's data went past the end of SPC700 memory. (Cannon Fodder) 1.04 - Fixed DSP1 ROM header detection bug. - More DSP1 work; still nothing works, although I know the multiply command is correct because I've compared the results against a real DSP1. 1.03 - Oops, the multi-player 5 disable code change broke the multi-player 5 being the default controller. - Implemented the colour window on the main screen - now Zelda's oval zoom window displays correctly and Krusty's Super Fun House clips the left-most 8 pixels as it does on the real SNES. - TERRANIGMA didn't like me returning a random value when it attempted to read a channel's the current sample byte. - Hacked in initial support for mode 7 priority-per-pixel - the priority bit doesn't actually change the priority of the pixel but the two games that I know of that use the feature look OK. (Winter Extreme Skiing and the intro of Tiny Toons Adventures). - Colour addition/subtraction code now uses RGB565 rather than RGB555 calculations - helps a little with the loss of the bottom bit of SNES colour data. - DSP1 emulation started - nothing works yet. 1.02 - Switched to adding back drop colour rather than fixed colour when sub-screen addition is enabled but there's nothing on the sub-screen. Uniracers seems to need it. - DISABLED it again. Causes problems for other ROMs and Uniracers itself on later screens. - Fixed XOR window logic combination mode and area inversion code, now Uniracers works correctly. - Oops, if colour window and half colour addition/subtraction were both switched on, area outside colour window was still being halved, it shouldn't. Hacky fix at the moment until I implement the correct fix. - Fixed several bugs with the mosaic effect and 16x16 tiles and a few possible background scroll offset bugs and the mosaic effect. - Optimised the sound sample generation code for cases when the SNES sample playback frequency was higher than the sound card playback rate. - Fixed possible click sound when a sample was first started to be played. 1.01 - Corrected scan-line count for PAL games - should be 312 lines verses 262 for NTSC. Was causing slow music on PAL games. - Added error correction code to the SPC700 timer update code - the SPC700 timers are updated using the emulated h-blank handler which is called every emulated 63.6 microseconds (15.720KHz) but the SPC700 timers need to be updated at multiples of 8KHz, hence the error. Was causing music to be played slightly too fast. - Switched back to using C SPC700 code - the old SPC700 asm code was lacking several optimisations that the C version had. It also had multiple speed hack cycle skipping bugs. Plus I hadn't even finished optimising all the code from the last time I converted the C compiler output. - Optimised SPC700 memory access routines a little. - Disabled code that prevented ROMs updating SPC700 timer values while the timer was running - it seems like it is allowed, even though docs on the 'net I've seen say its not. 1.0 - Fixed SuperScope support. - Added hi-res. option to my DOS port. - Fixed 4, 6, and 8 button standard PC joystick support. - Changed some types the source code was using BYTE -> uint8, WORD -> uint16, DWORD -> uint32 and BOOL -> bool8, types were clashing Windows typedefs but sizes didn't always match. 0.99 - 8-bit double height and/or width tile rendering was missing every other group of 4 pixels - screen pointer advance count was wrong. - Asm SPC700 emulation was ignoring the Shutdown flag - the result is its not possible to turn off cycle skipping for the SPC700 emulation. 0.98 - CPU to ROM address decoding code rewritten - used by Game Genie cheat codes, orginal code might have been the cause of some Game Genie codes not working. - Started to remove printf calls and replace them with calls to S9xMessage, port code can then dicide what to do with message. 0.97 - Re-enabled decompressed sample caching, still has a possible click problem but the sound code is a lot faster with it enabled. Added command line option to disable it if required. - Added '7' key support to rotate through available controller options, in the order multi-player5, mouse on #1, mouse on #2, superscope, standard controller and then back to multi-player5. - Hi-res. (512x448) support fixed. - Mouse support completed - Lemmings 2 and Mario Paint working a treat. - More colour window fixes. - Fixed freeze game problem when ZSNES SuperFX code is being used - ZSNES 'FX state was not being saved and restored. - ZSNES SuperFX asm emulation code plugged in to Snes9x. 0.96 - Looks like if the colour window is not enabled at all and the colour window selector is defined to only allow colour effects inside the colour window, then no effects should be visible. - Offset-per-tile rendering code didn't support width 64 screen size, which Chrono Trigger used on its title screen. - Contra 3 seems to prove that defining the clip window area to be 'outside' a window that covers the whole screen is not an area with no range. - No it doesn't. It proves that I shouldn't have initialised the right window edges to 255! Contra 3 enables clipping windows without first defining their range. - Debug frame advance feature was being prevented from forcing the next frame to be rendered by SyncSpeed which was being called after the debugger returned to the main loop. - H-DMA code was allowing ROMs to manually start H-DMA during the v-blank period, ROMs shouldn't be allowed to do this. - Asm code would not push the correct CPU status onto the emulated stack if returning from an NMI immediately triggered an IRQ - fixes Mortal Kombat 1 and War of the Gems. - 'd' dump memory debug command was not preserving the CYCLES count. - C versions of SNES memory access code had same problem as asm code on the DOS port except it didn't cause a crash just ROMs failed to work correctly. - Asm i386 code was using signed compares to check for special case memory areas - it was causing crash problems on the DOS port which was sometimes returning valid address values with the top bit set - i.e. they seemed like negative values! - Changed event reschedule code to always allow h-blank start events, used to disable them during v-blank period. - Added code to HDMA when end of visible lines reached. - Changed register 4212 code not to always return h-blank when in v-blank. - Clipping fixed colour addition to background area was off by one pixel on the right-hand edge. - HDMA: Finally worked out how the real SNES operates when ROMs manual start H-DMA during the frame - ROMs must set up the H-DMA line count and address values before H-DMA is started. - Fixed the asm code to remove all hard-wired structure offsets - one offset into the IPPU structure was wrong in the code because the structure had changed size. - Added colour window support and allowed graphic window settings to be different on the main screen and sub screen, just like a real SNES. - SuperFX LJMP instruction had bank and address values swapped. - Fixed possible memory overwrite problem because OBJList array was one element too short. - Added AND multi-graphic window combo support. - ROM image memory allocation allocates an extra 32K of RAM, then moves the pointer forward by that amount - stops the SuperFX emulation from accessing unallocated memory, possibly causing a crash. - SuperFX emulation now stores sign and zero flags in separate variables so the MERGE instruction can set flags correctly. - Added 65c816 instruction skipping to i386 asm code when 65c816 waiting in a simple loop for some 'event' to happen e.g. end of frame NMI. - Finally fixed the APU instruction skipping problem with the i386 asm code when the WAI instruction is used - caused slow music on some ROMs. - Offset-per-tile modes don't seem to support screen size - Mario All Stars Super Mario 2 requires this on title screen. Doesn't seem to effect Tetris Attack or Puzzle Bobble. - Changed SNES select and start keys from shift and control to space and enter - allows shift-fn key to save game positions without the SNES ROM also getting a select joypad button press. - Multiplayer5 support for controllers 3+ was broken for ROMs that used automatic hardware joypad reading rather than reading joypads serially. - ResetPPU was not clearing tile caches and marking OBJ as need recomputing. - Cached OBJ positions and sizes were not being recomputed if ROM changed global OBJ sizes during frame. - Fixed brightness multiplication problem on 16-bit code for green. - SPC700 emulation now uses one variable to store ZERO and NEGATIVE flags. - SPC700 emulation now only increments PC once at end of instruction. - New ROM type and interleaved detection code. - Reading sound DSP register ENDX also clears the value. The docs on the 'net said that only writing to the register cleared its value. Fixes sound in Zoop. - Fixed mode 4 colour palette problem on background #2 in tile-based graphics code. - Fixed graphics mode 4, offset-per-tile support. Only one set of offset data that is switchable between horizontal and vertical, unlike modes 2 and 6 which allow separate horizontal and vertical offsets per tile. - Modified the APU timer code again, if the timer is enabled, a write to the timer target register is only allowed if a value hasn't been written yet. Fixed Donkey Kong Country 1 and Earth Worm Jim 1 & 2. - Attack rate of 0ms changed from 1ms back to 0ms because of a group of ROMs that change from attack mode to decay mode in real-time. Will change back when I've added better SPC700 CPU and sound generation sync code. - Added support for ROMs set a new sound timer value while the timer is enabled (EWJ 1 & 2). - Added support for ROMs that read the sound envelope height (MK1, MK2, etc). - ROMs writing to the H-DMA enable register during visible scan-lines were restarting H-DMA for that frame causing random screen effect corruption. - Echo feedback seems to be after the FIR filter, not before as a diagram I've seen suggests. - Sound pitch modulation added. - Memory access routines changed to pass a single 24-bit address rather than the previous separate 8-bit bank and 16-bit address parameters. 0.3 - Updates to A-Bus address during a frame must not update H-DMA address. Fixes Actraiser 2 and Pacman 2. - Removed sound volume mangling - with echo support enabled it doesn't seem to be required. - Attack rate of 0ms changed to 1ms to help prevent click sound with sudden start of a sample playing. - Sample caching of samples that looped using part of the original sample created a click on the sound output. Caching disabled for the moment. Would require 512K of cache RAM to fix sample caching. - Colour addition/subtraction support added - but still a little buggy in places and very slow. - 16-bit colour support added. - Sustain sound volume was not being set if a sample using ADSR was started with both the attack rate and decay rate set to zero - resulted in missing sound samples on with some games. - Sound echo support added. - Sound channel mixing code was not completely clearing a channel's sound buffer when a channel finished playing a sample. - Sound mixing code rewritten to use one buffer, rather than writing each channel into a separate buffer then combining them into one buffer. - Memory access routines rewritten to use an 8K block lookup table rather than dedicated code for each ROM memory map - it was getting difficult to support the new types of SNES ROM memory maps becoming apparent. - Sound sample decoding wasn't decoding sound samples correctly if a previously cached sample was only partially overwritten by the ROM as opposed to being completely replaced. - Sound sample decoding wasn't clipping generated sample values correctly. - Changed H-DMA to start in the current frame only if enable register is written to during v-blank, h-blank or while the screen is blanked. - The SPC700 seems to start executing instructions before the 65c816 - shorter reset pulse? (NO - forgot the SPC700 executes instructions while DMA is taking place). - ROMs that reset the H-IRQ position so another IRQ would be triggered on the same scan-line where not supported - Super Off-Road: The Baj needs it. - $4212 bit 7 needs to go high at the end of h-blank at line 224 not at the start of h-blank - Bubsy needs it. - Sample decoding routine could write to memory outside sample cache area if address of block to decode was greater than $0x10000 - 9. - Walking mario can be seen on map screen of MarioWorld - needed sprite priority rotation working. ROM sets bit 7 of $2103 then sets rotation in $2102. Reset rotation at start of v-blank not at end. 0.24 - Fixed reading of DMA register values - now Ms Pacman works. - Saved sprite memory address being restored on the wrong scan-line - caused corrupt sprites on at least one game (GANBARE GOEMON 2). - Screen colour palette not being updated if ROM only wrote to low byte of palette register. - Possible memory corruption fixed if a ROM tried to write to an invalid sprite address via PPU registers. - X11 port support quick load and save by pressing function keys to load or shift + function keys to save. 0.23 - Added option to disable graphic window effects - T2: The Arcade Game doesn't seem to like them. - Mode 7 "outside screen area" register interpretation fixed - now the Actraiser map screen looks a lot better. - Old DMA code hack for Battle Toads: Double Dragon removed as it was no longer required and it was causing problems for Ys III. - Lowered max volume level of 16-bit sound mixing code to help with sound clipping problems is lots of SNES sound channels are playing. 0.22 - Crash bug fixed in mode 7 graphics windows code 0.21 - Fixed a noise channel volume bug - noise waveform was getting clipped. - Fixed 24bit X Window System server support on the Solaris port. - Sprites in priority level 1 on mode 7 were being drawn incorrectly behind graphics screen. - BG 3 priority 1 tiles sometimes not drawn dependent on the $2105 bit 3 setting. - Added graphic window support the tile redraw code. - Added mosaic support to tile redraw code. - Tile redraw code was drawing one line too many on screen-splits. - Tile-based redraw code made more intelligent about when a background should be displayed or not. - Added wrap within bank support to large DMAs just to support Rock 'n' Roll racing. 0.20 - DMA routines added lots of special cases and removed most calls to GetByte, using a pointer instead. - Multiple using PPU registers is now only computed when first byte of result is actually read. - Sound enabled by default if compiled without DEBUGGER defined. - Tile redraw method made the default. - Fixed CPU_SHUTDOWN so SPC700 continues to execute even if main CPU is "skipping" cycles waiting for an event to happen. - More command line options added. - Default cycles-per-scan-line to execute lowered to 90% from 100%. - +/- keys now work even if auto-frame rate adjust was enabled. - SPC700 emulation partially rewritten in assembler. - Asm 65c816 code change to use same speed up techniques as the C++ code. - Minor speed tweaks to the sound decoding and mixing code. - C++ SPC700 emulation changed to use same method as 65c816 emulation for computing and storing emulated CPU flags. - Mode 7 code rewritten and several scrolling offset bugs fixed. - Lo-ROM S-RAM memory map bug fixed - now Uniracers works. - Multiple speed ups and changes to the tile and line-based redraw code. - Tile and line redraw code changed to cache converted tiles between frames. - Variable cycle length timing made compile-tile switchable. - C++ 65c816 emulation changed to use several opcode jump tables to avoid a register size comparison test on most emulated instructions. - C++ 65c816 emulation changed how is computes and stores emulated CPU flags. - Fixed high frequency sound playback bug - the sample rate calculation was blowing the range of an unsigned long. - Fixed V-RAM reading so DKC3, Addams Family, Aladdin and Pacman all work. - Fixed sound code so ROMs can change from ADSR mode to decrease mode - fixes lots of ROMs. 0.12 released - Added dynamic speed regulation. - TCALL vector calculation change from n to 15 - n. - Fixed crash bug if ROM writes to sound DSP register numbers greater than 127. - Fixed DOS memory locked for interrupt code. - Added long name versions of command line switches. - Added command line switch for SPC700_SHUTDOWN code and WAI cycle skipping code. 0.1 released - All DOS memory is now locked from being swapped. - Fixed DOS port keyboard polling code - could get confused if a keyboard interrupt happened while keys were being checked. - SPC700 ADC instruction never cleared Overflow or Carry flags! - Changed selection of playback speeds for Solaris port. - Sample caching code was broken - cached samples were never used. - Added code speed ups for ROMs that use a lot of DMA to VRAM. - More cpu code asm speed up. - Fixed 16x16 size tiles on tile-based redraw code. - Fixed sound gain-mode increase and decrease volume envelopes. - Added code to support ROMs that reuse sprites in the same frame. - Fixed processing of negative volume levels. - Fixed SPC700 EOR1 instruction. - Added SPC700 shutdown code to stop executing SPC700 instructions if in a tight loop waiting for a timer or for the 65C816 to respond. - DOS playback rate was being forced to 16KHz by Allegro - fixed. - Fixed bug in SPC700 MOV1 C,bit, address. - Fixed a off-by-one loop sample pointer bug in MixSamples. - Added command line flags for cached-tile based drawing and sub-screen background layers priority swapping. - NOPE, got encoding of the OR1/EOR1,AND1 range of correct originally - got duff information from an "SPC700" programmer. - More SPC700 fixes: got the encoding of the OR1/EOR1,AND1 range of instructions wrong - I guessed wrong originally. - Sample looping bug fix on mono sound mixing code. - Sound pitch value no-longer clipped to 14 bits - apparently FF3 needs this. - Followed Paradox's suggestion and changed graphics code to place sub-screen background layers below main-screen background layers. Helps lots of games that use sub-screen addition/subtraction - now you don't have to toggle background layers on and off so often just to see hidden text, characters, or maps, etc. Made it switchable. Acts as a good intermediate solution until sub-screen addition/subtraction is actually implemented. - Modified sound skipper code to return random values when ROM is stuck waiting for the SPC700 CPU to respond - helps several ROMs that previously don't work with the currently selection of APU skippers. - Improved sound mixing code so volume is not attenuated so much, giving better results on 8bit sound cards. - Changed the frequency at which the joystick polling routine is called - now called every-other frame rather than every 3rd frame. - Recompiled Linux and DOS ports with the Pentium optimising version of gcc - gives a few percent speed increase. - Changed V-RAM increment count from 64 to 128 - apparently Final Fantasy 3 needs this as well. - Fixed sprite priority bug with Mode 7 - apparently Final Fantasy 3 needs this. - Fixed a screen clipping problem with the S-VGA mode. - Fixed bug that had crept in with -m 2 S-VGA mode (Linux version). - Fixed S-VGA Linux version with sound enabled. - The SPC700 ADC (X),(Y) instruction was broken - with all these SPC700 fixes now many more ROMs work with sound enabled. - The SPC700 Pop PSW instruction was not resetting the direct page location. - The SPC700 instruction MOV A,[DP+X] was incorrectly doing a MOV A,DP+X. - Got the SPC700 SETx and CLRx instruction encoding swapped around. - Fixed #define problem that was stopping DOS snapshot saving from working. 0.72 released - Fixed the DOS filename handling - old Unix code was screwing up with ROM filenames that contained backslashes (\) - the ROM would load but S-RAM loading and saving would fail and the default filename for snapshots wouldn't work. - This time really fixed Allegro library keyboard handling (DOS port); it was missing key some presses/releases (was stopping Chrono Trigger Left + Right + A button combo from working). - Added code to automatically remove headers off S-RAM save files with 512 byte headers. - 32Mbit ROMs in interleaved format are now automatically detected and converted. - Added -ss 3 sound skip method support to the asm version - now NBA Live '96 works again. - Added support for multi-part ROM images. 0.71 released - Made libgz.so statically linked (again) on Linux port - sorry. - Made writing to $4200 also clear any pending IRQs. This finally allows Battle Toads: Double Dragon, Spawn and Sieken 3 all the work with the same IRQ logic (but Sieken 3 still gets stuck in sound download code). - Fixed a H-DMA wobble bug - some frames could randomly miss a line of H-DMA causing the F-Zero screen to wobble, and slight text character corruption on games like DKC3. - Interleaved format ROM images are now swapped in-place, without the need for a temp 4Mb buffer (saves lots of disk swapping on a 16Mb Windows 95 machine). 0.7 released - Fixed Allegro library keyboard handling (DOS port); it was missing key some presses/releases. - DOS port had a different MAX_PATH value which moved the location of the SRAM size variable when using the asm CPU emulation core. This, in turn, caused the SRAM emulation to fail on the DOS port. Donkey Kong County 2 & 3 were reporting a ROM copier was connected to the SNES and refused to run. - Fixed assembler version of XCE - it was always leaving the carry flag clear - caused Killer Instinct and Super Punchout to think a ROM copier was fitted to the SNES and they all refused to run. - Fixed assembler versions of MVN/MVP - they weren't setting the data bank register to the destination bank of the instruction. - Fixed joystick detection on MS-DOS port - a single 2 or 4 button joystick in port 1 was being ignored if a second joystick was not present in port 2. - Fixed an uninitialised variable in graphics code - was causing random missing scan lines on Mode 7 screens. - Joysticks now scanned every 3rd frame (joystick scanning is slow in the PC). - Double-whoops, Metriod 3 had stopped working in v0.6 - fixed it (memory map bug). - Made bit 6 of $4211 set if v-counter == v-timer-position. - Made reading of $4200 read $4212 instead. - Adjusted DMA timing to always access ROM memory at slow speed - this seems to fix Battle Toads. - Added code to automatically clear pending IRQs when the horizontal line is no longer equal to the horizontal timer line - this fixes Seiken 3, it now just gets stuck in the sound CPU wait code - oh well. - Moved NMI back to its original pre-0.65 behaviour, now Puzzle Bobble works. - More graphics speed ups - the code to render background tiles with their priority bits set is only called if there are actual priority-bit tiles. - Changed default frame skip rate from 1 to 2 - its seems most people don't bother to read the docs, so I thought I'll help them out a bit! - Speeded up Mode 7 graphics on games like F-Zero that rewrite the matrix registers on each scan line using H-DMA. - Reorganised the graphics code and did a slight speed up - graphics code will be the next thing to rewrite in assembler. - Rewrote CPU core in assembler for Intel platforms - gives a very noticeable speed increase. - Fixed several problems with the APU sound CPU emulation - its now getting stable enough to try and implement sound. - Fixed bug that caused 1 byte of S-RAM to be emulated when ROM didn't expect any - it was enough to stop Street Fighter 2 and others from working - thanks Lord ESNES. - The TXS and TCS instructions shouldn't set the Z and N flags. - Looks like MVP/MVN instructions should ignore accumulator size - change code to always use all 16 bits and exit with accumulator set to 0xffff. - Whoops, accidently left some test code in which was causing the V-BLANK flag, bit 8 in register $4212, to be miss-calculated. - Fixed palette in mode 0. - Speeded up graphics drawing a little by skipping groups of 4 pixels that were all transparent. 0.65 released - S-VGA and MS-DOS ports now have a VGA mode command line flag. - Improved the fading code - should be much more smooth now. - Fixed second joy-pad support and re-mapped keys and joysticks to actually make a match between what my docs said and a real SNES (SNES docs I'd seen were wrong!). - Fixed a bug in Relative Long CPU addressing mode. - Ported Snes96 to MS-DOS. - Snapshot loading and saving no longer uses external gzip binary. - Added support for registers at $21c2 and $21c3. - Made reading the software latch for the horizontal and vertical counters also clear any pending IRQ. - Added sprite priority rotation. - Rewrote parts of the graphics routines to fix a sprite-to-sprite priority bug. - NMI flag changed again - now back to being reset by reading $4210 but actual NMI is delayed. - Made mode 7 background colour 0 transparent - this fixed several sprite priority problems a few games where having. - Finally worked out how sprite "Object Name Select" works and emulated it - this fixes many (if not all) of the corrupted sprites some games experienced. - Delayed NMI activation for one instruction to give time for loops that wait for bit 7 of $4210 to go high. - Special-cased line count of 128 on H-DMA to mean repeat previous data with a line count of 128 and not just terminate H-DMA on that channel. - APU sound CPU emulation added - just need to debug the thing. - Fixed Overflow flag setting in ADC and SBC instructions - it was never being set. - Rewrote how CPU instructions are fetched and how values are pushed and pulled from the stack - it gave a very large increase in emulation speed. - H-DMA was being started one scan-line too late. - Added CG-RAM reading support. - Added "Full Graphic" V-RAM reading. - Speeded up C version of CPU emulation quite a bit - could speed it up a little more before rewriting in assembler. - Fixed bugs in 16x16 tile drawing on 2bit and 8bit deep screens. 0.6 released - Speeded up 16x16 tile background rendering by removing a temp tile buffer it was using. The speed up also fixed a vertical scroll bug. - Fixed slight window clipping on 16x16 tile backgrounds. - Added automatic PAL/NTSC mode switching. - Fixed background and sprites so only visible if on main-screen or on sub-screen under correct circumstance. - Fixed lockup bug in DMA. - Stopped NMI flag from being reset by reading $4210 - was causing a couple of games to get stuck. - Whoops, got horizontal and vertical Mode 7 flip bits around the wrong way! - Fixed MIT shared memory pixmap support for X11 version (it was always turned off). - Fixed minor bug - first sprite in priority group was drawn twice. Didn't cause any visual bugs, it just slowed down redrawing a little. - Fixed DMA bug - transfer byte count should be 0 after DMA has finished. - Fixed a scaling bug if width < height. - Interleaved ROM image support added. - 16bit and 24bit X11 server support added - with scaling. - Added window scaling on X11 version. - Partial clip windows added - the only window overlap option implemented at the moment is OR, it seems it good enough for all the ROMs I've tested it with. - Partial Mosaic effect added (pixels only growing vertically). - Missing Mode 7 "outside screen area" option added. - Fixed mode 7 screen wrap "outside screen area" option. - Used new event processing to finally fix H-IRQ so it triggers at the correct position on the scan line. - New event processing added. - Linux version now statically links libgz.so (sorry). 0.5 released - Linux S-VGA version changed from using a 320x240 ModeX screen (slow) to a 256x256 chunky screen (faster) - thanks to Phillip Ezolt (pe28+@andrew.cmu.edu) for information on how to do this. - Mode 7 screen flipping added. - Included Snes97's CPU emulation code into Snes96. Didn't fix any bugs but slowed down the emulation some what and I couldn't compile it optimised because it was so large - so I removed it again. - Added a few extra features available via the keyboard. - Fixed a H-DMA transfer mode - bad documentation. - Fixed H-DMA indirect addressing (it was using the wrong CPU memory bank). - The Linux slow down bug is my crappy laptop enabling battery saving features ! - Changed graphics code to perform true line-by-line screen updates. - Fixed sprite drawing bugs. - Ported Snes97's graphics code to Snes96. - Fixed memory map for HiROM save RAM area. - Fixed HiROM memory map - now Killer Instinct and Donkey Kong County work ! - OK the slow down bug is just actually my laptop trying to save battery power by slowing the CPU clock! - The Linux slow down bug shows itself on DOS emulators running under DOSEMU so it must be a kernel problem (or feature). - Fixed H-DMA (again) to be complete emulation - all I need now is line-by-line screen update... - Fixed DMA to not copy too many bytes if byte count was not a multiple of the transfer mode quantity (caused corruption on Super Mario World map screen). - Changed mapping of keyboard to joy-pad buttons and added additional direction keys for joy-pad one so player one's right hand doesn't have to obscure player two's keyboard joy-pad buttons. - Changed joystick button layout to match SNES if using a 6 button joy-pad. - Changed snapshot format so I can easily use libgz on Linux. - Added few speed up tweaks that will be lost again when I add line-by-line screen update. - First visible scan-line changed from 8 to 1 to match with new docs. - New SNES information source found; fixed partial H-DMA emulation to include indirect addressing support. - Snapshot files are now compressed. - Compressed ROM images now supported on Linux. - Snapshot loading and saving added. - Joystick support for Linux added. One 2, 4 or 6 button joystick, or two 2 button joysticks supported (PC hardware limitation). - SVGA full screen support added for Linux. Still has the X11 slow down bug so can't blame the X11 server any more! Must be a kernel bug or a very odd emulator bug. - Added emulation of two joy-pads on the PC/Sun keyboard. - Removed -i command line flag as it is no longer used. -h value range has also changed: now 1 - 100 (percentage). - Actuate cycle counting rather than instruction counting now added including fast and slow ROM timing - should give much better timing information when line-by-line screen update added. - Bug fixed old-style joy-pad access used by some ROMs - Mario All Stars still gives problems if enabled and I don't know why; but at least Super Bomberman now works ! - Looks like if both horizontal and vertical IRQ are enabled then IRQ should only be triggered once per frame and not once per scan line - looking at the IRQ handler of a couple of ROMs seems to confirm this. - Added initial cycle counting - not accurate enough for some ROMs though. - Finally worked out how the odd VRAM address increments should work but only found one ROM, so far, that actually uses it. - Debugged the odd slow down problem with the Linux port - it seems to be a bug in the X Window System server - starve the X server of keyboard presses or mouse clicks or movement and the X server slows down, slowing down the emulator with it ! 0.4 released - Fixed sprite vertical clipping at top of screen. - No need to invert the Mode 7 transformation matrix before use - the ROM coder already had to! - Fixed Mode 7 scrolling offset when using special effects. - Added Mode 7 rotation, enlargement and reduction emulation. - DMA shouldn't zero the byte count value after a DMA has completed. - Added DMA reading (Addams Family was using it) - Fixed V-RAM read function - returned data should lag behind the V-RAM address by one byte/word. - Added mode 7 graphics only. 0.3 released - Speeded up the main CPU loop a bit. - Add more command line options: -f (default 1) -i (default 32768) -h (default 45, some games allow a lower setting resulting in a increased emulated frame rate) -t enable CPU tracing -ss (default 0, more methods to be added) -H disable H-DMA emulation -F Force Hi-ROM memory map - Modified planar to chunky conversion to use look up tables. - But now Mario All Stars won't start. Made emulation of $4016 optional with -o command line switch. - Thanks to Carlos (calb) of ESNES fame, I've added correct $4016 & $4017 joy-pad register processing - now several more ROMs will start once a button is pressed and can be controlled. - DMA wasn't updating DMA registers with the final CPU address used after the DMA had completed (caused sprite and background corruption with some ROMs). Still suspect another DMA side effect isn't being emulated correctly though. - Fixed setting of CPU overflow flag in ADC and SBC instructions in decimal mode. - Fixed MVP/MVN CPU instructions to leave X and Y values correct at end of loop - several more ROMs now work. Still don't know if MVP/MVN instructions should ignore the accumulator size flag or not. - Rewrote background drawing code - gives a large increase in speed. - Flag to only update X Windows colour palette when necessary was missing a case - caused some ROMs to start with a black screen. - Code to only update background tiles when changed wasn't working so I disabled it. - CPU WAI instruction needed to trigger on hardware IRQ even when interrupt enable flag was false. - DMA was not transferring 65536 bytes when byte count was 0. - Fixed matrix 16bit x 8bit multiplication (old debug code was causing junk value to be returned). - Fixed Makefile so version.h header file change recompiles file that shows version number in window title. - Added more reporting of used but unimplemented missing hardware features to debug command. - New ROM loading code from Jerremy included, can now cope with ROM images with no 512 byte header. - Speeded up emulated memory access a little bit. 0.2 released - Added matrix 16bit x 8bit multiplication for Super Off-Road Racer. - Added initial H-DMA emulation - visual effects using it will not be seen correctly until screen is updated line-by-line rather than the whole screen at end-of-frame. - Fixed horizontal sprite clipping (vertical clipping still has a problem). - Integrated large sprite bug fixes and new background drawing code from Jerremy. - Fixed large size per-sprite flag; always stayed true after sprite size was changed to large. - Rewrote the planar to chunky pixel conversion routines (still need more work). - Made registers $4016 & $4017 always return $ff - lots of ROMs that previously wouldn't go beyond the title screen thought old-style joy-pads were connected and were waiting for the user to press a button on them. - Frame skip rate now set to 1 instead of 5 on my P166 laptop! - Fixed NMI v-blank flag being incorrect set, caused some ROMs to lock. - X keyboard autorepeat now switched off when emulator has keyboard focus. - Added number key options to toggle backgrounds 1 to 4 and objs (sprites) on and off. - Fixed sprite clipping problems at edge of left hand side of screen. - Corrected Hi-ROM memory map (I think) (no I didn't) - Fixed most of the sprite-to-sprite priority problems. - Added sprite debug command, 'S'. - Added a debug command to show what missing hardware features a ROM was using. - Added horizontal and vertical beam position IRQ - horizontal always triggers at start of line at the moment. - Fixed SBC instruction to set carry flag the correct way around. Initial release 0.1 - Ported Windows 95 version of Snes96 to Linux on a PC and Solaris on a SparcStation. - Corrected work RAM memory map. apu/bapu/dsp/SPC_DSP.cpp000664 001750 001750 00000063604 12720446475 016067 0ustar00sergiosergio000000 000000 // snes_spc 0.9.0. http://www.slack.net/~ant/ #include "SPC_DSP.h" #include "blargg_endian.h" #include /* Copyright (C) 2007 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "blargg_source.h" #ifdef BLARGG_ENABLE_OPTIMIZER #include BLARGG_ENABLE_OPTIMIZER #endif #if INT_MAX < 0x7FFFFFFF #error "Requires that int type have at least 32 bits" #endif // TODO: add to blargg_endian.h #define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr )) #define GET_LE16A( addr ) GET_LE16( addr ) #define SET_LE16A( addr, data ) SET_LE16( addr, data ) static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] = { 0x45,0x8B,0x5A,0x9A,0xE4,0x82,0x1B,0x78,0x00,0x00,0xAA,0x96,0x89,0x0E,0xE0,0x80, 0x2A,0x49,0x3D,0xBA,0x14,0xA0,0xAC,0xC5,0x00,0x00,0x51,0xBB,0x9C,0x4E,0x7B,0xFF, 0xF4,0xFD,0x57,0x32,0x37,0xD9,0x42,0x22,0x00,0x00,0x5B,0x3C,0x9F,0x1B,0x87,0x9A, 0x6F,0x27,0xAF,0x7B,0xE5,0x68,0x0A,0xD9,0x00,0x00,0x9A,0xC5,0x9C,0x4E,0x7B,0xFF, 0xEA,0x21,0x78,0x4F,0xDD,0xED,0x24,0x14,0x00,0x00,0x77,0xB1,0xD1,0x36,0xC1,0x67, 0x52,0x57,0x46,0x3D,0x59,0xF4,0x87,0xA4,0x00,0x00,0x7E,0x44,0x00,0x4E,0x7B,0xFF, 0x75,0xF5,0x06,0x97,0x10,0xC3,0x24,0xBB,0x00,0x00,0x7B,0x7A,0xE0,0x60,0x12,0x0F, 0xF7,0x74,0x1C,0xE5,0x39,0x3D,0x73,0xC1,0x00,0x00,0x7A,0xB3,0xFF,0x4E,0x7B,0xFF }; // if ( io < -32768 ) io = -32768; // if ( io > 32767 ) io = 32767; #define CLAMP16( io )\ {\ if ( (int16_t) io != io )\ io = (io >> 31) ^ 0x7FFF;\ } // Access global DSP register #define REG(n) m.regs [r_##n] // Access voice DSP register #define VREG(r,n) r [v_##n] #define WRITE_SAMPLES( l, r, out ) \ {\ out [0] = l;\ out [1] = r;\ out += 2;\ if ( out >= m.out_end )\ {\ check( out == m.out_end );\ check( m.out_end != &m.extra [extra_size] || \ (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\ out = m.extra;\ m.out_end = &m.extra [extra_size];\ }\ }\ void SPC_DSP::set_output( sample_t* out, int size ) { require( (size & 1) == 0 ); // must be even if ( !out ) { out = m.extra; size = extra_size; } m.out_begin = out; m.out = out; m.out_end = out + size; } // Volume registers and efb are signed! Easy to forget int8_t cast. // Prefixes are to avoid accidental use of locals with same names. // Gaussian interpolation static short const gauss [512] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77, 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102, 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132, 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168, 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210, 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257, 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311, 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370, 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434, 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504, 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577, 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654, 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732, 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811, 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889, 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965, 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036, 1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102, 1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160, 1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210, 1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251, 1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280, 1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298, 1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305, }; inline int SPC_DSP::interpolate( voice_t const* v ) { // Make pointers into gaussian based on fractional position between samples int offset = v->interp_pos >> 4 & 0xFF; short const* fwd = gauss + 255 - offset; short const* rev = gauss + offset; // mirror left half of gaussian int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; int out; out = (fwd [ 0] * in [0]) >> 11; out += (fwd [256] * in [1]) >> 11; out += (rev [256] * in [2]) >> 11; out = (int16_t) out; out += (rev [ 0] * in [3]) >> 11; CLAMP16( out ); out &= ~1; return out; } //// Counters int const simple_counter_range = 2048 * 5 * 3; // 30720 static unsigned const counter_rates [32] = { simple_counter_range + 1, // never fires 2048, 1536, 1280, 1024, 768, 640, 512, 384, 320, 256, 192, 160, 128, 96, 80, 64, 48, 40, 32, 24, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1 }; static unsigned const counter_offsets [32] = { 1, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 536, 0, 1040, 0, 0 }; inline void SPC_DSP::init_counter() { m.counter = 0; } inline void SPC_DSP::run_counters() { if ( --m.counter < 0 ) m.counter = simple_counter_range - 1; } inline unsigned SPC_DSP::read_counter( int rate ) { return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate]; } //// Envelope inline void SPC_DSP::run_envelope( voice_t* const v ) { int env = v->env; if ( v->env_mode == env_release ) // 60% { if ( (env -= 0x8) < 0 ) env = 0; v->env = env; } else { int rate; int env_data = VREG(v->regs,adsr1); if ( m.t_adsr0 & 0x80 ) // 99% ADSR { if ( v->env_mode >= env_decay ) // 99% { env--; env -= env >> 8; rate = env_data & 0x1F; if ( v->env_mode == env_decay ) // 1% rate = (m.t_adsr0 >> 3 & 0x0E) + 0x10; } else // env_attack { rate = (m.t_adsr0 & 0x0F) * 2 + 1; env += rate < 31 ? 0x20 : 0x400; } } else // GAIN { int mode; env_data = VREG(v->regs,gain); mode = env_data >> 5; if ( mode < 4 ) // direct { env = env_data * 0x10; rate = 31; } else { rate = env_data & 0x1F; if ( mode == 4 ) // 4: linear decrease { env -= 0x20; } else if ( mode < 6 ) // 5: exponential decrease { env--; env -= env >> 8; } else // 6,7: linear increase { env += 0x20; if ( mode > 6 && (unsigned) v->hidden_env >= 0x600 ) env += 0x8 - 0x20; // 7: two-slope linear increase } } } // Sustain level if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) v->env_mode = env_sustain; v->hidden_env = env; // unsigned cast because linear decrease going negative also triggers this if ( (unsigned) env > 0x7FF ) { env = (env < 0 ? 0 : 0x7FF); if ( v->env_mode == env_attack ) v->env_mode = env_decay; } if ( !read_counter( rate ) ) v->env = env; // nothing else is controlled by the counter } } //// BRR Decoding inline void SPC_DSP::decode_brr( voice_t* v ) { // Arrange the four input nybbles in 0xABCD order for easy decoding int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; int const header = m.t_brr_header; // Write to next four samples in circular buffer int* pos = &v->buf [v->buf_pos]; int* end; if ( (v->buf_pos += 4) >= brr_buf_size ) v->buf_pos = 0; // Decode four samples for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) { // Extract nybble and sign-extend int s = (int16_t) nybbles >> 12; // Shift sample based on header int const shift = header >> 4; s = (s << shift) >> 1; if ( shift >= 0xD ) // handle invalid range s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) // Apply IIR filter (8 is the most commonly used) int const filter = header & 0x0C; int const p1 = pos [brr_buf_size - 1]; int const p2 = pos [brr_buf_size - 2] >> 1; if ( filter >= 8 ) { s += p1; s -= p2; if ( filter == 8 ) // s += p1 * 0.953125 - p2 * 0.46875 { s += p2 >> 4; s += (p1 * -3) >> 6; } else // s += p1 * 0.8984375 - p2 * 0.40625 { s += (p1 * -13) >> 7; s += (p2 * 3) >> 4; } } else if ( filter ) // s += p1 * 0.46875 { s += p1 >> 1; s += (-p1) >> 5; } // Adjust and write sample CLAMP16( s ); s = (int16_t) (s * 2); pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around } } //// Misc #define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n() MISC_CLOCK( 27 ) { m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON } MISC_CLOCK( 28 ) { m.t_non = REG(non); m.t_eon = REG(eon); m.t_dir = REG(dir); } MISC_CLOCK( 29 ) { if ( (m.every_other_sample ^= 1) != 0 ) m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read } MISC_CLOCK( 30 ) { if ( m.every_other_sample ) { m.kon = m.new_kon; m.t_koff = REG(koff) | m.mute_mask; } run_counters(); // Noise if ( !read_counter( REG(flg) & 0x1F ) ) { int feedback = (m.noise << 13) ^ (m.noise << 14); m.noise = (feedback & 0x4000) ^ (m.noise >> 1); } } //// Voices #define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v ) inline VOICE_CLOCK( V1 ) { m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4; m.t_srcn = VREG(v->regs,srcn); } inline VOICE_CLOCK( V2 ) { // Read sample pointer (ignored if not needed) uint8_t const* entry = &m.ram [m.t_dir_addr]; if ( !v->kon_delay ) entry += 2; m.t_brr_next_addr = GET_LE16A( entry ); m.t_adsr0 = VREG(v->regs,adsr0); // Read pitch, spread over two clocks m.t_pitch = VREG(v->regs,pitchl); } inline VOICE_CLOCK( V3a ) { m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8; } inline VOICE_CLOCK( V3b ) { // Read BRR header and byte m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF]; m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking } VOICE_CLOCK( V3c ) { // Pitch modulation using previous voice's output if ( m.t_pmon & v->vbit ) m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; if ( v->kon_delay ) { // Get ready to start BRR decoding on next sample if ( v->kon_delay == 5 ) { v->brr_addr = m.t_brr_next_addr; v->brr_offset = 1; v->buf_pos = 0; m.t_brr_header = 0; // header is ignored on this sample m.kon_check = true; if (take_spc_snapshot) { take_spc_snapshot = 0; if (spc_snapshot_callback) spc_snapshot_callback(); } } // Envelope is never run during KON v->env = 0; v->hidden_env = 0; // Disable BRR decoding until last three samples v->interp_pos = 0; if ( --v->kon_delay & 3 ) v->interp_pos = 0x4000; // Pitch is never added during KON m.t_pitch = 0; } // Gaussian interpolation { int output = interpolate( v ); // Noise if ( m.t_non & v->vbit ) output = (int16_t) (m.noise * 2); // Apply envelope m.t_output = (output * v->env) >> 11 & ~1; v->t_envx_out = (uint8_t) (v->env >> 4); } // Immediate silence due to end of sample or soft reset if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) { v->env_mode = env_release; v->env = 0; } if ( m.every_other_sample ) { // KOFF if ( m.t_koff & v->vbit ) v->env_mode = env_release; // KON if ( m.kon & v->vbit ) { v->kon_delay = 5; v->env_mode = env_attack; } } // Run envelope for next sample if ( !v->kon_delay ) run_envelope( v ); } inline void SPC_DSP::voice_output( voice_t const* v, int ch ) { // Apply left/right volume int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7; amp *= ((stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0); // Add to output total m.t_main_out [ch] += amp; CLAMP16( m.t_main_out [ch] ); // Optionally add to echo total if ( m.t_eon & v->vbit ) { m.t_echo_out [ch] += amp; CLAMP16( m.t_echo_out [ch] ); } } VOICE_CLOCK( V4 ) { // Decode BRR m.t_looped = 0; if ( v->interp_pos >= 0x4000 ) { decode_brr( v ); if ( (v->brr_offset += 2) >= brr_block_size ) { // Start decoding next BRR block assert( v->brr_offset == brr_block_size ); v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF; if ( m.t_brr_header & 1 ) { v->brr_addr = m.t_brr_next_addr; m.t_looped = v->vbit; } v->brr_offset = 1; } } // Apply pitch v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; // Keep from getting too far ahead (when using pitch modulation) if ( v->interp_pos > 0x7FFF ) v->interp_pos = 0x7FFF; // Output left voice_output( v, 0 ); } inline VOICE_CLOCK( V5 ) { // Output right voice_output( v, 1 ); // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier int endx_buf = REG(endx) | m.t_looped; // Clear bit in ENDX if KON just began if ( v->kon_delay == 5 ) endx_buf &= ~v->vbit; m.endx_buf = (uint8_t) endx_buf; } inline VOICE_CLOCK( V6 ) { (void) v; // avoid compiler warning about unused v m.outx_buf = (uint8_t) (m.t_output >> 8); } inline VOICE_CLOCK( V7 ) { // Update ENDX REG(endx) = m.endx_buf; m.envx_buf = v->t_envx_out; } inline VOICE_CLOCK( V8 ) { // Update OUTX VREG(v->regs,outx) = m.outx_buf; } inline VOICE_CLOCK( V9 ) { // Update ENVX VREG(v->regs,envx) = m.envx_buf; } // Most voices do all these in one clock, so make a handy composite inline VOICE_CLOCK( V3 ) { voice_V3a( v ); voice_V3b( v ); voice_V3c( v ); } // Common combinations of voice steps on different voices. This greatly reduces // code size and allows everything to be inlined in these functions. VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); } VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); } VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } //// Echo // Current echo buffer pointer for left/right channel #define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2]) // Sample in echo history buffer, where 0 is the oldest #define ECHO_FIR( i ) (m.echo_hist_pos [i]) // Calculate FIR point for left/right channel #define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6) #define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n() inline void SPC_DSP::echo_read( int ch ) { int s = GET_LE16SA( ECHO_PTR( ch ) ); // second copy simplifies wrap-around handling ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; } ECHO_CLOCK( 22 ) { // History if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) m.echo_hist_pos = m.echo_hist; m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; echo_read( 0 ); // FIR (using l and r temporaries below helps compiler optimize) int l = CALC_FIR( 0, 0 ); int r = CALC_FIR( 0, 1 ); m.t_echo_in [0] = l; m.t_echo_in [1] = r; } ECHO_CLOCK( 23 ) { int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); m.t_echo_in [0] += l; m.t_echo_in [1] += r; echo_read( 1 ); } ECHO_CLOCK( 24 ) { int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); m.t_echo_in [0] += l; m.t_echo_in [1] += r; } ECHO_CLOCK( 25 ) { int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); l = (int16_t) l; r = (int16_t) r; l += (int16_t) CALC_FIR( 7, 0 ); r += (int16_t) CALC_FIR( 7, 1 ); CLAMP16( l ); CLAMP16( r ); m.t_echo_in [0] = l & ~1; m.t_echo_in [1] = r & ~1; } inline int SPC_DSP::echo_output( int ch ) { int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) + (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7); CLAMP16( out ); return out; } ECHO_CLOCK( 26 ) { // Left output volumes // (save sample for next clock so we can output both together) m.t_main_out [0] = echo_output( 0 ); // Echo feedback int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); CLAMP16( l ); CLAMP16( r ); m.t_echo_out [0] = l & ~1; m.t_echo_out [1] = r & ~1; } ECHO_CLOCK( 27 ) { // Output int l = m.t_main_out [0]; int r = echo_output( 1 ); m.t_main_out [0] = 0; m.t_main_out [1] = 0; // TODO: global muting isn't this simple (turns DAC on and off // or something, causing small ~37-sample pulse when first muted) if ( REG(flg) & 0x40 ) { l = 0; r = 0; } // Output sample to DAC #ifdef SPC_DSP_OUT_HOOK SPC_DSP_OUT_HOOK( l, r ); #else sample_t* out = m.out; WRITE_SAMPLES( l, r, out ); m.out = out; #endif } ECHO_CLOCK( 28 ) { m.t_echo_enabled = REG(flg); } inline void SPC_DSP::echo_write( int ch ) { if ( !(m.t_echo_enabled & 0x20) ) SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); m.t_echo_out [ch] = 0; } ECHO_CLOCK( 29 ) { m.t_esa = REG(esa); if ( !m.echo_offset ) m.echo_length = (REG(edl) & 0x0F) * 0x800; m.echo_offset += 4; if ( m.echo_offset >= m.echo_length ) m.echo_offset = 0; // Write left echo echo_write( 0 ); m.t_echo_enabled = REG(flg); } ECHO_CLOCK( 30 ) { // Write right echo echo_write( 1 ); } //// Timing // Execute clock for a particular voice #define V( clock, voice ) voice_##clock( &m.voices [voice] ); /* The most common sequence of clocks uses composite operations for efficiency. For example, the following are equivalent to the individual steps on the right: V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5) V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4) V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */ // Voice 0 1 2 3 4 5 6 7 #define GEN_DSP_TIMING \ PHASE( 0) V(V5,0)V(V2,1)\ PHASE( 1) V(V6,0)V(V3,1)\ PHASE( 2) V(V7_V4_V1,0)\ PHASE( 3) V(V8_V5_V2,0)\ PHASE( 4) V(V9_V6_V3,0)\ PHASE( 5) V(V7_V4_V1,1)\ PHASE( 6) V(V8_V5_V2,1)\ PHASE( 7) V(V9_V6_V3,1)\ PHASE( 8) V(V7_V4_V1,2)\ PHASE( 9) V(V8_V5_V2,2)\ PHASE(10) V(V9_V6_V3,2)\ PHASE(11) V(V7_V4_V1,3)\ PHASE(12) V(V8_V5_V2,3)\ PHASE(13) V(V9_V6_V3,3)\ PHASE(14) V(V7_V4_V1,4)\ PHASE(15) V(V8_V5_V2,4)\ PHASE(16) V(V9_V6_V3,4)\ PHASE(17) V(V1,0) V(V7,5)V(V4,6)\ PHASE(18) V(V8_V5_V2,5)\ PHASE(19) V(V9_V6_V3,5)\ PHASE(20) V(V1,1) V(V7,6)V(V4,7)\ PHASE(21) V(V8,6)V(V5,7) V(V2,0) /* t_brr_next_addr order dependency */\ PHASE(22) V(V3a,0) V(V9,6)V(V6,7) echo_22();\ PHASE(23) V(V7,7) echo_23();\ PHASE(24) V(V8,7) echo_24();\ PHASE(25) V(V3b,0) V(V9,7) echo_25();\ PHASE(26) echo_26();\ PHASE(27) misc_27(); echo_27();\ PHASE(28) misc_28(); echo_28();\ PHASE(29) misc_29(); echo_29();\ PHASE(30) misc_30();V(V3c,0) echo_30();\ PHASE(31) V(V4,0) V(V1,2)\ #if !SPC_DSP_CUSTOM_RUN void SPC_DSP::run( int clocks_remain ) { require( clocks_remain > 0 ); int const phase = m.phase; m.phase = (phase + clocks_remain) & 31; switch ( phase ) { loop: #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: GEN_DSP_TIMING #undef PHASE if ( --clocks_remain ) goto loop; } } #endif //// Setup void SPC_DSP::init( void* ram_64k ) { m.ram = (uint8_t*) ram_64k; mute_voices( 0 ); disable_surround( false ); set_output( 0, 0 ); reset(); stereo_switch = 0xffff; take_spc_snapshot = 0; spc_snapshot_callback = 0; #ifndef NDEBUG // be sure this sign-extends assert( (int16_t) 0x8000 == -0x8000 ); // be sure right shift preserves sign assert( (-1 >> 1) == -1 ); // check clamp macro int i; i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); blargg_verify_byte_order(); #endif } void SPC_DSP::soft_reset_common() { require( m.ram ); // init() must have been called already m.noise = 0x4000; m.echo_hist_pos = m.echo_hist; m.every_other_sample = 1; m.echo_offset = 0; m.phase = 0; init_counter(); for (int i = 0; i < voice_count; i++) m.voices[i].voice_number = i; } void SPC_DSP::soft_reset() { REG(flg) = 0xE0; soft_reset_common(); } void SPC_DSP::load( uint8_t const regs [register_count] ) { memcpy( m.regs, regs, sizeof m.regs ); memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); // Internal state for ( int i = voice_count; --i >= 0; ) { voice_t* v = &m.voices [i]; v->brr_offset = 1; v->vbit = 1 << i; v->regs = &m.regs [i * 0x10]; } m.new_kon = REG(kon); m.t_dir = REG(dir); m.t_esa = REG(esa); soft_reset_common(); } void SPC_DSP::reset() { load( initial_regs ); } //// State save/load #if !SPC_NO_COPY_STATE_FUNCS void SPC_State_Copier::copy( void* state, size_t size ) { func( buf, state, size ); } int SPC_State_Copier::copy_int( int state, int size ) { BOOST::uint8_t s [2]; SET_LE16( s, state ); func( buf, &s, size ); return GET_LE16( s ); } void SPC_State_Copier::skip( int count ) { if ( count > 0 ) { char temp [64]; memset( temp, 0, sizeof temp ); do { int n = sizeof temp; if ( n > count ) n = count; count -= n; func( buf, temp, n ); } while ( count ); } } void SPC_State_Copier::extra() { int n = 0; SPC_State_Copier& copier = *this; SPC_COPY( uint8_t, n ); skip( n ); } void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) { SPC_State_Copier copier( io, copy ); // DSP registers copier.copy( m.regs, register_count ); // Internal state // Voices int i; for ( i = 0; i < voice_count; i++ ) { voice_t* v = &m.voices [i]; // BRR buffer int i; for ( i = 0; i < brr_buf_size; i++ ) { int s = v->buf [i]; SPC_COPY( int16_t, s ); v->buf [i] = v->buf [i + brr_buf_size] = s; } SPC_COPY( uint16_t, v->interp_pos ); SPC_COPY( uint16_t, v->brr_addr ); SPC_COPY( uint16_t, v->env ); SPC_COPY( int16_t, v->hidden_env ); SPC_COPY( uint8_t, v->buf_pos ); SPC_COPY( uint8_t, v->brr_offset ); SPC_COPY( uint8_t, v->kon_delay ); { int m = v->env_mode; SPC_COPY( uint8_t, m ); v->env_mode = (enum env_mode_t) m; } SPC_COPY( uint8_t, v->t_envx_out ); copier.extra(); } // Echo history for ( i = 0; i < echo_hist_size; i++ ) { int j; for ( j = 0; j < 2; j++ ) { int s = m.echo_hist_pos [i] [j]; SPC_COPY( int16_t, s ); m.echo_hist [i] [j] = s; // write back at offset 0 } } m.echo_hist_pos = m.echo_hist; memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); // Misc SPC_COPY( uint8_t, m.every_other_sample ); SPC_COPY( uint8_t, m.kon ); SPC_COPY( uint16_t, m.noise ); SPC_COPY( uint16_t, m.counter ); SPC_COPY( uint16_t, m.echo_offset ); SPC_COPY( uint16_t, m.echo_length ); SPC_COPY( uint8_t, m.phase ); SPC_COPY( uint8_t, m.new_kon ); SPC_COPY( uint8_t, m.endx_buf ); SPC_COPY( uint8_t, m.envx_buf ); SPC_COPY( uint8_t, m.outx_buf ); SPC_COPY( uint8_t, m.t_pmon ); SPC_COPY( uint8_t, m.t_non ); SPC_COPY( uint8_t, m.t_eon ); SPC_COPY( uint8_t, m.t_dir ); SPC_COPY( uint8_t, m.t_koff ); SPC_COPY( uint16_t, m.t_brr_next_addr ); SPC_COPY( uint8_t, m.t_adsr0 ); SPC_COPY( uint8_t, m.t_brr_header ); SPC_COPY( uint8_t, m.t_brr_byte ); SPC_COPY( uint8_t, m.t_srcn ); SPC_COPY( uint8_t, m.t_esa ); SPC_COPY( uint8_t, m.t_echo_enabled ); SPC_COPY( int16_t, m.t_main_out [0] ); SPC_COPY( int16_t, m.t_main_out [1] ); SPC_COPY( int16_t, m.t_echo_out [0] ); SPC_COPY( int16_t, m.t_echo_out [1] ); SPC_COPY( int16_t, m.t_echo_in [0] ); SPC_COPY( int16_t, m.t_echo_in [1] ); SPC_COPY( uint16_t, m.t_dir_addr ); SPC_COPY( uint16_t, m.t_pitch ); SPC_COPY( int16_t, m.t_output ); SPC_COPY( uint16_t, m.t_echo_ptr ); SPC_COPY( uint8_t, m.t_looped ); copier.extra(); } #endif //// Snes9x Accessor void SPC_DSP::set_spc_snapshot_callback( void (*callback) (void) ) { spc_snapshot_callback = callback; } void SPC_DSP::dump_spc_snapshot( void ) { take_spc_snapshot = 1; } void SPC_DSP::set_stereo_switch( int value ) { stereo_switch = value; } SPC_DSP::uint8_t SPC_DSP::reg_value( int ch, int addr ) { return m.voices[ch].regs[addr]; } int SPC_DSP::envx_value( int ch ) { return m.voices[ch].env; } ppu.h000664 001750 001750 00000052044 12720446475 012677 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _PPU_H_ #define _PPU_H_ #define FIRST_VISIBLE_LINE 1 #define TILE_2BIT 0 #define TILE_4BIT 1 #define TILE_8BIT 2 #define TILE_2BIT_EVEN 3 #define TILE_2BIT_ODD 4 #define TILE_4BIT_EVEN 5 #define TILE_4BIT_ODD 6 #define MAX_2BIT_TILES 4096 #define MAX_4BIT_TILES 2048 #define MAX_8BIT_TILES 1024 #define CLIP_OR 0 #define CLIP_AND 1 #define CLIP_XOR 2 #define CLIP_XNOR 3 struct ClipData { uint8 Count; uint8 DrawMode[6]; uint16 Left[6]; uint16 Right[6]; }; struct InternalPPU { struct ClipData Clip[2][6]; bool8 ColorsChanged; bool8 OBJChanged; bool8 DirectColourMapsNeedRebuild; uint8 *TileCache[7]; uint8 *TileCached[7]; uint16 VRAMReadBuffer; bool8 Interlace; bool8 InterlaceOBJ; bool8 PseudoHires; bool8 DoubleWidthPixels; bool8 DoubleHeightPixels; int CurrentLine; int PreviousLine; uint8 *XB; uint32 Red[256]; uint32 Green[256]; uint32 Blue[256]; uint16 ScreenColors[256]; uint8 MaxBrightness; bool8 RenderThisFrame; int RenderedScreenWidth; int RenderedScreenHeight; uint32 FrameCount; uint32 RenderedFramesCount; uint32 DisplayedRenderedFrameCount; uint32 TotalEmulatedFrames; uint32 SkippedFrames; uint32 FrameSkip; }; struct SOBJ { int16 HPos; uint16 VPos; uint8 HFlip; uint8 VFlip; uint16 Name; uint8 Priority; uint8 Palette; uint8 Size; }; struct SPPU { struct { bool8 High; uint8 Increment; uint16 Address; uint16 Mask1; uint16 FullGraphicCount; uint16 Shift; } VMA; uint32 WRAM; struct { uint16 SCBase; uint16 HOffset; uint16 VOffset; uint8 BGSize; uint16 NameBase; uint16 SCSize; } BG[4]; uint8 BGMode; uint8 BG3Priority; bool8 CGFLIP; uint8 CGFLIPRead; uint8 CGADD; uint16 CGDATA[256]; struct SOBJ OBJ[128]; bool8 OBJThroughMain; bool8 OBJThroughSub; bool8 OBJAddition; uint16 OBJNameBase; uint16 OBJNameSelect; uint8 OBJSizeSelect; uint16 OAMAddr; uint16 SavedOAMAddr; uint8 OAMPriorityRotation; uint8 OAMFlip; uint8 OAMReadFlip; uint16 OAMTileAddress; uint16 OAMWriteRegister; uint8 OAMData[512 + 32]; uint8 FirstSprite; uint8 LastSprite; uint8 RangeTimeOver; bool8 HTimerEnabled; bool8 VTimerEnabled; short HTimerPosition; short VTimerPosition; uint16 IRQHBeamPos; uint16 IRQVBeamPos; uint8 HBeamFlip; uint8 VBeamFlip; uint16 HBeamPosLatched; uint16 VBeamPosLatched; uint16 GunHLatch; uint16 GunVLatch; uint8 HVBeamCounterLatched; bool8 Mode7HFlip; bool8 Mode7VFlip; uint8 Mode7Repeat; short MatrixA; short MatrixB; short MatrixC; short MatrixD; short CentreX; short CentreY; short M7HOFS; short M7VOFS; uint8 Mosaic; uint8 MosaicStart; bool8 BGMosaic[4]; uint8 Window1Left; uint8 Window1Right; uint8 Window2Left; uint8 Window2Right; bool8 RecomputeClipWindows; uint8 ClipCounts[6]; uint8 ClipWindowOverlapLogic[6]; uint8 ClipWindow1Enable[6]; uint8 ClipWindow2Enable[6]; bool8 ClipWindow1Inside[6]; bool8 ClipWindow2Inside[6]; bool8 ForcedBlanking; uint8 FixedColourRed; uint8 FixedColourGreen; uint8 FixedColourBlue; uint8 Brightness; uint16 ScreenHeight; bool8 Need16x8Mulitply; uint8 BGnxOFSbyte; uint8 M7byte; uint8 HDMA; uint8 HDMAEnded; uint8 OpenBus1; uint8 OpenBus2; }; extern uint16 SignExtend[2]; extern struct SPPU PPU; extern struct InternalPPU IPPU; void S9xResetPPU (void); void S9xSoftResetPPU (void); void S9xSetPPU (uint8, uint16); uint8 S9xGetPPU (uint16); void S9xSetCPU (uint8, uint16); uint8 S9xGetCPU (uint16); void S9xUpdateHVTimerPosition (void); void S9xFixColourBrightness (void); void S9xDoAutoJoypad (void); #include "gfx.h" #include "memmap.h" typedef struct { uint8 _5C77; uint8 _5C78; uint8 _5A22; } SnesModel; extern SnesModel *Model; extern SnesModel M1SNES; extern SnesModel M2SNES; #define MAX_5C77_VERSION 0x01 #define MAX_5C78_VERSION 0x03 #define MAX_5A22_VERSION 0x02 static inline void FLUSH_REDRAW (void) { if (IPPU.PreviousLine != IPPU.CurrentLine) S9xUpdateScreen(); } static inline void REGISTER_2104 (uint8 Byte) { if (PPU.OAMAddr & 0x100) { int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1); if (Byte != PPU.OAMData[addr]) { FLUSH_REDRAW(); PPU.OAMData[addr] = Byte; IPPU.OBJChanged = TRUE; // X position high bit, and sprite size (x4) struct SOBJ *pObj = &PPU.OBJ[(addr & 0x1f) * 4]; pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 0) & 1]; pObj++->Size = Byte & 2; pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 2) & 1]; pObj++->Size = Byte & 8; pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 4) & 1]; pObj++->Size = Byte & 32; pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 6) & 1]; pObj->Size = Byte & 128; } PPU.OAMFlip ^= 1; if (!(PPU.OAMFlip & 1)) { ++PPU.OAMAddr; PPU.OAMAddr &= 0x1ff; if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; } } else { if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1)) IPPU.OBJChanged = TRUE; } } else if (!(PPU.OAMFlip & 1)) { PPU.OAMWriteRegister &= 0xff00; PPU.OAMWriteRegister |= Byte; PPU.OAMFlip |= 1; if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1)) IPPU.OBJChanged = TRUE; } else { PPU.OAMWriteRegister &= 0x00ff; uint8 lowbyte = (uint8) (PPU.OAMWriteRegister); uint8 highbyte = Byte; PPU.OAMWriteRegister |= Byte << 8; int addr = (PPU.OAMAddr << 1); if (lowbyte != PPU.OAMData[addr] || highbyte != PPU.OAMData[addr + 1]) { FLUSH_REDRAW(); PPU.OAMData[addr] = lowbyte; PPU.OAMData[addr + 1] = highbyte; IPPU.OBJChanged = TRUE; if (addr & 2) { // Tile PPU.OBJ[addr = PPU.OAMAddr >> 1].Name = PPU.OAMWriteRegister & 0x1ff; // priority, h and v flip. PPU.OBJ[addr].Palette = (highbyte >> 1) & 7; PPU.OBJ[addr].Priority = (highbyte >> 4) & 3; PPU.OBJ[addr].HFlip = (highbyte >> 6) & 1; PPU.OBJ[addr].VFlip = (highbyte >> 7) & 1; } else { // X position (low) PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xff00; PPU.OBJ[addr].HPos |= lowbyte; // Sprite Y position PPU.OBJ[addr].VPos = highbyte; } } PPU.OAMFlip &= ~1; ++PPU.OAMAddr; if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) { PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1; IPPU.OBJChanged = TRUE; } } } // This code is correct, however due to Snes9x's inaccurate timings, some games might be broken by this chage. :( #ifdef DEBUGGER #define CHECK_INBLANK() \ if (!PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \ { \ printf("Invalid VRAM acess at (%04d, %04d) blank:%d\n", CPU.Cycles, CPU.V_Counter, PPU.ForcedBlanking); \ if (Settings.BlockInvalidVRAMAccess) \ return; \ } #else #define CHECK_INBLANK() \ if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \ return; #endif static inline void REGISTER_2118 (uint8 Byte) { CHECK_INBLANK(); uint32 address; if (PPU.VMA.FullGraphicCount) { uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff; Memory.VRAM[address] = Byte; } else Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (!PPU.VMA.High) { #ifdef DEBUGGER if (Settings.TraceVRAM && !CPU.InDMAorHDMA) printf("VRAM write byte: $%04X (%d, %d)\n", PPU.VMA.Address, Memory.FillRAM[0x2115] & 3, (Memory.FillRAM[0x2115] & 0x0c) >> 2); #endif PPU.VMA.Address += PPU.VMA.Increment; } } static inline void REGISTER_2119 (uint8 Byte) { CHECK_INBLANK(); uint32 address; if (PPU.VMA.FullGraphicCount) { uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xffff; Memory.VRAM[address] = Byte; } else Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xffff] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (PPU.VMA.High) { #ifdef DEBUGGER if (Settings.TraceVRAM && !CPU.InDMAorHDMA) printf("VRAM write word: $%04X (%d, %d)\n", PPU.VMA.Address, Memory.FillRAM[0x2115] & 3, (Memory.FillRAM[0x2115] & 0x0c) >> 2); #endif PPU.VMA.Address += PPU.VMA.Increment; } } static inline void REGISTER_2118_tile (uint8 Byte) { CHECK_INBLANK(); uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; uint32 address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff; Memory.VRAM[address] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (!PPU.VMA.High) PPU.VMA.Address += PPU.VMA.Increment; } static inline void REGISTER_2119_tile (uint8 Byte) { CHECK_INBLANK(); uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; uint32 address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xffff; Memory.VRAM[address] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (PPU.VMA.High) PPU.VMA.Address += PPU.VMA.Increment; } static inline void REGISTER_2118_linear (uint8 Byte) { CHECK_INBLANK(); uint32 address; Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (!PPU.VMA.High) PPU.VMA.Address += PPU.VMA.Increment; } static inline void REGISTER_2119_linear (uint8 Byte) { CHECK_INBLANK(); uint32 address; Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xffff] = Byte; IPPU.TileCached[TILE_2BIT][address >> 4] = FALSE; IPPU.TileCached[TILE_4BIT][address >> 5] = FALSE; IPPU.TileCached[TILE_8BIT][address >> 6] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = FALSE; IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = FALSE; IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = FALSE; if (PPU.VMA.High) PPU.VMA.Address += PPU.VMA.Increment; } static inline void REGISTER_2122 (uint8 Byte) { if (PPU.CGFLIP) { if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8)) { FLUSH_REDRAW(); PPU.CGDATA[PPU.CGADD] &= 0x00ff; PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8; IPPU.ColorsChanged = TRUE; IPPU.Blue[PPU.CGADD] = IPPU.XB[(Byte >> 2) & 0x1f]; IPPU.Green[PPU.CGADD] = IPPU.XB[(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f]; IPPU.ScreenColors[PPU.CGADD] = (uint16) BUILD_PIXEL(IPPU.Red[PPU.CGADD], IPPU.Green[PPU.CGADD], IPPU.Blue[PPU.CGADD]); } PPU.CGADD++; } else { if (Byte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff)) { FLUSH_REDRAW(); PPU.CGDATA[PPU.CGADD] &= 0x7f00; PPU.CGDATA[PPU.CGADD] |= Byte; IPPU.ColorsChanged = TRUE; IPPU.Red[PPU.CGADD] = IPPU.XB[Byte & 0x1f]; IPPU.Green[PPU.CGADD] = IPPU.XB[(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f]; IPPU.ScreenColors[PPU.CGADD] = (uint16) BUILD_PIXEL(IPPU.Red[PPU.CGADD], IPPU.Green[PPU.CGADD], IPPU.Blue[PPU.CGADD]); } } PPU.CGFLIP ^= 1; } static inline void REGISTER_2180 (uint8 Byte) { Memory.RAM[PPU.WRAM++] = Byte; PPU.WRAM &= 0x1ffff; } static inline uint8 REGISTER_4212 (void) { uint8 byte = 0; if ((CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE) && (CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3)) byte = 1; if ((CPU.Cycles < Timings.HBlankEnd) || (CPU.Cycles >= Timings.HBlankStart)) byte |= 0x40; if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE) byte |= 0x80; return (byte); } #endif docs/portsofsnes9x.txt000664 001750 001750 00000014437 12720446475 016265 0ustar00sergiosergio000000 000000 These are all the known ports of Snes9X to other consoles/handhelds/etc as of 2011/08/28. They are all supported and welcomed on the official Snes9X site. **If you know of anyone who is currently working on a port of Snes9X, or if you have some interest in making a port, please have them go to the Snes9X forums (http://www.snes9x.com/phpbb2/) and have them register an account there. After that, speak to Ryan and/or Jerremy so you can be let into the devs area and the git so you can have access to the most current code, collaborate with the other developers, make the port officialized, etc.** Ports and how to get them running are as follows: *PSP Version of Snes9X* Name: Snes9X Euphoria Latest version: R5 Beta Homepage/forum: http://code.google.com/p/snes9x-euphoria/ Maintainer: Open due to Zack discontinuing the port; he has made the source code available. If you are interested in taking over the project or starting a new port from scratch, let Ryan and/or Jerremy know ASAP. HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * Downgrading/upgrading your firmware * Checking if your PSP-2000 series can use Pandora's Battery * Checking if your PSP-3000 series can use DaveeFTW's and/or some1's Downgrader * Creating Pandora's Battery (as needed) * Finding the hacks, HENs, CFWs, etc and how to use/install them 1. Make sure your PSP is hackable in some way. This means: * All PSP-1000 series and certain PSP-2000 series can use Pandora Battery; this would be considered fully hackable. * PSP-2000 series that can't use Pandora Battery, just about all PSP-3000 series, and PSP Gos are hackable via other means (DaveeFTW's and/or some1's Downgrader, etc); this would be considered partially hackable. 2. Make sure your PSP has custom firmware or a HEN that's useable (you'll have to upgrade/downgrade the firmware as necessary). (Hint: I personally prefer 5.50 GEN-D3 if your PSP can use Pandora Battery; latest version of 6.20 or 6.35 PRO CFW if your PSP can't use Pandora Battery (if you can't downgrade past 6.35, then you should be able to use 6.39 and/or 6.60 PRO).) 3. When that’s done, be sure to put the Snes9X Euphoria folder in /PSP/GAME on your PSP’s memory stick (PSP-1000/2000/3000 series) or internal memory (PSP Go). Be sure to copy the ROMs into the roms folder, saves (*.srm, etc) into the saves folder, and cheats into the cheats folder. Note: as of right now, there is no one to maintain the PSP port; I am leaving these instructions up just in case someone wants to take it over, and you can use these tips to get other homebrews going. *Wii/Gamecube version of Snes9X* Name: Snes9X GX Latest Version: 4.2.8 Homepage/forum: http://code.google.com/p/snes9x-gx Maintainer: Tantric HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * Finding and installing the latest versions of: Homebrew Channel, Snes9X GX Channel (optional), and/or IOS58 installer (also optional; this is to make the Snes9X GX channel work) * Finding a modchip for your GameCube and installing it Wii: You will need the latest Homebrew Channel installed on your Wii. After that, copy and paste the apps folder onto the root of your SD card; same goes for the snes9xgx folder. After that, copy over any ROMs you have to the \snes9xgx\roms folder, save files (*.srm, etc) to the \snes9xgx\saves folder, and cheats to the \snes9xgx\cheats folder. In addition, there appears to be a channel for Snes9X GX; you will need the Homebrew Channel installed and you MUST be on System Menu 4.3 so you can be on IOS58 (or use the IOS58 installer). After that, you should be able to run the installer from the Homebrew Channel, and you'll be good to go! Gamecube: You might need a modchip. *Android and iOS (Apple iPhone/iPod Touch) version of Snes9X* Name: Snes9X EX Latest Version: 1.4.2 (iOS); 1.4.7.1 (Android) Homepage/forum: http://www.explusalpha.com/home/snes9x-ex Maintainer: Rakashazi HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * iOS (iPhone/iPod Touch) ONLY!!!: Jailbreaking your firmware Android: Due to the Android Marketplace unfairly taking down Snes9X EX, you will have to visit Rakashazi's website and download the apk either using your PC (you'll have to connect the Android to your computer, mount the SD card, then copy the apk to it) or your Android, then run package installer (or easy installer is fine too) on your Android to install the app. iOS: You’ll have to jailbreak your firmware and install the Cydia app installer. Then you’ll have to install the BigBoss repository within Cydia and search for Snes9X EX; you may also want to search for the sshd and all needed stuff for that, as it’s the only way you can put the ROMs, saves, etc onto your iPhone/iPod Touch. After that you should be able to download and run from there :) Hint: a more detailed description of copying your ROMs/saves/etc over to the iOS device can be found here: http://snes9x.com/phpbb2/viewtopic.php?t=5107 *PS3 version of Snes9X* Name: Snes9X PS3 Latest Version: 4.4.9 Homepage/forum: https://code.google.com/p/snes9x-ps3/ (although for some reason, you may have to Google for the latest version) Maintainer: Squarepusher HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * Finding a HEN/Jailbreaker/CFW/etc onto your PS3 and installing it * (if necessary) Downgrading/Upgrading your PS3's firmware You’ll have to install a HEN/Jailbreaker/CFW/etc on your PS3 (you might have to upgrade or downgrade your PS3’s firmware as needed). After that, it should be as simple as copy the emulator, ROMs, saves, etc over to the PS3 and it should work :) *X-Box Version of Snes9X* Name: Snes9xbox Latest Version: V2 (V3 should be out soon) Homepage/forum: http://forums.xbox-scene.com/index.php?showforum=96 HOW TO GET IT RUNNING: *DISCLAIMER* You will need to do some Googling, including but not limited to: * Finding a softmod (hack) or a modchip and installing/using it * Finding a replacement dashboard such as XBMC Really, it's not hard. Read the readme, and use a softmod or modchip and a replacement dashboard. After that's installed, it should be as simple as copying over the emulator, ROMs, saves, etc to the X-Box and it should work. Updated most recently by: 2011/11/2 adventure_of_linkspc7110dec.h000664 001750 001750 00000003655 12720446475 013651 0ustar00sergiosergio000000 000000 /***** * SPC7110 emulator - version 0.03 (2008-08-10) * Copyright (c) 2008, byuu and neviksti * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * The software is provided "as is" and the author disclaims all warranties * with regard to this software including all implied warranties of * merchantibility and fitness, in no event shall the author be liable for * any special, direct, indirect, or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an * action of contract, negligence or other tortious action, arising out of * or in connection with the use or performance of this software. *****/ #ifndef _SPC7110DEC_H_ #define _SPC7110DEC_H_ class SPC7110Decomp { public: uint8 read(); void init(unsigned mode, unsigned offset, unsigned index); void reset(); SPC7110Decomp(); ~SPC7110Decomp(); unsigned decomp_mode; unsigned decomp_offset; //read() will spool chunks half the size of decomp_buffer_size enum { decomp_buffer_size = SPC7110_DECOMP_BUFFER_SIZE }; //must be >= 64, and must be a power of two uint8 *decomp_buffer; unsigned decomp_buffer_rdoffset; unsigned decomp_buffer_wroffset; unsigned decomp_buffer_length; void write(uint8 data); uint8 dataread(); void mode0(bool init); void mode1(bool init); void mode2(bool init); static const uint8 evolution_table[53][4]; static const uint8 mode2_context_table[32][2]; struct ContextState { uint8 index; uint8 invert; } context[32]; uint8 probability(unsigned n); uint8 next_lps(unsigned n); uint8 next_mps(unsigned n); bool toggle_invert(unsigned n); unsigned morton16[2][256]; unsigned morton32[4][256]; unsigned morton_2x8(unsigned data); unsigned morton_4x8(unsigned data); }; #endif apu/bapu/smp/core/000700 001750 001750 00000000000 12724164663 015144 5ustar00sergiosergio000000 000000 65c816.h000664 001750 001750 00000020441 12720446475 012723 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _65C816_H_ #define _65C816_H_ #define Carry 1 #define Zero 2 #define IRQ 4 #define Decimal 8 #define IndexFlag 16 #define MemoryFlag 32 #define Overflow 64 #define Negative 128 #define Emulation 256 #define SetCarry() (ICPU._Carry = 1) #define ClearCarry() (ICPU._Carry = 0) #define SetZero() (ICPU._Zero = 0) #define ClearZero() (ICPU._Zero = 1) #define SetIRQ() (Registers.PL |= IRQ) #define ClearIRQ() (Registers.PL &= ~IRQ) #define SetDecimal() (Registers.PL |= Decimal) #define ClearDecimal() (Registers.PL &= ~Decimal) #define SetIndex() (Registers.PL |= IndexFlag) #define ClearIndex() (Registers.PL &= ~IndexFlag) #define SetMemory() (Registers.PL |= MemoryFlag) #define ClearMemory() (Registers.PL &= ~MemoryFlag) #define SetOverflow() (ICPU._Overflow = 1) #define ClearOverflow() (ICPU._Overflow = 0) #define SetNegative() (ICPU._Negative = 0x80) #define ClearNegative() (ICPU._Negative = 0) #define CheckCarry() (ICPU._Carry) #define CheckZero() (ICPU._Zero == 0) #define CheckIRQ() (Registers.PL & IRQ) #define CheckDecimal() (Registers.PL & Decimal) #define CheckIndex() (Registers.PL & IndexFlag) #define CheckMemory() (Registers.PL & MemoryFlag) #define CheckOverflow() (ICPU._Overflow) #define CheckNegative() (ICPU._Negative & 0x80) #define CheckEmulation() (Registers.P.W & Emulation) #define SetFlags(f) (Registers.P.W |= (f)) #define ClearFlags(f) (Registers.P.W &= ~(f)) #define CheckFlag(f) (Registers.PL & (f)) typedef union { #ifdef LSB_FIRST struct { uint8 l, h; } B; #else struct { uint8 h, l; } B; #endif uint16 W; } pair; typedef union { #ifdef LSB_FIRST struct { uint8 xPCl, xPCh, xPB, z; } B; struct { uint16 xPC, d; } W; #else struct { uint8 z, xPB, xPCh, xPCl; } B; struct { uint16 d, xPC; } W; #endif uint32 xPBPC; } PC_t; struct SRegisters { uint8 DB; pair P; pair A; pair D; pair S; pair X; pair Y; PC_t PC; }; #define AL A.B.l #define AH A.B.h #define XL X.B.l #define XH X.B.h #define YL Y.B.l #define YH Y.B.h #define SL S.B.l #define SH S.B.h #define DL D.B.l #define DH D.B.h #define PL P.B.l #define PH P.B.h #define PBPC PC.xPBPC #define PCw PC.W.xPC #define PCh PC.B.xPCh #define PCl PC.B.xPCl #define PB PC.B.xPB extern struct SRegisters Registers; #endif apu/bapu/snes/000700 001750 001750 00000000000 12724164663 014365 5ustar00sergiosergio000000 000000 dsp4.cpp000664 001750 001750 00000161366 12720446475 013310 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ /* Due recognition and credit are given on Overload's DSP website. Thank those contributors for their hard work on this chip. Fixed-point math reminder: [sign, integer, fraction] 1.15.00 * 1.15.00 = 2.30.00 -> 1.30.00 (DSP) -> 1.31.00 (LSB is '0') 1.15.00 * 1.00.15 = 2.15.15 -> 1.15.15 (DSP) -> 1.15.16 (LSB is '0') */ #include "snes9x.h" #include "memmap.h" #define DSP4_CLEAR_OUT() \ { DSP4.out_count = 0; DSP4.out_index = 0; } #define DSP4_WRITE_BYTE(d) \ { WRITE_WORD(DSP4.output + DSP4.out_count, (d)); DSP4.out_count++; } #define DSP4_WRITE_WORD(d) \ { WRITE_WORD(DSP4.output + DSP4.out_count, (d)); DSP4.out_count += 2; } #ifndef MSB_FIRST #define DSP4_WRITE_16_WORD(d) \ { memcpy(DSP4.output + DSP4.out_count, (d), 32); DSP4.out_count += 32; } #else #define DSP4_WRITE_16_WORD(d) \ { for (int p = 0; p < 16; p++) DSP4_WRITE_WORD((d)[p]); } #endif // used to wait for dsp i/o #define DSP4_WAIT(x) \ DSP4.in_index = 0; DSP4.Logic = (x); return // 1.7.8 -> 1.15.16 #define SEX78(a) (((int32) ((int16) (a))) << 8) // 1.15.0 -> 1.15.16 #define SEX16(a) (((int32) ((int16) (a))) << 16) static int16 DSP4_READ_WORD (void); static int32 DSP4_READ_DWORD (void); static int16 DSP4_Inverse (int16); static void DSP4_Multiply (int16, int16, int32 *); static void DSP4_OP01 (void); static void DSP4_OP03 (void); static void DSP4_OP05 (void); static void DSP4_OP06 (void); static void DSP4_OP07 (void); static void DSP4_OP08 (void); static void DSP4_OP09 (void); static void DSP4_OP0A (int16, int16 *, int16 *, int16 *, int16 *); static void DSP4_OP0B (bool8 *, int16, int16, int16, bool8, bool8); static void DSP4_OP0D (void); static void DSP4_OP0E (void); static void DSP4_OP0F (void); static void DSP4_OP10 (void); static void DSP4_OP11 (int16, int16, int16, int16, int16 *); static void DSP4_SetByte (void); static void DSP4_GetByte (void); static int16 DSP4_READ_WORD (void) { int16 out; out = READ_WORD(DSP4.parameters + DSP4.in_index); DSP4.in_index += 2; return (out); } static int32 DSP4_READ_DWORD (void) { int32 out; out = READ_DWORD(DSP4.parameters + DSP4.in_index); DSP4.in_index += 4; return (out); } static int16 DSP4_Inverse (int16 value) { // Attention: This lookup table is not verified const uint16 div_lut[64] = { 0x0000, 0x8000, 0x4000, 0x2aaa, 0x2000, 0x1999, 0x1555, 0x1249, 0x1000, 0x0e38, 0x0ccc, 0x0ba2, 0x0aaa, 0x09d8, 0x0924, 0x0888, 0x0800, 0x0787, 0x071c, 0x06bc, 0x0666, 0x0618, 0x05d1, 0x0590, 0x0555, 0x051e, 0x04ec, 0x04bd, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x03e0, 0x03c3, 0x03a8, 0x038e, 0x0375, 0x035e, 0x0348, 0x0333, 0x031f, 0x030c, 0x02fa, 0x02e8, 0x02d8, 0x02c8, 0x02b9, 0x02aa, 0x029c, 0x028f, 0x0282, 0x0276, 0x026a, 0x025e, 0x0253, 0x0249, 0x023e, 0x0234, 0x022b, 0x0222, 0x0219, 0x0210, 0x0208 }; // saturate bounds if (value < 0) value = 0; if (value > 63) value = 63; return (div_lut[value]); } static void DSP4_Multiply (int16 Multiplicand, int16 Multiplier, int32 *Product) { *Product = (Multiplicand * Multiplier << 1) >> 1; } static void DSP4_OP01 (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; case 3: goto resume3; break; } //////////////////////////////////////////////////// // process initial inputs // sort inputs DSP4.world_y = DSP4_READ_DWORD(); DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); DSP4.world_x = DSP4_READ_DWORD(); DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.world_yofs = DSP4_READ_WORD(); DSP4.world_dy = DSP4_READ_DWORD(); DSP4.world_dx = DSP4_READ_DWORD(); DSP4.distance = DSP4_READ_WORD(); DSP4_READ_WORD(); // 0x0000 DSP4.world_xenv = DSP4_READ_DWORD(); DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // initial (x, y, offset) at starting raster line DSP4.view_x1 = (DSP4.world_x + DSP4.world_xenv) >> 16; DSP4.view_y1 = DSP4.world_y >> 16; DSP4.view_xofs1 = DSP4.world_x >> 16; DSP4.view_yofs1 = DSP4.world_yofs; DSP4.view_turnoff_x = 0; DSP4.view_turnoff_dx = 0; // first raster line DSP4.poly_raster[0][0] = DSP4.poly_bottom[0][0]; do { //////////////////////////////////////////////////// // process one iteration of projection // perspective projection of world (x, y, scroll) points // based on the current projection lines DSP4.view_x2 = (((DSP4.world_x + DSP4.world_xenv) >> 16) * DSP4.distance >> 15) + (DSP4.view_turnoff_x * DSP4.distance >> 15); DSP4.view_y2 = (DSP4.world_y >> 16) * DSP4.distance >> 15; DSP4.view_xofs2 = DSP4.view_x2; DSP4.view_yofs2 = (DSP4.world_yofs * DSP4.distance >> 15) + DSP4.poly_bottom[0][0] - DSP4.view_y2; // 1. World x-location before transformation // 2. Viewer x-position at the next // 3. World y-location before perspective projection // 4. Viewer y-position below the horizon // 5. Number of raster lines drawn in this iteration DSP4_CLEAR_OUT(); DSP4_WRITE_WORD((DSP4.world_x + DSP4.world_xenv) >> 16); DSP4_WRITE_WORD(DSP4.view_x2); DSP4_WRITE_WORD(DSP4.world_y >> 16); DSP4_WRITE_WORD(DSP4.view_y2); ////////////////////////////////////////////////////// // SR = 0x00 // determine # of raster lines used DSP4.segments = DSP4.poly_raster[0][0] - DSP4.view_y2; // prevent overdraw if (DSP4.view_y2 >= DSP4.poly_raster[0][0]) DSP4.segments = 0; else DSP4.poly_raster[0][0] = DSP4.view_y2; // don't draw outside the window if (DSP4.view_y2 < DSP4.poly_top[0][0]) { DSP4.segments = 0; // flush remaining raster lines if (DSP4.view_y1 >= DSP4.poly_top[0][0]) DSP4.segments = DSP4.view_y1 - DSP4.poly_top[0][0]; } // SR = 0x80 DSP4_WRITE_WORD(DSP4.segments); ////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 px_dx, py_dy; int32 x_scroll, y_scroll; // SR = 0x00 // linear interpolation (lerp) between projected points px_dx = (DSP4.view_xofs2 - DSP4.view_xofs1) * DSP4_Inverse(DSP4.segments) << 1; py_dy = (DSP4.view_yofs2 - DSP4.view_yofs1) * DSP4_Inverse(DSP4.segments) << 1; // starting step values x_scroll = SEX16(DSP4.poly_cx[0][0] + DSP4.view_xofs1); y_scroll = SEX16(-DSP4.viewport_bottom + DSP4.view_yofs1 + DSP4.view_yofsenv + DSP4.poly_cx[1][0] - DSP4.world_yofs); // SR = 0x80 // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { // 1. HDMA memory pointer (bg1) // 2. vertical scroll offset ($210E) // 3. horizontal scroll offset ($210D) DSP4_WRITE_WORD(DSP4.poly_ptr[0][0]); DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); // update memory address DSP4.poly_ptr[0][0] -= 4; // update screen values x_scroll += px_dx; y_scroll += py_dy; } } //////////////////////////////////////////////////// // Post-update // update new viewer (x, y, scroll) to last raster line drawn DSP4.view_x1 = DSP4.view_x2; DSP4.view_y1 = DSP4.view_y2; DSP4.view_xofs1 = DSP4.view_xofs2; DSP4.view_yofs1 = DSP4.view_yofs2; // add deltas for projection lines DSP4.world_dx += SEX78(DSP4.world_ddx); DSP4.world_dy += SEX78(DSP4.world_ddy); // update projection lines DSP4.world_x += (DSP4.world_dx + DSP4.world_xenv); DSP4.world_y += DSP4.world_dy; // update road turnoff position DSP4.view_turnoff_x += DSP4.view_turnoff_dx; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(1); resume1: // check for termination DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) break; // road turnoff if ((uint16) DSP4.distance == 0x8001) { DSP4.in_count = 6; DSP4_WAIT(2); resume2: DSP4.distance = DSP4_READ_WORD(); DSP4.view_turnoff_x = DSP4_READ_WORD(); DSP4.view_turnoff_dx = DSP4_READ_WORD(); // factor in new changes DSP4.view_x1 += (DSP4.view_turnoff_x * DSP4.distance >> 15); DSP4.view_xofs1 += (DSP4.view_turnoff_x * DSP4.distance >> 15); // update stepping values DSP4.view_turnoff_x += DSP4.view_turnoff_dx; DSP4.in_count = 2; DSP4_WAIT(1); } // already have 2 bytes read DSP4.in_count = 6; DSP4_WAIT(3); resume3: // inspect inputs DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // no envelope here DSP4.world_xenv = 0; } while (1); // terminate op DSP4.waiting4command = TRUE; } static void DSP4_OP03 (void) { DSP4.OAM_RowMax = 33; memset(DSP4.OAM_Row, 0, 64); } static void DSP4_OP05 (void) { DSP4.OAM_index = 0; DSP4.OAM_bits = 0; memset(DSP4.OAM_attr, 0, 32); DSP4.sprite_count = 0; } static void DSP4_OP06 (void) { DSP4_CLEAR_OUT(); DSP4_WRITE_16_WORD(DSP4.OAM_attr); } static void DSP4_OP07 (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; } //////////////////////////////////////////////////// // sort inputs DSP4.world_y = DSP4_READ_DWORD(); DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); DSP4.world_x = DSP4_READ_DWORD(); DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.world_yofs = DSP4_READ_WORD(); DSP4.distance = DSP4_READ_WORD(); DSP4.view_y2 = DSP4_READ_WORD(); DSP4.view_dy = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_x2 = DSP4_READ_WORD(); DSP4.view_dx = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_yofsenv = DSP4_READ_WORD(); // initial (x, y, offset) at starting raster line DSP4.view_x1 = DSP4.world_x >> 16; DSP4.view_y1 = DSP4.world_y >> 16; DSP4.view_xofs1 = DSP4.view_x1; DSP4.view_yofs1 = DSP4.world_yofs; // first raster line DSP4.poly_raster[0][0] = DSP4.poly_bottom[0][0]; do { //////////////////////////////////////////////////// // process one iteration of projection // add shaping DSP4.view_x2 += DSP4.view_dx; DSP4.view_y2 += DSP4.view_dy; // vertical scroll calculation DSP4.view_xofs2 = DSP4.view_x2; DSP4.view_yofs2 = (DSP4.world_yofs * DSP4.distance >> 15) + DSP4.poly_bottom[0][0] - DSP4.view_y2; // 1. Viewer x-position at the next // 2. Viewer y-position below the horizon // 3. Number of raster lines drawn in this iteration DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(DSP4.view_x2); DSP4_WRITE_WORD(DSP4.view_y2); ////////////////////////////////////////////////////// // SR = 0x00 // determine # of raster lines used DSP4.segments = DSP4.view_y1 - DSP4.view_y2; // prevent overdraw if (DSP4.view_y2 >= DSP4.poly_raster[0][0]) DSP4.segments = 0; else DSP4.poly_raster[0][0] = DSP4.view_y2; // don't draw outside the window if (DSP4.view_y2 < DSP4.poly_top[0][0]) { DSP4.segments = 0; // flush remaining raster lines if (DSP4.view_y1 >= DSP4.poly_top[0][0]) DSP4.segments = DSP4.view_y1 - DSP4.poly_top[0][0]; } // SR = 0x80 DSP4_WRITE_WORD(DSP4.segments); ////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 px_dx, py_dy; int32 x_scroll, y_scroll; // SR = 0x00 // linear interpolation (lerp) between projected points px_dx = (DSP4.view_xofs2 - DSP4.view_xofs1) * DSP4_Inverse(DSP4.segments) << 1; py_dy = (DSP4.view_yofs2 - DSP4.view_yofs1) * DSP4_Inverse(DSP4.segments) << 1; // starting step values x_scroll = SEX16(DSP4.poly_cx[0][0] + DSP4.view_xofs1); y_scroll = SEX16(-DSP4.viewport_bottom + DSP4.view_yofs1 + DSP4.view_yofsenv + DSP4.poly_cx[1][0] - DSP4.world_yofs); // SR = 0x80 // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { // 1. HDMA memory pointer (bg2) // 2. vertical scroll offset ($2110) // 3. horizontal scroll offset ($210F) DSP4_WRITE_WORD(DSP4.poly_ptr[0][0]); DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); // update memory address DSP4.poly_ptr[0][0] -= 4; // update screen values x_scroll += px_dx; y_scroll += py_dy; } } ///////////////////////////////////////////////////// // Post-update // update new viewer (x, y, scroll) to last raster line drawn DSP4.view_x1 = DSP4.view_x2; DSP4.view_y1 = DSP4.view_y2; DSP4.view_xofs1 = DSP4.view_xofs2; DSP4.view_yofs1 = DSP4.view_yofs2; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(1); resume1: // check for opcode termination DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) break; // already have 2 bytes in queue DSP4.in_count = 10; DSP4_WAIT(2); resume2: // inspect inputs DSP4.view_y2 = DSP4_READ_WORD(); DSP4.view_dy = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_x2 = DSP4_READ_WORD(); DSP4.view_dx = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_yofsenv = DSP4_READ_WORD(); } while (1); DSP4.waiting4command = TRUE; } static void DSP4_OP08 (void) { int16 win_left, win_right; int16 view_x[2], view_y[2]; int16 envelope[2][2]; DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; } //////////////////////////////////////////////////// // process initial inputs for two polygons // clip values DSP4.poly_clipRt[0][0] = DSP4_READ_WORD(); DSP4.poly_clipRt[0][1] = DSP4_READ_WORD(); DSP4.poly_clipRt[1][0] = DSP4_READ_WORD(); DSP4.poly_clipRt[1][1] = DSP4_READ_WORD(); DSP4.poly_clipLf[0][0] = DSP4_READ_WORD(); DSP4.poly_clipLf[0][1] = DSP4_READ_WORD(); DSP4.poly_clipLf[1][0] = DSP4_READ_WORD(); DSP4.poly_clipLf[1][1] = DSP4_READ_WORD(); // unknown (constant) (ex. 1P/2P = $00A6, $00A6, $00A6, $00A6) DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); // unknown (constant) (ex. 1P/2P = $00A5, $00A5, $00A7, $00A7) DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); // polygon centering (left, right) DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[0][1] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][1] = DSP4_READ_WORD(); // HDMA pointer locations DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][1] = DSP4_READ_WORD(); DSP4.poly_ptr[1][0] = DSP4_READ_WORD(); DSP4.poly_ptr[1][1] = DSP4_READ_WORD(); // starting raster line below the horizon DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_bottom[0][1] = DSP4_READ_WORD(); DSP4.poly_bottom[1][0] = DSP4_READ_WORD(); DSP4.poly_bottom[1][1] = DSP4_READ_WORD(); // top boundary line to clip DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][1] = DSP4_READ_WORD(); DSP4.poly_top[1][0] = DSP4_READ_WORD(); DSP4.poly_top[1][1] = DSP4_READ_WORD(); // unknown // (ex. 1P = $2FC8, $0034, $FF5C, $0035) // // (ex. 2P = $3178, $0034, $FFCC, $0035) // (ex. 2P = $2FC8, $0034, $FFCC, $0035) DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); DSP4_READ_WORD(); // look at guidelines for both polygon shapes DSP4.distance = DSP4_READ_WORD(); view_x[0] = DSP4_READ_WORD(); view_y[0] = DSP4_READ_WORD(); view_x[1] = DSP4_READ_WORD(); view_y[1] = DSP4_READ_WORD(); // envelope shaping guidelines (one frame only) envelope[0][0] = DSP4_READ_WORD(); envelope[0][1] = DSP4_READ_WORD(); envelope[1][0] = DSP4_READ_WORD(); envelope[1][1] = DSP4_READ_WORD(); // starting base values to project from DSP4.poly_start[0] = view_x[0]; DSP4.poly_start[1] = view_x[1]; // starting raster lines to begin drawing DSP4.poly_raster[0][0] = view_y[0]; DSP4.poly_raster[0][1] = view_y[0]; DSP4.poly_raster[1][0] = view_y[1]; DSP4.poly_raster[1][1] = view_y[1]; // starting distances DSP4.poly_plane[0] = DSP4.distance; DSP4.poly_plane[1] = DSP4.distance; // SR = 0x00 // re-center coordinates win_left = DSP4.poly_cx[0][0] - view_x[0] + envelope[0][0]; win_right = DSP4.poly_cx[0][1] - view_x[0] + envelope[0][1]; // saturate offscreen data for polygon #1 if (win_left < DSP4.poly_clipLf[0][0]) win_left = DSP4.poly_clipLf[0][0]; if (win_left > DSP4.poly_clipRt[0][0]) win_left = DSP4.poly_clipRt[0][0]; if (win_right < DSP4.poly_clipLf[0][1]) win_right = DSP4.poly_clipLf[0][1]; if (win_right > DSP4.poly_clipRt[0][1]) win_right = DSP4.poly_clipRt[0][1]; // SR = 0x80 // initial output for polygon #1 DSP4_CLEAR_OUT(); DSP4_WRITE_BYTE(win_left & 0xff); DSP4_WRITE_BYTE(win_right & 0xff); do { int16 polygon; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(1); resume1: // terminate op DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) break; // already have 2 bytes in queue DSP4.in_count = 16; DSP4_WAIT(2); resume2: // look at guidelines for both polygon shapes view_x[0] = DSP4_READ_WORD(); view_y[0] = DSP4_READ_WORD(); view_x[1] = DSP4_READ_WORD(); view_y[1] = DSP4_READ_WORD(); // envelope shaping guidelines (one frame only) envelope[0][0] = DSP4_READ_WORD(); envelope[0][1] = DSP4_READ_WORD(); envelope[1][0] = DSP4_READ_WORD(); envelope[1][1] = DSP4_READ_WORD(); //////////////////////////////////////////////////// // projection begins // init DSP4_CLEAR_OUT(); ////////////////////////////////////////////// // solid polygon renderer - 2 shapes for (polygon = 0; polygon < 2; polygon++) { int32 left_inc, right_inc; int16 x1_final, x2_final; int16 env[2][2]; int16 poly; // SR = 0x00 // # raster lines to draw DSP4.segments = DSP4.poly_raster[polygon][0] - view_y[polygon]; // prevent overdraw if (DSP4.segments > 0) { // bump drawing cursor DSP4.poly_raster[polygon][0] = view_y[polygon]; DSP4.poly_raster[polygon][1] = view_y[polygon]; } else DSP4.segments = 0; // don't draw outside the window if (view_y[polygon] < DSP4.poly_top[polygon][0]) { DSP4.segments = 0; // flush remaining raster lines if (view_y[polygon] >= DSP4.poly_top[polygon][0]) DSP4.segments = view_y[polygon] - DSP4.poly_top[polygon][0]; } // SR = 0x80 // tell user how many raster structures to read in DSP4_WRITE_WORD(DSP4.segments); // normal parameters poly = polygon; ///////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 w_left, w_right; // road turnoff selection if ((uint16) envelope[polygon][0] == (uint16) 0xc001) poly = 1; else if (envelope[polygon][1] == 0x3fff) poly = 1; /////////////////////////////////////////////// // left side of polygon // perspective correction on additional shaping parameters env[0][0] = envelope[polygon][0] * DSP4.poly_plane[poly] >> 15; env[0][1] = envelope[polygon][0] * DSP4.distance >> 15; // project new shapes (left side) x1_final = view_x[poly] + env[0][0]; x2_final = DSP4.poly_start[poly] + env[0][1]; // interpolate between projected points with shaping left_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4.segments) << 1; if (DSP4.segments == 1) left_inc = -left_inc; /////////////////////////////////////////////// // right side of polygon // perspective correction on additional shaping parameters env[1][0] = envelope[polygon][1] * DSP4.poly_plane[poly] >> 15; env[1][1] = envelope[polygon][1] * DSP4.distance >> 15; // project new shapes (right side) x1_final = view_x[poly] + env[1][0]; x2_final = DSP4.poly_start[poly] + env[1][1]; // interpolate between projected points with shaping right_inc = (x2_final - x1_final) * DSP4_Inverse(DSP4.segments) << 1; if (DSP4.segments == 1) right_inc = -right_inc; /////////////////////////////////////////////// // update each point on the line w_left = SEX16(DSP4.poly_cx[polygon][0] - DSP4.poly_start[poly] + env[0][0]); w_right = SEX16(DSP4.poly_cx[polygon][1] - DSP4.poly_start[poly] + env[1][0]); // update distance drawn into world DSP4.poly_plane[polygon] = DSP4.distance; // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { int16 x_left, x_right; // project new coordinates w_left += left_inc; w_right += right_inc; // grab integer portion, drop fraction (no rounding) x_left = w_left >> 16; x_right = w_right >> 16; // saturate offscreen data if (x_left < DSP4.poly_clipLf[polygon][0]) x_left = DSP4.poly_clipLf[polygon][0]; if (x_left > DSP4.poly_clipRt[polygon][0]) x_left = DSP4.poly_clipRt[polygon][0]; if (x_right < DSP4.poly_clipLf[polygon][1]) x_right = DSP4.poly_clipLf[polygon][1]; if (x_right > DSP4.poly_clipRt[polygon][1]) x_right = DSP4.poly_clipRt[polygon][1]; // 1. HDMA memory pointer // 2. Left window position ($2126/$2128) // 3. Right window position ($2127/$2129) DSP4_WRITE_WORD(DSP4.poly_ptr[polygon][0]); DSP4_WRITE_BYTE(x_left & 0xff); DSP4_WRITE_BYTE(x_right & 0xff); // update memory pointers DSP4.poly_ptr[polygon][0] -= 4; DSP4.poly_ptr[polygon][1] -= 4; } // end rasterize line } //////////////////////////////////////////////// // Post-update // new projection spot to continue rasterizing from DSP4.poly_start[polygon] = view_x[poly]; } // end polygon rasterizer } while (1); // unknown output DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(0); DSP4.waiting4command = TRUE; } static void DSP4_OP09 (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; case 3: goto resume3; break; case 4: goto resume4; break; case 5: goto resume5; break; case 6: goto resume6; break; } //////////////////////////////////////////////////// // process initial inputs // grab screen information DSP4.viewport_cx = DSP4_READ_WORD(); DSP4.viewport_cy = DSP4_READ_WORD(); DSP4_READ_WORD(); // 0x0000 DSP4.viewport_left = DSP4_READ_WORD(); DSP4.viewport_right = DSP4_READ_WORD(); DSP4.viewport_top = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); // starting raster line below the horizon DSP4.poly_bottom[0][0] = DSP4.viewport_bottom - DSP4.viewport_cy; DSP4.poly_raster[0][0] = 0x100; do { //////////////////////////////////////////////////// // check for new sprites DSP4.in_count = 4; DSP4_WAIT(1); resume1: //////////////////////////////////////////////// // raster overdraw check DSP4.raster = DSP4_READ_WORD(); // continue updating the raster line where overdraw begins if (DSP4.raster < DSP4.poly_raster[0][0]) { DSP4.sprite_clipy = DSP4.viewport_bottom - (DSP4.poly_bottom[0][0] - DSP4.raster); DSP4.poly_raster[0][0] = DSP4.raster; } ///////////////////////////////////////////////// // identify sprite // op termination DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) goto terminate; // no sprite if (DSP4.distance == 0x0000) continue; //////////////////////////////////////////////////// // process projection information // vehicle sprite if ((uint16) DSP4.distance == 0x9000) { int16 car_left, car_right, car_back; int16 impact_left, impact_back; int16 world_spx, world_spy; int16 view_spx, view_spy; uint16 energy; // we already have 4 bytes we want DSP4.in_count = 14; DSP4_WAIT(2); resume2: // filter inputs energy = DSP4_READ_WORD(); impact_back = DSP4_READ_WORD(); car_back = DSP4_READ_WORD(); impact_left = DSP4_READ_WORD(); car_left = DSP4_READ_WORD(); DSP4.distance = DSP4_READ_WORD(); car_right = DSP4_READ_WORD(); // calculate car's world (x, y) values world_spx = car_right - car_left; world_spy = car_back; // add in collision vector [needs bit-twiddling] world_spx -= energy * (impact_left - car_left) >> 16; world_spy -= energy * (car_back - impact_back) >> 16; // perspective correction for world (x, y) view_spx = world_spx * DSP4.distance >> 15; view_spy = world_spy * DSP4.distance >> 15; // convert to screen values DSP4.sprite_x = DSP4.viewport_cx + view_spx; DSP4.sprite_y = DSP4.viewport_bottom - (DSP4.poly_bottom[0][0] - view_spy); // make the car's (x)-coordinate available DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(world_spx); // grab a few remaining vehicle values DSP4.in_count = 4; DSP4_WAIT(3); resume3: // add vertical lift factor DSP4.sprite_y += DSP4_READ_WORD(); } // terrain sprite else { int16 world_spx, world_spy; int16 view_spx, view_spy; // we already have 4 bytes we want DSP4.in_count = 10; DSP4_WAIT(4); resume4: // sort loop inputs DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_raster[0][1] = DSP4_READ_WORD(); world_spx = DSP4_READ_WORD(); world_spy = DSP4_READ_WORD(); // compute base raster line from the bottom DSP4.segments = DSP4.poly_bottom[0][0] - DSP4.raster; // perspective correction for world (x, y) view_spx = world_spx * DSP4.distance >> 15; view_spy = world_spy * DSP4.distance >> 15; // convert to screen values DSP4.sprite_x = DSP4.viewport_cx + view_spx - DSP4.poly_cx[0][0]; DSP4.sprite_y = DSP4.viewport_bottom - DSP4.segments + view_spy; } // default sprite size: 16x16 DSP4.sprite_size = 1; DSP4.sprite_attr = DSP4_READ_WORD(); //////////////////////////////////////////////////// // convert tile data to SNES OAM format do { int16 sp_x, sp_y, sp_attr, sp_dattr; int16 sp_dx, sp_dy; int16 pixels; uint16 header; bool8 draw; DSP4.in_count = 2; DSP4_WAIT(5); resume5: draw = TRUE; // opcode termination DSP4.raster = DSP4_READ_WORD(); if (DSP4.raster == -0x8000) goto terminate; // stop code if (DSP4.raster == 0x0000 && !DSP4.sprite_size) break; // toggle sprite size if (DSP4.raster == 0x0000) { DSP4.sprite_size = !DSP4.sprite_size; continue; } // check for valid sprite header header = DSP4.raster; header >>= 8; if (header != 0x20 && header != 0x2e && // This is for attractor sprite header != 0x40 && header != 0x60 && header != 0xa0 && header != 0xc0 && header != 0xe0) break; // read in rest of sprite data DSP4.in_count = 4; DSP4_WAIT(6); resume6: draw = TRUE; ///////////////////////////////////// // process tile data // sprite deltas sp_dattr = DSP4.raster; sp_dy = DSP4_READ_WORD(); sp_dx = DSP4_READ_WORD(); // update coordinates to screen space sp_x = DSP4.sprite_x + sp_dx; sp_y = DSP4.sprite_y + sp_dy; // update sprite nametable/attribute information sp_attr = DSP4.sprite_attr + sp_dattr; // allow partially visibile tiles pixels = DSP4.sprite_size ? 15 : 7; DSP4_CLEAR_OUT(); // transparent tile to clip off parts of a sprite (overdraw) if (DSP4.sprite_clipy - pixels <= sp_y && sp_y <= DSP4.sprite_clipy && sp_x >= DSP4.viewport_left - pixels && sp_x <= DSP4.viewport_right && DSP4.sprite_clipy >= DSP4.viewport_top - pixels && DSP4.sprite_clipy <= DSP4.viewport_bottom) DSP4_OP0B(&draw, sp_x, DSP4.sprite_clipy, 0x00EE, DSP4.sprite_size, 0); // normal sprite tile if (sp_x >= DSP4.viewport_left - pixels && sp_x <= DSP4.viewport_right && sp_y >= DSP4.viewport_top - pixels && sp_y <= DSP4.viewport_bottom && sp_y <= DSP4.sprite_clipy) DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, DSP4.sprite_size, 0); // no following OAM data DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1); } while (1); } while (1); terminate: DSP4.waiting4command = TRUE; } static void DSP4_OP0A (int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4) { const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80, 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 }; *o4 = OP0A_Values[(n2 & 0x000f)]; *o3 = OP0A_Values[(n2 & 0x00f0) >> 4]; *o2 = OP0A_Values[(n2 & 0x0f00) >> 8]; *o1 = OP0A_Values[(n2 & 0xf000) >> 12]; } static void DSP4_OP0B (bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop) { int16 Row1, Row2; // SR = 0x00 // align to nearest 8-pixel row Row1 = (sp_y >> 3) & 0x1f; Row2 = (Row1 + 1) & 0x1f; // check boundaries if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb))) *draw = 0; if (size) { if (DSP4.OAM_Row[Row1] + 1 >= DSP4.OAM_RowMax) *draw = 0; if (DSP4.OAM_Row[Row2] + 1 >= DSP4.OAM_RowMax) *draw = 0; } else { if (DSP4.OAM_Row[Row1] >= DSP4.OAM_RowMax) *draw = 0; } // emulator fail-safe (unknown if this really exists) if (DSP4.sprite_count >= 128) *draw = 0; // SR = 0x80 if (*draw) { // Row tiles if (size) { DSP4.OAM_Row[Row1] += 2; DSP4.OAM_Row[Row2] += 2; } else DSP4.OAM_Row[Row1]++; // yield OAM output DSP4_WRITE_WORD(1); // pack OAM data: x, y, name, attr DSP4_WRITE_BYTE(sp_x & 0xff); DSP4_WRITE_BYTE(sp_y & 0xff); DSP4_WRITE_WORD(sp_attr); DSP4.sprite_count++; // OAM: size, msb data // save post-oam table data for future retrieval DSP4.OAM_attr[DSP4.OAM_index] |= ((sp_x < 0 || sp_x > 255) << DSP4.OAM_bits); DSP4.OAM_bits++; DSP4.OAM_attr[DSP4.OAM_index] |= (size << DSP4.OAM_bits); DSP4.OAM_bits++; // move to next byte in buffer if (DSP4.OAM_bits == 16) { DSP4.OAM_bits = 0; DSP4.OAM_index++; } } else if (stop) // yield no OAM output DSP4_WRITE_WORD(0); } static void DSP4_OP0D (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; } //////////////////////////////////////////////////// // process initial inputs // sort inputs DSP4.world_y = DSP4_READ_DWORD(); DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); DSP4.world_x = DSP4_READ_DWORD(); DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.world_yofs = DSP4_READ_WORD(); DSP4.world_dy = DSP4_READ_DWORD(); DSP4.world_dx = DSP4_READ_DWORD(); DSP4.distance = DSP4_READ_WORD(); DSP4_READ_WORD(); // 0x0000 DSP4.world_xenv = SEX78(DSP4_READ_WORD()); DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // initial (x, y, offset) at starting raster line DSP4.view_x1 = (DSP4.world_x + DSP4.world_xenv) >> 16; DSP4.view_y1 = DSP4.world_y >> 16; DSP4.view_xofs1 = DSP4.world_x >> 16; DSP4.view_yofs1 = DSP4.world_yofs; // first raster line DSP4.poly_raster[0][0] = DSP4.poly_bottom[0][0]; do { //////////////////////////////////////////////////// // process one iteration of projection // perspective projection of world (x, y, scroll) points // based on the current projection lines DSP4.view_x2 = (((DSP4.world_x + DSP4.world_xenv) >> 16) * DSP4.distance >> 15) + (DSP4.view_turnoff_x * DSP4.distance >> 15); DSP4.view_y2 = (DSP4.world_y >> 16) * DSP4.distance >> 15; DSP4.view_xofs2 = DSP4.view_x2; DSP4.view_yofs2 = (DSP4.world_yofs * DSP4.distance >> 15) + DSP4.poly_bottom[0][0] - DSP4.view_y2; // 1. World x-location before transformation // 2. Viewer x-position at the current // 3. World y-location before perspective projection // 4. Viewer y-position below the horizon // 5. Number of raster lines drawn in this iteration DSP4_CLEAR_OUT(); DSP4_WRITE_WORD((DSP4.world_x + DSP4.world_xenv) >> 16); DSP4_WRITE_WORD(DSP4.view_x2); DSP4_WRITE_WORD(DSP4.world_y >> 16); DSP4_WRITE_WORD(DSP4.view_y2); ////////////////////////////////////////////////////////// // SR = 0x00 // determine # of raster lines used DSP4.segments = DSP4.view_y1 - DSP4.view_y2; // prevent overdraw if (DSP4.view_y2 >= DSP4.poly_raster[0][0]) DSP4.segments = 0; else DSP4.poly_raster[0][0] = DSP4.view_y2; // don't draw outside the window if (DSP4.view_y2 < DSP4.poly_top[0][0]) { DSP4.segments = 0; // flush remaining raster lines if (DSP4.view_y1 >= DSP4.poly_top[0][0]) DSP4.segments = DSP4.view_y1 - DSP4.poly_top[0][0]; } // SR = 0x80 DSP4_WRITE_WORD(DSP4.segments); ////////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 px_dx, py_dy; int32 x_scroll, y_scroll; // SR = 0x00 // linear interpolation (lerp) between projected points px_dx = (DSP4.view_xofs2 - DSP4.view_xofs1) * DSP4_Inverse(DSP4.segments) << 1; py_dy = (DSP4.view_yofs2 - DSP4.view_yofs1) * DSP4_Inverse(DSP4.segments) << 1; // starting step values x_scroll = SEX16(DSP4.poly_cx[0][0] + DSP4.view_xofs1); y_scroll = SEX16(-DSP4.viewport_bottom + DSP4.view_yofs1 + DSP4.view_yofsenv + DSP4.poly_cx[1][0] - DSP4.world_yofs); // SR = 0x80 // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { // 1. HDMA memory pointer (bg1) // 2. vertical scroll offset ($210E) // 3. horizontal scroll offset ($210D) DSP4_WRITE_WORD(DSP4.poly_ptr[0][0]); DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); // update memory address DSP4.poly_ptr[0][0] -= 4; // update screen values x_scroll += px_dx; y_scroll += py_dy; } } ///////////////////////////////////////////////////// // Post-update // update new viewer (x, y, scroll) to last raster line drawn DSP4.view_x1 = DSP4.view_x2; DSP4.view_y1 = DSP4.view_y2; DSP4.view_xofs1 = DSP4.view_xofs2; DSP4.view_yofs1 = DSP4.view_yofs2; // add deltas for projection lines DSP4.world_dx += SEX78(DSP4.world_ddx); DSP4.world_dy += SEX78(DSP4.world_ddy); // update projection lines DSP4.world_x += (DSP4.world_dx + DSP4.world_xenv); DSP4.world_y += DSP4.world_dy; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(1); resume1: // inspect input DSP4.distance = DSP4_READ_WORD(); // terminate op if (DSP4.distance == -0x8000) break; // already have 2 bytes in queue DSP4.in_count = 6; DSP4_WAIT(2); resume2: // inspect inputs DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // no envelope here DSP4.world_xenv = 0; } while (1); DSP4.waiting4command = TRUE; } static void DSP4_OP0E (void) { DSP4.OAM_RowMax = 16; memset(DSP4.OAM_Row, 0, 64); } static void DSP4_OP0F (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; case 3: goto resume3; break; case 4: goto resume4; break; } //////////////////////////////////////////////////// // process initial inputs // sort inputs DSP4_READ_WORD(); // 0x0000 DSP4.world_y = DSP4_READ_DWORD(); DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); DSP4.world_x = DSP4_READ_DWORD(); DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.world_yofs = DSP4_READ_WORD(); DSP4.world_dy = DSP4_READ_DWORD(); DSP4.world_dx = DSP4_READ_DWORD(); DSP4.distance = DSP4_READ_WORD(); DSP4_READ_WORD(); // 0x0000 DSP4.world_xenv = DSP4_READ_DWORD(); DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // initial (x, y, offset) at starting raster line DSP4.view_x1 = (DSP4.world_x + DSP4.world_xenv) >> 16; DSP4.view_y1 = DSP4.world_y >> 16; DSP4.view_xofs1 = DSP4.world_x >> 16; DSP4.view_yofs1 = DSP4.world_yofs; DSP4.view_turnoff_x = 0; DSP4.view_turnoff_dx = 0; // first raster line DSP4.poly_raster[0][0] = DSP4.poly_bottom[0][0]; do { //////////////////////////////////////////////////// // process one iteration of projection // perspective projection of world (x, y, scroll) points // based on the current projection lines DSP4.view_x2 = ((DSP4.world_x + DSP4.world_xenv) >> 16) * DSP4.distance >> 15; DSP4.view_y2 = (DSP4.world_y >> 16) * DSP4.distance >> 15; DSP4.view_xofs2 = DSP4.view_x2; DSP4.view_yofs2 = (DSP4.world_yofs * DSP4.distance >> 15) + DSP4.poly_bottom[0][0] - DSP4.view_y2; // 1. World x-location before transformation // 2. Viewer x-position at the next // 3. World y-location before perspective projection // 4. Viewer y-position below the horizon // 5. Number of raster lines drawn in this iteration DSP4_CLEAR_OUT(); DSP4_WRITE_WORD((DSP4.world_x + DSP4.world_xenv) >> 16); DSP4_WRITE_WORD(DSP4.view_x2); DSP4_WRITE_WORD(DSP4.world_y >> 16); DSP4_WRITE_WORD(DSP4.view_y2); ////////////////////////////////////////////////////// // SR = 0x00 // determine # of raster lines used DSP4.segments = DSP4.poly_raster[0][0] - DSP4.view_y2; // prevent overdraw if (DSP4.view_y2 >= DSP4.poly_raster[0][0]) DSP4.segments = 0; else DSP4.poly_raster[0][0] = DSP4.view_y2; // don't draw outside the window if (DSP4.view_y2 < DSP4.poly_top[0][0]) { DSP4.segments = 0; // flush remaining raster lines if (DSP4.view_y1 >= DSP4.poly_top[0][0]) DSP4.segments = DSP4.view_y1 - DSP4.poly_top[0][0]; } // SR = 0x80 DSP4_WRITE_WORD(DSP4.segments); ////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 px_dx, py_dy; int32 x_scroll, y_scroll; for (DSP4.lcv = 0; DSP4.lcv < 4; DSP4.lcv++) { // grab inputs DSP4.in_count = 4; DSP4_WAIT(1); resume1: for (;;) { int16 dist; int16 color, red, green, blue; dist = DSP4_READ_WORD(); color = DSP4_READ_WORD(); // U1+B5+G5+R5 red = color & 0x1f; green = (color >> 5) & 0x1f; blue = (color >> 10) & 0x1f; // dynamic lighting red = (red * dist >> 15) & 0x1f; green = (green * dist >> 15) & 0x1f; blue = (blue * dist >> 15) & 0x1f; color = red | (green << 5) | (blue << 10); DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(color); break; } } ////////////////////////////////////////////////////// // SR = 0x00 // linear interpolation (lerp) between projected points px_dx = (DSP4.view_xofs2 - DSP4.view_xofs1) * DSP4_Inverse(DSP4.segments) << 1; py_dy = (DSP4.view_yofs2 - DSP4.view_yofs1) * DSP4_Inverse(DSP4.segments) << 1; // starting step values x_scroll = SEX16(DSP4.poly_cx[0][0] + DSP4.view_xofs1); y_scroll = SEX16(-DSP4.viewport_bottom + DSP4.view_yofs1 + DSP4.view_yofsenv + DSP4.poly_cx[1][0] - DSP4.world_yofs); // SR = 0x80 // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { // 1. HDMA memory pointer // 2. vertical scroll offset ($210E) // 3. horizontal scroll offset ($210D) DSP4_WRITE_WORD(DSP4.poly_ptr[0][0]); DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); // update memory address DSP4.poly_ptr[0][0] -= 4; // update screen values x_scroll += px_dx; y_scroll += py_dy; } } //////////////////////////////////////////////////// // Post-update // update new viewer (x, y, scroll) to last raster line drawn DSP4.view_x1 = DSP4.view_x2; DSP4.view_y1 = DSP4.view_y2; DSP4.view_xofs1 = DSP4.view_xofs2; DSP4.view_yofs1 = DSP4.view_yofs2; // add deltas for projection lines DSP4.world_dx += SEX78(DSP4.world_ddx); DSP4.world_dy += SEX78(DSP4.world_ddy); // update projection lines DSP4.world_x += (DSP4.world_dx + DSP4.world_xenv); DSP4.world_y += DSP4.world_dy; // update road turnoff position DSP4.view_turnoff_x += DSP4.view_turnoff_dx; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(2); resume2: // check for termination DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) break; // road splice if ((uint16) DSP4.distance == 0x8001) { DSP4.in_count = 6; DSP4_WAIT(3); resume3: DSP4.distance = DSP4_READ_WORD(); DSP4.view_turnoff_x = DSP4_READ_WORD(); DSP4.view_turnoff_dx = DSP4_READ_WORD(); // factor in new changes DSP4.view_x1 += (DSP4.view_turnoff_x * DSP4.distance >> 15); DSP4.view_xofs1 += (DSP4.view_turnoff_x * DSP4.distance >> 15); // update stepping values DSP4.view_turnoff_x += DSP4.view_turnoff_dx; DSP4.in_count = 2; DSP4_WAIT(2); } // already have 2 bytes in queue DSP4.in_count = 6; DSP4_WAIT(4); resume4: // inspect inputs DSP4.world_ddy = DSP4_READ_WORD(); DSP4.world_ddx = DSP4_READ_WORD(); DSP4.view_yofsenv = DSP4_READ_WORD(); // no envelope here DSP4.world_xenv = 0; } while (1); // terminate op DSP4.waiting4command = TRUE; } static void DSP4_OP10 (void) { DSP4.waiting4command = FALSE; // op flow control switch (DSP4.Logic) { case 1: goto resume1; break; case 2: goto resume2; break; case 3: goto resume3; break; } //////////////////////////////////////////////////// // sort inputs DSP4_READ_WORD(); // 0x0000 DSP4.world_y = DSP4_READ_DWORD(); DSP4.poly_bottom[0][0] = DSP4_READ_WORD(); DSP4.poly_top[0][0] = DSP4_READ_WORD(); DSP4.poly_cx[1][0] = DSP4_READ_WORD(); DSP4.viewport_bottom = DSP4_READ_WORD(); DSP4.world_x = DSP4_READ_DWORD(); DSP4.poly_cx[0][0] = DSP4_READ_WORD(); DSP4.poly_ptr[0][0] = DSP4_READ_WORD(); DSP4.world_yofs = DSP4_READ_WORD(); DSP4.distance = DSP4_READ_WORD(); DSP4.view_y2 = DSP4_READ_WORD(); DSP4.view_dy = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_x2 = DSP4_READ_WORD(); DSP4.view_dx = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_yofsenv = DSP4_READ_WORD(); // initial (x, y, offset) at starting raster line DSP4.view_x1 = DSP4.world_x >> 16; DSP4.view_y1 = DSP4.world_y >> 16; DSP4.view_xofs1 = DSP4.view_x1; DSP4.view_yofs1 = DSP4.world_yofs; // first raster line DSP4.poly_raster[0][0] = DSP4.poly_bottom[0][0]; do { //////////////////////////////////////////////////// // process one iteration of projection // add shaping DSP4.view_x2 += DSP4.view_dx; DSP4.view_y2 += DSP4.view_dy; // vertical scroll calculation DSP4.view_xofs2 = DSP4.view_x2; DSP4.view_yofs2 = (DSP4.world_yofs * DSP4.distance >> 15) + DSP4.poly_bottom[0][0] - DSP4.view_y2; // 1. Viewer x-position at the next // 2. Viewer y-position below the horizon // 3. Number of raster lines drawn in this iteration DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(DSP4.view_x2); DSP4_WRITE_WORD(DSP4.view_y2); ////////////////////////////////////////////////////// // SR = 0x00 // determine # of raster lines used DSP4.segments = DSP4.view_y1 - DSP4.view_y2; // prevent overdraw if (DSP4.view_y2 >= DSP4.poly_raster[0][0]) DSP4.segments = 0; else DSP4.poly_raster[0][0] = DSP4.view_y2; // don't draw outside the window if (DSP4.view_y2 < DSP4.poly_top[0][0]) { DSP4.segments = 0; // flush remaining raster lines if (DSP4.view_y1 >= DSP4.poly_top[0][0]) DSP4.segments = DSP4.view_y1 - DSP4.poly_top[0][0]; } // SR = 0x80 DSP4_WRITE_WORD(DSP4.segments); ////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { for (DSP4.lcv = 0; DSP4.lcv < 4; DSP4.lcv++) { // grab inputs DSP4.in_count = 4; DSP4_WAIT(1); resume1: for (;;) { int16 dist; int16 color, red, green, blue; dist = DSP4_READ_WORD(); color = DSP4_READ_WORD(); // U1+B5+G5+R5 red = color & 0x1f; green = (color >> 5) & 0x1f; blue = (color >> 10) & 0x1f; // dynamic lighting red = (red * dist >> 15) & 0x1f; green = (green * dist >> 15) & 0x1f; blue = (blue * dist >> 15) & 0x1f; color = red | (green << 5) | (blue << 10); DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(color); break; } } } ////////////////////////////////////////////////////// // scan next command if no SR check needed if (DSP4.segments) { int32 px_dx, py_dy; int32 x_scroll, y_scroll; // SR = 0x00 // linear interpolation (lerp) between projected points px_dx = (DSP4.view_xofs2 - DSP4.view_xofs1) * DSP4_Inverse(DSP4.segments) << 1; py_dy = (DSP4.view_yofs2 - DSP4.view_yofs1) * DSP4_Inverse(DSP4.segments) << 1; // starting step values x_scroll = SEX16(DSP4.poly_cx[0][0] + DSP4.view_xofs1); y_scroll = SEX16(-DSP4.viewport_bottom + DSP4.view_yofs1 + DSP4.view_yofsenv + DSP4.poly_cx[1][0] - DSP4.world_yofs); // SR = 0x80 // rasterize line for (DSP4.lcv = 0; DSP4.lcv < DSP4.segments; DSP4.lcv++) { // 1. HDMA memory pointer (bg2) // 2. vertical scroll offset ($2110) // 3. horizontal scroll offset ($210F) DSP4_WRITE_WORD(DSP4.poly_ptr[0][0]); DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); // update memory address DSP4.poly_ptr[0][0] -= 4; // update screen values x_scroll += px_dx; y_scroll += py_dy; } } ///////////////////////////////////////////////////// // Post-update // update new viewer (x, y, scroll) to last raster line drawn DSP4.view_x1 = DSP4.view_x2; DSP4.view_y1 = DSP4.view_y2; DSP4.view_xofs1 = DSP4.view_xofs2; DSP4.view_yofs1 = DSP4.view_yofs2; //////////////////////////////////////////////////// // command check // scan next command DSP4.in_count = 2; DSP4_WAIT(2); resume2: // check for opcode termination DSP4.distance = DSP4_READ_WORD(); if (DSP4.distance == -0x8000) break; // already have 2 bytes in queue DSP4.in_count = 10; DSP4_WAIT(3); resume3: // inspect inputs DSP4.view_y2 = DSP4_READ_WORD(); DSP4.view_dy = DSP4_READ_WORD() * DSP4.distance >> 15; DSP4.view_x2 = DSP4_READ_WORD(); DSP4.view_dx = DSP4_READ_WORD() * DSP4.distance >> 15; } while (1); DSP4.waiting4command = TRUE; } static void DSP4_OP11 (int16 A, int16 B, int16 C, int16 D, int16 *M) { // 0x155 = 341 = Horizontal Width of the Screen *M = ((A * 0x0155 >> 2) & 0xf000) | ((B * 0x0155 >> 6) & 0x0f00) | ((C * 0x0155 >> 10) & 0x00f0) | ((D * 0x0155 >> 14) & 0x000f); } static void DSP4_SetByte (void) { // clear pending read if (DSP4.out_index < DSP4.out_count) { DSP4.out_index++; return; } if (DSP4.waiting4command) { if (DSP4.half_command) { DSP4.command |= (DSP4.byte << 8); DSP4.in_index = 0; DSP4.waiting4command = FALSE; DSP4.half_command = FALSE; DSP4.out_count = 0; DSP4.out_index = 0; DSP4.Logic = 0; switch (DSP4.command) { case 0x0000: DSP4.in_count = 4; break; case 0x0001: DSP4.in_count = 44; break; case 0x0003: DSP4.in_count = 0; break; case 0x0005: DSP4.in_count = 0; break; case 0x0006: DSP4.in_count = 0; break; case 0x0007: DSP4.in_count = 34; break; case 0x0008: DSP4.in_count = 90; break; case 0x0009: DSP4.in_count = 14; break; case 0x000a: DSP4.in_count = 6; break; case 0x000b: DSP4.in_count = 6; break; case 0x000d: DSP4.in_count = 42; break; case 0x000e: DSP4.in_count = 0; break; case 0x000f: DSP4.in_count = 46; break; case 0x0010: DSP4.in_count = 36; break; case 0x0011: DSP4.in_count = 8; break; default: DSP4.waiting4command = TRUE; break; } } else { DSP4.command = DSP4.byte; DSP4.half_command = TRUE; } } else { DSP4.parameters[DSP4.in_index] = DSP4.byte; DSP4.in_index++; } if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index) { // Actually execute the command DSP4.waiting4command = TRUE; DSP4.out_index = 0; DSP4.in_index = 0; switch (DSP4.command) { // 16-bit multiplication case 0x0000: { int16 multiplier, multiplicand; int32 product; multiplier = DSP4_READ_WORD(); multiplicand = DSP4_READ_WORD(); DSP4_Multiply(multiplicand, multiplier, &product); DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(product); DSP4_WRITE_WORD(product >> 16); break; } // single-player track projection case 0x0001: DSP4_OP01(); break; // single-player selection case 0x0003: DSP4_OP03(); break; // clear OAM case 0x0005: DSP4_OP05(); break; // transfer OAM case 0x0006: DSP4_OP06(); break; // single-player track turnoff projection case 0x0007: DSP4_OP07(); break; // solid polygon projection case 0x0008: DSP4_OP08(); break; // sprite projection case 0x0009: DSP4_OP09(); break; // unknown case 0x000A: { DSP4_READ_WORD(); int16 in2a = DSP4_READ_WORD(); DSP4_READ_WORD(); int16 out1a, out2a, out3a, out4a; DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a); DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(out1a); DSP4_WRITE_WORD(out2a); DSP4_WRITE_WORD(out3a); DSP4_WRITE_WORD(out4a); break; } // set OAM case 0x000B: { int16 sp_x = DSP4_READ_WORD(); int16 sp_y = DSP4_READ_WORD(); int16 sp_attr = DSP4_READ_WORD(); bool8 draw = TRUE; DSP4_CLEAR_OUT(); DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, 0, 1); break; } // multi-player track projection case 0x000D: DSP4_OP0D(); break; // multi-player selection case 0x000E: DSP4_OP0E(); break; // single-player track projection with lighting case 0x000F: DSP4_OP0F(); break; // single-player track turnoff projection with lighting case 0x0010: DSP4_OP10(); break; // unknown: horizontal mapping command case 0x0011: { int16 a, b, c, d, m; d = DSP4_READ_WORD(); c = DSP4_READ_WORD(); b = DSP4_READ_WORD(); a = DSP4_READ_WORD(); DSP4_OP11(a, b, c, d, &m); DSP4_CLEAR_OUT(); DSP4_WRITE_WORD(m); break; } default: break; } } } static void DSP4_GetByte (void) { if (DSP4.out_count) { DSP4.byte = (uint8) DSP4.output[DSP4.out_index & 0x1FF]; DSP4.out_index++; if (DSP4.out_count == DSP4.out_index) DSP4.out_count = 0; } else DSP4.byte = 0xff; } void DSP4SetByte (uint8 byte, uint16 address) { if (address < DSP0.boundary) { DSP4.byte = byte; DSP4.address = address; DSP4_SetByte(); } } uint8 DSP4GetByte (uint16 address) { if (address < DSP0.boundary) { DSP4.address = address; DSP4_GetByte(); return (DSP4.byte); } return (0x80); } apu/bapu/smp/000700 001750 001750 00000000000 12724164663 014214 5ustar00sergiosergio000000 000000 crosshairs.cpp000664 001750 001750 00000040732 12720446475 014607 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef HAVE_LIBPNG #include #endif #include "port.h" #include "crosshairs.h" static const char *crosshairs[32] = { "` " // Crosshair 0 (no image) " " " " " " " " " " " " " " " " " " " " " " " " " " " ", "` " // Crosshair 1 (the classic small dot) " " " " " " " " " " " " " #. " " " " " " " " " " " " " " ", "` " // Crosshair 2 (a standard cross) " " " " " " " .#. " " .#. " " ...#... " " ####### " " ...#... " " .#. " " .#. " " " " " " " " ", "` .#. " // Crosshair 3 (a standard cross) " .#. " " .#. " " .#. " " .#. " " .#. " ".......#......." "###############" ".......#......." " .#. " " .#. " " .#. " " .#. " " .#. " " .#. ", "` " // Crosshair 4 (an X) " " " " " . . " " .#. .#. " " .#. .#. " " .#.#. " " .#. " " .#.#. " " .#. .#. " " .#. .#. " " . . " " " " " " ", "`. . " // Crosshair 5 (an X) ".#. .#." " .#. .#. " " .#. .#. " " .#. .#. " " .#. .#. " " .#.#. " " .#. " " .#.#. " " .#. .#. " " .#. .#. " " .#. .#. " " .#. .#. " ".#. .#." " . . ", "` " // Crosshair 6 (a combo) " " " " " " " # . # " " # . # " " #.# " " ...#... " " #.# " " # . # " " # . # " " " " " " " " ", "` . " // Crosshair 7 (a combo) " # . # " " # . # " " # . # " " # . # " " # . # " " #.# " ".......#......." " #.# " " # . # " " # . # " " # . # " " # . # " " # . # " " . ", "` # " // Crosshair 8 (a diamond cross) " #.# " " # . # " " # . # " " # . # " " # . # " " # . # " "#......#......#" " # . # " " # . # " " # . # " " # . # " " # . # " " #.# " " # ", "` ### " // Crosshair 9 (a circle cross) " ## . ## " " # . # " " # . # " " # . # " " # . # " "# . #" "#......#......#" "# . #" " # . # " " # . # " " # . # " " # . # " " ## . ## " " ### ", "` .#. " // Crosshair 10 (a square cross) " .#. " " .#. " " ....#.... " " .#######. " " .# #. " "....# #...." "##### #####" "....# #...." " .# #. " " .#######. " " ....#.... " " .#. " " .#. " " .#. ", "` .#. " // Crosshair 11 (an interrupted cross) " .#. " " .#. " " .#. " " .#. " " " "..... ....." "##### #####" "..... ....." " " " .#. " " .#. " " .#. " " .#. " " .#. ", "`. . " // Crosshair 12 (an interrupted X) ".#. .#." " .#. .#. " " .#. .#. " " .#. .#. " " " " " " " " " " " " .#. .#. " " .#. .#. " " .#. .#. " ".#. .#." " . . ", "` . " // Crosshair 13 (an interrupted combo) " # . # " " # . # " " # . # " " # . # " " " " " "..... ....." " " " " " # . # " " # . # " " # . # " " # . # " " . ", "`#### #### " // Crosshair 14 "#.... ....#" "#. .#" "#. .#" "#. .#" " # " " # " " ##### " " # " " # " "#. .#" "#. .#" "#. .#" "#.... ....#" " #### #### ", "` .# #. " // Crosshair 15 " .# #. " " .# #. " "....# #...." "##### #####" " " " " " " " " " " "##### #####" "....# #...." " .# #. " " .# #. " " .# #. ", "` # " // Crosshair 16 " # " " # " " ....#.... " " . # . " " . # . " " . # . " "###############" " . # . " " . # . " " . # . " " ....#.... " " # " " # " " # ", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; bool S9xLoadCrosshairFile (int idx, const char *filename) { if (idx < 1 || idx > 31) return (false); char *s = (char *) calloc(15 * 15 + 1, sizeof(char)); if (s == NULL) { fprintf(stderr, "S9xLoadCrosshairFile: malloc error while reading "); perror(filename); return (false); } FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "S9xLoadCrosshairFile: Couldn't open "); perror(filename); free(s); return (false); } size_t l = fread(s, 1, 8, fp); if (l != 8) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); free(s); fclose(fp); return (false); } #ifdef HAVE_LIBPNG png_structp png_ptr; png_infop info_ptr; if (!png_sig_cmp((png_byte *) s, 0, 8)) { png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { free(s); fclose(fp); return (false); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type != PNG_COLOR_TYPE_PALETTE) { fprintf(stderr, "S9xLoadCrosshairFile: Input PNG is not a palettized image!\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } if (bit_depth == 16) png_set_strip_16(png_ptr); if (width != 15 || height != 15) { fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 15x15 PNG\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_color *pngpal; png_byte *trans; int num_palette = 0, num_trans = 0; int transcol = -1, fgcol = -1, bgcol = -1; png_get_PLTE(png_ptr, info_ptr, &pngpal, &num_palette); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); if (num_palette != 3 || num_trans != 1) { fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 3-color PNG with 1 trasnparent color\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } for (int i = 0; i < 3; i++) { if (trans[0] == i) transcol = i; else if (pngpal[i].red == 0 && pngpal[i].green == 0 && pngpal[i].blue == 0) bgcol = i; else if (pngpal[i].red == 255 && pngpal[i].green == 255 && pngpal[i].blue == 255) fgcol = i; } if (transcol < 0 || fgcol < 0 || bgcol < 0) { fprintf(stderr, "S9xLoadCrosshairFile: PNG must have 3 colors: white (fg), black (bg), and transparent.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_byte *row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; for (int r = 0; r < 15 * 15; r += 15) { png_read_row(png_ptr, row_pointer, NULL); for (int i = 0; i < 15; i++) { if (row_pointer[i] == transcol) s[r + i] = ' '; else if (row_pointer[i] == fgcol) s[r + i] = '#'; else if (row_pointer[i] == bgcol) s[r + i] = '.'; else { fprintf(stderr, "S9xLoadCrosshairFile: WTF? This was supposed to be a 3-color PNG!\n"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); free(s); fclose(fp); return (false); } } } s[15 * 15] = 0; png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); } else #endif { l = fread(s + 8, 1, 15 - 8, fp); if (l != 15 - 8) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); free(s); fclose(fp); return (false); } if (getc(fp) != '\n') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } for (int r = 1; r < 15; r++) { l = fread(s + r * 15, 1, 15, fp); if (l != 15) { fprintf(stderr, "S9xLoadCrosshairFile: File is too short! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } if (getc(fp) != '\n') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } } for (int i = 0; i < 15 * 15; i++) { if (s[i] != ' ' && s[i] != '#' && s[i] != '.') { fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format! (note: PNG support is not available)\n"); free(s); fclose(fp); return (false); } } } fclose(fp); if (crosshairs[idx] != NULL && crosshairs[idx][0] != '`') free((void *) crosshairs[idx]); crosshairs[idx] = s; return (true); } const char * S9xGetCrosshair (int idx) { if (idx < 0 || idx > 31) return (NULL); return (crosshairs[idx]); } apu/bapu/smp/core/op_mov.b000664 001750 001750 00000010006 12720446475 016617 0ustar00sergiosergio000000 000000 mov_a_x(0x7d, a, x), mov_a_y(0xdd, a, y), mov_x_a(0x5d, x, a), mov_y_a(0xfd, y, a), mov_x_sp(0x9d, x, sp) { 1:op_io(); regs.$1 = regs.$2; regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } mov_sp_x(0xbd, sp, x) { 1:op_io(); regs.$1 = regs.$2; } mov_a_const(0xe8, a), mov_x_const(0xcd, x), mov_y_const(0x8d, y) { 1:regs.$1 = op_readpc(); regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } mov_a_ix(0xe6) { 1:op_io(); 2:regs.a = op_readdp(regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } mov_a_ixinc(0xbf) { 1:op_io(); 2:regs.a = op_readdp(regs.x++); 3:op_io(); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } mov_a_dp(0xe4, a), mov_x_dp(0xf8, x), mov_y_dp(0xeb, y) { 1:sp = op_readpc(); 2:regs.$1 = op_readdp(sp); regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } mov_a_dpx(0xf4, a, x), mov_x_dpy(0xf9, x, y), mov_y_dpx(0xfb, y, x) { 1:sp = op_readpc(); 2:op_io(); 3:regs.$1 = op_readdp(sp + regs.$2); regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } mov_a_addr(0xe5, a), mov_x_addr(0xe9, x), mov_y_addr(0xec, y) { 1:sp = op_readpc(); 2:sp |= op_readpc() << 8; 3:regs.$1 = op_readaddr(sp); regs.p.n = !!(regs.$1 & 0x80); regs.p.z = (regs.$1 == 0); } mov_a_addrx(0xf5, x), mov_a_addry(0xf6, y) { 1:sp = op_readpc(); 2:sp |= op_readpc() << 8; 3:op_io(); 4:regs.a = op_readaddr(sp + regs.$1); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } mov_a_idpx(0xe7) { 1:dp = op_readpc() + regs.x; 2:op_io(); 3:sp = op_readdp(dp); 4:sp |= op_readdp(dp + 1) << 8; 5:regs.a = op_readaddr(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } mov_a_idpy(0xf7) { 1:dp = op_readpc(); 2:op_io(); 3:sp = op_readdp(dp); 4:sp |= op_readdp(dp + 1) << 8; 5:regs.a = op_readaddr(sp + regs.y); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } mov_dp_dp(0xfa) { 1:sp = op_readpc(); 2:rd = op_readdp(sp); 3:dp = op_readpc(); 4:op_writedp(dp, rd); } mov_dp_const(0x8f) { 1:rd = op_readpc(); 2:dp = op_readpc(); 3:op_readdp(dp); 4:op_writedp(dp, rd); } mov_ix_a(0xc6) { 1:op_io(); 2:op_readdp(regs.x); 3:op_writedp(regs.x, regs.a); } mov_ixinc_a(0xaf) { 1:op_io(); 2:op_io(); 3:op_writedp(regs.x++, regs.a); } mov_dp_a(0xc4, a), mov_dp_x(0xd8, x), mov_dp_y(0xcb, y) { 1:dp = op_readpc(); 2:op_readdp(dp); 3:op_writedp(dp, regs.$1); } mov_dpx_a(0xd4, x, a), mov_dpy_x(0xd9, y, x), mov_dpx_y(0xdb, x, y) { 1:dp = op_readpc(); 2:op_io(); dp += regs.$1; 3:op_readdp(dp); 4:op_writedp(dp, regs.$2); } mov_addr_a(0xc5, a), mov_addr_x(0xc9, x), mov_addr_y(0xcc, y) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:op_readaddr(dp); 4:op_writeaddr(dp, regs.$1); } mov_addrx_a(0xd5, x), mov_addry_a(0xd6, y) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:op_io(); dp += regs.$1; 4:op_readaddr(dp); 5:op_writeaddr(dp, regs.a); } mov_idpx_a(0xc7) { 1:sp = op_readpc(); 2:op_io(); sp += regs.x; 3:dp = op_readdp(sp); 4:dp |= op_readdp(sp + 1) << 8; 5:op_readaddr(dp); 6:op_writeaddr(dp, regs.a); } mov_idpy_a(0xd7) { 1:sp = op_readpc(); 2:dp = op_readdp(sp); 3:dp |= op_readdp(sp + 1) << 8; 4:op_io(); dp += regs.y; 5:op_readaddr(dp); 6:op_writeaddr(dp, regs.a); } movw_ya_dp(0xba) { 1:sp = op_readpc(); 2:regs.a = op_readdp(sp); 3:op_io(); 4:regs.y = op_readdp(sp + 1); regs.p.n = !!(regs.ya & 0x8000); regs.p.z = (regs.ya == 0); } movw_dp_ya(0xda) { 1:dp = op_readpc(); 2:op_readdp(dp); 3:op_writedp(dp, regs.a); 4:op_writedp(dp + 1, regs.y); } mov1_c_bit(0xaa) { 1:sp = op_readpc(); 2:sp |= op_readpc() << 8; 3:bit = sp >> 13; sp &= 0x1fff; rd = op_readaddr(sp); regs.p.c = !!(rd & (1 << bit)); } mov1_bit_c(0xca) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); if(regs.p.c)rd |= (1 << bit); else rd &= ~(1 << bit); 4:op_io(); 5:op_writeaddr(dp, rd); } seta018.cpp000664 001750 001750 00000022530 12720446475 013610 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "seta.h" static int line; // line counter uint8 S9xGetST018 (uint32 Address) { uint8 t = 0; uint16 address = (uint16) Address & 0xFFFF; line++; // these roles may be flipped // op output if (address == 0x3804) { if (ST018.out_count) { t = (uint8) ST018.output[ST018.out_index]; ST018.out_index++; if (ST018.out_count == ST018.out_index) ST018.out_count = 0; } else t = 0x81; } // status register else if (address == 0x3800) t = ST018.status; #ifdef DEBUGGER printf("ST018 R: %06X %02X\n", Address, t); #endif return (t); } void S9xSetST018 (uint8 Byte, uint32 Address) { static bool reset = false; uint16 address = (uint16) Address & 0xFFFF; #ifdef DEBUGGER printf("ST018 W: %06X %02X\n", Address, Byte); #endif line++; if (!reset) { // bootup values ST018.waiting4command = true; ST018.part_command = 0; reset = true; } Memory.SRAM[address] = Byte; // default status for now ST018.status = 0x00; // op data goes through this address if (address == 0x3804) { // check for new commands: 3 bytes length if (ST018.waiting4command && ST018.part_command == 2) { ST018.waiting4command = false; ST018.in_index = 0; ST018.out_index = 0; ST018.part_command = 0; // 3-byte commands ST018.pass = 0; // data streams into the chip ST018.command <<= 8; ST018.command |= Byte; switch (ST018.command & 0xFFFFFF) { case 0x0100: ST018.in_count = 0; break; case 0xFF00: ST018.in_count = 0; break; default: ST018.waiting4command = true; break; } } else if (ST018.waiting4command) { // 3-byte commands ST018.part_command++; ST018.command <<= 8; ST018.command |= Byte; } } // extra parameters else if (address == 0x3802) { ST018.parameters[ST018.in_index] = Byte; ST018.in_index++; } if (ST018.in_count == ST018.in_index) { // qctually execute the command ST018.waiting4command = true; ST018.in_index = 0; ST018.out_index = 0; switch (ST018.command) { // hardware check? case 0x0100: ST018.waiting4command = false; ST018.pass++; if (ST018.pass == 1) { ST018.in_count = 1; ST018.out_count = 2; // Overload's research ST018.output[0x00] = 0x81; ST018.output[0x01] = 0x81; } else { //ST018.in_count = 1; ST018.out_count = 3; // no reason to change this //ST018.output[0x00] = 0x81; //ST018.output[0x01] = 0x81; ST018.output[0x02] = 0x81; // done processing requests if (ST018.pass == 3) ST018.waiting4command = true; } break; // unknown: feels like a security detection // format identical to 0x0100 case 0xFF00: ST018.waiting4command = false; ST018.pass++; if (ST018.pass == 1) { ST018.in_count = 1; ST018.out_count = 2; // Overload's research ST018.output[0x00] = 0x81; ST018.output[0x01] = 0x81; } else { //ST018.in_count = 1; ST018.out_count = 3; // no reason to change this //ST018.output[0x00] = 0x81; //ST018.output[0x01] = 0x81; ST018.output[0x02] = 0x81; // done processing requests if (ST018.pass == 3) ST018.waiting4command = true; } break; } } } docs/snapshots.txt000664 001750 001750 00000006654 12720446475 015443 0ustar00sergiosergio000000 000000 ***** Important notice ******************************************************** This document describes the snapshot file format for Snes9x 1.52 and later, not compatible with 1.51. ******************************************************************************* Snes9x snapshot file format: (may be gzip-compressed) Begins with fixed length signature, consisting of a string, ':', a 4-digit decimal version, and a '\n'. #!s9xsnp:0006 <-- '\n' after the 6 Then we have various blocks. The block format is: 3-character block name, ':', 6-digit length, ':', then the data. Blocks are written in a defined order. Structs are written packed with their members in a defined order, in big-endian order where applicable. NAM:000019:Chrono Trigger.zip Currently defined blocks (in order) are: Essential parts: NAM - ROM filename, from Memory.ROMFilename. 0-terminated string. CPU - struct SCPUState, CPU internal state variables. REG - struct SRegisters, emulated CPU registers. PPU - struct SPPU, PPU internal variables. Note that IPPU is never saved. DMA - struct SDMA, DMA/HDMA state variables. VRA - Memory.VRAM, 0x10000 bytes. RAM - Memory.RAM, 0x20000 bytes (WRAM). SRA - Memory.SRAM, 0x20000 bytes. FIL - Memory.FillRAM, 0x8000 bytes (register backing store). SND - All of sound emulated registers and state valiables. CTL - struct SControlSnapshot, controller emulation. TIM - struct STimings, variables about timings between emulated events. Optional parts: SFX - struct FxRegs_s, Super FX. SA1 - struct SSA1, SA1 internal state variables. SAR - struct SSA1Registers, SA1 emulated registers. DP1 - struct SDSP1, DSP-1. DP2 - struct SDSP2, DSP-2. DP4 - struct SDSP4, DSP-4. CX4 - Memory.C4RAM, 0x2000 bytes. ST0 - struct SST010, ST-010. OBC - struct SOBC1, OBC1 internal state variables. OBM - Memory.OBC1RAM, 0x2000 byts. S71 - struct SSPC7110Snapshot, SPC7110. SRT - struct SSRTCSnapshot, S-RTC internal state variables. CLK - struct SRTCData, S-RTC emulated registers. BSX - struct SBSX, BS-X. SHO - rendered SNES screen. MOV - struct SnapshotMovieInfo. MID - Some block of data the movie subsystem. ================== Without changing the snapshot version number: --------------------------------------------- Blocks may be safely added at the END of the file, as anything after the last block is ignored. Blocks may not be moved or removed. Blocks may not decrease in size. Say you decrease from 10 bytes to 5. Then later you increase back to 8. The only way you could safely do this is if bytes 5-7 still mean the same thing they meant when the block was 10 bytes long. Blocks may increase in size as you wish, as long as you can handle old savestates with the old shorter size. Struct members may not change in interpretation. New struct members may be added (at the END!) only if you can cope with them being binary-0 in older savestates. Struct members may not be removed or changed in size/type. With changing the snapshot version number: ------------------------------------------ Blocks may be added, moved, or removed at will. Blocks may decrease in size. Struct members may be added, moved, or deleted, and their interpretations/types may be changed. Use the 'debuted_in' and 'deleted_in' fields to indicate when the new member debuted or the old member went away. apu/bapu/smp/smp_state.cpp000664 001750 001750 00000006776 12720446475 016753 0ustar00sergiosergio000000 000000 #include "../snes/snes.hpp" #include typedef struct spc_file { uint8 header[33]; uint8 idtag[3]; uint8 version_minor; uint8 pc_low; uint8 pc_high; uint8 a; uint8 x; uint8 y; uint8 psw; uint8 sp; uint8 unused_a[2]; uint8 id666[210]; uint8 apuram[65536]; uint8 dsp_registers[128]; uint8 unused_b[64]; uint8 iplrom[64]; } spc_file; namespace SNES { #include "../dsp/blargg_endian.h" void SMP::save_spc (uint8 *block) { spc_file out; const char *header = "SNES-SPC700 Sound File Data v0.30"; memcpy (out.header, header, 33); out.idtag[0] = out.idtag[1] = 26; out.idtag[2] = 27; out.version_minor = 30; out.pc_low = regs.pc & 0xff; out.pc_high = (regs.pc >> 8) & 0xff; out.a = regs.B.a; out.x = regs.x; out.y = regs.B.y; out.psw = (uint8) ((unsigned) regs.p); out.sp = regs.sp; out.unused_a[0] = out.unused_a[1] = 0; memset (out.id666, 0, 210); memcpy (out.apuram, apuram, 65536); for (int i = 0xf2; i <= 0xf9; i++) { out.apuram[i] = mmio_read (i); } for (int i = 0xfd; i <= 0xff; i++) { out.apuram[i] = mmio_read (i); } for (int i = 0; i < 128; i++) { out.dsp_registers[i] = dsp.read (i); } memset (out.unused_b, 0, 64); memcpy (out.iplrom, iplrom, 64); memcpy (block, &out, 66048); } void SMP::save_state(uint8 **block) { uint8 *ptr = *block; memcpy(ptr, apuram, 64 * 1024); ptr += 64 * 1024; #undef INT32 #define INT32(i) set_le32(ptr, (i)); ptr += sizeof(int32) INT32(clock); INT32(opcode_number); INT32(opcode_cycle); INT32(regs.pc); INT32(regs.sp); INT32(regs.B.a); INT32(regs.x); INT32(regs.B.y); INT32(regs.p.n); INT32(regs.p.v); INT32(regs.p.p); INT32(regs.p.b); INT32(regs.p.h); INT32(regs.p.i); INT32(regs.p.z); INT32(regs.p.c); INT32(status.iplrom_enable); INT32(status.dsp_addr); INT32(status.ram00f8); INT32(status.ram00f9); INT32(timer0.enable); INT32(timer0.target); INT32(timer0.stage1_ticks); INT32(timer0.stage2_ticks); INT32(timer0.stage3_ticks); INT32(timer1.enable); INT32(timer1.target); INT32(timer1.stage1_ticks); INT32(timer1.stage2_ticks); INT32(timer1.stage3_ticks); INT32(timer2.enable); INT32(timer2.target); INT32(timer2.stage1_ticks); INT32(timer2.stage2_ticks); INT32(timer2.stage3_ticks); INT32(rd); INT32(wr); INT32(dp); INT32(sp); INT32(ya); INT32(bit); *block = ptr; } void SMP::load_state(uint8 **block) { uint8 *ptr = *block; memcpy(apuram, ptr, 64 * 1024); ptr += 64 * 1024; #undef INT32 #define INT32(i) i = get_le32(ptr); ptr += sizeof(int32) INT32(clock); INT32(opcode_number); INT32(opcode_cycle); INT32(regs.pc); INT32(regs.sp); INT32(regs.B.a); INT32(regs.x); INT32(regs.B.y); INT32(regs.p.n); INT32(regs.p.v); INT32(regs.p.p); INT32(regs.p.b); INT32(regs.p.h); INT32(regs.p.i); INT32(regs.p.z); INT32(regs.p.c); INT32(status.iplrom_enable); INT32(status.dsp_addr); INT32(status.ram00f8); INT32(status.ram00f9); INT32(timer0.enable); INT32(timer0.target); INT32(timer0.stage1_ticks); INT32(timer0.stage2_ticks); INT32(timer0.stage3_ticks); INT32(timer1.enable); INT32(timer1.target); INT32(timer1.stage1_ticks); INT32(timer1.stage2_ticks); INT32(timer1.stage3_ticks); INT32(timer2.enable); INT32(timer2.target); INT32(timer2.stage1_ticks); INT32(timer2.stage2_ticks); INT32(timer2.stage3_ticks); INT32(rd); INT32(wr); INT32(dp); INT32(sp); INT32(ya); INT32(bit); *block = ptr; } } /* namespace SNES */ font.h000664 001750 001750 00000060425 12720446475 013043 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _FONT_H_ #define _FONT_H_ static const char *font[] = { //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " . . . . .. . . ", " .#. .#.#. . . ... .#. . . .##. .#. .#. . . . . ", " .#. .#.#. .#.#. .###. .#..#. .#. .#. .#. .#. .#.#. .#. .#. ", " .#. .#.#. .#####. .#.#. ..#. .#.#. .#. .#. .#. .#. ..#.. .... .#. ", " .#. . . .#.#. .###. .#.. .#. . .#. .#. .###. .#####. .. .####. .. .#. ", " . .#####. .#.#. .#..#. .#.#. .#. .#. .#. ..#.. .##. .... .##. .#. ", " .#. .#.#. .###. . .#. .#.#. .#. .#. .#.#. .#. .#. .##. . ", " . . . ... . . . . . . . . .#. .. ", " . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " . . .. .... . .... .. .... .. .. . ", " .#. .#. .##. .####. .#. .####. .##. .####. .##. .##. .. .. . . .#. ", ".#.#. .##. .#..#. ...#. .##. .#... .#.. ...#. .#..#. .#..#. .##. .##. .#. .... .#. .#.#. ", ".#.#. .#. . .#. .##. .#.#. .###. .###. .#. .##. .#..#. .##. .##. .#. .####. .#. ..#. ", ".#.#. .#. .#. ...#. .####. ...#. .#..#. .#. .#..#. .###. .. .. .#. .... .#. .#. ", ".#.#. .#. .#.. .#..#. ..#. .#..#. .#..#. .#. .#..#. ..#. .##. .##. .#. .####. .#. . ", " .#. .###. .####. .##. .#. .##. .##. .#. .##. .##. .##. .#. .#. .... .#. .#. ", " . ... .... .. . .. .. . .. .. .. .#. . . . ", " . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .. .. ... .. ... .... .... .. . . ... . . . . . . . . .. ", " .##. .##. .###. .##. .###. .####. .####. .##. .#..#. .###. .#. .#..#. .#. .#. .#. .#. .#. .##. ", ".#..#. .#..#. .#..#. .#..#. .#..#. .#... .#... .#..#. .#..#. .#. .#. .#.#. .#. .##.##. .##..#. .#..#. ", ".#.##. .#..#. .###. .#. . .#..#. .###. .###. .#... .####. .#. .#. .##. .#. .#.#.#. .#.#.#. .#..#. ", ".#.##. .####. .#..#. .#. . .#..#. .#.. .#.. .#.##. .#..#. .#. . .#. .##. .#. .#...#. .#.#.#. .#..#. ", ".#... .#..#. .#..#. .#..#. .#..#. .#... .#. .#..#. .#..#. .#. .#..#. .#.#. .#... .#. .#. .#..##. .#..#. ", " .##. .#..#. .###. .##. .###. .####. .#. .###. .#..#. .###. .##. .#..#. .####. .#. .#. .#. .#. .##. ", " .. . . ... .. ... .... . ... . . ... .. . . .... . . . . .. ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " ... .. ... .. ... . . . . . . . . . . .... ... ... . ", ".###. .##. .###. .##. .###. .#. .#. .#. .#. .#. .#. .#..#. .#.#. .####. .###. . .###. .#. ", ".#..#. .#..#. .#..#. .#..#. .#. .#. .#. .#. .#. .#...#. .#..#. .#.#. ...#. .#.. .#. ..#. .#.#. ", ".#..#. .#..#. .#..#. .#.. .#. .#. .#. .#. .#. .#.#.#. .##. .#.#. .#. .#. .#. .#. . . ", ".###. .#..#. .###. ..#. .#. .#. .#. .#. .#. .#.#.#. .#..#. .#. .#. .#. .#. .#. ", ".#.. .##.#. .#.#. .#..#. .#. .#...#. .#.#. .##.##. .#..#. .#. .#... .#.. .#. ..#. .... ", ".#. .##. .#..#. .##. .#. .###. .#. .#. .#. .#..#. .#. .####. .###. . .###. .####. ", " . ..#. . . .. . ... . . . . . . .... ... ... .... ", " . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .. . . . . . . . .. ", ".##. .#. .#. .#. .#. .#. .#. .#. .##. ", " .#. ... .#.. .. ..#. .. .#.#. ... .#.. .. . .#.. .#. .. .. ... .. ", " .#. .###. .###. .##. .###. .##. .#.. .###. .###. .##. .#. .#.#. .#. .##.##. .###. .##. ", " . .#..#. .#..#. .#.. .#..#. .#.##. .###. .#..#. .#..#. .#. .#. .##. .#. .#.#.#. .#..#. .#..#. ", " .#.##. .#..#. .#.. .#..#. .##.. .#. .##. .#..#. .#. ..#. .#.#. .#. .#...#. .#..#. .#..#. ", " .#.#. .###. .##. .###. .##. .#. .#... .#..#. .###. .#.#. .#..#. .###. .#. .#. .#..#. .##. ", " . . ... .. ... .. . .###. . . ... .#. . . ... . . . . .. ", " ... . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " . . . . . . ", " .#. .#. .#. .#. .#.#. ", " ... ... ... ... .#. . . . . . . . . . . .... .#. .#. .#. .#.#. ", ".###. .###. .###. .###. .###. .#..#. .#.#. .#...#. .#..#. .#..#. .####. .##. .#. .##. . . ", ".#..#. .#..#. .#..#. .##.. .#. .#..#. .#.#. .#.#.#. .##. .#..#. ..#. .#. .#. .#. ", ".#..#. .#..#. .#. . ..##. .#.. .#..#. .#.#. .#.#.#. .##. .#.#. .#.. .#. .#. .#. ", ".###. .###. .#. .###. .##. .###. .#. .#.#. .#..#. .#. .####. .#. .#. .#. ", ".#.. ..#. . ... .. ... . . . . . .#. .... . . . ", " . . . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " ", " ", " ", " ", " ", " ", " ", " ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " ", " ", " ", " ", " ", " ", " ", " ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .. ..... ", " .##. .#####. ... . . . . .. ", " .#. . .. ....#. .###. .#. .#. .#. .#.. .##. . . . ", " .#. .#. .##. .#####. .#. .#. .###. ... .###. .###. .. .#. .#.#.#. ", " . .#. .#. . .##. ....#. .#. .##. .#.#. .###. .#. .##.#. .##. .##. .#.#.#. ", " .#. . .#. .#. .. ...#. .#. .#. ..#. .#. .##. .#.. ..#. .#. ...#. ", " .#.#. .##. .#. .###. .#. .#. .#. .###. .#. .#. .####. .##. .##. ", " .#. .. .#. ... . . . ... . . .... .. .. ", " . . ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .... . . ... . . . .... . . . .. . ..... . . . ", " .####. .#. ..#.. .###. ...#. ..#.. ..#.. .####. .#... .... .#.#. .##..#. .#####. .#... .#. .#. ", " .... ...#. .#. .#####. .#. .#####. .#####. .#####. .#..#. .####. .####. .#####. .. .#. ....#. .#####. .#. .#. ", ".####. .##. .## .#...#. .#. ...#. ..#.#. ..#.. .# .#. .#..#. ...#. .#.#. .##..#. .#. .#..#. .#..#. ", " .... .#. .#.# . .#. .#. .##. .#..#. .#####. .#. .#. . .#. .#. ..#. .. .#. .#. .#.#. . .#. ", " .#. .#. ..#. ..#.. .#.#. .#..#. ..#.. . .#. .#. ...#. .#. ...#. .#.#. .#... ...#. ", " .#. .#. .##. .#####. .#..#. .#..#. .#. .#. .#. .####. .#. .###. .#. .#. .###. .###. ", " . . .. ..... . . . . . . . .... . ... . . ... ... ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .... .. . . . ... . . ... .... . . . ..... . . ", " .####. ..##. .#.#.#. .###. .#. ..#.. .###. .####. ..#.. .#. . . .#. .. .#####. .#. ..#.. ..... ", " .#..#. .###. .#.#.#. ..... .#. .#####. ... ...#. .#####. .#. .#.#. .#..##. ....#. .#.#. .#####. .#####. ", " .####. ..#. .#.#.#. .#####. .##. ..#.. .#.#. ....#. .#. .#.#. .###.. .#. .#..#. ..#.. .#. ", ".#...#. .####. . ..#. ..#.. .#.#. .#. .#. .###. .#. .#. .#. .#.. .#. . .#. .#.#.#. .#.#. ", " . .#. ..#. ...#. .#. .#.. ..#. ..... .#.#. .#.#.#. .#. .#. .#. .#.... ..#. .#. .#.#.#. .#. ", " .#. .##. .###. .#. .#. .##. .#####. .#. .#. ..#.. .#. .#. .#. .####. .##. .#. ..#.. .#. ", " . .. ... . . .. ..... . . . . . . .... .. . . . ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " .. . . ... . .... .... . . . . . ..... . . . . ", " .##. .#. .#. .###. .#... ... .####. .####. .#..#. .#.#. .#. ..... .#####. ....#. .#.#. .#. ", " ..#. .#. . .#. .#. .#.##. .###. ...#. ..... .#..#. .#.#. .#. .#####. .#...#. .###.#. .#.#. .#.#. ", " .##. .#. . .#.#. .#####. .##.#. .#. .###. .#####. .#..#. .#.#. .#. . .#...#. . .#. ....#. . . .#. ", " ..#. .#..#. .##. ..#.. .#.#. ..#. ..#. ....#. . .#. .#.#. .#..#. .#...#. .#. .#. . ", " .##. .####. ..#.#. .#.. .#. ...#. ...#. ..#. ..#. .#.#. .#.#. .#####. ..#. ...#. ", " ..#. ...#. .##. . .###. .#. .#####. .####. .##. .##. .#..##. .##. .#...#. .##. .###. ", " . . .. ... . ..... .... .. ... . .. .. . . .. ... ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " ", " ", " ", " ", " ", " ", " ", " ", " ", //2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 " ", " ", " ", " ", " ", " ", " ", " ", " " }; #endif seta.cpp000664 001750 001750 00000014510 12720446475 013356 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "seta.h" uint8 (*GetSETA) (uint32) = &S9xGetST010; void (*SetSETA) (uint32, uint8) = &S9xSetST010; uint8 S9xGetSetaDSP (uint32 Address) { return (GetSETA(Address)); } void S9xSetSetaDSP (uint8 Byte, uint32 Address) { SetSETA (Address, Byte); } libretro/msvc/msvc-2010/000700 001750 001750 00000000000 12724164663 016023 5ustar00sergiosergio000000 000000 seta.h000664 001750 001750 00000016120 12720446475 013022 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SETA_H_ #define _SETA_H_ #define ST_010 0x01 #define ST_011 0x02 #define ST_018 0x03 struct SST010 { uint8 input_params[16]; uint8 output_params[16]; uint8 op_reg; uint8 execute; bool8 control_enable; }; struct SST011 { bool8 waiting4command; uint8 status; uint8 command; uint32 in_count; uint32 in_index; uint32 out_count; uint32 out_index; uint8 parameters[512]; uint8 output[512]; }; struct SST018 { bool8 waiting4command; uint8 status; uint8 part_command; uint8 pass; uint32 command; uint32 in_count; uint32 in_index; uint32 out_count; uint32 out_index; uint8 parameters[512]; uint8 output[512]; }; extern struct SST010 ST010; extern struct SST011 ST011; extern struct SST018 ST018; uint8 S9xGetST010 (uint32); void S9xSetST010 (uint32, uint8); uint8 S9xGetST011 (uint32); void S9xSetST011 (uint32, uint8); uint8 S9xGetST018 (uint32); void S9xSetST018 (uint8, uint32); uint8 S9xGetSetaDSP (uint32); void S9xSetSetaDSP (uint8, uint32); extern uint8 (*GetSETA) (uint32); extern void (*SetSETA) (uint32, uint8); #endif tile.h000664 001750 001750 00000014337 12720446475 013033 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _TILE_H_ #define _TILE_H_ void S9xInitTileRenderer (void); void S9xSelectTileRenderers (int, bool8, bool8); void S9xSelectTileConverter (int, bool8, bool8, bool8); #endif sdd1emu.cpp000664 001750 001750 00000035366 12720446475 014000 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ /* S-DD1 decompressor * * Based on code and documentation by Andreas Naive, who deserves a great deal * of thanks and credit for figuring this out. * * Andreas says: * The author is greatly indebted with The Dumper, without whose help and * patience providing him with real S-DD1 data the research had never been * possible. He also wish to note that in the very beggining of his research, * Neviksti had done some steps in the right direction. By last, the author is * indirectly indebted to all the people that worked and contributed in the * S-DD1 issue in the past. */ #include "port.h" #include "sdd1emu.h" static int valid_bits; static uint16 in_stream; static uint8 *in_buf; static uint8 bit_ctr[8]; static uint8 context_states[32]; static int context_MPS[32]; static int bitplane_type; static int high_context_bits; static int low_context_bits; static int prev_bits[8]; static struct { uint8 code_size; uint8 MPS_next; uint8 LPS_next; } evolution_table[] = { /* 0 */ { 0,25,25}, /* 1 */ { 0, 2, 1}, /* 2 */ { 0, 3, 1}, /* 3 */ { 0, 4, 2}, /* 4 */ { 0, 5, 3}, /* 5 */ { 1, 6, 4}, /* 6 */ { 1, 7, 5}, /* 7 */ { 1, 8, 6}, /* 8 */ { 1, 9, 7}, /* 9 */ { 2,10, 8}, /* 10 */ { 2,11, 9}, /* 11 */ { 2,12,10}, /* 12 */ { 2,13,11}, /* 13 */ { 3,14,12}, /* 14 */ { 3,15,13}, /* 15 */ { 3,16,14}, /* 16 */ { 3,17,15}, /* 17 */ { 4,18,16}, /* 18 */ { 4,19,17}, /* 19 */ { 5,20,18}, /* 20 */ { 5,21,19}, /* 21 */ { 6,22,20}, /* 22 */ { 6,23,21}, /* 23 */ { 7,24,22}, /* 24 */ { 7,24,23}, /* 25 */ { 0,26, 1}, /* 26 */ { 1,27, 2}, /* 27 */ { 2,28, 4}, /* 28 */ { 3,29, 8}, /* 29 */ { 4,30,12}, /* 30 */ { 5,31,16}, /* 31 */ { 6,32,18}, /* 32 */ { 7,24,22} }; static uint8 run_table[128] = { 128, 64, 96, 32, 112, 48, 80, 16, 120, 56, 88, 24, 104, 40, 72, 8, 124, 60, 92, 28, 108, 44, 76, 12, 116, 52, 84, 20, 100, 36, 68, 4, 126, 62, 94, 30, 110, 46, 78, 14, 118, 54, 86, 22, 102, 38, 70, 6, 122, 58, 90, 26, 106, 42, 74, 10, 114, 50, 82, 18, 98, 34, 66, 2, 127, 63, 95, 31, 111, 47, 79, 15, 119, 55, 87, 23, 103, 39, 71, 7, 123, 59, 91, 27, 107, 43, 75, 11, 115, 51, 83, 19, 99, 35, 67, 3, 125, 61, 93, 29, 109, 45, 77, 13, 117, 53, 85, 21, 101, 37, 69, 5, 121, 57, 89, 25, 105, 41, 73, 9, 113, 49, 81, 17, 97, 33, 65, 1 }; static inline uint8 GetCodeword(int bits){ uint8 tmp; if(!valid_bits){ in_stream|=*(in_buf++); valid_bits=8; } in_stream<<=1; valid_bits--; in_stream^=0x8000; if(in_stream&0x8000) return 0x80+(1<>8) | (0x7f>>bits); in_stream<<=bits; valid_bits-=bits; if(valid_bits<0){ in_stream |= (*(in_buf++))<<(-valid_bits); valid_bits+=8; } return run_table[tmp]; } static inline uint8 GolombGetBit(int code_size){ if(!bit_ctr[code_size]) bit_ctr[code_size]=GetCodeword(code_size); bit_ctr[code_size]--; if(bit_ctr[code_size]==0x80){ bit_ctr[code_size]=0; return 2; /* secret code for 'last zero'. ones are always last. */ } return (bit_ctr[code_size]==0)?1:0; } static inline uint8 ProbGetBit(uint8 context){ uint8 state=context_states[context]; uint8 bit=GolombGetBit(evolution_table[state].code_size); if(bit&1){ context_states[context]=evolution_table[state].LPS_next; if(state<2){ context_MPS[context]^=1; return context_MPS[context]; /* just inverted, so just return it */ } else{ return context_MPS[context]^1; /* we know bit is 1, so use a constant */ } } else if(bit){ context_states[context]=evolution_table[state].MPS_next; /* zero here, zero there, no difference so drop through. */ } return context_MPS[context]; /* we know bit is 0, so don't bother xoring */ } static inline uint8 GetBit(uint8 cur_bitplane){ uint8 bit; bit=ProbGetBit(((cur_bitplane&1)<<4) | ((prev_bits[cur_bitplane]&high_context_bits)>>5) | (prev_bits[cur_bitplane]&low_context_bits)); prev_bits[cur_bitplane] <<= 1; prev_bits[cur_bitplane] |= bit; return bit; } void SDD1_decompress(uint8 *out, uint8 *in, int len){ uint8 bit, i, plane; uint8 byte1, byte2; if(len==0) len=0x10000; bitplane_type=in[0]>>6; switch(in[0]&0x30){ case 0x00: high_context_bits=0x01c0; low_context_bits =0x0001; break; case 0x10: high_context_bits=0x0180; low_context_bits =0x0001; break; case 0x20: high_context_bits=0x00c0; low_context_bits =0x0001; break; case 0x30: high_context_bits=0x0180; low_context_bits =0x0003; break; } in_stream=(in[0]<<11) | (in[1]<<3); valid_bits=5; in_buf=in+2; memset(bit_ctr, 0, sizeof(bit_ctr)); memset(context_states, 0, sizeof(context_states)); memset(context_MPS, 0, sizeof(context_MPS)); memset(prev_bits, 0, sizeof(prev_bits)); switch(bitplane_type){ case 0: while(1) { for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ if(GetBit(0)) byte1 |= bit; if(GetBit(1)) byte2 |= bit; } *(out++)=byte1; if(!--len) return; *(out++)=byte2; if(!--len) return; } break; case 1: i=plane=0; while(1) { for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ if(GetBit(plane)) byte1 |= bit; if(GetBit(plane+1)) byte2 |= bit; } *(out++)=byte1; if(!--len) return; *(out++)=byte2; if(!--len) return; if(!(i+=32)) plane = (plane+2)&7; } break; case 2: i=plane=0; while(1) { for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ if(GetBit(plane)) byte1 |= bit; if(GetBit(plane+1)) byte2 |= bit; } *(out++)=byte1; if(!--len) return; *(out++)=byte2; if(!--len) return; if(!(i+=32)) plane ^= 2; } break; case 3: do { for(byte1=plane=0, bit=1; bit; bit<<=1, plane++){ if(GetBit(plane)) byte1 |= bit; } *(out++)=byte1; } while(--len); break; } } #if 0 static uint8 cur_plane; static uint8 num_bits; static uint8 next_byte; void SDD1_init(uint8 *in){ bitplane_type=in[0]>>6; switch(in[0]&0x30){ case 0x00: high_context_bits=0x01c0; low_context_bits =0x0001; break; case 0x10: high_context_bits=0x0180; low_context_bits =0x0001; break; case 0x20: high_context_bits=0x00c0; low_context_bits =0x0001; break; case 0x30: high_context_bits=0x0180; low_context_bits =0x0003; break; } in_stream=(in[0]<<11) | (in[1]<<3); valid_bits=5; in_buf=in+2; memset(bit_ctr, 0, sizeof(bit_ctr)); memset(context_states, 0, sizeof(context_states)); memset(context_MPS, 0, sizeof(context_MPS)); memset(prev_bits, 0, sizeof(prev_bits)); cur_plane=0; num_bits=0; } uint8 SDD1_get_byte(void){ uint8 bit; uint8 byte=0; switch(bitplane_type){ case 0: num_bits+=16; if(num_bits&16){ next_byte=0; for(bit=0x80; bit; bit>>=1){ if(GetBit(0)) byte |= bit; if(GetBit(1)) next_byte |= bit; } return byte; } else { return next_byte; } case 1: num_bits+=16; if(num_bits&16){ next_byte=0; for(bit=0x80; bit; bit>>=1){ if(GetBit(cur_plane)) byte |= bit; if(GetBit(cur_plane+1)) next_byte |= bit; } return byte; } else { if(!num_bits) cur_plane = (cur_plane+2)&7; return next_byte; } case 2: num_bits+=16; if(num_bits&16){ next_byte=0; for(bit=0x80; bit; bit>>=1){ if(GetBit(cur_plane)) byte |= bit; if(GetBit(cur_plane+1)) next_byte |= bit; } return byte; } else { if(!num_bits) cur_plane ^= 2; return next_byte; } case 3: for(cur_plane=0, bit=1; bit; bit<<=1, cur_plane++){ if(GetBit(cur_plane)) byte |= bit; } return byte; default: /* should never happen */ return 0; } } #endif apu/bapu/snes/snes.hpp000664 001750 001750 00000001726 12720446475 016070 0ustar00sergiosergio000000 000000 #ifndef __SNES_HPP #define __SNES_HPP #include "snes9x.h" #define SNES9X #if defined(__GNUC__) #define inline inline #define alwaysinline inline __attribute__((always_inline)) #elif defined(_MSC_VER) #define inline inline #define alwaysinline inline __forceinline #else #define inline inline #define alwaysinline inline #endif #define debugvirtual namespace SNES { struct Processor { unsigned frequency; int32 clock; }; #include "../smp/smp.hpp" #include "../dsp/sdsp.hpp" class CPU { public: enum { Threaded = false }; int frequency; uint8 registers[4]; inline void reset () { registers[0] = registers[1] = registers[2] = registers[3] = 0; } alwaysinline void port_write (uint8 port, uint8 data) { registers[port & 3] = data; } alwaysinline uint8 port_read (uint8 port) { return registers[port & 3]; } }; extern CPU cpu; } /* namespace SNES */ #endif screenshot.cpp000664 001750 001750 00000021604 12720446475 014601 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef HAVE_LIBPNG #include #endif #include "snes9x.h" #include "memmap.h" #include "display.h" #include "screenshot.h" bool8 S9xDoScreenshot (int width, int height) { Settings.TakeScreenshot = FALSE; #ifdef HAVE_LIBPNG FILE *fp; png_structp png_ptr; png_infop info_ptr; png_color_8 sig_bit; int imgwidth, imgheight; const char *fname; fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR); fp = fopen(fname, "wb"); if (!fp) { S9xMessage(S9X_ERROR, 0, "Failed to take screenshot."); return (FALSE); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(fp); remove(fname); S9xMessage(S9X_ERROR, 0, "Failed to take screenshot."); return (FALSE); } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp) NULL); fclose(fp); remove(fname); S9xMessage(S9X_ERROR, 0, "Failed to take screenshot."); return (FALSE); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); remove(fname); S9xMessage(S9X_ERROR, 0, "Failed to take screenshot."); return (FALSE); } imgwidth = width; imgheight = height; if (Settings.StretchScreenshots == 1) { if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED) imgheight = height << 1; } else if (Settings.StretchScreenshots == 2) { if (width <= SNES_WIDTH) imgwidth = width << 1; if (height <= SNES_HEIGHT_EXTENDED) imgheight = height << 1; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); sig_bit.red = 5; sig_bit.green = 5; sig_bit.blue = 5; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); png_set_packing(png_ptr); png_byte *row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; uint16 *screen = GFX.Screen; for (int y = 0; y < height; y++, screen += GFX.RealPPL) { png_byte *rowpix = row_pointer; for (int x = 0; x < width; x++) { uint32 r, g, b; DECOMPOSE_PIXEL(screen[x], r, g, b); *(rowpix++) = r; *(rowpix++) = g; *(rowpix++) = b; if (imgwidth != width) { *(rowpix++) = r; *(rowpix++) = g; *(rowpix++) = b; } } png_write_row(png_ptr, row_pointer); if (imgheight != height) png_write_row(png_ptr, row_pointer); } delete [] row_pointer; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); fprintf(stderr, "%s saved.\n", fname); const char *base = S9xBasename(fname); sprintf(String, "Saved screenshot %s", base); S9xMessage(S9X_INFO, 0, String); return (TRUE); #else fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n"); return (FALSE); #endif } apu/bapu/smp/core/op_rmw.b000664 001750 001750 00000002704 12720446475 016631 0ustar00sergiosergio000000 000000 inc_a(0xbc, inc, a), inc_x(0x3d, inc, x), inc_y(0xfc, inc, y), dec_a(0x9c, dec, a), dec_x(0x1d, dec, x), dec_y(0xdc, dec, y), asl_a(0x1c, asl, a), lsr_a(0x5c, lsr, a), rol_a(0x3c, rol, a), ror_a(0x7c, ror, a) { 1:op_io(); regs.$2 = op_$1(regs.$2); } inc_dp(0xab, inc), dec_dp(0x8b, dec), asl_dp(0x0b, asl), lsr_dp(0x4b, lsr), rol_dp(0x2b, rol), ror_dp(0x6b, ror) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); 3:rd = op_$1(rd); op_writedp(dp, rd); } inc_dpx(0xbb, inc), dec_dpx(0x9b, dec), asl_dpx(0x1b, asl), lsr_dpx(0x5b, lsr), rol_dpx(0x3b, rol), ror_dpx(0x7b, ror) { 1:dp = op_readpc(); 2:op_io(); 3:rd = op_readdp(dp + regs.x); 4:rd = op_$1(rd); op_writedp(dp + regs.x, rd); } inc_addr(0xac, inc), dec_addr(0x8c, dec), asl_addr(0x0c, asl), lsr_addr(0x4c, lsr), rol_addr(0x2c, rol), ror_addr(0x6c, ror) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:rd = op_readaddr(dp); 4:rd = op_$1(rd); op_writeaddr(dp, rd); } tset_addr_a(0x0e, |), tclr_addr_a(0x4e, &~) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:rd = op_readaddr(dp); regs.p.n = !!((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); 4:op_readaddr(dp); 5:op_writeaddr(dp, rd $1 regs.a); } incw_dp(0x3a, ++), decw_dp(0x1a, --) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); rd$1; 3:op_writedp(dp++, rd); 4:rd += op_readdp(dp) << 8; 5:op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); } obc1.cpp000664 001750 001750 00000020121 12720446475 013241 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" uint8 S9xGetOBC1 (uint16 Address) { switch (Address) { case 0x7ff0: return (Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2)]); case 0x7ff1: return (Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 1]); case 0x7ff2: return (Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 2]); case 0x7ff3: return (Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 3]); case 0x7ff4: return (Memory.OBC1RAM[OBC1.basePtr + (OBC1.address >> 2) + 0x200]); } return (Memory.OBC1RAM[Address - 0x6000]); } void S9xSetOBC1 (uint8 Byte, uint16 Address) { switch (Address) { case 0x7ff0: Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2)] = Byte; break; case 0x7ff1: Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 1] = Byte; break; case 0x7ff2: Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 2] = Byte; break; case 0x7ff3: Memory.OBC1RAM[OBC1.basePtr + (OBC1.address << 2) + 3] = Byte; break; case 0x7ff4: { uint8 Temp; Temp = Memory.OBC1RAM[OBC1.basePtr + (OBC1.address >> 2) + 0x200]; Temp = (Temp & ~(3 << OBC1.shift)) | ((Byte & 3) << OBC1.shift); Memory.OBC1RAM[OBC1.basePtr + (OBC1.address >> 2) + 0x200] = Temp; break; } case 0x7ff5: if (Byte & 1) OBC1.basePtr = 0x1800; else OBC1.basePtr = 0x1c00; break; case 0x7ff6: OBC1.address = Byte & 0x7f; OBC1.shift = (Byte & 3) << 1; break; } Memory.OBC1RAM[Address - 0x6000] = Byte; } void S9xResetOBC1 (void) { for (int i = 0; i <= 0x1fff; i++) Memory.OBC1RAM[i] = 0xff; if (Memory.OBC1RAM[0x1ff5] & 1) OBC1.basePtr = 0x1800; else OBC1.basePtr = 0x1c00; OBC1.address = Memory.OBC1RAM[0x1ff6] & 0x7f; OBC1.shift = (Memory.OBC1RAM[0x1ff6] & 3) << 1; } uint8 * S9xGetBasePointerOBC1 (uint16 Address) { if (Address >= 0x7ff0 && Address <= 0x7ff6) return (NULL); return (Memory.OBC1RAM - 0x6000); } uint8 * S9xGetMemPointerOBC1 (uint16 Address) { if (Address >= 0x7ff0 && Address <= 0x7ff6) return (NULL); return (Memory.OBC1RAM + Address - 0x6000); } controls.h000664 001750 001750 00000035673 12720446475 013747 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CONTROLS_H_ #define _CONTROLS_H_ #define S9xNoMapping 0 #define S9xButtonJoypad 1 #define S9xButtonMouse 2 #define S9xButtonSuperscope 3 #define S9xButtonJustifier 4 #define S9xButtonCommand 5 #define S9xButtonMulti 6 #define S9xAxisJoypad 7 #define S9xPointer 8 #define S9xButtonPseudopointer 254 #define S9xAxisPseudopointer 253 #define S9xAxisPseudobuttons 252 // These are automatically kicked out to the S9xHandlePortCommand function. // If your port wants to define port-specific commands or whatever, use these values for the s9xcommand_t type field. #define S9xButtonPort 251 #define S9xAxisPort 250 #define S9xPointerPort 249 #define S9xBadMapping 255 #define InvalidControlID ((uint32) -1) // S9xButtonPseudopointer and S9xAxisPseudopointer will report pointer motion using IDs PseudoPointerBase through PseudoPointerBase+7. // S9xAxisPseudopointer command types. S9xAxisPseudobuttons will report buttons with IDs PseudoButtonBase to PseudoButtonBase+255. #define PseudoPointerBase (InvalidControlID - 8) #define PseudoButtonBase (PseudoPointerBase - 256) typedef struct { uint8 type; uint8 multi_press:2; uint8 button_norpt:1; union { union { struct { uint8 idx:3; // Pad number 0-7 uint8 toggle:1; // If set, toggle turbo/sticky for the button uint8 turbo:1; // If set, be a 'turbo' button uint8 sticky:1; // If set, toggle button state (on/turbo or off) when pressed and do nothing on release uint16 buttons; // Which buttons to actuate. Use SNES_*_MASK constants from snes9x.h } joypad; struct { uint8 idx:1; // Mouse number 0-1 uint8 left:1; // buttons uint8 right:1; } mouse; struct { uint8 fire:1; uint8 cursor:1; uint8 turbo:1; uint8 pause:1; uint8 aim_offscreen:1; // Pretend we're pointing the gun offscreen (ignore the pointer) } scope; struct { uint8 idx:3; // Pseudo-pointer number 0-7 uint8 speed_type:2; // 0=variable, 1=slow, 2=med, 3=fast int8 UD:2; // -1=up, 1=down, 0=no vertical motion int8 LR:2; // -1=left, 1=right, 0=no horizontal motion } pointer; struct { uint8 idx:1; // Justifier number 0-1 uint8 trigger:1; // buttons uint8 start:1; uint8 aim_offscreen:1; // Pretend we're pointing the gun offscreen (ignore the pointer) } justifier; int32 multi_idx; uint16 command; } button; union { struct { uint8 idx:3; // Pad number 0-7 uint8 invert:1; // 1 = positive is Left/Up/Y/X/L uint8 axis:3; // 0=Left/Right, 1=Up/Down, 2=Y/A, 3=X/B, 4=L/R uint8 threshold; // (threshold+1)/256% deflection is a button press } joypad; struct { uint8 idx:3; // Pseudo-pointer number 0-7 uint8 speed_type:2; // 0=variable, 1=slow, 2=med, 3=fast uint8 invert:1; // 1 = invert axis, so positive is up/left uint8 HV:1; // 0=horizontal, 1=vertical } pointer; struct { uint8 threshold; // (threshold+1)/256% deflection is a button press uint8 negbutton; // Button ID for negative deflection uint8 posbutton; // Button ID for positive deflection } button; } axis; struct // Which SNES-pointers to control with this pointer { uint16 aim_mouse0:1; uint16 aim_mouse1:1; uint16 aim_scope:1; uint16 aim_justifier0:1; uint16 aim_justifier1:1; } pointer; uint8 port[4]; }; } s9xcommand_t; // Starting out... void S9xUnmapAllControls (void); // Setting which controllers are plugged in. enum controllers { CTL_NONE, // all ids ignored CTL_JOYPAD, // use id1 to specify 0-7 CTL_MOUSE, // use id1 to specify 0-1 CTL_SUPERSCOPE, CTL_JUSTIFIER, // use id1: 0=one justifier, 1=two justifiers CTL_MP5 // use id1-id4 to specify pad 0-7 (or -1) }; void S9xSetController (int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4); // port=0-1 void S9xGetController (int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4); void S9xReportControllers (void); // Call this when you're done with S9xSetController, or if you change any of the controller Settings.*Master flags. // Returns true if something was disabled. bool S9xVerifyControllers (void); // Functions for translation s9xcommand_t's into strings, and vice versa. // free() the returned string after you're done with it. char * S9xGetCommandName (s9xcommand_t command); s9xcommand_t S9xGetCommandT (const char *name); // Returns an array of strings naming all the snes9x commands. // Note that this is only the strings for S9xButtonCommand! // The idea is that this would be used for a pull-down list in a config GUI. DO NOT free() the returned value. const char ** S9xGetAllSnes9xCommands (void); // Generic mapping functions s9xcommand_t S9xGetMapping (uint32 id); void S9xUnmapID (uint32 id); // Button mapping functions. // If a button is mapped with poll=TRUE, then S9xPollButton will be called whenever snes9x feels a need for that mapping. // Otherwise, snes9x will assume you will call S9xReportButton() whenever the button state changes. // S9xMapButton() will fail and return FALSE if mapping.type isn't an S9xButton* type. bool S9xMapButton (uint32 id, s9xcommand_t mapping, bool poll); void S9xReportButton (uint32 id, bool pressed); // Pointer mapping functions. // If a pointer is mapped with poll=TRUE, then S9xPollPointer will be called whenever snes9x feels a need for that mapping. // Otherwise, snes9x will assume you will call S9xReportPointer() whenever the pointer position changes. // S9xMapPointer() will fail and return FALSE if mapping.type isn't an S9xPointer* type. // Note that position [0,0] is considered the upper-left corner of the 'screen', // and either [255,223] or [255,239] is the lower-right. // Note that the SNES mouse doesn't aim at a particular point, // so the SNES's idea of where the mouse pointer is will probably differ from your OS's idea. bool S9xMapPointer (uint32 id, s9xcommand_t mapping, bool poll); void S9xReportPointer (uint32 id, int16 x, int16 y); // Axis mapping functions. // If an axis is mapped with poll=TRUE, then S9xPollAxis will be called whenever snes9x feels a need for that mapping. // Otherwise, snes9x will assume you will call S9xReportAxis() whenever the axis deflection changes. // S9xMapAxis() will fail and return FALSE if mapping.type isn't an S9xAxis* type. // Note that value is linear -32767 through 32767 with 0 being no deflection. // If your axis reports differently you should transform the value before passing it to S9xReportAxis(). bool S9xMapAxis (uint32 id, s9xcommand_t mapping, bool poll); void S9xReportAxis (uint32 id, int16 value); // Do whatever the s9xcommand_t says to do. // If cmd.type is a button type, data1 should be TRUE (non-0) or FALSE (0) to indicate whether the 'button' is pressed or released. // If cmd.type is an axis, data1 holds the deflection value. // If cmd.type is a pointer, data1 and data2 are the positions of the pointer. void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2); ////////// // These functions are called by snes9x into your port, so each port should implement them. // If something was mapped with poll=TRUE, these functions will be called when snes9x needs the button/axis/pointer state. // Fill in the reference options as appropriate. bool S9xPollButton (uint32 id, bool *pressed); bool S9xPollPointer (uint32 id, int16 *x, int16 *y); bool S9xPollAxis (uint32 id, int16 *value); // These are called when snes9x tries to apply a command with a S9x*Port type. // data1 and data2 are filled in like S9xApplyCommand. void S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2); // Called before already-read SNES joypad data is being used by the game if your port defines SNES_JOY_READ_CALLBACKS. #ifdef SNES_JOY_READ_CALLBACKS void S9xOnSNESPadRead (void); #endif // These are for your use. s9xcommand_t S9xGetPortCommandT (const char *name); char * S9xGetPortCommandName (s9xcommand_t command); void S9xSetupDefaultKeymap (void); bool8 S9xMapInput (const char *name, s9xcommand_t *cmd); ////////// // These functions are called from snes9x into this subsystem. No need to use them from a port. // Use when resetting snes9x. void S9xControlsReset (void); void S9xControlsSoftReset (void); // Use when writing to $4016. void S9xSetJoypadLatch (bool latch); // Use when reading $4016/7 (JOYSER0 and JOYSER1). uint8 S9xReadJOYSERn (int n); // End-Of-Frame processing. Sets gun latch variables and tries to draw crosshairs void S9xControlEOF (void); // Functions and a structure for snapshot. struct SControlSnapshot { uint8 ver; uint8 port1_read_idx[2]; uint8 dummy1[4]; // for future expansion uint8 port2_read_idx[2]; uint8 dummy2[4]; uint8 mouse_speed[2]; uint8 justifier_select; uint8 dummy3[8]; bool8 pad_read, pad_read_last; uint8 internal[60]; // yes, we need to save this! }; void S9xControlPreSaveState (struct SControlSnapshot *s); void S9xControlPostLoadState (struct SControlSnapshot *s); #endif sa1.cpp000664 001750 001750 00000067444 12720446475 013124 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" uint8 SA1OpenBus; static void S9xSA1SetBWRAMMemMap (uint8); static void S9xSetSA1MemMap (uint32, uint8); static void S9xSA1CharConv2 (void); static void S9xSA1DMA (void); static void S9xSA1ReadVariableLengthData (bool8, bool8); void S9xSA1Init (void) { SA1.Cycles = 0; SA1.PrevCycles = 0; SA1.Flags = 0; SA1.WaitingForInterrupt = FALSE; memset(&Memory.FillRAM[0x2200], 0, 0x200); Memory.FillRAM[0x2200] = 0x20; Memory.FillRAM[0x2220] = 0x00; Memory.FillRAM[0x2221] = 0x01; Memory.FillRAM[0x2222] = 0x02; Memory.FillRAM[0x2223] = 0x03; Memory.FillRAM[0x2228] = 0x0f; SA1.in_char_dma = FALSE; SA1.TimerIRQLastState = FALSE; SA1.HTimerIRQPos = 0; SA1.VTimerIRQPos = 0; SA1.HCounter = 0; SA1.VCounter = 0; SA1.PrevHCounter = 0; SA1.arithmetic_op = 0; SA1.op1 = 0; SA1.op2 = 0; SA1.sum = 0; SA1.overflow = FALSE; SA1.VirtualBitmapFormat = 0; SA1.variable_bit_pos = 0; SA1Registers.PBPC = 0; SA1Registers.PB = 0; SA1Registers.PCw = 0; SA1Registers.D.W = 0; SA1Registers.DB = 0; SA1Registers.SH = 1; SA1Registers.SL = 0xFF; SA1Registers.XH = 0; SA1Registers.YH = 0; SA1Registers.P.W = 0; SA1.ShiftedPB = 0; SA1.ShiftedDB = 0; SA1SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); SA1ClearFlags(Decimal); SA1.MemSpeed = SLOW_ONE_CYCLE; SA1.MemSpeedx2 = SLOW_ONE_CYCLE * 2; SA1.S9xOpcodes = S9xSA1OpcodesM1X1; SA1.S9xOpLengths = S9xOpLengthsM1X1; S9xSA1SetPCBase(SA1Registers.PBPC); S9xSA1UnpackStatus(); S9xSA1FixCycles(); SA1.BWRAM = Memory.SRAM; CPU.IRQExternal = FALSE; } static void S9xSA1SetBWRAMMemMap (uint8 val) { if (val & 0x80) { for (int c = 0; c < 0x400; c += 16) { SA1.Map[c + 6] = SA1.Map[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; SA1.Map[c + 7] = SA1.Map[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; SA1.WriteMap[c + 6] = SA1.WriteMap[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; SA1.WriteMap[c + 7] = SA1.WriteMap[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; } SA1.BWRAM = Memory.SRAM + (val & 0x7f) * 0x2000 / 4; } else { for (int c = 0; c < 0x400; c += 16) { SA1.Map[c + 6] = SA1.Map[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM; SA1.Map[c + 7] = SA1.Map[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM; SA1.WriteMap[c + 6] = SA1.WriteMap[c + 0x806] = (uint8 *) CMemory::MAP_BWRAM; SA1.WriteMap[c + 7] = SA1.WriteMap[c + 0x807] = (uint8 *) CMemory::MAP_BWRAM; } SA1.BWRAM = Memory.SRAM + (val & 7) * 0x2000; } } void S9xSA1PostLoadState (void) { SA1.ShiftedPB = (uint32) SA1Registers.PB << 16; SA1.ShiftedDB = (uint32) SA1Registers.DB << 16; S9xSA1SetPCBase(SA1Registers.PBPC); S9xSA1UnpackStatus(); S9xSA1FixCycles(); SA1.VirtualBitmapFormat = (Memory.FillRAM[0x223f] & 0x80) ? 2 : 4; Memory.BWRAM = Memory.SRAM + (Memory.FillRAM[0x2224] & 7) * 0x2000; S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]); } static void S9xSetSA1MemMap (uint32 which1, uint8 map) { int start = which1 * 0x100 + 0xc00; int start2 = which1 * 0x200; if (which1 >= 2) start2 += 0x400; for (int c = 0; c < 0x100; c += 16) { uint8 *block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)]; for (int i = c; i < c + 16; i++) Memory.Map[start + i] = SA1.Map[start + i] = block; } for (int c = 0; c < 0x200; c += 16) { // conversion to int is needed here - map is promoted but which1 is not int32 offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000; uint8 *block = &Memory.ROM[offset]; for (int i = c + 8; i < c + 16; i++) Memory.Map[start2 + i] = SA1.Map[start2 + i] = block; } } uint8 S9xGetSA1 (uint32 address) { switch (address) { case 0x2300: // S-CPU flag return ((Memory.FillRAM[0x2209] & 0x5f) | (Memory.FillRAM[0x2300] & 0xa0)); case 0x2301: // SA-1 flag return ((Memory.FillRAM[0x2200] & 0x0f) | (Memory.FillRAM[0x2301] & 0xf0)); case 0x2302: // H counter (L) SA1.HTimerIRQPos = SA1.HCounter / ONE_DOT_CYCLE; SA1.VTimerIRQPos = SA1.VCounter; return ((uint8) SA1.HTimerIRQPos); case 0x2303: // H counter (H) return ((uint8) (SA1.HTimerIRQPos >> 8)); case 0x2304: // V counter (L) return ((uint8) SA1.VTimerIRQPos); case 0x2305: // V counter (H) return ((uint8) (SA1.VTimerIRQPos >> 8)); case 0x2306: // arithmetic result (LLL) return ((uint8) SA1.sum); case 0x2307: // arithmetic result (LLH) return ((uint8) (SA1.sum >> 8)); case 0x2308: // arithmetic result (LHL) return ((uint8) (SA1.sum >> 16)); case 0x2309: // arithmetic result (LLH) return ((uint8) (SA1.sum >> 24)); case 0x230a: // arithmetic result (HLL) return ((uint8) (SA1.sum >> 32)); case 0x230b: // arithmetic overflow return (SA1.overflow ? 0x80 : 0); case 0x230c: // variable-length data read port (L) return (Memory.FillRAM[0x230c]); case 0x230d: // variable-length data read port (H) { uint8 byte = Memory.FillRAM[0x230d]; if (Memory.FillRAM[0x2258] & 0x80) S9xSA1ReadVariableLengthData(TRUE, FALSE); return (byte); } case 0x230e: // version code register return (0x01); default: break; } return (Memory.FillRAM[address]); } void S9xSetSA1 (uint8 byte, uint32 address) { switch (address) { case 0x2200: // SA-1 control #ifdef DEBUGGER if (byte & 0x60) printf("SA-1 sleep\n"); #endif // SA-1 reset if (!(byte & 0x80) && (Memory.FillRAM[0x2200] & 0x20)) { #ifdef DEBUGGER printf("SA-1 reset\n"); #endif SA1Registers.PBPC = 0; SA1Registers.PB = 0; SA1Registers.PCw = Memory.FillRAM[0x2203] | (Memory.FillRAM[0x2204] << 8); S9xSA1SetPCBase(SA1Registers.PBPC); } // SA-1 IRQ control if (byte & 0x80) { Memory.FillRAM[0x2301] |= 0x80; if (Memory.FillRAM[0x220a] & 0x80) Memory.FillRAM[0x220b] &= ~0x80; } // SA-1 NMI control if (byte & 0x10) { Memory.FillRAM[0x2301] |= 0x10; if (Memory.FillRAM[0x220a] & 0x10) Memory.FillRAM[0x220b] &= ~0x10; } break; case 0x2201: // S-CPU interrupt enable // S-CPU IRQ enable if (((byte ^ Memory.FillRAM[0x2201]) & 0x80) && (Memory.FillRAM[0x2300] & byte & 0x80)) { Memory.FillRAM[0x2202] &= ~0x80; CPU.IRQExternal = TRUE; } // S-CPU CHDMA IRQ enable if (((byte ^ Memory.FillRAM[0x2201]) & 0x20) && (Memory.FillRAM[0x2300] & byte & 0x20)) { Memory.FillRAM[0x2202] &= ~0x20; CPU.IRQExternal = TRUE; } break; case 0x2202: // S-CPU interrupt clear // S-CPU IRQ clear if (byte & 0x80) Memory.FillRAM[0x2300] &= ~0x80; // S-CPU CHDMA IRQ clear if (byte & 0x20) Memory.FillRAM[0x2300] &= ~0x20; if (!(Memory.FillRAM[0x2300] & 0xa0)) CPU.IRQExternal = FALSE; break; case 0x2203: // SA-1 reset vector (L) case 0x2204: // SA-1 reset vector (H) case 0x2205: // SA-1 NMI vector (L) case 0x2206: // SA-1 NMI vector (H) case 0x2207: // SA-1 IRQ vector (L) case 0x2208: // SA-1 IRQ vector (H) break; case 0x2209: // S-CPU control // 0x40: S-CPU IRQ overwrite // 0x20: S-CPU NMI overwrite // S-CPU IRQ control if (byte & 0x80) { Memory.FillRAM[0x2300] |= 0x80; if (Memory.FillRAM[0x2201] & 0x80) { Memory.FillRAM[0x2202] &= ~0x80; CPU.IRQExternal = TRUE; } } break; case 0x220a: // SA-1 interrupt enable // SA-1 IRQ enable if (((byte ^ Memory.FillRAM[0x220a]) & 0x80) && (Memory.FillRAM[0x2301] & byte & 0x80)) Memory.FillRAM[0x220b] &= ~0x80; // SA-1 timer IRQ enable if (((byte ^ Memory.FillRAM[0x220a]) & 0x40) && (Memory.FillRAM[0x2301] & byte & 0x40)) Memory.FillRAM[0x220b] &= ~0x40; // SA-1 DMA IRQ enable if (((byte ^ Memory.FillRAM[0x220a]) & 0x20) && (Memory.FillRAM[0x2301] & byte & 0x20)) Memory.FillRAM[0x220b] &= ~0x20; // SA-1 NMI enable if (((byte ^ Memory.FillRAM[0x220a]) & 0x10) && (Memory.FillRAM[0x2301] & byte & 0x10)) Memory.FillRAM[0x220b] &= ~0x10; break; case 0x220b: // SA-1 interrupt clear // SA-1 IRQ clear if (byte & 0x80) Memory.FillRAM[0x2301] &= ~0x80; // SA-1 timer IRQ clear if (byte & 0x40) Memory.FillRAM[0x2301] &= ~0x40; // SA-1 DMA IRQ clear if (byte & 0x20) Memory.FillRAM[0x2301] &= ~0x20; // SA-1 NMI clear if (byte & 0x10) Memory.FillRAM[0x2301] &= ~0x10; break; case 0x220c: // S-CPU NMI vector (L) case 0x220d: // S-CPU NMI vector (H) case 0x220e: // S-CPU IRQ vector (L) case 0x220f: // S-CPU IRQ vector (H) break; case 0x2210: // SA-1 timer control // 0x80: mode (linear / HV) // 0x02: V timer enable // 0x01: H timer enable #ifdef DEBUGGER printf("SA-1 timer control write:%02x\n", byte); #endif break; case 0x2211: // SA-1 timer reset SA1.HCounter = 0; SA1.VCounter = 0; break; case 0x2212: // SA-1 H-timer (L) SA1.HTimerIRQPos = byte | (Memory.FillRAM[0x2213] << 8); break; case 0x2213: // SA-1 H-timer (H) SA1.HTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2212]; break; case 0x2214: // SA-1 V-timer (L) SA1.VTimerIRQPos = byte | (Memory.FillRAM[0x2215] << 8); break; case 0x2215: // SA-1 V-timer (H) SA1.VTimerIRQPos = (byte << 8) | Memory.FillRAM[0x2214]; break; case 0x2220: // MMC bank C case 0x2221: // MMC bank D case 0x2222: // MMC bank E case 0x2223: // MMC bank F S9xSetSA1MemMap(address - 0x2220, byte); break; case 0x2224: // S-CPU BW-RAM mapping Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000; break; case 0x2225: // SA-1 BW-RAM mapping if (byte != Memory.FillRAM[0x2225]) S9xSA1SetBWRAMMemMap(byte); break; case 0x2226: // S-CPU BW-RAM write enable case 0x2227: // SA-1 BW-RAM write enable case 0x2228: // BW-RAM write-protected area case 0x2229: // S-CPU I-RAM write protection case 0x222a: // SA-1 I-RAM write protection break; case 0x2230: // DMA control // 0x80: enable // 0x40: priority (DMA / SA-1) // 0x20: character conversion / normal // 0x10: BW-RAM -> I-RAM / SA-1 -> I-RAM // 0x04: destinatin (BW-RAM / I-RAM) // 0x03: source break; case 0x2231: // character conversion DMA parameters // 0x80: CHDEND (complete / incomplete) // 0x03: color mode // (byte >> 2) & 7: virtual VRAM width if (byte & 0x80) SA1.in_char_dma = FALSE; break; case 0x2232: // DMA source start address (LL) case 0x2233: // DMA source start address (LH) case 0x2234: // DMA source start address (HL) break; case 0x2235: // DMA destination start address (LL) break; case 0x2236: // DMA destination start address (LH) Memory.FillRAM[0x2236] = byte; if ((Memory.FillRAM[0x2230] & 0xa4) == 0x80) // Normal DMA to I-RAM S9xSA1DMA(); else if ((Memory.FillRAM[0x2230] & 0xb0) == 0xb0) // CC1 { SA1.in_char_dma = TRUE; Memory.FillRAM[0x2300] |= 0x20; if (Memory.FillRAM[0x2201] & 0x20) { Memory.FillRAM[0x2202] &= ~0x20; CPU.IRQExternal = TRUE; } } break; case 0x2237: // DMA destination start address (HL) Memory.FillRAM[0x2237] = byte; if ((Memory.FillRAM[0x2230] & 0xa4) == 0x84) // Normal DMA to BW-RAM S9xSA1DMA(); break; case 0x2238: // DMA terminal counter (L) case 0x2239: // DMA terminal counter (H) break; case 0x223f: // BW-RAM bitmap format SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4; break; case 0x2240: // bitmap register 0 case 0x2241: // bitmap register 1 case 0x2242: // bitmap register 2 case 0x2243: // bitmap register 3 case 0x2244: // bitmap register 4 case 0x2245: // bitmap register 5 case 0x2246: // bitmap register 6 case 0x2247: // bitmap register 7 case 0x2248: // bitmap register 8 case 0x2249: // bitmap register 9 case 0x224a: // bitmap register A case 0x224b: // bitmap register B case 0x224c: // bitmap register C case 0x224d: // bitmap register D case 0x224e: // bitmap register E break; case 0x224f: // bitmap register F Memory.FillRAM[0x224f] = byte; if ((Memory.FillRAM[0x2230] & 0xb0) == 0xa0) // CC2 { memmove(&Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, &Memory.FillRAM[0x2240], 16); SA1.in_char_dma = (SA1.in_char_dma + 1) & 7; if ((SA1.in_char_dma & 3) == 0) S9xSA1CharConv2(); } break; case 0x2250: // arithmetic control if (byte & 2) SA1.sum = 0; SA1.arithmetic_op = byte & 3; break; case 0x2251: // multiplicand / dividend (L) SA1.op1 = (SA1.op1 & 0xff00) | byte; break; case 0x2252: // multiplicand / dividend (H) SA1.op1 = (SA1.op1 & 0x00ff) | (byte << 8); break; case 0x2253: // multiplier / divisor (L) SA1.op2 = (SA1.op2 & 0xff00) | byte; break; case 0x2254: // multiplier / divisor (H) SA1.op2 = (SA1.op2 & 0x00ff) | (byte << 8); switch (SA1.arithmetic_op) { case 0: // signed multiplication SA1.sum = (int16) SA1.op1 * (int16) SA1.op2; SA1.op2 = 0; break; case 1: // unsigned division if (SA1.op2 == 0) SA1.sum = 0; else { int16 quotient = (int16) SA1.op1 / (uint16) SA1.op2; uint16 remainder = (int16) SA1.op1 % (uint16) SA1.op2; SA1.sum = (remainder << 16) | quotient; } SA1.op1 = 0; SA1.op2 = 0; break; case 2: // cumulative sum default: SA1.sum += (int16) SA1.op1 * (int16) SA1.op2; SA1.overflow = (SA1.sum >= (1ULL << 40)); SA1.sum &= (1ULL << 40) - 1; SA1.op2 = 0; break; } break; case 0x2258: // variable bit-field length / auto inc / start Memory.FillRAM[0x2258] = byte; S9xSA1ReadVariableLengthData(TRUE, FALSE); return; case 0x2259: // variable bit-field start address (LL) case 0x225a: // variable bit-field start address (LH) case 0x225b: // variable bit-field start address (HL) Memory.FillRAM[address] = byte; // XXX: ??? SA1.variable_bit_pos = 0; S9xSA1ReadVariableLengthData(FALSE, TRUE); return; default: break; } if (address >= 0x2200 && address <= 0x22ff) Memory.FillRAM[address] = byte; } static void S9xSA1CharConv2 (void) { uint32 dest = Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8); uint32 offset = (SA1.in_char_dma & 7) ? 0 : 1; int depth = (Memory.FillRAM[0x2231] & 3) == 0 ? 8 : (Memory.FillRAM[0x2231] & 3) == 1 ? 4 : 2; int bytes_per_char = 8 * depth; uint8 *p = &Memory.FillRAM[0x3000] + (dest & 0x7ff) + offset * bytes_per_char; uint8 *q = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000] + offset * 64; switch (depth) { case 2: for (int l = 0; l < 8; l++, q += 8) { for (int b = 0; b < 8; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); } p += 2; } break; case 4: for (int l = 0; l < 8; l++, q += 8) { for (int b = 0; b < 8; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); } p += 2; } break; case 8: for (int l = 0; l < 8; l++, q += 8) { for (int b = 0; b < 8; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1); *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1); *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1); *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1); } p += 2; } break; } } static void S9xSA1DMA (void) { uint32 src = Memory.FillRAM[0x2232] | (Memory.FillRAM[0x2233] << 8) | (Memory.FillRAM[0x2234] << 16); uint32 dst = Memory.FillRAM[0x2235] | (Memory.FillRAM[0x2236] << 8) | (Memory.FillRAM[0x2237] << 16); uint32 len = Memory.FillRAM[0x2238] | (Memory.FillRAM[0x2239] << 8); uint8 *s, *d; switch (Memory.FillRAM[0x2230] & 3) { case 0: // ROM s = SA1.Map[((src & 0xffffff) >> MEMMAP_SHIFT)]; if (s >= (uint8 *) CMemory::MAP_LAST) s += (src & 0xffff); else s = Memory.ROM + (src & 0xffff); break; case 1: // BW-RAM src &= Memory.SRAMMask; len &= Memory.SRAMMask; s = Memory.SRAM + src; break; default: case 2: src &= 0x3ff; len &= 0x3ff; s = &Memory.FillRAM[0x3000] + src; break; } if (Memory.FillRAM[0x2230] & 4) { dst &= Memory.SRAMMask; len &= Memory.SRAMMask; d = Memory.SRAM + dst; } else { dst &= 0x3ff; len &= 0x3ff; d = &Memory.FillRAM[0x3000] + dst; } memmove(d, s, len); // SA-1 DMA IRQ control Memory.FillRAM[0x2301] |= 0x20; if (Memory.FillRAM[0x220a] & 0x20) Memory.FillRAM[0x220b] &= ~0x20; } static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift) { uint32 addr = Memory.FillRAM[0x2259] | (Memory.FillRAM[0x225a] << 8) | (Memory.FillRAM[0x225b] << 16); uint8 shift = Memory.FillRAM[0x2258] & 15; if (no_shift) shift = 0; else if (shift == 0) shift = 16; uint8 s = shift + SA1.variable_bit_pos; if (s >= 16) { addr += (s >> 4) << 1; s &= 15; } uint32 data = S9xSA1GetWord(addr) | (S9xSA1GetWord(addr + 2) << 16); data >>= s; Memory.FillRAM[0x230c] = (uint8) data; Memory.FillRAM[0x230d] = (uint8) (data >> 8); if (inc) { SA1.variable_bit_pos = (SA1.variable_bit_pos + shift) & 15; Memory.FillRAM[0x2259] = (uint8) addr; Memory.FillRAM[0x225a] = (uint8) (addr >> 8); Memory.FillRAM[0x225b] = (uint8) (addr >> 16); } } uint8 S9xSA1GetByte (uint32 address) { uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) return (*(GetAddress + (address & 0xffff))); switch ((pint) GetAddress) { case CMemory::MAP_PPU: return (S9xGetSA1(address & 0xffff)); case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: return (*(Memory.SRAM + (address & 0xffff))); case CMemory::MAP_BWRAM: return (*(SA1.BWRAM + ((address & 0x7fff) - 0x6000))); case CMemory::MAP_BWRAM_BITMAP: address -= 0x600000; if (SA1.VirtualBitmapFormat == 2) return ((Memory.SRAM[(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3); else return ((Memory.SRAM[(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15); case CMemory::MAP_BWRAM_BITMAP2: address = (address & 0xffff) - 0x6000; if (SA1.VirtualBitmapFormat == 2) return ((SA1.BWRAM[(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3); else return ((SA1.BWRAM[(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15); default: return (SA1OpenBus); } } uint16 S9xSA1GetWord (uint32 address, s9xwrap_t w) { PC_t a; SA1OpenBus = S9xSA1GetByte(address); switch (w) { case WRAP_PAGE: a.xPBPC = address; a.B.xPCl++; return (SA1OpenBus | (S9xSA1GetByte(a.xPBPC) << 8)); case WRAP_BANK: a.xPBPC = address; a.W.xPC++; return (SA1OpenBus | (S9xSA1GetByte(a.xPBPC) << 8)); case WRAP_NONE: default: return (SA1OpenBus | (S9xSA1GetByte(address + 1) << 8)); } } void S9xSA1SetByte (uint8 byte, uint32 address) { uint8 *SetAddress = SA1.WriteMap[(address & 0xffffff) >> MEMMAP_SHIFT]; if (SetAddress >= (uint8 *) CMemory::MAP_LAST) { *(SetAddress + (address & 0xffff)) = byte; return; } switch ((pint) SetAddress) { case CMemory::MAP_PPU: S9xSetSA1(byte, address & 0xffff); return; case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: *(Memory.SRAM + (address & 0xffff)) = byte; return; case CMemory::MAP_BWRAM: *(SA1.BWRAM + ((address & 0x7fff) - 0x6000)) = byte; return; case CMemory::MAP_BWRAM_BITMAP: address -= 0x600000; if (SA1.VirtualBitmapFormat == 2) { uint8 *ptr = &Memory.SRAM[(address >> 2) & 0xffff]; *ptr &= ~(3 << ((address & 3) << 1)); *ptr |= (byte & 3) << ((address & 3) << 1); } else { uint8 *ptr = &Memory.SRAM[(address >> 1) & 0xffff]; *ptr &= ~(15 << ((address & 1) << 2)); *ptr |= (byte & 15) << ((address & 1) << 2); } return; case CMemory::MAP_BWRAM_BITMAP2: address = (address & 0xffff) - 0x6000; if (SA1.VirtualBitmapFormat == 2) { uint8 *ptr = &SA1.BWRAM[(address >> 2) & 0xffff]; *ptr &= ~(3 << ((address & 3) << 1)); *ptr |= (byte & 3) << ((address & 3) << 1); } else { uint8 *ptr = &SA1.BWRAM[(address >> 1) & 0xffff]; *ptr &= ~(15 << ((address & 1) << 2)); *ptr |= (byte & 15) << ((address & 1) << 2); } return; default: return; } } void S9xSA1SetWord (uint16 Word, uint32 address, enum s9xwrap_t w, enum s9xwriteorder_t o) { PC_t a; if (!o) S9xSA1SetByte((uint8) Word, address); switch (w) { case WRAP_PAGE: a.xPBPC = address; a.B.xPCl++; S9xSA1SetByte(Word >> 8, a.xPBPC); break; case WRAP_BANK: a.xPBPC = address; a.W.xPC++; S9xSA1SetByte(Word >> 8, a.xPBPC); break; case WRAP_NONE: default: S9xSA1SetByte(Word >> 8, address + 1); break; } if (o) S9xSA1SetByte((uint8) Word, address); } void S9xSA1SetPCBase (uint32 address) { SA1Registers.PBPC = address & 0xffffff; SA1.ShiftedPB = address & 0xff0000; // FIXME SA1.MemSpeed = memory_speed(address); SA1.MemSpeedx2 = SA1.MemSpeed << 1; uint8 *GetAddress = SA1.Map[(address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { SA1.PCBase = GetAddress; return; } switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) SA1.PCBase = NULL; else SA1.PCBase = (Memory.SRAM + ((((address & 0xff0000) >> 1) | (address & 0x7fff)) & Memory.SRAMMask)) - (address & 0xffff); return; case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) SA1.PCBase = NULL; else SA1.PCBase = (Memory.SRAM + (((address & 0x7fff) - 0x6000 + ((address & 0xf0000) >> 3)) & Memory.SRAMMask)) - (address & 0xffff); return; case CMemory::MAP_BWRAM: SA1.PCBase = SA1.BWRAM - 0x6000 - (address & 0x8000); return; case CMemory::MAP_SA1RAM: SA1.PCBase = Memory.SRAM; return; default: SA1.PCBase = NULL; return; } } netplay.cpp000664 001750 001750 00000103636 12720446475 014106 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef NETPLAY_SUPPORT #ifdef _DEBUG #define NP_DEBUG 1 #endif #define NP_DEBUG 3 // FF-FIXME #include #include #include #include #include #include "snes9x.h" #ifdef __WIN32__ #include #include #include "win32/wsnes9x.h" #define ioctl ioctlsocket #define close(h) if(h){closesocket(h);} #define read(a,b,c) recv(a, b, c, 0) #define write(a,b,c) send(a, b, c, 0) #else #include #include #include #include #include #include #include #include #include #include #ifdef __SVR4 #include #endif #endif #ifdef USE_THREADS #include #include #include #endif #include "memmap.h" #include "netplay.h" #include "snapshot.h" #include "display.h" void S9xNPClientLoop (void *); bool8 S9xNPLoadROM (uint32 len); bool8 S9xNPLoadROMDialog (const char *); bool8 S9xNPGetROMImage (uint32 len); void S9xNPGetSRAMData (uint32 len); void S9xNPGetFreezeFile (uint32 len); unsigned long START = 0; bool8 S9xNPConnect (); bool8 S9xNPConnectToServer (const char *hostname, int port, const char *rom_name) { if (!S9xNPInitialise ()) return (FALSE); S9xNPDisconnect (); NetPlay.MySequenceNum = 0; NetPlay.ServerSequenceNum = 0; NetPlay.Connected = FALSE; NetPlay.Abort = FALSE; NetPlay.Player = 0; NetPlay.Paused = FALSE; NetPlay.PercentageComplete = 0; NetPlay.Socket = 0; if (NetPlay.ServerHostName) free ((char *) NetPlay.ServerHostName); NetPlay.ServerHostName = strdup (hostname); if (NetPlay.ROMName) free ((char *) NetPlay.ROMName); NetPlay.ROMName = strdup (rom_name); NetPlay.Port = port; NetPlay.PendingWait4Sync = FALSE; #ifdef __WIN32__ if (GUI.ClientSemaphore == NULL) GUI.ClientSemaphore = CreateSemaphore (NULL, 0, NP_JOYPAD_HIST_SIZE, NULL); if (NetPlay.ReplyEvent == NULL) NetPlay.ReplyEvent = CreateEvent (NULL, FALSE, FALSE, NULL); _beginthread (S9xNPClientLoop, 0, NULL); return (TRUE); #endif return S9xNPConnect(); } bool8 S9xNPConnect () { struct sockaddr_in address; struct hostent *hostinfo; unsigned int addr; address.sin_family = AF_INET; address.sin_port = htons (NetPlay.Port); #ifdef NP_DEBUG printf ("CLIENT: Looking up server's hostname (%s) @%ld\n", NetPlay.ServerHostName, S9xGetMilliTime () - START); #endif S9xNPSetAction ("Looking up server's hostname..."); if ((int) (addr = inet_addr (NetPlay.ServerHostName)) == -1) { if ((hostinfo = gethostbyname (NetPlay.ServerHostName))) { memcpy ((char *)&address.sin_addr, hostinfo->h_addr, hostinfo->h_length); } else { S9xNPSetError ("Unable to look up server's IP address from hostname.\n\n" "Unknown hostname or may be your nameserver isn't set\n" "up correctly?"); return (FALSE); } } else { memcpy ((char *)&address.sin_addr, &addr, sizeof (addr)); } #ifdef NP_DEBUG printf ("CLIENT: Creating socket @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Creating network socket..."); if ((NetPlay.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) { S9xNPSetError ("Creating network socket failed."); return (FALSE); } #ifdef NP_DEBUG printf ("CLIENT: Trying to connect to server @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Trying to connect to Snes9X server..."); if (connect (NetPlay.Socket, (struct sockaddr *) &address, sizeof (address)) < 0) { char buf [100]; #ifdef __WIN32__ if (WSAGetLastError () == WSAECONNREFUSED) #else if (errno == ECONNREFUSED) #endif { S9xNPSetError ("Connection to remote server socket refused:\n\n" "Is there actually a Snes9X NetPlay server running\n" "on the remote machine on this port?"); } else { sprintf (buf, "Connection to server failed with error number %d", #ifdef __WIN32__ WSAGetLastError () #else errno #endif ); S9xNPSetError(buf); S9xNPDisconnect (); } return (FALSE); } NetPlay.Connected = TRUE; #ifdef NP_DEBUG printf ("CLIENT: Sending 'HELLO' message @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Sending 'HELLO' message..."); /* Send the server a HELLO packet*/ int len = 7 + 4 + strlen (NetPlay.ROMName) + 1; uint8 *tmp = new uint8 [len]; uint8 *ptr = tmp; *ptr++ = NP_CLNT_MAGIC; *ptr++ = NetPlay.MySequenceNum++; *ptr++ = NP_CLNT_HELLO; WRITE_LONG (ptr, len); ptr += 4; #ifdef __WIN32__ uint32 ft = Settings.FrameTime; WRITE_LONG (ptr, ft); #else WRITE_LONG (ptr, Settings.FrameTime); #endif ptr += 4; strcpy ((char *) ptr, NetPlay.ROMName); if (!S9xNPSendData (NetPlay.Socket, tmp, len)) { S9xNPSetError ("Sending 'HELLO' message failed."); S9xNPDisconnect (); delete[] tmp; return (FALSE); } delete[] tmp; #ifdef NP_DEBUG printf ("CLIENT: Waiting for 'WELCOME' reply from server @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Waiting for 'HELLO' reply from server..."); uint8 header [7]; if (!S9xNPGetData (NetPlay.Socket, header, 7) || header [0] != NP_SERV_MAGIC || header [1] != 0 || (header [2] & 0x1f) != NP_SERV_HELLO) { S9xNPSetError ("Error in 'HELLO' reply packet received from server."); S9xNPDisconnect (); return (FALSE); } #ifdef NP_DEBUG printf ("CLIENT: Got 'WELCOME' reply @%ld\n", S9xGetMilliTime () - START); #endif len = READ_LONG (&header [3]); if (len > 256) { S9xNPSetError ("Error in 'HELLO' reply packet received from server."); S9xNPDisconnect (); return (FALSE); } uint8 *data = new uint8 [len]; if (!S9xNPGetData (NetPlay.Socket, data, len - 7)) { S9xNPSetError ("Error in 'HELLO' reply packet received from server."); delete[] data; S9xNPDisconnect (); return (FALSE); } if (data [0] != NP_VERSION) { S9xNPSetError ("The Snes9X NetPlay server implements a different\n" "version of the protocol. Disconnecting."); delete[] data; S9xNPDisconnect (); return (FALSE); } NetPlay.FrameCount = READ_LONG (&data [2]); if (!(header [2] & 0x80) && strcmp ((char *) data + 4 + 2, NetPlay.ROMName) != 0) { if (!S9xNPLoadROMDialog ((char *) data + 4 + 2)) { delete[] data; S9xNPDisconnect (); return (FALSE); } } NetPlay.Player = data [1]; delete[] data; NetPlay.PendingWait4Sync = TRUE; Settings.NetPlay = TRUE; S9xNPResetJoypadReadPos (); NetPlay.ServerSequenceNum = 1; #ifdef NP_DEBUG printf ("CLIENT: Sending 'READY' to server @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Sending 'READY' to the server..."); return (S9xNPSendReady ((header [2] & 0x80) ? NP_CLNT_WAITING_FOR_ROM_IMAGE : NP_CLNT_READY)); } bool8 S9xNPSendReady (uint8 op) { uint8 ready [7]; uint8 *ptr = ready; *ptr++ = NP_CLNT_MAGIC; *ptr++ = NetPlay.MySequenceNum++; *ptr++ = op; WRITE_LONG (ptr, 7); ptr += 4; if (!S9xNPSendData (NetPlay.Socket, ready, 7)) { S9xNPDisconnect (); S9xNPSetError ("Sending 'READY' message failed."); return (FALSE); } return (TRUE); } bool8 S9xNPSendPause (bool8 paused) { #ifdef NP_DEBUG printf ("CLIENT: Pause - %s @%ld\n", paused ? "YES" : "NO", S9xGetMilliTime () - START); #endif uint8 pause [7]; uint8 *ptr = pause; *ptr++ = NP_CLNT_MAGIC; *ptr++ = NetPlay.MySequenceNum++; *ptr++ = NP_CLNT_PAUSE | (paused ? 0x80 : 0); WRITE_LONG (ptr, 7); ptr += 4; if (!S9xNPSendData (NetPlay.Socket, pause, 7)) { S9xNPSetError ("Sending 'PAUSE' message failed."); S9xNPDisconnect (); return (FALSE); } return (TRUE); } #ifdef __WIN32__ void S9xNPClientLoop (void *) { NetPlay.Waiting4EmulationThread = FALSE; if (S9xNPConnect ()) { S9xClearPause (PAUSE_NETPLAY_CONNECT); while (NetPlay.Connected) { if (S9xNPWaitForHeartBeat ()) { LONG prev; if (!ReleaseSemaphore (GUI.ClientSemaphore, 1, &prev)) { #ifdef NP_DEBUG printf ("CLIENT: ReleaseSemaphore failed - already hit max count (%d) %ld\n", NP_JOYPAD_HIST_SIZE, S9xGetMilliTime () - START); #endif S9xNPSetWarning ("NetPlay: Client may be out of sync with server."); } else { if (!NetPlay.Waiting4EmulationThread && prev == (int) NetPlay.MaxBehindFrameCount) { NetPlay.Waiting4EmulationThread = TRUE; S9xNPSendPause (TRUE); } } } else { S9xNPDisconnect (); } } } else { S9xClearPause (PAUSE_NETPLAY_CONNECT); } #ifdef NP_DEBUG printf ("CLIENT: Client thread exiting @%ld\n", S9xGetMilliTime () - START); #endif } #endif bool8 S9xNPCheckForHeartBeat (uint32 time_msec) { fd_set read_fds; struct timeval timeout; int res; int i; int max_fd = NetPlay.Socket; FD_ZERO (&read_fds); FD_SET (NetPlay.Socket, &read_fds); timeout.tv_sec = 0; timeout.tv_usec = time_msec * 1000; res = select (max_fd + 1, &read_fds, NULL, NULL, &timeout); i = (res > 0 && FD_ISSET(NetPlay.Socket, &read_fds)); #if defined(NP_DEBUG) && NP_DEBUG >= 4 printf ("CLIENT: S9xCheckForHeartBeat %s @%ld\n", (i?"successful":"still waiting"), S9xGetMilliTime () - START); #endif return i; } bool8 S9xNPWaitForHeartBeatDelay (uint32 time_msec) { if (!S9xNPCheckForHeartBeat(time_msec)) return FALSE; if (!S9xNPWaitForHeartBeat()) { S9xNPDisconnect(); return FALSE; } return TRUE; } bool8 S9xNPWaitForHeartBeat () { uint8 header [3 + 4 + 4 * 5]; while (S9xNPGetData (NetPlay.Socket, header, 3 + 4)) { if (header [0] != NP_SERV_MAGIC) { S9xNPSetError ("Bad magic value from server while waiting for heart-beat message\n"); S9xNPDisconnect (); return (FALSE); } if (header [1] != NetPlay.ServerSequenceNum) { char buf [200]; sprintf (buf, "Unexpected message sequence number from server, expected %d, got %d\n", NetPlay.ServerSequenceNum, header [1]); S9xNPSetWarning (buf); NetPlay.ServerSequenceNum = header [1] + 1; } else NetPlay.ServerSequenceNum++; if ((header [2] & 0x1f) == NP_SERV_JOYPAD) { // Top 2 bits + 1 of opcode is joypad data count. int num = (header [2] >> 6) + 1; if (num) { if (!S9xNPGetData (NetPlay.Socket, header + 3 + 4, num * 4)) { S9xNPSetError ("Error while receiving 'JOYPAD' message."); S9xNPDisconnect (); return (FALSE); } } NetPlay.Frame [NetPlay.JoypadWriteInd] = READ_LONG (&header [3]); int i; for (i = 0; i < num; i++) NetPlay.Joypads [NetPlay.JoypadWriteInd][i] = READ_LONG (&header [3 + 4 + i * sizeof (uint32)]); for (i = 0; i < NP_MAX_CLIENTS; i++) NetPlay.JoypadsReady [NetPlay.JoypadWriteInd][i] = TRUE; NetPlay.Paused = (header [2] & 0x20) != 0; NetPlay.JoypadWriteInd = (NetPlay.JoypadWriteInd + 1) % NP_JOYPAD_HIST_SIZE; if (NetPlay.JoypadWriteInd != (NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE) { //printf ("(%d)", (NetPlay.JoypadWriteInd - NetPlay.JoypadReadInd) % NP_JOYPAD_HIST_SIZE); fflush (stdout); } //printf ("CLIENT: HB: @%d\n", S9xGetMilliTime () - START); return (TRUE); } else { uint32 len = READ_LONG (&header [3]); switch (header [2] & 0x1f) { case NP_SERV_RESET: #ifdef NP_DEBUG printf ("CLIENT: RESET received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDiscardHeartbeats (); S9xReset (); NetPlay.FrameCount = READ_LONG (&header [3]); S9xNPResetJoypadReadPos (); S9xNPSendReady (); break; case NP_SERV_PAUSE: NetPlay.Paused = (header [2] & 0x20) != 0; if (NetPlay.Paused) S9xNPSetWarning("CLIENT: Server has paused."); else S9xNPSetWarning("CLIENT: Server has resumed."); break; case NP_SERV_LOAD_ROM: #ifdef NP_DEBUG printf ("CLIENT: LOAD_ROM received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDiscardHeartbeats (); if (S9xNPLoadROM (len - 7)) S9xNPSendReady (NP_CLNT_LOADED_ROM); break; case NP_SERV_ROM_IMAGE: #ifdef NP_DEBUG printf ("CLIENT: ROM_IMAGE received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDiscardHeartbeats (); if (S9xNPGetROMImage (len - 7)) S9xNPSendReady (NP_CLNT_RECEIVED_ROM_IMAGE); break; case NP_SERV_SRAM_DATA: #ifdef NP_DEBUG printf ("CLIENT: SRAM_DATA received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDiscardHeartbeats (); S9xNPGetSRAMData (len - 7); break; case NP_SERV_FREEZE_FILE: #ifdef NP_DEBUG printf ("CLIENT: FREEZE_FILE received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDiscardHeartbeats (); S9xNPGetFreezeFile (len - 7); S9xNPResetJoypadReadPos (); S9xNPSendReady (); break; default: #ifdef NP_DEBUG printf ("CLIENT: UNKNOWN received @%ld\n", S9xGetMilliTime () - START); #endif S9xNPDisconnect (); return (FALSE); } } } S9xNPDisconnect (); return (FALSE); } bool8 S9xNPLoadROMDialog (const char *rom_name) { NetPlay.Answer = FALSE; #ifdef __WIN32__ ResetEvent (NetPlay.ReplyEvent); #ifdef NP_DEBUG printf ("CLIENT: Asking GUI thread to open ROM load dialog...\n"); #endif PostMessage (GUI.hWnd, WM_USER + 3, (uint32) rom_name, (uint32) rom_name); #ifdef NP_DEBUG printf ("CLIENT: Waiting for reply from GUI thread...\n"); #endif WaitForSingleObject (NetPlay.ReplyEvent, INFINITE); #ifdef NP_DEBUG printf ("CLIENT: Got reply from GUI thread (%d)\n", NetPlay.Answer); #endif #else NetPlay.Answer = TRUE; #endif return (NetPlay.Answer); } bool8 S9xNPLoadROM (uint32 len) { uint8 *data = new uint8 [len]; S9xNPSetAction ("Receiving ROM name..."); if (!S9xNPGetData (NetPlay.Socket, data, len)) { S9xNPSetError ("Error while receiving ROM name."); delete[] data; S9xNPDisconnect (); return (FALSE); } S9xNPSetAction ("Opening LoadROM dialog..."); if (!S9xNPLoadROMDialog ((char *) data)) { S9xNPSetError ("Disconnected from NetPlay server because you are playing a different game!"); delete[] data; S9xNPDisconnect (); return (FALSE); } delete[] data; return (TRUE); } bool8 S9xNPGetROMImage (uint32 len) { uint8 rom_info [5]; S9xNPSetAction ("Receiving ROM information..."); if (!S9xNPGetData (NetPlay.Socket, rom_info, 5)) { S9xNPSetError ("Error while receiving ROM information."); S9xNPDisconnect (); return (FALSE); } uint32 CalculatedSize = READ_LONG (&rom_info [1]); #ifdef NP_DEBUG printf ("CLIENT: Hi-ROM: %s, Size: %04x\n", rom_info [0] ? "Y" : "N", CalculatedSize); #endif if (CalculatedSize + 5 >= len || CalculatedSize >= CMemory::MAX_ROM_SIZE) { S9xNPSetError ("Size error in ROM image data received from server."); S9xNPDisconnect (); return (FALSE); } Memory.HiROM = rom_info [0]; Memory.LoROM = !Memory.HiROM; Memory.HeaderCount = 0; Memory.CalculatedSize = CalculatedSize; // Load up ROM image #ifdef NP_DEBUG printf ("CLIENT: Receiving ROM image @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Receiving ROM image..."); if (!S9xNPGetData (NetPlay.Socket, Memory.ROM, Memory.CalculatedSize)) { S9xNPSetError ("Error while receiving ROM image from server."); Settings.StopEmulation = TRUE; S9xNPDisconnect (); return (FALSE); } #ifdef NP_DEBUG printf ("CLIENT: Receiving ROM filename @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Receiving ROM filename..."); uint32 filename_len = len - Memory.CalculatedSize - 5; if (filename_len > PATH_MAX || !S9xNPGetData (NetPlay.Socket, (uint8 *) Memory.ROMFilename, filename_len)) { S9xNPSetError ("Error while receiving ROM filename from server."); S9xNPDisconnect (); Settings.StopEmulation = TRUE; return (FALSE); } Memory.InitROM (); S9xReset (); S9xNPResetJoypadReadPos (); Settings.StopEmulation = FALSE; #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_NULL, 0, 0); #endif return (TRUE); } void S9xNPGetSRAMData (uint32 len) { if (len > 0x10000) { S9xNPSetError ("Length error in S-RAM data received from server."); S9xNPDisconnect (); return; } S9xNPSetAction ("Receiving S-RAM data..."); if (len > 0 && !S9xNPGetData (NetPlay.Socket, Memory.SRAM, len)) { S9xNPSetError ("Error while receiving S-RAM data from server."); S9xNPDisconnect (); } S9xNPSetAction ("", TRUE); } void S9xNPGetFreezeFile (uint32 len) { uint8 frame_count [4]; #ifdef NP_DEBUG printf ("CLIENT: Receiving freeze file information @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Receiving freeze file information..."); if (!S9xNPGetData (NetPlay.Socket, frame_count, 4)) { S9xNPSetError ("Error while receiving freeze file information from server."); S9xNPDisconnect (); return; } NetPlay.FrameCount = READ_LONG (frame_count); #ifdef NP_DEBUG printf ("CLIENT: Receiving freeze file @%ld...\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Receiving freeze file..."); uint8 *data = new uint8 [len]; if (!S9xNPGetData (NetPlay.Socket, data, len - 4)) { S9xNPSetError ("Error while receiving freeze file from server."); S9xNPDisconnect (); delete[] data; return; } S9xNPSetAction ("", TRUE); //FIXME: Setting umask here wouldn't hurt. FILE *file; #ifdef HAVE_MKSTEMP int fd; char fname[] = "/tmp/snes9x_fztmpXXXXXX"; if ((fd = mkstemp(fname)) >= 0) { if ((file = fdopen (fd, "wb"))) #else char fname [L_tmpnam]; if (tmpnam (fname)) { if ((file = fopen (fname, "wb"))) #endif { if (fwrite (data, 1, len, file) == len) { fclose(file); #ifndef __WIN32__ /* We need .s96 extension, else .s96 is added by unix code */ char buf[PATH_MAX +1 ]; strncpy(buf, fname, PATH_MAX); strcat(buf, ".s96"); rename(fname, buf); if (!S9xUnfreezeGame (buf)) #else if (!S9xUnfreezeGame (fname)) #endif S9xNPSetError ("Unable to load freeze file just received."); } else { S9xNPSetError ("Failed to write to temporary freeze file."); fclose(file); } } else { S9xNPSetError ("Failed to create temporary freeze file."); } remove (fname); } else { S9xNPSetError ("Unable to get name for temporary freeze file."); } delete[] data; } uint32 S9xNPGetJoypad (int which1) { if (Settings.NetPlay && which1 < 8) { #ifdef NP_DEBUG if(!NetPlay.JoypadsReady [NetPlay.JoypadReadInd][which1]) { S9xNPSetWarning ("Missing input from server!"); } #endif NetPlay.JoypadsReady [NetPlay.JoypadReadInd][which1] = FALSE; return (NetPlay.Joypads [NetPlay.JoypadReadInd][which1]); } return (0); } void S9xNPStepJoypadHistory () { if ((NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE != NetPlay.JoypadWriteInd) { NetPlay.JoypadReadInd = (NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE; if (NetPlay.FrameCount != NetPlay.Frame [NetPlay.JoypadReadInd]) { S9xNPSetWarning ("This Snes9X session may be out of sync with the server."); #ifdef NP_DEBUG printf ("*** CLIENT: client out of sync with server (%d, %d) @%ld\n", NetPlay.FrameCount, NetPlay.Frame [NetPlay.JoypadReadInd], S9xGetMilliTime () - START); #endif } } else { #ifdef NP_DEBUG printf ("*** CLIENT: S9xNPStepJoypadHistory NOT OK@%ld\n", S9xGetMilliTime () - START); #endif } } void S9xNPResetJoypadReadPos () { #ifdef NP_DEBUG printf ("CLIENT: ResetJoyReadPos @%ld\n", S9xGetMilliTime () - START); fflush (stdout); #endif NetPlay.JoypadWriteInd = 0; NetPlay.JoypadReadInd = NP_JOYPAD_HIST_SIZE - 1; for (int h = 0; h < NP_JOYPAD_HIST_SIZE; h++) memset ((void *) &NetPlay.Joypads [h], 0, sizeof (NetPlay.Joypads [0])); for (int h = 0; h < NP_JOYPAD_HIST_SIZE; h++) memset ((void *) &NetPlay.JoypadsReady [h], 0, sizeof (NetPlay.JoypadsReady [0])); } bool8 S9xNPSendJoypadUpdate (uint32 joypad) { uint8 data [7]; uint8 *ptr = data; *ptr++ = NP_CLNT_MAGIC; *ptr++ = NetPlay.MySequenceNum++; *ptr++ = NP_CLNT_JOYPAD; joypad |= 0x80000000; WRITE_LONG (ptr, joypad); if (!S9xNPSendData (NetPlay.Socket, data, 7)) { S9xNPSetError ("Error while sending joypad data server."); S9xNPDisconnect (); return (FALSE); } return (TRUE); } void S9xNPDisconnect () { close (NetPlay.Socket); NetPlay.Socket = -1; NetPlay.Connected = FALSE; Settings.NetPlay = FALSE; } bool8 S9xNPSendData (int socket, const uint8 *data, int length) { int len = length; const uint8 *ptr = data; NetPlay.PercentageComplete = 0; do { if (NetPlay.Abort) return (FALSE); int num_bytes = len; // Write the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > 512) num_bytes = 512; int sent = write (socket, (char *) ptr, num_bytes); if (sent < 0) { if (errno == EINTR #ifdef EAGAIN || errno == EAGAIN #endif #ifdef EWOULDBLOCK || errno == EWOULDBLOCK #endif ) { #ifdef NP_DEBUG printf ("CLIENT: EINTR, EAGAIN or EWOULDBLOCK while sending data @%ld\n", S9xGetMilliTime () - START); #endif continue; } return (FALSE); } else if (sent == 0) { return (FALSE); } len -= sent; ptr += sent; NetPlay.PercentageComplete = (uint8) (((length - len) * 100) / length); } while (len > 0); return (TRUE); } bool8 S9xNPGetData (int socket, uint8 *data, int length) { int len = length; uint8 *ptr = data; int chunk = length / 50; if (chunk < 1024) chunk = 1024; NetPlay.PercentageComplete = 0; do { if (NetPlay.Abort) return (FALSE); int num_bytes = len; // Read the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > chunk) num_bytes = chunk; int got = read (socket, (char *) ptr, num_bytes); if (got < 0) { if (errno == EINTR #ifdef EAGAIN || errno == EAGAIN #endif #ifdef EWOULDBLOCK || errno == EWOULDBLOCK #endif #ifdef WSAEWOULDBLOCK || errno == WSAEWOULDBLOCK #endif ) { #ifdef NP_DEBUG printf ("CLIENT: EINTR, EAGAIN or EWOULDBLOCK while receiving data @%ld\n", S9xGetMilliTime () - START); #endif continue; } #ifdef WSAEMSGSIZE if (errno != WSAEMSGSIZE) { return (FALSE); } else { got = num_bytes; #ifdef NP_DEBUG printf ("CLIENT: WSAEMSGSIZE, actual bytes %d while receiving data @%ld\n", got, S9xGetMilliTime () - START); #endif } #else return (FALSE); #endif } else if (got == 0) { return (FALSE); } len -= got; ptr += got; if (!Settings.NetPlayServer && length > 1024) { NetPlay.PercentageComplete = (uint8) (((length - len) * 100) / length); #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER, NetPlay.PercentageComplete, NetPlay.PercentageComplete); Sleep (0); #endif } } while (len > 0); return (TRUE); } bool8 S9xNPInitialise () { #ifdef __WIN32__ static bool8 initialised = FALSE; if (!initialised) { initialised = TRUE; WSADATA data; #ifdef NP_DEBUG START = S9xGetMilliTime (); printf ("CLIENT/SERVER: Initialising WinSock @%ld\n", S9xGetMilliTime () - START); #endif S9xNPSetAction ("Initialising Windows sockets interface..."); if (WSAStartup (MAKEWORD (1, 0), &data) != 0) { S9xNPSetError ("Call to init Windows sockets failed. Do you have WinSock2 installed?"); return (FALSE); } } #endif return (TRUE); } void S9xNPDiscardHeartbeats () { // Discard any pending heartbeats and wait for any frame that is currently // being emulated to complete. #ifdef NP_DEBUG printf ("CLIENT: DiscardHeartbeats @%ld, finished @", S9xGetMilliTime () - START); fflush (stdout); #endif #ifdef __WIN32__ while (WaitForSingleObject (GUI.ClientSemaphore, 200) == WAIT_OBJECT_0) ; #endif #ifdef NP_DEBUG printf ("%ld\n", S9xGetMilliTime () - START); #endif NetPlay.Waiting4EmulationThread = FALSE; } void S9xNPSetAction (const char *action, bool8 force) { #ifdef NP_DEBUG printf ("NPSetAction: %s, forced = %d %ld\n", action, force, S9xGetMilliTime () - START); #endif if (force || !Settings.NetPlayServer) { strncpy (NetPlay.ActionMsg, action, NP_MAX_ACTION_LEN - 1); NetPlay.ActionMsg [NP_MAX_ACTION_LEN - 1] = 0; #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER, 0, 0); Sleep (0); #endif } } void S9xNPSetError (const char *error) { #if defined(NP_DEBUG) && NP_DEBUG == 2 printf("ERROR: %s\n", error); fflush (stdout); #endif strncpy (NetPlay.ErrorMsg, error, NP_MAX_ACTION_LEN - 1); NetPlay.ErrorMsg [NP_MAX_ACTION_LEN - 1] = 0; #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER + 1, 0, 0); Sleep (0); #endif } void S9xNPSetWarning (const char *warning) { #if defined(NP_DEBUG) && NP_DEBUG == 3 printf("Warning: %s\n", warning); fflush (stdout); #endif strncpy (NetPlay.WarningMsg, warning, NP_MAX_ACTION_LEN - 1); NetPlay.WarningMsg [NP_MAX_ACTION_LEN - 1] = 0; #ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER + 2, 0, 0); Sleep (0); #endif } #endif memmap.h000664 001750 001750 00000025673 12720446475 013357 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _MEMMAP_H_ #define _MEMMAP_H_ #define MEMMAP_BLOCK_SIZE (0x1000) #define MEMMAP_NUM_BLOCKS (0x1000000 / MEMMAP_BLOCK_SIZE) #define MEMMAP_SHIFT (12) #define MEMMAP_MASK (MEMMAP_BLOCK_SIZE - 1) struct CMemory { enum { MAX_ROM_SIZE = 0x800000 }; enum file_formats { FILE_ZIP, FILE_JMA, FILE_DEFAULT }; enum { NOPE, YEAH, BIGFIRST, SMALLFIRST }; enum { MAP_TYPE_I_O, MAP_TYPE_ROM, MAP_TYPE_RAM }; enum { MAP_CPU, MAP_PPU, MAP_LOROM_SRAM, MAP_LOROM_SRAM_B, MAP_HIROM_SRAM, MAP_DSP, MAP_SA1RAM, MAP_BWRAM, MAP_BWRAM_BITMAP, MAP_BWRAM_BITMAP2, MAP_SPC7110_ROM, MAP_SPC7110_DRAM, MAP_RONLY_SRAM, MAP_C4, MAP_OBC_RAM, MAP_SETA_DSP, MAP_SETA_RISC, MAP_BSX, MAP_NONE, MAP_LAST }; uint8 NSRTHeader[32]; int32 HeaderCount; uint8 *RAM; uint8 *ROM; uint8 *SRAM; uint8 *VRAM; uint8 *FillRAM; uint8 *BWRAM; uint8 *C4RAM; uint8 *OBC1RAM; uint8 *BSRAM; uint8 *BIOSROM; uint8 *Map[MEMMAP_NUM_BLOCKS]; uint8 *WriteMap[MEMMAP_NUM_BLOCKS]; uint8 BlockIsRAM[MEMMAP_NUM_BLOCKS]; uint8 BlockIsROM[MEMMAP_NUM_BLOCKS]; uint8 ExtendedFormat; char ROMFilename[PATH_MAX + 1]; char ROMName[ROM_NAME_LEN]; char RawROMName[ROM_NAME_LEN]; char ROMId[5]; int32 CompanyId; uint8 ROMRegion; uint8 ROMSpeed; uint8 ROMType; uint8 ROMSize; uint32 ROMChecksum; uint32 ROMComplementChecksum; uint32 ROMCRC32; int32 ROMFramesPerSecond; bool8 HiROM; bool8 LoROM; uint8 SRAMSize; uint32 SRAMMask; uint32 CalculatedSize; uint32 CalculatedChecksum; // ports can assign this to perform some custom action upon loading a ROM (such as adjusting controls) void (*PostRomInitFunc) (void); bool8 Init (void); void Deinit (void); int ScoreHiROM (bool8, int32 romoff = 0); int ScoreLoROM (bool8, int32 romoff = 0); uint32 HeaderRemove (uint32, uint8 *); uint32 FileLoader (uint8 *, const char *, uint32); uint32 MemLoader (uint8 *, const char*, uint32); bool8 LoadROMMem (const uint8 *, uint32); bool8 LoadROM (const char *); bool8 LoadROMInt (int32); bool8 LoadMultiCartMem (const uint8 *, uint32, const uint8 *, uint32, const uint8 *, uint32); bool8 LoadMultiCart (const char *, const char *); bool8 LoadMultiCartInt (); bool8 LoadSufamiTurbo (); bool8 LoadSameGame (); bool8 LoadGNEXT (); bool8 LoadSRAM (const char *); bool8 SaveSRAM (const char *); void ClearSRAM (bool8 onlyNonSavedSRAM = 0); bool8 LoadSRTC (void); bool8 SaveSRTC (void); char * Safe (const char *); char * SafeANK (const char *); void ParseSNESHeader (uint8 *); void InitROM (void); uint32 map_mirror (uint32, uint32); void map_lorom (uint32, uint32, uint32, uint32, uint32, bool = true); void map_hirom (uint32, uint32, uint32, uint32, uint32, bool = true); void map_lorom_offset (uint32, uint32, uint32, uint32, uint32, uint32, bool = true); void map_hirom_offset (uint32, uint32, uint32, uint32, uint32, uint32, bool = true); void map_space (uint32, uint32, uint32, uint32, uint8 *, bool = true); void map_index (uint32, uint32, uint32, uint32, int, int, bool = true); void map_System (void); void map_WRAM (void); void map_LoROMSRAM (void); void map_HiROMSRAM (void); void map_DSP (void); void map_C4 (void); void map_OBC1 (void); void map_SetaRISC (void); void map_SetaDSP (void); void map_WriteProtectROM (void); void Map_Initialize (void); void Map_LoROMMap (void); void Map_NoMAD1LoROMMap (void); void Map_JumboLoROMMap (void); void Map_ROM24MBSLoROMMap (void); void Map_SRAM512KLoROMMap (void); void Map_SufamiTurboLoROMMap (void); void Map_SufamiTurboPseudoLoROMMap (void); void Map_SuperFXLoROMMap (void); void Map_SetaDSPLoROMMap (void); void Map_SDD1LoROMMap (void); void Map_SA1LoROMMap (void); void Map_GNEXTSA1LoROMMap (void); void Map_HiROMMap (void); void Map_ExtendedHiROMMap (void); void Map_SameGameHiROMMap (void); void Map_SPC7110HiROMMap (void); uint16 checksum_calc_sum (uint8 *, uint32); uint16 checksum_mirror_sum (uint8 *, uint32 &, uint32 mask = 0x800000); void Checksum_Calculate (void); bool8 match_na (const char *); bool8 match_nn (const char *); bool8 match_nc (const char *); bool8 match_id (const char *); void ApplyROMFixes (void); void CheckForAnyPatch (const char *, bool8, int32 &); void MakeRomInfoText (char *); const char * MapType (void); const char * StaticRAMSize (void); const char * Size (void); const char * Revision (void); const char * KartContents (void); const char * Country (void); const char * PublishingCompany (void); }; struct SMulti { int cartType; int32 cartSizeA, cartSizeB; int32 sramSizeA, sramSizeB; uint32 sramMaskA, sramMaskB; uint32 cartOffsetA, cartOffsetB; uint8 *sramA, *sramB; char fileNameA[PATH_MAX + 1], fileNameB[PATH_MAX + 1]; }; extern CMemory Memory; extern SMulti Multi; void S9xAutoSaveSRAM (void); bool8 LoadZip(const char *, uint32 *, uint8 *); enum s9xwrap_t { WRAP_NONE, WRAP_BANK, WRAP_PAGE }; enum s9xwriteorder_t { WRITE_01, WRITE_10 }; #include "getset.h" #endif logger.cpp000664 001750 001750 00000016764 12720446475 013716 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "movie.h" #include "logger.h" static int resetno = 0; static int framecounter = 0; static FILE *video = NULL; static FILE *audio = NULL; void S9xResetLogger (void) { if (!Settings.DumpStreams) return; char buffer[128]; S9xCloseLogger(); framecounter = 0; sprintf(buffer, "videostream%d.dat", resetno); video = fopen(buffer, "wb"); if (!video) { printf("Opening %s failed. Logging cancelled.\n", buffer); return; } sprintf(buffer, "audiostream%d.dat", resetno); audio = fopen(buffer, "wb"); if (!audio) { printf("Opening %s failed. Logging cancelled.\n", buffer); fclose(video); return; } resetno++; } void S9xCloseLogger (void) { if (video) { fclose(video); video = NULL; } if (audio) { fclose(audio); audio = NULL; } } void S9xVideoLogger (void *pixels, int width, int height, int depth, int bytes_per_line) { int fc = S9xMovieGetFrameCounter(); if (fc > 0) framecounter = fc; else framecounter++; if (video) { char *data = (char *) pixels; size_t ignore; for (int i = 0; i < height; i++) ignore = fwrite(data + i * bytes_per_line, depth, width, video); fflush(video); fflush(audio); if (Settings.DumpStreamsMaxFrames > 0 && framecounter >= Settings.DumpStreamsMaxFrames) { printf("Logging ended.\n"); S9xCloseLogger(); } } } void S9xAudioLogger (void *samples, int length) { if (audio) { size_t ignore; ignore = fwrite(samples, 1, length, audio); } } libretro/jni/000700 001750 001750 00000000000 12724164663 014303 5ustar00sergiosergio000000 000000 tile.cpp000664 001750 001750 00000120571 12720446475 013364 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ // This file includes itself multiple times. // The other option would be to have 4 files, where A includes B, and B includes C 3 times, and C includes D 5 times. // Look for the following marker to find where the divisions are. // Top-level compilation. #ifndef _NEWTILE_CPP #define _NEWTILE_CPP #include "snes9x.h" #include "ppu.h" #include "tile.h" static uint32 pixbit[8][16]; static uint8 hrbit_odd[256]; static uint8 hrbit_even[256]; void S9xInitTileRenderer (void) { register int i; for (i = 0; i < 16; i++) { register uint32 b = 0; #ifdef LSB_FIRST if (i & 8) b |= 1; if (i & 4) b |= 1 << 8; if (i & 2) b |= 1 << 16; if (i & 1) b |= 1 << 24; #else if (i & 8) b |= 1 << 24; if (i & 4) b |= 1 << 16; if (i & 2) b |= 1 << 8; if (i & 1) b |= 1; #endif for (uint8 bitshift = 0; bitshift < 8; bitshift++) pixbit[bitshift][i] = b << bitshift; } for (i = 0; i < 256; i++) { register uint8 m = 0; register uint8 s = 0; if (i & 0x80) s |= 8; if (i & 0x40) m |= 8; if (i & 0x20) s |= 4; if (i & 0x10) m |= 4; if (i & 0x08) s |= 2; if (i & 0x04) m |= 2; if (i & 0x02) s |= 1; if (i & 0x01) m |= 1; hrbit_odd[i] = m; hrbit_even[i] = s; } } // Here are the tile converters, selected by S9xSelectTileConverter(). // Really, except for the definition of DOBIT and the number of times it is called, they're all the same. #define DOBIT(n, i) \ if ((pix = *(tp + (n)))) \ { \ p1 |= pixbit[(i)][pix >> 4]; \ p2 |= pixbit[(i)][pix & 0xf]; \ } static uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32) { register uint8 *tp = &Memory.VRAM[TileAddr]; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; for (line = 8; line != 0; line--, tp += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } static uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32) { register uint8 *tp = &Memory.VRAM[TileAddr]; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; for (line = 8; line != 0; line--, tp += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); DOBIT(16, 2); DOBIT(17, 3); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } static uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32) { register uint8 *tp = &Memory.VRAM[TileAddr]; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; for (line = 8; line != 0; line--, tp += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); DOBIT(16, 2); DOBIT(17, 3); DOBIT(32, 4); DOBIT(33, 5); DOBIT(48, 6); DOBIT(49, 7); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } #undef DOBIT #define DOBIT(n, i) \ if ((pix = hrbit_odd[*(tp1 + (n))])) \ p1 |= pixbit[(i)][pix]; \ if ((pix = hrbit_odd[*(tp2 + (n))])) \ p2 |= pixbit[(i)][pix]; static uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) { register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; if (Tile == 0x3ff) tp2 = tp1 - (0x3ff << 4); else tp2 = tp1 + (1 << 4); for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } static uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) { register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; if (Tile == 0x3ff) tp2 = tp1 - (0x3ff << 5); else tp2 = tp1 + (1 << 5); for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); DOBIT(16, 2); DOBIT(17, 3); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } #undef DOBIT #define DOBIT(n, i) \ if ((pix = hrbit_even[*(tp1 + (n))])) \ p1 |= pixbit[(i)][pix]; \ if ((pix = hrbit_even[*(tp2 + (n))])) \ p2 |= pixbit[(i)][pix]; static uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) { register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; if (Tile == 0x3ff) tp2 = tp1 - (0x3ff << 4); else tp2 = tp1 + (1 << 4); for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } static uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) { register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; uint32 *p = (uint32 *) pCache; uint32 non_zero = 0; uint8 line; if (Tile == 0x3ff) tp2 = tp1 - (0x3ff << 5); else tp2 = tp1 + (1 << 5); for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) { uint32 p1 = 0; uint32 p2 = 0; register uint8 pix; DOBIT( 0, 0); DOBIT( 1, 1); DOBIT(16, 2); DOBIT(17, 3); *p++ = p1; *p++ = p2; non_zero |= p1 | p2; } return (non_zero ? TRUE : BLANK_TILE); } #undef DOBIT // First-level include: Get all the renderers. #include "tile.cpp" // Functions to select which converter and renderer to use. void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj) { void (**DT) (uint32, uint32, uint32, uint32); void (**DCT) (uint32, uint32, uint32, uint32, uint32, uint32); void (**DMP) (uint32, uint32, uint32, uint32, uint32, uint32); void (**DB) (uint32, uint32, uint32); void (**DM7BG1) (uint32, uint32, int); void (**DM7BG2) (uint32, uint32, int); bool8 M7M1, M7M2; M7M1 = PPU.BGMosaic[0] && PPU.Mosaic > 1; M7M2 = PPU.BGMosaic[1] && PPU.Mosaic > 1; bool8 interlace = obj ? FALSE : IPPU.Interlace; bool8 hires = !sub && (BGMode == 5 || BGMode == 6 || IPPU.PseudoHires); if (!IPPU.DoubleWidthPixels) // normal width { DT = Renderers_DrawTile16Normal1x1; DCT = Renderers_DrawClippedTile16Normal1x1; DMP = Renderers_DrawMosaicPixel16Normal1x1; DB = Renderers_DrawBackdrop16Normal1x1; DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Normal1x1 : Renderers_DrawMode7BG1Normal1x1; DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal1x1 : Renderers_DrawMode7BG2Normal1x1; GFX.LinesPerTile = 8; } else if(hires) // hires double width { if (interlace) { DT = Renderers_DrawTile16HiresInterlace; DCT = Renderers_DrawClippedTile16HiresInterlace; DMP = Renderers_DrawMosaicPixel16HiresInterlace; DB = Renderers_DrawBackdrop16Hires; DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Hires : Renderers_DrawMode7BG1Hires; DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Hires : Renderers_DrawMode7BG2Hires; GFX.LinesPerTile = 4; } else { DT = Renderers_DrawTile16Hires; DCT = Renderers_DrawClippedTile16Hires; DMP = Renderers_DrawMosaicPixel16Hires; DB = Renderers_DrawBackdrop16Hires; DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Hires : Renderers_DrawMode7BG1Hires; DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Hires : Renderers_DrawMode7BG2Hires; GFX.LinesPerTile = 8; } } else // normal double width { if (interlace) { DT = Renderers_DrawTile16Interlace; DCT = Renderers_DrawClippedTile16Interlace; DMP = Renderers_DrawMosaicPixel16Interlace; DB = Renderers_DrawBackdrop16Normal2x1; DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Normal2x1 : Renderers_DrawMode7BG1Normal2x1; DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal2x1 : Renderers_DrawMode7BG2Normal2x1; GFX.LinesPerTile = 4; } else { DT = Renderers_DrawTile16Normal2x1; DCT = Renderers_DrawClippedTile16Normal2x1; DMP = Renderers_DrawMosaicPixel16Normal2x1; DB = Renderers_DrawBackdrop16Normal2x1; DM7BG1 = M7M1 ? Renderers_DrawMode7MosaicBG1Normal2x1 : Renderers_DrawMode7BG1Normal2x1; DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal2x1 : Renderers_DrawMode7BG2Normal2x1; GFX.LinesPerTile = 8; } } GFX.DrawTileNomath = DT[0]; GFX.DrawClippedTileNomath = DCT[0]; GFX.DrawMosaicPixelNomath = DMP[0]; GFX.DrawBackdropNomath = DB[0]; GFX.DrawMode7BG1Nomath = DM7BG1[0]; GFX.DrawMode7BG2Nomath = DM7BG2[0]; int i; if (!Settings.Transparency) i = 0; else { i = (Memory.FillRAM[0x2131] & 0x80) ? 4 : 1; if (Memory.FillRAM[0x2131] & 0x40) { i++; if (Memory.FillRAM[0x2130] & 2) i++; } } GFX.DrawTileMath = DT[i]; GFX.DrawClippedTileMath = DCT[i]; GFX.DrawMosaicPixelMath = DMP[i]; GFX.DrawBackdropMath = DB[i]; GFX.DrawMode7BG1Math = DM7BG1[i]; GFX.DrawMode7BG2Math = DM7BG2[i]; } void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic) { switch (depth) { case 8: BG.ConvertTile = BG.ConvertTileFlip = ConvertTile8; BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_8BIT]; BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_8BIT]; BG.TileShift = 6; BG.PaletteShift = 0; BG.PaletteMask = 0; BG.DirectColourMode = Memory.FillRAM[0x2130] & 1; break; case 4: if (hires) { if (sub || mosaic) { BG.ConvertTile = ConvertTile4h_even; BG.Buffer = IPPU.TileCache[TILE_4BIT_EVEN]; BG.Buffered = IPPU.TileCached[TILE_4BIT_EVEN]; BG.ConvertTileFlip = ConvertTile4h_odd; BG.BufferFlip = IPPU.TileCache[TILE_4BIT_ODD]; BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_ODD]; } else { BG.ConvertTile = ConvertTile4h_odd; BG.Buffer = IPPU.TileCache[TILE_4BIT_ODD]; BG.Buffered = IPPU.TileCached[TILE_4BIT_ODD]; BG.ConvertTileFlip = ConvertTile4h_even; BG.BufferFlip = IPPU.TileCache[TILE_4BIT_EVEN]; BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_EVEN]; } } else { BG.ConvertTile = BG.ConvertTileFlip = ConvertTile4; BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_4BIT]; BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_4BIT]; } BG.TileShift = 5; BG.PaletteShift = 10 - 4; BG.PaletteMask = 7 << 4; BG.DirectColourMode = FALSE; break; case 2: if (hires) { if (sub || mosaic) { BG.ConvertTile = ConvertTile2h_even; BG.Buffer = IPPU.TileCache[TILE_2BIT_EVEN]; BG.Buffered = IPPU.TileCached[TILE_2BIT_EVEN]; BG.ConvertTileFlip = ConvertTile2h_odd; BG.BufferFlip = IPPU.TileCache[TILE_2BIT_ODD]; BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_ODD]; } else { BG.ConvertTile = ConvertTile2h_odd; BG.Buffer = IPPU.TileCache[TILE_2BIT_ODD]; BG.Buffered = IPPU.TileCached[TILE_2BIT_ODD]; BG.ConvertTileFlip = ConvertTile2h_even; BG.BufferFlip = IPPU.TileCache[TILE_2BIT_EVEN]; BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_EVEN]; } } else { BG.ConvertTile = BG.ConvertTileFlip = ConvertTile2; BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_2BIT]; BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_2BIT]; } BG.TileShift = 4; BG.PaletteShift = 10 - 2; BG.PaletteMask = 7 << 2; BG.DirectColourMode = FALSE; break; } } /*****************************************************************************/ #else #ifndef NAME1 // First-level: Get all the renderers. /*****************************************************************************/ #define GET_CACHED_TILE() \ uint32 TileNumber; \ uint32 TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift); \ if (Tile & 0x100) \ TileAddr += BG.NameSelect; \ TileAddr &= 0xffff; \ TileNumber = TileAddr >> BG.TileShift; \ if (Tile & H_FLIP) \ { \ pCache = &BG.BufferFlip[TileNumber << 6]; \ if (!BG.BufferedFlip[TileNumber]) \ BG.BufferedFlip[TileNumber] = BG.ConvertTileFlip(pCache, TileAddr, Tile & 0x3ff); \ } \ else \ { \ pCache = &BG.Buffer[TileNumber << 6]; \ if (!BG.Buffered[TileNumber]) \ BG.Buffered[TileNumber] = BG.ConvertTile(pCache, TileAddr, Tile & 0x3ff); \ } #define IS_BLANK_TILE() \ ( ( (Tile & H_FLIP) ? BG.BufferedFlip[TileNumber] : BG.Buffered[TileNumber]) == BLANK_TILE) #define SELECT_PALETTE() \ if (BG.DirectColourMode) \ { \ if (IPPU.DirectColourMapsNeedRebuild) \ S9xBuildDirectColourMaps(); \ GFX.RealScreenColors = DirectColourMaps[(Tile >> 10) & 7]; \ } \ else \ GFX.RealScreenColors = &IPPU.ScreenColors[((Tile >> BG.PaletteShift) & BG.PaletteMask) + BG.StartPalette]; \ GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors #define NOMATH(Op, Main, Sub, SD) \ (Main) #define REGMATH(Op, Main, Sub, SD) \ (COLOR_##Op((Main), ((SD) & 0x20) ? (Sub) : GFX.FixedColour)) #define MATHF1_2(Op, Main, Sub, SD) \ (GFX.ClipColors ? (COLOR_##Op((Main), GFX.FixedColour)) : (COLOR_##Op##1_2((Main), GFX.FixedColour))) #define MATHS1_2(Op, Main, Sub, SD) \ (GFX.ClipColors ? REGMATH(Op, Main, Sub, SD) : (((SD) & 0x20) ? COLOR_##Op##1_2((Main), (Sub)) : COLOR_##Op((Main), GFX.FixedColour))) // Basic routine to render an unclipped tile. // Input parameters: // BPSTART = either StartLine or (StartLine * 2 + BG.InterlaceLine), // so interlace modes can render every other line from the tile. // PITCH = 1 or 2, again so interlace can count lines properly. // DRAW_PIXEL(N, M) is a routine to actually draw the pixel. N is the pixel in the row to draw, // and M is a test which if false means the pixel should be skipped. // Z1 is the "draw if Z1 > cur_depth". // Z2 is the "cur_depth = new_depth". OBJ need the two separate. // Pix is the pixel to draw. #define Z1 GFX.Z1 #define Z2 GFX.Z2 #define DRAW_TILE() \ uint8 *pCache; \ register int32 l; \ register uint8 *bp, Pix; \ \ GET_CACHED_TILE(); \ if (IS_BLANK_TILE()) \ return; \ SELECT_PALETTE(); \ \ if (!(Tile & (V_FLIP | H_FLIP))) \ { \ bp = pCache + BPSTART; \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ { \ DRAW_PIXEL(0, Pix = bp[0]); \ DRAW_PIXEL(1, Pix = bp[1]); \ DRAW_PIXEL(2, Pix = bp[2]); \ DRAW_PIXEL(3, Pix = bp[3]); \ DRAW_PIXEL(4, Pix = bp[4]); \ DRAW_PIXEL(5, Pix = bp[5]); \ DRAW_PIXEL(6, Pix = bp[6]); \ DRAW_PIXEL(7, Pix = bp[7]); \ } \ } \ else \ if (!(Tile & V_FLIP)) \ { \ bp = pCache + BPSTART; \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ { \ DRAW_PIXEL(0, Pix = bp[7]); \ DRAW_PIXEL(1, Pix = bp[6]); \ DRAW_PIXEL(2, Pix = bp[5]); \ DRAW_PIXEL(3, Pix = bp[4]); \ DRAW_PIXEL(4, Pix = bp[3]); \ DRAW_PIXEL(5, Pix = bp[2]); \ DRAW_PIXEL(6, Pix = bp[1]); \ DRAW_PIXEL(7, Pix = bp[0]); \ } \ } \ else \ if (!(Tile & H_FLIP)) \ { \ bp = pCache + 56 - BPSTART; \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ { \ DRAW_PIXEL(0, Pix = bp[0]); \ DRAW_PIXEL(1, Pix = bp[1]); \ DRAW_PIXEL(2, Pix = bp[2]); \ DRAW_PIXEL(3, Pix = bp[3]); \ DRAW_PIXEL(4, Pix = bp[4]); \ DRAW_PIXEL(5, Pix = bp[5]); \ DRAW_PIXEL(6, Pix = bp[6]); \ DRAW_PIXEL(7, Pix = bp[7]); \ } \ } \ else \ { \ bp = pCache + 56 - BPSTART; \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ { \ DRAW_PIXEL(0, Pix = bp[7]); \ DRAW_PIXEL(1, Pix = bp[6]); \ DRAW_PIXEL(2, Pix = bp[5]); \ DRAW_PIXEL(3, Pix = bp[4]); \ DRAW_PIXEL(4, Pix = bp[3]); \ DRAW_PIXEL(5, Pix = bp[2]); \ DRAW_PIXEL(6, Pix = bp[1]); \ DRAW_PIXEL(7, Pix = bp[0]); \ } \ } #define NAME1 DrawTile16 #define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount // Second-level include: Get the DrawTile16 renderers. #include "tile.cpp" #undef NAME1 #undef ARGS #undef DRAW_TILE #undef Z1 #undef Z2 // Basic routine to render a clipped tile. Inputs same as above. #define Z1 GFX.Z1 #define Z2 GFX.Z2 #define DRAW_TILE() \ uint8 *pCache; \ register int32 l; \ register uint8 *bp, Pix, w; \ \ GET_CACHED_TILE(); \ if (IS_BLANK_TILE()) \ return; \ SELECT_PALETTE(); \ \ if (!(Tile & (V_FLIP | H_FLIP))) \ { \ bp = pCache + BPSTART; \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ { \ w = Width; \ switch (StartPixel) \ { \ case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; \ case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \ } \ } \ } \ else \ if (!(Tile & V_FLIP)) \ { \ bp = pCache + BPSTART; \ for (l = LineCount; l > 0; l--, bp += 8 * PITCH, Offset += GFX.PPL) \ { \ w = Width; \ switch (StartPixel) \ { \ case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; \ case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \ } \ } \ } \ else \ if (!(Tile & H_FLIP)) \ { \ bp = pCache + 56 - BPSTART; \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ { \ w = Width; \ switch (StartPixel) \ { \ case 0: DRAW_PIXEL(0, Pix = bp[0]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[1]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[2]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[3]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[4]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[5]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[6]); if (!--w) break; \ case 7: DRAW_PIXEL(7, Pix = bp[7]); break; \ } \ } \ } \ else \ { \ bp = pCache + 56 - BPSTART; \ for (l = LineCount; l > 0; l--, bp -= 8 * PITCH, Offset += GFX.PPL) \ { \ w = Width; \ switch (StartPixel) \ { \ case 0: DRAW_PIXEL(0, Pix = bp[7]); if (!--w) break; \ case 1: DRAW_PIXEL(1, Pix = bp[6]); if (!--w) break; \ case 2: DRAW_PIXEL(2, Pix = bp[5]); if (!--w) break; \ case 3: DRAW_PIXEL(3, Pix = bp[4]); if (!--w) break; \ case 4: DRAW_PIXEL(4, Pix = bp[3]); if (!--w) break; \ case 5: DRAW_PIXEL(5, Pix = bp[2]); if (!--w) break; \ case 6: DRAW_PIXEL(6, Pix = bp[1]); if (!--w) break; \ case 7: DRAW_PIXEL(7, Pix = bp[0]); break; \ } \ } \ } #define NAME1 DrawClippedTile16 #define ARGS uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount // Second-level include: Get the DrawClippedTile16 renderers. #include "tile.cpp" #undef NAME1 #undef ARGS #undef DRAW_TILE #undef Z1 #undef Z2 // Basic routine to render a single mosaic pixel. // DRAW_PIXEL, BPSTART, Z1, Z2 and Pix are the same as above, but PITCH is not used. #define Z1 GFX.Z1 #define Z2 GFX.Z2 #define DRAW_TILE() \ uint8 *pCache; \ register int32 l, w; \ register uint8 Pix; \ \ GET_CACHED_TILE(); \ if (IS_BLANK_TILE()) \ return; \ SELECT_PALETTE(); \ \ if (Tile & H_FLIP) \ StartPixel = 7 - StartPixel; \ \ if (Tile & V_FLIP) \ Pix = pCache[56 - BPSTART + StartPixel]; \ else \ Pix = pCache[BPSTART + StartPixel]; \ \ if (Pix) \ { \ for (l = LineCount; l > 0; l--, Offset += GFX.PPL) \ { \ for (w = Width - 1; w >= 0; w--) \ DRAW_PIXEL(w, 1); \ } \ } #define NAME1 DrawMosaicPixel16 #define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount // Second-level include: Get the DrawMosaicPixel16 renderers. #include "tile.cpp" #undef NAME1 #undef ARGS #undef DRAW_TILE #undef Z1 #undef Z2 // Basic routine to render the backdrop. // DRAW_PIXEL is the same as above, but since we're just replicating a single pixel there's no need for PITCH or BPSTART // (or interlace at all, really). // The backdrop is always depth = 1, so Z1 = Z2 = 1. And backdrop is always color 0. #define NO_INTERLACE 1 #define Z1 1 #define Z2 1 #define Pix 0 #define DRAW_TILE() \ register uint32 l, x; \ \ GFX.RealScreenColors = IPPU.ScreenColors; \ GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \ \ for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) \ { \ for (x = Left; x < Right; x++) \ DRAW_PIXEL(x, 1); \ } #define NAME1 DrawBackdrop16 #define ARGS uint32 Offset, uint32 Left, uint32 Right // Second-level include: Get the DrawBackdrop16 renderers. #include "tile.cpp" #undef NAME1 #undef ARGS #undef DRAW_TILE #undef Pix #undef Z1 #undef Z2 #undef NO_INTERLACE // Basic routine to render a chunk of a Mode 7 BG. // Mode 7 has no interlace, so BPSTART and PITCH are unused. // We get some new parameters, so we can use the same DRAW_TILE to do BG1 or BG2: // DCMODE tests if Direct Color should apply. // BG is the BG, so we use the right clip window. // MASK is 0xff or 0x7f, the 'color' portion of the pixel. // We define Z1/Z2 to either be constant 5 or to vary depending on the 'priority' portion of the pixel. #define CLIP_10_BIT_SIGNED(a) (((a) & 0x2000) ? ((a) | ~0x3ff) : ((a) & 0x3ff)) extern struct SLineMatrixData LineMatrixData[240]; #define NO_INTERLACE 1 #define Z1 (D + 7) #define Z2 (D + 7) #define MASK 0xff #define DCMODE (Memory.FillRAM[0x2130] & 1) #define BG 0 #define DRAW_TILE_NORMAL() \ uint8 *VRAM1 = Memory.VRAM + 1; \ \ if (DCMODE) \ { \ if (IPPU.DirectColourMapsNeedRebuild) \ S9xBuildDirectColourMaps(); \ GFX.RealScreenColors = DirectColourMaps[0]; \ } \ else \ GFX.RealScreenColors = IPPU.ScreenColors; \ \ GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \ \ int aa, cc; \ int startx; \ \ uint32 Offset = GFX.StartY * GFX.PPL; \ struct SLineMatrixData *l = &LineMatrixData[GFX.StartY]; \ \ for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Offset += GFX.PPL, l++) \ { \ int yy, starty; \ \ int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; \ int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \ \ int32 CentreX = ((int32) l->CentreX << 19) >> 19; \ int32 CentreY = ((int32) l->CentreY << 19) >> 19; \ \ if (PPU.Mode7VFlip) \ starty = 255 - (int) (Line + 1); \ else \ starty = Line + 1; \ \ yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \ \ int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \ int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \ \ if (PPU.Mode7HFlip) \ { \ startx = Right - 1; \ aa = -l->MatrixA; \ cc = -l->MatrixC; \ } \ else \ { \ startx = Left; \ aa = l->MatrixA; \ cc = l->MatrixC; \ } \ \ int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \ int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \ int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \ \ uint8 Pix; \ \ if (!PPU.Mode7Repeat) \ { \ for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \ { \ int X = ((AA + BB) >> 8) & 0x3ff; \ int Y = ((CC + DD) >> 8) & 0x3ff; \ \ uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ \ DRAW_PIXEL(x, Pix = (b & MASK)); \ } \ } \ else \ { \ for (uint32 x = Left; x < Right; x++, AA += aa, CC += cc) \ { \ int X = ((AA + BB) >> 8); \ int Y = ((CC + DD) >> 8); \ \ uint8 b; \ \ if (((X | Y) & ~0x3ff) == 0) \ { \ uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ } \ else \ if (PPU.Mode7Repeat == 3) \ b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \ else \ continue; \ \ DRAW_PIXEL(x, Pix = (b & MASK)); \ } \ } \ } #define DRAW_TILE_MOSAIC() \ uint8 *VRAM1 = Memory.VRAM + 1; \ \ if (DCMODE) \ { \ if (IPPU.DirectColourMapsNeedRebuild) \ S9xBuildDirectColourMaps(); \ GFX.RealScreenColors = DirectColourMaps[0]; \ } \ else \ GFX.RealScreenColors = IPPU.ScreenColors; \ \ GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; \ \ int aa, cc; \ int startx, StartY = GFX.StartY; \ \ int HMosaic = 1, VMosaic = 1, MosaicStart = 0; \ int32 MLeft = Left, MRight = Right; \ \ if (PPU.BGMosaic[0]) \ { \ VMosaic = PPU.Mosaic; \ MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % VMosaic; \ StartY -= MosaicStart; \ } \ \ if (PPU.BGMosaic[BG]) \ { \ HMosaic = PPU.Mosaic; \ MLeft -= MLeft % HMosaic; \ MRight += HMosaic - 1; \ MRight -= MRight % HMosaic; \ } \ \ uint32 Offset = StartY * GFX.PPL; \ struct SLineMatrixData *l = &LineMatrixData[StartY]; \ \ for (uint32 Line = StartY; Line <= GFX.EndY; Line += VMosaic, Offset += VMosaic * GFX.PPL, l += VMosaic) \ { \ if (Line + VMosaic > GFX.EndY) \ VMosaic = GFX.EndY - Line + 1; \ \ int yy, starty; \ \ int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; \ int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \ \ int32 CentreX = ((int32) l->CentreX << 19) >> 19; \ int32 CentreY = ((int32) l->CentreY << 19) >> 19; \ \ if (PPU.Mode7VFlip) \ starty = 255 - (int) (Line + 1); \ else \ starty = Line + 1; \ \ yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \ \ int BB = ((l->MatrixB * starty) & ~63) + ((l->MatrixB * yy) & ~63) + (CentreX << 8); \ int DD = ((l->MatrixD * starty) & ~63) + ((l->MatrixD * yy) & ~63) + (CentreY << 8); \ \ if (PPU.Mode7HFlip) \ { \ startx = MRight - 1; \ aa = -l->MatrixA; \ cc = -l->MatrixC; \ } \ else \ { \ startx = MLeft; \ aa = l->MatrixA; \ cc = l->MatrixC; \ } \ \ int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \ int AA = l->MatrixA * startx + ((l->MatrixA * xx) & ~63); \ int CC = l->MatrixC * startx + ((l->MatrixC * xx) & ~63); \ \ uint8 Pix; \ uint8 ctr = 1; \ \ if (!PPU.Mode7Repeat) \ { \ for (int32 x = MLeft; x < MRight; x++, AA += aa, CC += cc) \ { \ if (--ctr) \ continue; \ ctr = HMosaic; \ \ int X = ((AA + BB) >> 8) & 0x3ff; \ int Y = ((CC + DD) >> 8) & 0x3ff; \ \ uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ \ if ((Pix = (b & MASK))) \ { \ for (int32 h = MosaicStart; h < VMosaic; h++) \ { \ for (int32 w = x + HMosaic - 1; w >= x; w--) \ DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \ } \ } \ } \ } \ else \ { \ for (int32 x = MLeft; x < MRight; x++, AA += aa, CC += cc) \ { \ if (--ctr) \ continue; \ ctr = HMosaic; \ \ int X = ((AA + BB) >> 8); \ int Y = ((CC + DD) >> 8); \ \ uint8 b; \ \ if (((X | Y) & ~0x3ff) == 0) \ { \ uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ } \ else \ if (PPU.Mode7Repeat == 3) \ b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \ else \ continue; \ \ if ((Pix = (b & MASK))) \ { \ for (int32 h = MosaicStart; h < VMosaic; h++) \ { \ for (int32 w = x + HMosaic - 1; w >= x; w--) \ DRAW_PIXEL(w + h * GFX.PPL, (w >= (int32) Left && w < (int32) Right)); \ } \ } \ } \ } \ \ MosaicStart = 0; \ } #define DRAW_TILE() DRAW_TILE_NORMAL() #define NAME1 DrawMode7BG1 #define ARGS uint32 Left, uint32 Right, int D // Second-level include: Get the DrawMode7BG1 renderers. #include "tile.cpp" #undef NAME1 #undef DRAW_TILE #define DRAW_TILE() DRAW_TILE_MOSAIC() #define NAME1 DrawMode7MosaicBG1 // Second-level include: Get the DrawMode7MosaicBG1 renderers. #include "tile.cpp" #undef DRAW_TILE #undef NAME1 #undef Z1 #undef Z2 #undef MASK #undef DCMODE #undef BG #define NAME1 DrawMode7BG2 #define DRAW_TILE() DRAW_TILE_NORMAL() #define Z1 (D + ((b & 0x80) ? 11 : 3)) #define Z2 (D + ((b & 0x80) ? 11 : 3)) #define MASK 0x7f #define DCMODE 0 #define BG 1 // Second-level include: Get the DrawMode7BG2 renderers. #include "tile.cpp" #undef NAME1 #undef DRAW_TILE #define DRAW_TILE() DRAW_TILE_MOSAIC() #define NAME1 DrawMode7MosaicBG2 // Second-level include: Get the DrawMode7MosaicBG2 renderers. #include "tile.cpp" #undef MASK #undef DCMODE #undef BG #undef NAME1 #undef ARGS #undef DRAW_TILE #undef DRAW_TILE_NORMAL #undef DRAW_TILE_MOSAIC #undef Z1 #undef Z2 #undef NO_INTERLACE /*****************************************************************************/ #else #ifndef NAME2 // Second-level: Get all the NAME1 renderers. /*****************************************************************************/ #define BPSTART StartLine #define PITCH 1 // The 1x1 pixel plotter, for speedhacking modes. #define DRAW_PIXEL(N, M) \ if (Z1 > GFX.DB[Offset + N] && (M)) \ { \ GFX.S[Offset + N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + N], GFX.SubZBuffer[Offset + N]); \ GFX.DB[Offset + N] = Z2; \ } #define NAME2 Normal1x1 // Third-level include: Get the Normal1x1 renderers. #include "tile.cpp" #undef NAME2 #undef DRAW_PIXEL // The 2x1 pixel plotter, for normal rendering when we've used hires/interlace already this frame. #define DRAW_PIXEL_N2x1(N, M) \ if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \ { \ GFX.S[Offset + 2 * N] = GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \ GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \ } #define DRAW_PIXEL(N, M) DRAW_PIXEL_N2x1(N, M) #define NAME2 Normal2x1 // Third-level include: Get the Normal2x1 renderers. #include "tile.cpp" #undef NAME2 #undef DRAW_PIXEL // Hires pixel plotter, this combines the main and subscreen pixels as appropriate to render hires or pseudo-hires images. // Use it only on the main screen, subscreen should use Normal2x1 instead. // Hires math: // Main pixel is mathed as normal: Main(x, y) * Sub(x, y). // Sub pixel is mathed somewhat weird: Basically, for Sub(x + 1, y) we apply the same operation we applied to Main(x, y) // (e.g. no math, add fixed, add1/2 subscreen) using Main(x, y) as the "corresponding subscreen pixel". // Also, color window clipping clips Sub(x + 1, y) if Main(x, y) is clipped, not Main(x + 1, y). // We don't know how Sub(0, y) is handled. #define DRAW_PIXEL_H2x1(N, M) \ if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \ { \ GFX.S[Offset + 2 * N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \ GFX.S[Offset + 2 * N + 1] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \ GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \ } /* The logic above shifts everything one pixel to the left, thus producing a blank line on the right. The code below places the pixel on correct positions but would incur two additional branches for the edges on every pixel. */ //#define DRAW_PIXEL_H2x1(N, M) \ // if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \ // { \ // GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \ // if ((Offset + 2 * N ) % GFX.RealPPL != (SNES_WIDTH - 1) << 1) \ // GFX.S[Offset + 2 * N + 2] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \ // if ((Offset + 2 * N) % GFX.RealPPL == 0) \ // GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \ // GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \ // } #define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M) #define NAME2 Hires // Third-level include: Get the Hires renderers. #include "tile.cpp" #undef NAME2 #undef DRAW_PIXEL // Interlace: Only draw every other line, so we'll redefine BPSTART and PITCH to do so. // Otherwise, it's the same as Normal2x1/Hires2x1. #undef BPSTART #undef PITCH #define BPSTART (StartLine * 2 + BG.InterlaceLine) #define PITCH 2 #ifndef NO_INTERLACE #define DRAW_PIXEL(N, M) DRAW_PIXEL_N2x1(N, M) #define NAME2 Interlace // Third-level include: Get the double width Interlace renderers. #include "tile.cpp" #undef NAME2 #undef DRAW_PIXEL #define DRAW_PIXEL(N, M) DRAW_PIXEL_H2x1(N, M) #define NAME2 HiresInterlace // Third-level include: Get the HiresInterlace renderers. #include "tile.cpp" #undef NAME2 #undef DRAW_PIXEL #endif #undef BPSTART #undef PITCH /*****************************************************************************/ #else // Third-level: Renderers for each math mode for NAME1 + NAME2. /*****************************************************************************/ #define CONCAT3(A, B, C) A##B##C #define MAKENAME(A, B, C) CONCAT3(A, B, C) static void MAKENAME(NAME1, _, NAME2) (ARGS) { #define MATH(A, B, C) NOMATH(x, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, Add_, NAME2) (ARGS) { #define MATH(A, B, C) REGMATH(ADD, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, AddF1_2_, NAME2) (ARGS) { #define MATH(A, B, C) MATHF1_2(ADD, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, AddS1_2_, NAME2) (ARGS) { #define MATH(A, B, C) MATHS1_2(ADD, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, Sub_, NAME2) (ARGS) { #define MATH(A, B, C) REGMATH(SUB, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, SubF1_2_, NAME2) (ARGS) { #define MATH(A, B, C) MATHF1_2(SUB, A, B, C) DRAW_TILE(); #undef MATH } static void MAKENAME(NAME1, SubS1_2_, NAME2) (ARGS) { #define MATH(A, B, C) MATHS1_2(SUB, A, B, C) DRAW_TILE(); #undef MATH } static void (*MAKENAME(Renderers_, NAME1, NAME2)[7]) (ARGS) = { MAKENAME(NAME1, _, NAME2), MAKENAME(NAME1, Add_, NAME2), MAKENAME(NAME1, AddF1_2_, NAME2), MAKENAME(NAME1, AddS1_2_, NAME2), MAKENAME(NAME1, Sub_, NAME2), MAKENAME(NAME1, SubF1_2_, NAME2), MAKENAME(NAME1, SubS1_2_, NAME2) }; #undef MAKENAME #undef CONCAT3 #endif #endif #endif fxdbg.cpp000664 001750 001750 00000054657 12720446475 013534 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef DEBUGGER #include "snes9x.h" #include "fxinst.h" #include "fxemu.h" /* When printing a line from the pipe, it could look like this: 01:8006 f4 fb 86 iwt r4, #$86fb The values are: program bank : 01 adress : 8006 values at memory address 8006 : f4 fb 86 instruction in the pipe : iwt r4, #$86fb Note! If the instruction has more than one byte (like in 'iwt') and the instruction is in a delay slot, the second and third byte displayed will not be the same as those used. Since the instrction is in a delay slot, the first byte of the instruction will be taken from the pipe at the address after the branch instruction, and the next one or two bytes will be taken from the address that the branch points to. This is a bit complicated, but I've taken this into account, in this debug function. (See the diffrence of how the values vPipe1 and vPipe2 are read, compared to the values vByte1 and vByte2) */ /* static const char *fx_apvMnemonicTable[] = { // ALT0 Table // 00 - 0f "stop", "nop", "cache", "lsr", "rol", "bra $%04x", "blt $%04x", "bge $%04x", "bne $%04x", "beq $%04x", "bpl $%04x", "bmi $%04x", "bcc $%04x", "bcs $%04x", "bvc $%04x", "bvs $%04x", // 10 - 1f "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", // 20 - 2f "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", // 30 - 3f "stw (r0)", "stw (r1)", "stw (r2)", "stw (r3)", "stw (r4)", "stw (r5)", "stw (r6)", "stw (r7)", "stw (r8)", "stw (r9)", "stw (r10)", "stw (r11)", "loop", "alt1", "alt2", "alt3", // 40 - 4f "ldw (r0)", "ldw (r1)", "ldw (r2)", "ldw (r3)", "ldw (r4)", "ldw (r5)", "ldw (r6)", "ldw (r7)", "ldw (r8)", "ldw (r9)", "ldw (r10)", "ldw (r11)", "plot", "swap", "color", "not", // 50 - 5f "add r0", "add r1", "add r2", "add r3", "add r4", "add r5", "add r6", "add r7", "add r8", "add r9", "add r10", "add r11", "add r12", "add r13", "add r14", "add r15", // 60 - 6f "sub r0", "sub r1", "sub r2", "sub r3", "sub r4", "sub r5", "sub r6", "sub r7", "sub r8", "sub r9", "sub r10", "sub r11", "sub r12", "sub r13", "sub r14", "sub r15", // 70 - 7f "merge", "and r1", "and r2", "and r3", "and r4", "and r5", "and r6", "and r7", "and r8", "and r9", "and r10", "and r11", "and r12", "and r13", "and r14", "and r15", // 80 - 8f "mult r0", "mult r1", "mult r2", "mult r3", "mult r4", "mult r5", "mult r6", "mult r7", "mult r8", "mult r9", "mult r10", "mult r11", "mult r12", "mult r13", "mult r14", "mult r15", // 90 - 9f "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "asr", "ror", "jmp (r8)", "jmp (r9)", "jmp (r10)", "jmp (r11)", "jmp (r12)", "jmp (r13)", "lob", "fmult", // a0 - af "ibt r0, #$%02x", "ibt r1, #$%02x", "ibt r2, #$%02x", "ibt r3, #$%02x", "ibt r4, #$%02x", "ibt r5, #$%02x", "ibt r6, #$%02x", "ibt r7, #$%02x", "ibt r8, #$%02x", "ibt r9, #$%02x", "ibt r10, #$%02x", "ibt r11, #$%02x", "ibt r12, #$%02x", "ibt r13, #$%02x", "ibt r14, #$%02x", "ibt r15, #$%02x", // b0 - bf "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", // c0 - cf "hib", "or r1", "or r2", "or r3", "or r4", "or r5", "or r6", "or r7", "or r8", "or r9", "or r10", "or r11", "or r12", "or r13", "or r14", "or r15", // d0 - df "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "getc", // e0 - ef "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getb", // f0 - ff "iwt r0, #$%04x", "iwt r1, #$%04x", "iwt r2, #$%04x", "iwt r3, #$%04x", "iwt r4, #$%04x", "iwt r5, #$%04x", "iwt r6, #$%04x", "iwt r7, #$%04x", "iwt r8, #$%04x", "iwt r9, #$%04x", "iwt r10, #$%04x", "iwt r11, #$%04x", "iwt r12, #$%04x", "iwt r13, #$%04x", "iwt r14, #$%04x", "iwt r15, #$%04x", // ALT1 Table // 00 - 0f "stop", "nop", "cache", "lsr", "rol", "bra $%04x", "blt $%04x", "bge $%04x", "bne $%04x", "beq $%04x", "bpl $%04x", "bmi $%04x", "bcc $%04x", "bcs $%04x", "bvc $%04x", "bvs $%04x", // 10 - 1f "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", // 20 - 2f "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", // 30 - 3f "stb (r0)", "stb (r1)", "stb (r2)", "stb (r3)", "stb (r4)", "stb (r5)", "stb (r6)", "stb (r7)", "stb (r8)", "stb (r9)", "stb (r10)", "stb (r11)", "loop", "alt1", "alt2", "alt3", // 40 - 4f "ldb (r0)", "ldb (r1)", "ldb (r2)", "ldb (r3)", "ldb (r4)", "ldb (r5)", "ldb (r6)", "ldb (r7)", "ldb (r8)", "ldb (r9)", "ldb (r10)", "ldb (r11)", "rpix", "swap", "cmode", "not", // 50 - 5f "adc r0", "adc r1", "adc r2", "adc r3", "adc r4", "adc r5", "adc r6", "adc r7", "adc r8", "adc r9", "adc r10", "adc r11", "adc r12", "adc r13", "adc r14", "adc r15", // 60 - 6f "sbc r0", "sbc r1", "sbc r2", "sbc r3", "sbc r4", "sbc r5", "sbc r6", "sbc r7", "sbc r8", "sbc r9", "sbc r10", "sbc r11", "sbc r12", "sbc r13", "sbc r14", "sbc r15", // 70 - 7f "merge", "bic r1", "bic r2", "bic r3", "bic r4", "bic r5", "bic r6", "bic r7", "bic r8", "bic r9", "bic r10", "bic r11", "bic r12", "bic r13", "bic r14", "bic r15", // 80 - 8f "umult r0", "umult r1", "umult r2", "umult r3", "umult r4", "umult r5", "umult r6", "umult r7", "umult r8", "umult r9", "umult r10", "umult r11", "umult r12", "umult r13", "umult r14", "umult r15", // 90 - 9f "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "div2", "ror", "ljmp (r8)", "ljmp (r9)", "ljmp (r10)", "ljmp (r11)", "ljmp (r12)", "ljmp (r13)", "lob", "lmult", // a0 - af "lms r0, ($%04x)", "lms r1, ($%04x)", "lms r2, ($%04x)", "lms r3, ($%04x)", "lms r4, ($%04x)", "lms r5, ($%04x)", "lms r6, ($%04x)", "lms r7, ($%04x)", "lms r8, ($%04x)", "lms r9, ($%04x)", "lms r10, ($%04x)", "lms r11, ($%04x)", "lms r12, ($%04x)", "lms r13, ($%04x)", "lms r14, ($%04x)", "lms r15, ($%04x)", // b0 - bf "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", // c0 - cf "hib", "xor r1", "xor r2", "xor r3", "xor r4", "xor r5", "xor r6", "xor r7", "xor r8", "xor r9", "xor r10", "xor r11", "xor r12", "xor r13", "xor r14", "xor r15", // d0 - df "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "getc", // e0 - ef "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbh", // f0 - ff "lm r0, ($%04x)", "lm r1, ($%04x)", "lm r2, ($%04x)", "lm r3, ($%04x)", "lm r4, ($%04x)", "lm r5, ($%04x)", "lm r6, ($%04x)", "lm r7, ($%04x)", "lm r8, ($%04x)", "lm r9, ($%04x)", "lm r10, ($%04x)", "lm r11, ($%04x)", "lm r12, ($%04x)", "lm r13, ($%04x)", "lm r14, ($%04x)", "lm r15, ($%04x)", // ALT2 Table // 00 - 0f "stop", "nop", "cache", "lsr", "rol", "bra $%04x", "blt $%04x", "bge $%04x", "bne $%04x", "beq $%04x", "bpl $%04x", "bmi $%04x", "bcc $%04x", "bcs $%04x", "bvc $%04x", "bvs $%04x", // 10 - 1f "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", // 20 - 2f "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", // 30 - 3f "stw (r0)", "stw (r1)", "stw (r2)", "stw (r3)", "stw (r4)", "stw (r5)", "stw (r6)", "stw (r7)", "stw (r8)", "stw (r9)", "stw (r10)", "stw (r11)", "loop", "alt1", "alt2", "alt3", // 40 - 4f "ldw (r0)", "ldw (r1)", "ldw (r2)", "ldw (r3)", "ldw (r4)", "ldw (r5)", "ldw (r6)", "ldw (r7)", "ldw (r8)", "ldw (r9)", "ldw (r10)", "ldw (r11)", "plot", "swap", "color", "not", // 50 - 5f "add #0", "add #1", "add #2", "add #3", "add #4", "add #5", "add #6", "add #7", "add #8", "add #9", "add #10", "add #11", "add #12", "add #13", "add #14", "add #15", // 60 - 6f "sub #0", "sub #1", "sub #2", "sub #3", "sub #4", "sub #5", "sub #6", "sub #7", "sub #8", "sub #9", "sub #10", "sub #11", "sub #12", "sub #13", "sub #14", "sub #15", // 70 - 7f "merge", "and #1", "and #2", "and #3", "and #4", "and #5", "and #6", "and #7", "and #8", "and #9", "and #10", "and #11", "and #12", "and #13", "and #14", "and #15", // 80 - 8f "mult #0", "mult #1", "mult #2", "mult #3", "mult #4", "mult #5", "mult #6", "mult #7", "mult #8", "mult #9", "mult #10", "mult #11", "mult #12", "mult #13", "mult #14", "mult #15", // 90 - 9f "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "asr", "ror", "jmp (r8)", "jmp (r9)", "jmp (r10)", "jmp (r11)", "jmp (r12)", "jmp (r13)", "lob", "fmult", // a0 - af "sms ($%04x), r0", "sms ($%04x), r1", "sms ($%04x), r2", "sms ($%04x), r3", "sms ($%04x), r4", "sms ($%04x), r5", "sms ($%04x), r6", "sms ($%04x), r7", "sms ($%04x), r8", "sms ($%04x), r9", "sms ($%04x), r10", "sms ($%04x), r11", "sms ($%04x), r12", "sms ($%04x), r13", "sms ($%04x), r14", "sms ($%04x), r15", // b0 - bf "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", // c0 - cf "hib", "or #1", "or #2", "or #3", "or #4", "or #5", "or #6", "or #7", "or #8", "or #9", "or #10", "or #11", "or #12", "or #13", "or #14", "or #15", // d0 - df "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "ramb", // e0 - ef "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbl", // f0 - ff "sm ($%04x), r0", "sm ($%04x), r1", "sm ($%04x), r2", "sm ($%04x), r3", "sm ($%04x), r4", "sm ($%04x), r5", "sm ($%04x), r6", "sm ($%04x), r7", "sm ($%04x), r8", "sm ($%04x), r9", "sm ($%04x), r10", "sm ($%04x), r11", "sm ($%04x), r12", "sm ($%04x), r13", "sm ($%04x), r14", "sm ($%04x), r15", // ALT3 Table // 00 - 0f "stop", "nop", "cache", "lsr", "rol", "bra $%04x", "blt $%04x", "bge $%04x", "bne $%04x", "beq $%04x", "bpl $%04x", "bmi $%04x", "bcc $%04x", "bcs $%04x", "bvc $%04x", "bvs $%04x", // 10 - 1f "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", // 20 - 2f "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", // 30 - 3f "stb (r0)", "stb (r1)", "stb (r2)", "stb (r3)", "stb (r4)", "stb (r5)", "stb (r6)", "stb (r7)", "stb (r8)", "stb (r9)", "stb (r10)", "stb (r11)", "loop", "alt1", "alt2", "alt3", // 40 - 4f "ldb (r0)", "ldb (r1)", "ldb (r2)", "ldb (r3)", "ldb (r4)", "ldb (r5)", "ldb (r6)", "ldb (r7)", "ldb (r8)", "ldb (r9)", "ldb (r10)", "ldb (r11)", "rpix", "swap", "cmode", "not", // 50 - 5f "adc #0", "adc #1", "adc #2", "adc #3", "adc #4", "adc #5", "adc #6", "adc #7", "adc #8", "adc #9", "adc #10", "adc #11", "adc #12", "adc #13", "adc #14", "adc #15", // 60 - 6f "cmp r0", "cmp r1", "cmp r2", "cmp r3", "cmp r4", "cmp r5", "cmp r6", "cmp r7", "cmp r8", "cmp r9", "cmp r10", "cmp r11", "cmp r12", "cmp r13", "cmp r14", "cmp r15", // 70 - 7f "merge", "bic #1", "bic #2", "bic #3", "bic #4", "bic #5", "bic #6", "bic #7", "bic #8", "bic #9", "bic #10", "bic #11", "bic #12", "bic #13", "bic #14", "bic #15", // 80 - 8f "umult #0", "umult #1", "umult #2", "umult #3", "umult #4", "umult #5", "umult #6", "umult #7", "umult #8", "umult #9", "umult #10", "umult #11", "umult #12", "umult #13", "umult #14", "umult #15", // 90 - 9f "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "div2", "ror", "ljmp (r8)", "ljmp (r9)", "ljmp (r10)", "ljmp (r11)", "ljmp (r12)", "ljmp (r13)", "lob", "lmult", // a0 - af "lms r0, ($%04x)", "lms r1, ($%04x)", "lms r2, ($%04x)", "lms r3, ($%04x)", "lms r4, ($%04x)", "lms r5, ($%04x)", "lms r6, ($%04x)", "lms r7, ($%04x)", "lms r8, ($%04x)", "lms r9, ($%04x)", "lms r10, ($%04x)", "lms r11, ($%04x)", "lms r12, ($%04x)", "lms r13, ($%04x)", "lms r14, ($%04x)", "lms r15, ($%04x)", // b0 - bf "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", // c0 - cf "hib", "xor #1", "xor #2", "xor #3", "xor #4", "xor #5", "xor #6", "xor #7", "xor #8", "xor #9", "xor #10", "xor #11", "xor #12", "xor #13", "xor #14", "xor #15", // d0 - df "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "romb", // e0 - ef "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbs", // f0 - ff "lm r0, ($%04x)", "lm r1, ($%04x)", "lm r2, ($%04x)", "lm r3, ($%04x)", "lm r4, ($%04x)", "lm r5, ($%04x)", "lm r6, ($%04x)", "lm r7, ($%04x)", "lm r8, ($%04x)", "lm r9, ($%04x)", "lm r10, ($%04x)", "lm r11, ($%04x)", "lm r12, ($%04x)", "lm r13, ($%04x)", "lm r14, ($%04x)", "lm r15, ($%04x)" }; */ /* static void FxPipeString (char *pvString) { uint32 vOpcode = (GSU.vStatusReg & 0x300) | ((uint32) PIPE); const char *m = fx_apvMnemonicTable[vOpcode]; uint8 vPipe1, vPipe2, vByte1, vByte2; uint8 vPipeBank = GSU.vPipeAdr >> 16; char *p; // The next two bytes after the pipe's address vPipe1 = GSU.apvRomBank[vPipeBank][USEX16(GSU.vPipeAdr + 1)]; vPipe2 = GSU.apvRomBank[vPipeBank][USEX16(GSU.vPipeAdr + 2)]; // The actual next two bytes to be read vByte1 = PRGBANK(USEX16(R15)); vByte2 = PRGBANK(USEX16(R15 + 1)); // Print ROM address of the pipe sprintf(pvString, "%02x:%04x %02x ", USEX8(vPipeBank), USEX16(GSU.vPipeAdr), USEX8(PIPE)); p = &pvString[strlen(pvString)]; if (PIPE >= 0x05 && PIPE <= 0x0f) // Check if it's a branch instruction { sprintf(&pvString[11], "%02x ", USEX8(vPipe1)); #ifdef BRANCH_DELAY_RELATIVE sprintf(p, m, USEX16(R15 + SEX8(vByte1) + 1)); #else sprintf(p, m, USEX16(R15 + SEX8(vByte1) - 1)); #endif } else if (PIPE >= 0x10 && PIPE <= 0x1f && TF(B)) // Check for 'move' instruction sprintf(p, "move r%d, r%d", USEX8(PIPE & 0x0f), (uint32) (GSU.pvSreg - GSU.avReg)); else if (PIPE >= 0xa0 && PIPE <= 0xaf) // Check for 'ibt', 'lms' or 'sms' { sprintf(&pvString[11], "%02x ", USEX8(vPipe1)); if ((GSU.vStatusReg & 0x300) == 0x100 || (GSU.vStatusReg & 0x300) == 0x200) sprintf(p, m, USEX16(vByte1) << 1); else sprintf(p, m, USEX16(vByte1)); } else if (PIPE >= 0xb0 && PIPE <= 0xbf && TF(B)) // Check for 'moves' sprintf(p, "moves r%d, r%d", (uint32) (GSU.pvDreg - GSU.avReg), USEX8(PIPE & 0x0f)); else if (PIPE >= 0xf0) // Check for 'iwt', 'lm' or 'sm' { sprintf(&pvString[11], "%02x %02x ", USEX8(vPipe1), USEX8(vPipe2)); sprintf(p, m, USEX8(vByte1) | (USEX16(vByte2) << 8)); } else // Normal instruction strcpy(p, m); } */ #endif cpuexec.cpp000664 001750 001750 00000036144 12720446475 014065 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "cpuops.h" #include "dma.h" #include "apu/apu.h" #include "fxemu.h" #include "snapshot.h" #ifdef DEBUGGER #include "debug.h" #include "missing.h" #endif //#define CPU_OPCODE_INSTRUMENTATION /* Pipe the output to : * | grep -B1 EXEC=NMI | grep -v EXEC=NMI | grep EXEC= | sort | uniq -c | sort -nr * */ static inline void S9xReschedule (void); void S9xMainLoop (void) { for (;;) { if (CPU.NMILine) { if (Timings.NMITriggerPos <= CPU.Cycles) { CPU.NMILine = FALSE; Timings.NMITriggerPos = 0xffff; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } S9xOpcode_NMI(); #ifdef CPU_OPCODE_INSTRUMENTATION puts("** EXEC=NMI"); #endif } } if (CPU.IRQTransition || CPU.IRQExternal) { if (CPU.IRQPending) CPU.IRQPending--; else { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } CPU.IRQTransition = FALSE; CPU.IRQPending = Timings.IRQPendCount; if (!CheckFlag(IRQ)) S9xOpcode_IRQ(); } } #ifdef DEBUGGER if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) { for (int Break = 0; Break != 6; Break++) { if (S9xBreakpoint[Break].Enabled && S9xBreakpoint[Break].Bank == Registers.PB && S9xBreakpoint[Break].Address == Registers.PCw) { if (S9xBreakpoint[Break].Enabled == 2) S9xBreakpoint[Break].Enabled = TRUE; else CPU.Flags |= DEBUG_MODE_FLAG; } } } if (CPU.Flags & DEBUG_MODE_FLAG) break; if (CPU.Flags & TRACE_FLAG) S9xTrace(); if (CPU.Flags & SINGLE_STEP_FLAG) { CPU.Flags &= ~SINGLE_STEP_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } #endif if (CPU.Flags & SCAN_KEYS_FLAG) break; register uint8 Op; register struct SOpcodes *Opcodes; if (CPU.PCBase) { Op = CPU.PCBase[Registers.PCw]; CPU.PrevCycles = CPU.Cycles; CPU.Cycles += CPU.MemSpeed; S9xCheckInterrupts(); Opcodes = ICPU.S9xOpcodes; } else { Op = S9xGetByte(Registers.PBPC); OpenBus = Op; Opcodes = S9xOpcodesSlow; } if ((Registers.PCw & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) { uint8 *oldPCBase = CPU.PCBase; CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + ((uint16) (Registers.PCw + 4))); if (oldPCBase != CPU.PCBase || (Registers.PCw & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) Opcodes = S9xOpcodesSlow; } #ifdef CPU_OPCODE_INSTRUMENTATION printf("EXEC=%.6X\n",Registers.PBPC); #endif Registers.PCw++; (*Opcodes[Op].S9xOpcode)(); if (Settings.SA1) S9xSA1MainLoop(); } S9xPackStatus(); if (CPU.Flags & SCAN_KEYS_FLAG) { #ifdef DEBUGGER if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) #endif S9xSyncSpeed(); CPU.Flags &= ~SCAN_KEYS_FLAG; } } static inline void S9xReschedule (void) { switch (CPU.WhichEvent) { case HC_HBLANK_START_EVENT: CPU.WhichEvent = HC_HDMA_START_EVENT; CPU.NextEvent = Timings.HDMAStart; break; case HC_HDMA_START_EVENT: CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; CPU.NextEvent = Timings.H_Max; break; case HC_HCOUNTER_MAX_EVENT: CPU.WhichEvent = HC_HDMA_INIT_EVENT; CPU.NextEvent = Timings.HDMAInit; break; case HC_HDMA_INIT_EVENT: CPU.WhichEvent = HC_RENDER_EVENT; CPU.NextEvent = Timings.RenderPos; break; case HC_RENDER_EVENT: CPU.WhichEvent = HC_WRAM_REFRESH_EVENT; CPU.NextEvent = Timings.WRAMRefreshPos; break; case HC_WRAM_REFRESH_EVENT: CPU.WhichEvent = HC_HBLANK_START_EVENT; CPU.NextEvent = Timings.HBlankStart; break; } } void S9xDoHEventProcessing (void) { #ifdef DEBUGGER static char eventname[7][32] = { "", "HC_HBLANK_START_EVENT", "HC_HDMA_START_EVENT ", "HC_HCOUNTER_MAX_EVENT", "HC_HDMA_INIT_EVENT ", "HC_RENDER_EVENT ", "HC_WRAM_REFRESH_EVENT" }; #endif #ifdef DEBUGGER if (Settings.TraceHCEvent) S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d", eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); #endif switch (CPU.WhichEvent) { case HC_HBLANK_START_EVENT: S9xReschedule(); break; case HC_HDMA_START_EVENT: S9xReschedule(); if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) { #ifdef DEBUGGER S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA); #endif PPU.HDMA = S9xDoHDMA(PPU.HDMA); } break; case HC_HCOUNTER_MAX_EVENT: if (Settings.SuperFX) { if (!SuperFX.oneLineDone) S9xSuperFXExec(); SuperFX.oneLineDone = FALSE; } S9xAPUEndScanline(); CPU.Cycles -= Timings.H_Max; CPU.PrevCycles -= Timings.H_Max; S9xAPUSetReferenceTime(CPU.Cycles); if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) Timings.NMITriggerPos -= Timings.H_Max; CPU.V_Counter++; if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 { CPU.V_Counter = 0; Timings.InterlaceField ^= 1; // From byuu: // [NTSC] // interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd. // non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames. // [PAL] // interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. // non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. if (IPPU.Interlace && !Timings.InterlaceField) Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) else Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) Memory.FillRAM[0x213F] ^= 0x80; PPU.RangeTimeOver = 0; // FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. Memory.FillRAM[0x4210] = Model->_5A22; CPU.NMILine = FALSE; Timings.NMITriggerPos = 0xffff; ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPU.Flags |= SCAN_KEYS_FLAG; } // From byuu: // In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame. // On odd frames, scanline 240 is one dot short. // In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, // and odd frames have 262 scanlines. // Interlace mode scanline 240 on odd frames is not missing a dot. if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 else Timings.H_Max = Timings.H_Max_Master; // HC=1364 if (Model->_5A22 == 2) { if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240 { if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 } } else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). { S9xEndScreenRefresh(); PPU.HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. #ifdef DEBUGGER missing.dma_this_frame = 0; #endif IPPU.MaxBrightness = PPU.Brightness; PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1; if (!PPU.ForcedBlanking) { PPU.OAMAddr = PPU.SavedOAMAddr; uint8 tmp = 0; if (PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr & 0xFE) >> 1; if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp) { PPU.FirstSprite = tmp; IPPU.OBJChanged = TRUE; } PPU.OAMFlip = 0; } // FIXME: writing to $4210 will wait 6 cycles. Memory.FillRAM[0x4210] = 0x80 | Model->_5A22; if (Memory.FillRAM[0x4200] & 0x80) { // FIXME: triggered at HC=6, checked just before the final CPU cycle, // then, when to call S9xOpcode_NMI()? CPU.NMILine = TRUE; Timings.NMITriggerPos = 6 + 6; } } if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true { if (Memory.FillRAM[0x4200] & 1) S9xDoAutoJoypad(); } if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1 S9xStartScreenRefresh(); S9xReschedule(); break; case HC_HDMA_INIT_EVENT: S9xReschedule(); if (CPU.V_Counter == 0) { #ifdef DEBUGGER S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA); #endif S9xStartHDMA(); } break; case HC_RENDER_EVENT: if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight) RenderLine((uint8) (CPU.V_Counter - FIRST_VISIBLE_LINE)); S9xReschedule(); break; case HC_WRAM_REFRESH_EVENT: #ifdef DEBUGGER S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles); #endif CPU.PrevCycles = CPU.Cycles; CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; S9xCheckInterrupts(); S9xReschedule(); break; } #ifdef DEBUGGER if (Settings.TraceHCEvent) S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d", eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles); #endif } docs/000700 001750 001750 00000000000 12724164663 012631 5ustar00sergiosergio000000 000000 cpuops.h000664 001750 001750 00000014415 12720446475 013404 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CPUOPS_H_ #define _CPUOPS_H_ void S9xOpcode_NMI (void); void S9xOpcode_IRQ (void); #ifndef SA1_OPCODES #define CHECK_FOR_IRQ() {} // if (CPU.IRQLine) S9xOpcode_IRQ(); } #else #define CHECK_FOR_IRQ() {} #endif #endif snapshot.h000664 001750 001750 00000015361 12720446475 013733 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SNAPSHOT_H_ #define _SNAPSHOT_H_ #include "snes9x.h" #define SNAPSHOT_MAGIC "#!s9xsnp" #define SNAPSHOT_VERSION_IRQ 7 #define SNAPSHOT_VERSION_BAPU 8 #define SNAPSHOT_VERSION 8 #define SUCCESS 1 #define WRONG_FORMAT (-1) #define WRONG_VERSION (-2) #define FILE_NOT_FOUND (-3) #define WRONG_MOVIE_SNAPSHOT (-4) #define NOT_A_MOVIE_SNAPSHOT (-5) #define SNAPSHOT_INCONSISTENT (-6) void S9xResetSaveTimer (bool8); bool8 S9xFreezeGame (const char *); uint32 S9xFreezeSize (void); bool8 S9xFreezeGameMem (uint8 *,uint32); bool8 S9xUnfreezeGame (const char *); int S9xUnfreezeGameMem (const uint8 *,uint32); void S9xFreezeToStream (STREAM); int S9xUnfreezeFromStream (STREAM); #endif apu/bapu/dsp/sdsp.cpp000664 001750 001750 00000001233 12720446475 015673 0ustar00sergiosergio000000 000000 #include #define DSP_CPP namespace SNES { DSP dsp; #include "SPC_DSP.cpp" void DSP::power() { spc_dsp.init(smp.apuram); spc_dsp.reset(); clock = 0; } void DSP::reset() { spc_dsp.soft_reset(); clock = 0; } static void from_dsp_to_state (uint8 **buf, void *var, size_t size) { memcpy(*buf, var, size); *buf += size; } static void to_dsp_from_state (uint8 **buf, void *var, size_t size) { memcpy(var, *buf, size); *buf += size; } void DSP::save_state (uint8 **ptr) { spc_dsp.copy_state(ptr, from_dsp_to_state); } void DSP::load_state (uint8 **ptr) { spc_dsp.copy_state(ptr, to_dsp_from_state); } DSP::DSP() { clock = 0; } } libretro/libretro.cpp000664 001750 001750 00000107152 12720446475 016073 0ustar00sergiosergio000000 000000 #include "libretro.h" #include "snes9x.h" #include "memmap.h" #include "srtc.h" #include "apu/apu.h" #include "apu/bapu/snes/snes.hpp" #include "gfx.h" #include "snapshot.h" #include "controls.h" #include "cheats.h" #include "movie.h" #include "logger.h" #include "display.h" #include "conffile.h" #include #ifdef _WIN32 #include #else #include #endif #include #include #include #define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD) #define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN) #define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN) #define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN) #define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC) #define RETRO_GAME_TYPE_BSX 0x101 #define RETRO_GAME_TYPE_BSX_SLOTTED 0x102 #define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103 #define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104 static retro_log_printf_t log_cb = NULL; static retro_video_refresh_t video_cb = NULL; static retro_audio_sample_t audio_cb = NULL; static retro_audio_sample_batch_t audio_batch_cb = NULL; static retro_input_poll_t poll_cb = NULL; static retro_input_state_t input_state_cb = NULL; void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; } void retro_set_audio_sample(retro_audio_sample_t cb) { audio_cb = cb; } void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; } void retro_set_input_poll(retro_input_poll_t cb) { poll_cb = cb; } void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; } static retro_environment_t environ_cb; static bool use_overscan = false; static bool rom_loaded = false; void retro_set_environment(retro_environment_t cb) { environ_cb = cb; struct retro_variable variables[] = { // These variable names and possible values constitute an ABI with ZMZ (ZSNES Libretro player). // Changing "Show layer 1" is fine, but don't change "layer_1"/etc or the possible values ("Yes|No"). // Adding more variables and rearranging them is safe. { "snes9x_overclock", "SuperFX Overclock; disabled|40MHz|60MHz|80MHz|100MHz" }, { "snes9x_layer_1", "Show layer 1; Yes|No" }, { "snes9x_layer_2", "Show layer 2; Yes|No" }, { "snes9x_layer_3", "Show layer 3; Yes|No" }, { "snes9x_layer_4", "Show layer 4; Yes|No" }, { "snes9x_layer_5", "Show sprite layer; Yes|No" }, { "snes9x_gfx_clip", "Enable graphic clip windows; Yes|No" }, { "snes9x_gfx_transp", "Enable transparency effects; Yes|No" }, { "snes9x_sndchan_1", "Enable sound channel 1; Yes|No" }, { "snes9x_sndchan_2", "Enable sound channel 2; Yes|No" }, { "snes9x_sndchan_3", "Enable sound channel 3; Yes|No" }, { "snes9x_sndchan_4", "Enable sound channel 4; Yes|No" }, { "snes9x_sndchan_5", "Enable sound channel 5; Yes|No" }, { "snes9x_sndchan_6", "Enable sound channel 6; Yes|No" }, { "snes9x_sndchan_7", "Enable sound channel 7; Yes|No" }, { "snes9x_sndchan_8", "Enable sound channel 8; Yes|No" }, { NULL, NULL }, }; environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables); static const struct retro_controller_description port_1[] = { { "SNES Joypad", RETRO_DEVICE_JOYPAD }, { "SNES Mouse", RETRO_DEVICE_MOUSE }, { "Multitap", RETRO_DEVICE_JOYPAD_MULTITAP }, }; static const struct retro_controller_description port_2[] = { { "SNES Joypad", RETRO_DEVICE_JOYPAD }, { "SNES Mouse", RETRO_DEVICE_MOUSE }, { "Multitap", RETRO_DEVICE_JOYPAD_MULTITAP }, { "SuperScope", RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE }, { "Justifier", RETRO_DEVICE_LIGHTGUN_JUSTIFIER }, }; static const struct retro_controller_info ports[] = { { port_1, 3 }, { port_2, 5 }, { 0 }, }; environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); } extern void S9xResetSuperFX(void); static void update_variables(void) { bool reset_sfx = false; char key[256]; struct retro_variable var; var.key = "snes9x_overclock"; var.value = NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var)) { if (strcmp(var.value, "disabled") == 0) { Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6; reset_sfx = true; } else if (strcmp(var.value, "40MHz") == 0) { Settings.SuperFXSpeedPerLine = 0.417 * 40.5e6; reset_sfx = true; } else if (strcmp(var.value, "60MHz") == 0) { Settings.SuperFXSpeedPerLine = 0.417 * 60.5e6; reset_sfx = true; } else if (strcmp(var.value, "80MHz") == 0) { Settings.SuperFXSpeedPerLine = 0.417 * 80.5e6; reset_sfx = true; } else if (strcmp(var.value, "100MHz") == 0) { Settings.SuperFXSpeedPerLine = 0.417 * 100.5e6; reset_sfx = true; } } int disabled_channels=0; strcpy(key, "snes9x_sndchan_x"); var.key=key; for (int i=0;i<8;i++) { key[strlen("snes9x_sndchan_")]='1'+i; var.value=NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && var.value[0]=='N') disabled_channels|=1<> 1); } void retro_get_system_info(struct retro_system_info *info) { memset(info,0,sizeof(retro_system_info)); info->library_name = "Snes9x"; info->library_version = VERSION; info->valid_extensions = "smc|sfc|swc|fig"; info->need_fullpath = false; info->block_extract = false; } void retro_get_system_av_info(struct retro_system_av_info *info) { memset(info,0,sizeof(retro_system_av_info)); info->geometry.base_width = SNES_WIDTH; info->geometry.base_height = use_overscan ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT; info->geometry.max_width = MAX_SNES_WIDTH; info->geometry.max_height = MAX_SNES_HEIGHT; info->geometry.aspect_ratio = 4.0f / 3.0f; info->timing.sample_rate = 32040.5; info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0; } unsigned retro_api_version() { return RETRO_API_VERSION; } void retro_reset() { S9xSoftReset(); } static unsigned snes_devices[2]; void retro_set_controller_port_device(unsigned port, unsigned device) { if (port < 2) { int offset = snes_devices[0] == RETRO_DEVICE_JOYPAD_MULTITAP ? 4 : 1; switch (device) { case RETRO_DEVICE_JOYPAD: S9xSetController(port, CTL_JOYPAD, port * offset, 0, 0, 0); snes_devices[port] = RETRO_DEVICE_JOYPAD; break; case RETRO_DEVICE_JOYPAD_MULTITAP: S9xSetController(port, CTL_MP5, port * offset, port * offset + 1, port * offset + 2, port * offset + 3); snes_devices[port] = RETRO_DEVICE_JOYPAD_MULTITAP; break; case RETRO_DEVICE_MOUSE: S9xSetController(port, CTL_MOUSE, 0, 0, 0, 0); snes_devices[port] = RETRO_DEVICE_MOUSE; break; case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); snes_devices[port] = RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE; break; case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIER; break; default: if (log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Invalid device.\n"); } if (!port) retro_set_controller_port_device(1, snes_devices[1]); } else if(device != RETRO_DEVICE_NONE) log_cb(RETRO_LOG_INFO, "[libretro]: Nonexistent Port (%d).\n", port); } void retro_cheat_reset() { S9xDeleteCheats(); S9xApplyCheats(); } void retro_cheat_set(unsigned index, bool enabled, const char *code) { uint32 address; uint8 val; bool8 sram; uint8 bytes[3];//used only by GoldFinger, ignored for now if (S9xGameGenieToRaw(code, address, val)!=NULL && S9xProActionReplayToRaw(code, address, val)!=NULL && S9xGoldFingerToRaw(code, address, sram, val, bytes)!=NULL) { // bad code, ignore return; } if (index>Cheat.num_cheats) return; // cheat added in weird order, ignore if (index==Cheat.num_cheats) Cheat.num_cheats++; Cheat.c[index].address = address; Cheat.c[index].byte = val; Cheat.c[index].enabled = enabled; Cheat.c[index].saved = FALSE; // it'll be saved next time cheats run anyways Settings.ApplyCheats=true; S9xApplyCheats(); } #define MAX_MAPS 32 static struct retro_memory_descriptor memorydesc[MAX_MAPS]; static unsigned memorydesc_c; static bool merge_mapping() { if (memorydesc_c==1) return false;//can't merge the only one struct retro_memory_descriptor * a=&memorydesc[MAX_MAPS - (memorydesc_c-1)]; struct retro_memory_descriptor * b=&memorydesc[MAX_MAPS - memorydesc_c]; //printf("test %x/%x\n",a->start,b->start); if (a->flags != b->flags) return false; if (a->disconnect != b->disconnect) return false; if (a->len != b->len) return false; if (a->addrspace || b->addrspace) return false;//we don't use these if (((char*)a->ptr)+a->offset==((char*)b->ptr)+b->offset && a->select==b->select) { //printf("merge/mirror\n"); a->select&=~(a->start^b->start); memorydesc_c--; return true; } uint32 len=a->len; if (!len) len=(0x1000000 - a->select); if (len && ((len-1) & (len | a->disconnect))==0 && ((char*)a->ptr)+a->offset+len == ((char*)b->ptr)+b->offset) { //printf("merge/consec\n"); a->select &=~ len; a->disconnect &=~ len; memorydesc_c--; return true; } //printf("nomerge\n"); return false; } void S9xAppendMapping(struct retro_memory_descriptor *desc) { //do it backwards - snes9x defines the last one to win, while we define the first one to win //printf("add %x\n",desc->start); memcpy(&memorydesc[MAX_MAPS - (++memorydesc_c)], desc, sizeof(struct retro_memory_descriptor)); while (merge_mapping()) {} } static void init_descriptors(void) { struct retro_input_descriptor desc[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 0 }, }; environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); } bool retro_load_game(const struct retro_game_info *game) { init_descriptors(); memorydesc_c = 0; if(game->data == NULL && game->size == 0 && game->path != NULL) rom_loaded = Memory.LoadROM(game->path); else rom_loaded = Memory.LoadROMMem((const uint8_t*)game->data ,game->size); int pixel_format = RGB555; if(environ_cb) { pixel_format = RGB565; enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565; if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) pixel_format = RGB555; } S9xGraphicsDeinit(); S9xSetRenderPixelFormat(pixel_format); S9xGraphicsInit(); if (!rom_loaded && log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Rom loading failed...\n"); struct retro_memory_map map={ memorydesc+MAX_MAPS-memorydesc_c, memorydesc_c }; if (rom_loaded) environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &map); return rom_loaded; } void retro_unload_game(void) {} bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) { init_descriptors(); memorydesc_c = 0; switch (game_type) { case RETRO_GAME_TYPE_BSX: if(num_info == 1) { rom_loaded = Memory.LoadROMMem((const uint8_t*)info[0].data,info[0].size); } else if(num_info == 2) { memcpy(Memory.BIOSROM,(const uint8_t*)info[0].data,info[0].size); rom_loaded = Memory.LoadROMMem((const uint8_t*)info[1].data,info[1].size); } if (!rom_loaded && log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: BSX ROM loading failed...\n"); break; case RETRO_GAME_TYPE_BSX_SLOTTED: if(num_info == 2) rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[0].data, info[0].size, (const uint8_t*)info[1].data, info[1].size, NULL, 0); if (!rom_loaded && log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Multirom loading failed...\n"); break; case RETRO_GAME_TYPE_SUFAMI_TURBO: if(num_info == 3) rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[1].data, info[1].size, (const uint8_t*)info[2].data, info[2].size, (const uint8_t*)info[0].data, info[0].size); if (!rom_loaded && log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Sufami Turbo ROM loading failed...\n"); break; default: rom_loaded = false; break; } struct retro_memory_map map={ memorydesc+MAX_MAPS-memorydesc_c, memorydesc_c }; if (rom_loaded) environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &map); return rom_loaded; } static void map_buttons(); static void check_system_specs(void) { /* TODO - might have to variably set performance level based on SuperFX/SA-1/etc */ unsigned level = 12; environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); } void retro_init(void) { struct retro_log_callback log; if (environ_cb) { if (!environ_cb(RETRO_ENVIRONMENT_GET_OVERSCAN, &use_overscan)) use_overscan = false; } if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) log_cb = log.log; else log_cb = NULL; memset(&Settings, 0, sizeof(Settings)); Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6; Settings.MouseMaster = TRUE; Settings.SuperScopeMaster = TRUE; Settings.JustifierMaster = TRUE; Settings.MultiPlayer5Master = TRUE; Settings.FrameTimePAL = 20000; Settings.FrameTimeNTSC = 16667; Settings.SixteenBitSound = TRUE; Settings.Stereo = TRUE; Settings.SoundPlaybackRate = 32000; Settings.SoundInputRate = 32000; Settings.SupportHiRes = TRUE; Settings.Transparency = TRUE; Settings.AutoDisplayMessages = TRUE; Settings.InitialInfoStringTimeout = 120; Settings.HDMATimingHack = 100; Settings.BlockInvalidVRAMAccessMaster = TRUE; Settings.WrongMovieStateProtection = TRUE; Settings.DumpStreamsMaxFrames = -1; Settings.StretchScreenshots = 0; Settings.SnapshotScreenshots = FALSE; Settings.CartAName[0] = 0; Settings.CartBName[0] = 0; Settings.AutoSaveDelay = 1; Settings.DontSaveOopsSnapshot = TRUE; CPU.Flags = 0; if (!Memory.Init() || !S9xInitAPU()) { Memory.Deinit(); S9xDeinitAPU(); if (log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Failed to init Memory or APU.\n"); exit(1); } S9xInitSound(16, 0); S9xSetSoundMute(FALSE); S9xSetSamplesAvailableCallback(S9xAudioCallback, NULL); GFX.Pitch = MAX_SNES_WIDTH * sizeof(uint16); GFX.Screen = (uint16*) calloc(1, GFX.Pitch * MAX_SNES_HEIGHT); S9xGraphicsInit(); S9xInitInputDevices(); for (int i = 0; i < 2; i++) { S9xSetController(i, CTL_JOYPAD, i, 0, 0, 0); snes_devices[i] = RETRO_DEVICE_JOYPAD; } S9xUnmapAllControls(); map_buttons(); check_system_specs(); } #define MAP_BUTTON(id, name) S9xMapButton((id), S9xGetCommandT((name)), false) #define MAKE_BUTTON(pad, btn) (((pad)<<4)|(btn)) #define PAD_1 1 #define PAD_2 2 #define PAD_3 3 #define PAD_4 4 #define PAD_5 5 #define BTN_B RETRO_DEVICE_ID_JOYPAD_B #define BTN_Y RETRO_DEVICE_ID_JOYPAD_Y #define BTN_SELECT RETRO_DEVICE_ID_JOYPAD_SELECT #define BTN_START RETRO_DEVICE_ID_JOYPAD_START #define BTN_UP RETRO_DEVICE_ID_JOYPAD_UP #define BTN_DOWN RETRO_DEVICE_ID_JOYPAD_DOWN #define BTN_LEFT RETRO_DEVICE_ID_JOYPAD_LEFT #define BTN_RIGHT RETRO_DEVICE_ID_JOYPAD_RIGHT #define BTN_A RETRO_DEVICE_ID_JOYPAD_A #define BTN_X RETRO_DEVICE_ID_JOYPAD_X #define BTN_L RETRO_DEVICE_ID_JOYPAD_L #define BTN_R RETRO_DEVICE_ID_JOYPAD_R #define BTN_FIRST BTN_B #define BTN_LAST BTN_R #define MOUSE_X RETRO_DEVICE_ID_MOUSE_X #define MOUSE_Y RETRO_DEVICE_ID_MOUSE_Y #define MOUSE_LEFT RETRO_DEVICE_ID_MOUSE_LEFT #define MOUSE_RIGHT RETRO_DEVICE_ID_MOUSE_RIGHT #define MOUSE_FIRST MOUSE_X #define MOUSE_LAST MOUSE_RIGHT #define SCOPE_X RETRO_DEVICE_ID_SUPER_SCOPE_X #define SCOPE_Y RETRO_DEVICE_ID_SUPER_SCOPE_Y #define SCOPE_TRIGGER RETRO_DEVICE_ID_LIGHTGUN_TRIGGER #define SCOPE_CURSOR RETRO_DEVICE_ID_LIGHTGUN_CURSOR #define SCOPE_TURBO RETRO_DEVICE_ID_LIGHTGUN_TURBO #define SCOPE_PAUSE RETRO_DEVICE_ID_LIGHTGUN_PAUSE #define SCOPE_FIRST SCOPE_X #define SCOPE_LAST SCOPE_PAUSE #define JUSTIFIER_X RETRO_DEVICE_ID_JUSTIFIER_X #define JUSTIFIER_Y RETRO_DEVICE_ID_JUSTIFIER_Y #define JUSTIFIER_TRIGGER RETRO_DEVICE_ID_LIGHTGUN_TRIGGER #define JUSTIFIER_OFFSCREEN RETRO_DEVICE_ID_LIGHTGUN_TURBO #define JUSTIFIER_START RETRO_DEVICE_ID_LIGHTGUN_PAUSE #define JUSTIFIER_FIRST JUSTIFIER_X #define JUSTIFIER_LAST JUSTIFIER_START #define BTN_POINTER (BTN_LAST + 1) #define BTN_POINTER2 (BTN_POINTER + 1) static void map_buttons() { MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_A), "Joypad1 A"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_B), "Joypad1 B"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_X), "Joypad1 X"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_Y), "Joypad1 Y"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_SELECT), "{Joypad1 Select,Mouse1 L}"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_START), "{Joypad1 Start,Mouse1 R}"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_L), "Joypad1 L"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_R), "Joypad1 R"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_LEFT), "Joypad1 Left"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_RIGHT), "Joypad1 Right"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_UP), "Joypad1 Up"); MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_DOWN), "Joypad1 Down"); S9xMapPointer((BTN_POINTER), S9xGetCommandT("Pointer Mouse1+Superscope+Justifier1"), false); S9xMapPointer((BTN_POINTER2), S9xGetCommandT("Pointer Mouse2"), false); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_A), "Joypad2 A"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_B), "Joypad2 B"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_X), "Joypad2 X"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_Y), "Joypad2 Y"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_SELECT), "{Joypad2 Select,Mouse2 L,Superscope Fire,Justifier1 Trigger}"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_START), "{Joypad2 Start,Mouse2 R,Superscope Cursor,Justifier1 Start}"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_L), "Joypad2 L"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_R), "Joypad2 R"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_LEFT), "Joypad2 Left"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_RIGHT), "Joypad2 Right"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_UP), "{Joypad2 Up,Superscope ToggleTurbo,Justifier1 AimOffscreen}"); MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_DOWN), "{Joypad2 Down,Superscope Pause}"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_A), "Joypad3 A"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_B), "Joypad3 B"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_X), "Joypad3 X"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_Y), "Joypad3 Y"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_SELECT), "Joypad3 Select"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_START), "Joypad3 Start"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_L), "Joypad3 L"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_R), "Joypad3 R"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_LEFT), "Joypad3 Left"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_RIGHT), "Joypad3 Right"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_UP), "Joypad3 Up"); MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_DOWN), "Joypad3 Down"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_A), "Joypad4 A"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_B), "Joypad4 B"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_X), "Joypad4 X"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_Y), "Joypad4 Y"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_SELECT), "Joypad4 Select"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_START), "Joypad4 Start"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_L), "Joypad4 L"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_R), "Joypad4 R"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_LEFT), "Joypad4 Left"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_RIGHT), "Joypad4 Right"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_UP), "Joypad4 Up"); MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_DOWN), "Joypad4 Down"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_A), "Joypad5 A"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_B), "Joypad5 B"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_X), "Joypad5 X"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_Y), "Joypad5 Y"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_SELECT), "Joypad5 Select"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_START), "Joypad5 Start"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_L), "Joypad5 L"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_R), "Joypad5 R"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_LEFT), "Joypad5 Left"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_RIGHT), "Joypad5 Right"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_UP), "Joypad5 Up"); MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_DOWN), "Joypad5 Down"); } // libretro uses relative values for analogue devices. // S9x seems to use absolute values, but do convert these into relative values in the core. (Why?!) // Hack around it. :) static int16_t snes_mouse_state[2][2] = {{0}, {0}}; static int16_t snes_scope_state[2] = {0}; static int16_t snes_justifier_state[2][2] = {{0}, {0}}; static void report_buttons() { int _x, _y; int offset = snes_devices[0] == RETRO_DEVICE_JOYPAD_MULTITAP ? 4 : 1; for (int port = 0; port <= 1; port++) { switch (snes_devices[port]) { case RETRO_DEVICE_JOYPAD: for (int i = BTN_FIRST; i <= BTN_LAST; i++) S9xReportButton(MAKE_BUTTON(port * offset + 1, i), input_state_cb(port * offset, RETRO_DEVICE_JOYPAD, 0, i)); break; case RETRO_DEVICE_JOYPAD_MULTITAP: for (int j = 0; j < 4; j++) for (int i = BTN_FIRST; i <= BTN_LAST; i++) S9xReportButton(MAKE_BUTTON(port * offset + j + 1, i), input_state_cb(port * offset + j, RETRO_DEVICE_JOYPAD, 0, i)); break; case RETRO_DEVICE_MOUSE: _x = input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); _y = input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); snes_mouse_state[port][0] += _x; snes_mouse_state[port][1] += _y; S9xReportPointer(BTN_POINTER + port, snes_mouse_state[port][0], snes_mouse_state[port][1]); for (int i = MOUSE_LEFT; i <= MOUSE_LAST; i++) S9xReportButton(MAKE_BUTTON(port + 1, i), input_state_cb(port, RETRO_DEVICE_MOUSE, 0, i)); break; case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: snes_scope_state[0] += input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_X); snes_scope_state[1] += input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); if (snes_scope_state[0] < 0) snes_scope_state[0] = 0; else if (snes_scope_state[0] > (SNES_WIDTH-1)) snes_scope_state[0] = SNES_WIDTH-1; if (snes_scope_state[1] < 0) snes_scope_state[1] = 0; else if (snes_scope_state[1] > (SNES_HEIGHT-1)) snes_scope_state[1] = SNES_HEIGHT-1; S9xReportPointer(BTN_POINTER, snes_scope_state[0], snes_scope_state[1]); for (int i = SCOPE_TRIGGER; i <= SCOPE_LAST; i++) S9xReportButton(MAKE_BUTTON(2, i), input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, i)); break; case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS: snes_justifier_state[port][0] += input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_X); snes_justifier_state[port][1] += input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); if (snes_justifier_state[port][0] < 0) snes_justifier_state[port][0] = 0; else if (snes_justifier_state[port][0] > (SNES_WIDTH-1)) snes_justifier_state[port][0] = SNES_WIDTH-1; if (snes_justifier_state[port][1] < 0) snes_justifier_state[port][1] = 0; else if (snes_justifier_state[port][1] > (SNES_HEIGHT-1)) snes_justifier_state[port][1] = SNES_HEIGHT-1; S9xReportPointer(BTN_POINTER, snes_justifier_state[port][0], snes_justifier_state[port][1]); for (int i = JUSTIFIER_TRIGGER; i <= JUSTIFIER_LAST; i++) S9xReportButton(MAKE_BUTTON(2, i), input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, i)); break; default: if (log_cb) log_cb(RETRO_LOG_ERROR, "[libretro]: Unknown device...\n"); } } } void retro_run() { bool updated = false; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) update_variables(); poll_cb(); report_buttons(); S9xMainLoop(); } void retro_deinit() { S9xDeinitAPU(); Memory.Deinit(); S9xGraphicsDeinit(); S9xUnmapAllControls(); free(GFX.Screen); } unsigned retro_get_region() { return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; } void* retro_get_memory_data(unsigned type) { void* data; switch(type) { case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM: case RETRO_MEMORY_SAVE_RAM: data = Memory.SRAM; break; case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM: data = Multi.sramB; break; case RETRO_MEMORY_RTC: data = RTCData.reg; break; case RETRO_MEMORY_SYSTEM_RAM: data = Memory.RAM; break; case RETRO_MEMORY_VIDEO_RAM: data = Memory.VRAM; break; //case RETRO_MEMORY_ROM: // data = Memory.ROM; // break; default: data = NULL; break; } return data; } size_t retro_get_memory_size(unsigned type) { size_t size; switch(type) { case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM: case RETRO_MEMORY_SAVE_RAM: size = (unsigned) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0); if (size > 0x20000) size = 0x20000; break; case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM: size = (unsigned) (Multi.cartType && Multi.sramSizeB ? (1 << (Multi.sramSizeB + 3)) * 128 : 0); break; case RETRO_MEMORY_RTC: size = (Settings.SRTC || Settings.SPC7110RTC)?20:0; break; case RETRO_MEMORY_SYSTEM_RAM: size = 128 * 1024; break; case RETRO_MEMORY_VIDEO_RAM: size = 64 * 1024; break; //case RETRO_MEMORY_ROM: // size = Memory.CalculatedSize; // break; default: size = 0; break; } return size; } size_t retro_serialize_size() { return rom_loaded ? S9xFreezeSize() : 0; } bool retro_serialize(void *data, size_t size) { if (S9xFreezeGameMem((uint8_t*)data,size) == FALSE) return false; return true; } bool retro_unserialize(const void* data, size_t size) { if (S9xUnfreezeGameMem((const uint8_t*)data,size) != SUCCESS) return false; return true; } bool8 S9xDeinitUpdate(int width, int height) { if (!use_overscan) { if (height >= SNES_HEIGHT << 1) { height = SNES_HEIGHT << 1; } else { height = SNES_HEIGHT; } } else { if (height > SNES_HEIGHT_EXTENDED) { if (height < SNES_HEIGHT_EXTENDED << 1) memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * ((SNES_HEIGHT_EXTENDED << 1) - height)); height = SNES_HEIGHT_EXTENDED << 1; } else { if (height < SNES_HEIGHT_EXTENDED) memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * (SNES_HEIGHT_EXTENDED - height)); height = SNES_HEIGHT_EXTENDED; } } video_cb(GFX.Screen, width, height, GFX.Pitch); return TRUE; } bool8 S9xContinueUpdate(int width, int height) { return S9xDeinitUpdate(width, height); } // Dummy functions that should probably be implemented correctly later. void S9xParsePortConfig(ConfigFile&, int) {} void S9xSyncSpeed() {} const char* S9xStringInput(const char* in) { return in; } const char* S9xGetFilename(const char* in, s9x_getdirtype) { return in; } const char* S9xGetDirectory(s9x_getdirtype) { return ""; } void S9xInitInputDevices() {} const char* S9xChooseFilename(unsigned char) { return ""; } void S9xHandlePortCommand(s9xcommand_t, short, short) {} bool S9xPollButton(unsigned int, bool*) { return false; } void S9xToggleSoundChannel(int) {} const char* S9xGetFilenameInc(const char* in, s9x_getdirtype) { return ""; } const char* S9xBasename(const char* in) { return in; } bool8 S9xInitUpdate() { return TRUE; } void S9xExtraUsage() {} bool8 S9xOpenSoundDevice() { return TRUE; } void S9xMessage(int, int, const char*) {} bool S9xPollAxis(unsigned int, short*) { return FALSE; } void S9xSetPalette() {} void S9xParseArg(char**, int&, int) {} void S9xExit() {} bool S9xPollPointer(unsigned int, short*, short*) { return false; } const char *S9xChooseMovieFilename(unsigned char) { return NULL; } bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file) { if(read_only) { if((*file = OPEN_STREAM(filepath, "rb")) != 0) { return (TRUE); } } else { if((*file = OPEN_STREAM(filepath, "wb")) != 0) { return (TRUE); } } return (FALSE); } void S9xCloseSnapshotFile(STREAM file) { CLOSE_STREAM(file); } void S9xAutoSaveSRAM() { return; } #ifndef __WIN32__ // S9x weirdness. void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext) { *drive = 0; const char *slash = strrchr(path, SLASH_CHAR), *dot = strrchr(path, '.'); if (dot && slash && dot < slash) dot = NULL; if (!slash) { *dir = 0; strcpy(fname, path); if (dot) { fname[dot - path] = 0; strcpy(ext, dot + 1); } else *ext = 0; } else { strcpy(dir, path); dir[slash - path] = 0; strcpy(fname, slash + 1); if (dot) { fname[dot - slash - 1] = 0; strcpy(ext, dot + 1); } else *ext = 0; } } void _makepath (char *path, const char *, const char *dir, const char *fname, const char *ext) { if (dir && *dir) { strcpy(path, dir); strcat(path, SLASH_STR); } else *path = 0; strcat(path, fname); if (ext && *ext) { strcat(path, "."); strcat(path, ext); } } #endif // __WIN32__ apu/resampler.h000664 001750 001750 00000002342 12720446475 014646 0ustar00sergiosergio000000 000000 /* Simple resampler based on bsnes's ruby audio library */ #ifndef __RESAMPLER_H #define __RESAMPLER_H #include "ring_buffer.h" class Resampler : public ring_buffer { public: virtual void clear (void) = 0; virtual void time_ratio (double) = 0; virtual void read (short *, int) = 0; virtual int avail (void) = 0; Resampler (int num_samples) : ring_buffer (num_samples << 1) { } ~Resampler () { } inline bool push (short *src, int num_samples) { if (max_write () < num_samples) return false; !num_samples || ring_buffer::push ((unsigned char *) src, num_samples << 1); return true; } inline int space_empty (void) { return buffer_size - size; } inline int space_filled (void) { return size; } inline int max_write (void) { return space_empty () >> 1; } inline void resize (int num_samples) { ring_buffer::resize (num_samples << 1); } }; #endif /* __RESAMPLER_H */ missing.h000664 001750 001750 00000016741 12720446475 013550 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef DEBUGGER #ifndef _MISSING_H_ #define _MISSING_H_ struct MissingHDMA { uint8 used; uint8 bbus_address; uint8 abus_bank; uint16 abus_address; uint8 indirect_address; uint8 force_table_address_write; uint8 force_table_address_read; uint8 line_count_write; uint8 line_count_read; }; struct Missing { struct MissingHDMA hdma[8]; uint8 emulate6502; uint8 decimal_mode; uint8 mv_8bit_index; uint8 mv_8bit_acc; uint8 interlace; uint8 lines_239; uint8 pseudo_512; uint8 modes[8]; uint8 mode7_fx; uint8 mode7_flip; uint8 mode7_bgmode; uint8 direct; uint8 matrix_multiply; uint8 oam_read; uint8 vram_read; uint8 cgram_read; uint8 wram_read; uint8 dma_read; uint8 vram_inc; uint8 vram_full_graphic_inc; uint8 virq; uint8 hirq; uint16 virq_pos; uint16 hirq_pos; uint8 h_v_latch; uint8 h_counter_read; uint8 v_counter_read; uint8 fast_rom; uint8 window1[6]; uint8 window2[6]; uint8 sprite_priority_rotation; uint8 subscreen; uint8 subscreen_add; uint8 subscreen_sub; uint8 fixed_colour_add; uint8 fixed_colour_sub; uint8 mosaic; uint8 sprite_double_height; uint8 dma_channels; uint8 dma_this_frame; uint8 oam_address_read; uint8 bg_offset_read; uint8 matrix_read; uint8 hdma_channels; uint8 hdma_this_frame; uint16 unknownppu_read; uint16 unknownppu_write; uint16 unknowncpu_read; uint16 unknowncpu_write; uint16 unknowndsp_read; uint16 unknowndsp_write; }; extern struct Missing missing; #endif #endif srtc.h000664 001750 001750 00000014742 12720446475 013051 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SRTC_H_ #define _SRTC_H_ struct SRTCData { uint8 reg[20]; }; // for snapshot only struct SSRTCSnapshot { int32 rtc_mode; // enum RTC_Mode int32 rtc_index; // signed }; extern struct SRTCData RTCData; extern struct SSRTCSnapshot srtcsnap; void S9xInitSRTC (void); void S9xResetSRTC (void); void S9xSRTCPreSaveState (void); void S9xSRTCPostLoadState (int); void S9xSetSRTC (uint8, uint16); uint8 S9xGetSRTC (uint16); #endif docs/control-inputs.txt000664 001750 001750 00000005663 12720446475 016420 0ustar00sergiosergio000000 000000 Control input names are completely defined by the individual ports. This document is intended to collect the rules for all ports. The various meta-characters in the rules are: # - A number. The range is determined by the context ## - A two-digit number (i.e. with leading zeros) [...] - Something optional (...) - For grouping with | | - "or", choose one of the options. <...> - A named field {...} - A list of possible values. Multiple values may be used, but they must be in the order listed and joined with +-signs. "" - 'ditto', used to indicate the same list as the above line. ================================================================================ Unix ================================================================================ Input names: Jxx:Axis# Axis # on joystick xx. Axis0 may be Up/Down, and Axis1 Left/Right. Jxx:B# Button # on joystick xx. Jxx:{M1,M2,M3,M4,M5,M6,M7,M8}+B# Used with the 'JSx Meta#' port Jxx:{M1,M2,M3,M4,M5,M6,M7,M8}+Axis# command. Jxx:X+B# Used to 'define' this key for all Jxx:X+Axis# combinations of JS Meta. Port-specific Commands: JSx Meta# Used to specify modifier keys (i.e. Shift, Control) to affect the specified joystick. For example, you could map J00:B20 to "JS0 Meta1", then map J00:B0 to "Joypad1 A" and J00:M1+B0 to "Joypad1 Turbo A". '#' may range from 1-8. Jsx ToggleMeta# Like the above, but toggles the meta-state each time the button is pressed. ================================================================================ Unix/X11 ================================================================================ Keyboard Input: Note that only one keyboard (K00) is currently supported. If you know how to support multiple keyboards (and can test it!), feel free to fix x11.cpp and delete this note. Keyboard modifiers are S=Shift, C=Control, A=Alt, M=Meta. Combine them in order, i.e. all 4 would be "SCAM". Kxx: Key names are as recognized by XStringToKeysym. Kxx:+ Note however that keys are mapped by keycode, so for example on a standard qwerty keyboard "K00:colon" and "K00:semicolon" are identical. Pointer Input: Note that only one mouse (M00) is currently supported. If you know how to support multiple pointing devices (and can test it!), feel free to fix x11.cpp and delete this note. Mxx:Pointer Map the mouse pointer. If someone has a mouse Mxx:Pointer# device with multiple pointers, fix x11.cpp to report that and you can use the second syntax. Mxx:B# Mouse buttons. libretro/Makefile000664 001750 001750 00000014062 12720446475 015202 0ustar00sergiosergio000000 000000 DEBUG = 0 HAVE_EXCEPTIONS = 0 ifeq ($(platform),) platform = unix ifeq ($(shell uname -a),) platform = win else ifneq ($(findstring Darwin,$(shell uname -a)),) platform = osx arch = intel ifeq ($(shell uname -p),powerpc) arch = ppc endif else ifneq ($(findstring MINGW,$(shell uname -a)),) platform = win else ifneq ($(findstring win,$(shell uname -a)),) platform = win endif endif CXX ?= g++ CC ?= gcc TARGET_NAME = snes9x LIBM = -lm # Unix ifeq ($(platform), unix) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC SHARED := -shared -Wl,--version-script=link.T ifneq ($(findstring Haiku,$(shell uname -a)),) LIBM := endif # OS X else ifeq ($(platform), osx) TARGET := $(TARGET_NAME)_libretro.dylib fpic := -fPIC SHARED := -dynamiclib arch = intel ifeq ($(shell uname -p),powerpc) arch = ppc endif ifeq ($(arch),ppc) CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ endif OSXVER = `sw_vers -productVersion | cut -d. -f 2` OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"` fpic += -mmacosx-version-min=10.1 # iOS else ifneq (,$(findstring ios,$(platform))) TARGET := $(TARGET_NAME)_libretro_ios.dylib fpic := -fPIC SHARED := -dynamiclib ifeq ($(IOSSDK),) IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path) endif CC = clang -arch armv7 -isysroot $(IOSSDK) CXX = clang++ -arch armv7 -isysroot $(IOSSDK) CXXFLAGS += -DIOS CXXFLAGS += -DARM ifeq ($(platform),ios9) CC += -miphoneos-version-min=8.0 CXX += -miphoneos-version-min=8.0 CFLAGS += -miphoneos-version-min=8.0 CXXFLAGS += -miphoneos-version-min=8.0 else CC += -miphoneos-version-min=5.0 CXX += -miphoneos-version-min=5.0 CFLAGS += -miphoneos-version-min=5.0 CXXFLAGS += -miphoneos-version-min=5.0 endif else ifeq ($(platform), theos_ios) DEPLOYMENT_IOSVERSION = 5.0 TARGET = iphone:latest:$(DEPLOYMENT_IOSVERSION) ARCHS = armv7 armv7s TARGET_IPHONEOS_DEPLOYMENT_VERSION=$(DEPLOYMENT_IOSVERSION) THEOS_BUILD_DIR := objs include $(THEOS)/makefiles/common.mk LIBRARY_NAME = $(TARGET_NAME)_libretro_ios # QNX else ifeq ($(platform), qnx) TARGET := $(TARGET_NAME)_libretro_qnx.so fpic := -fPIC SHARED := -shared -Wl,--version-script=link.T CC = qcc -Vgcc_notarmv7le CXX = QCC -Vgcc_notarmv7le AR = QCC -Vgcc_ntoarmv7le CXXFLAGS += -D__BLACKBERRY_QNX__ CXXFLAGS += -DARM HAVE_EXCEPTIONS = 1 # Vita else ifeq ($(platform), vita) TARGET := $(TARGET_NAME)_libretro_vita.so fpic := -fPIC CC = arm-vita-eabi-gcc$(EXE_EXT) CXX = arm-vita-eabi-g++$(EXE_EXT) AR = arm-vita-eabi-ar$(EXE_EXT) CXXFLAGS += -DVITA HAVE_EXCEPTIONS = 1 # PS3 else ifeq ($(platform), ps3) TARGET := $(TARGET_NAME)_libretro_ps3.a CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ STATIC_LINKING = 1 # sncps3 else ifeq ($(platform), sncps3) TARGET := $(TARGET_NAME)_libretro_ps3.a CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ STATIC_LINKING = 1 # Lightweight PS3 Homebrew SDK else ifeq ($(platform), psl1ght) TARGET := $(TARGET_NAME)_libretro_psl1ght.a CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT) CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT) AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT) CXXFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__ STATIC_LINKING = 1 # Xbox 360 else ifeq ($(platform), xenon) TARGET := $(TARGET_NAME)_libretro_xenon360.a CC = xenon-gcc$(EXE_EXT) CXX = xenon-g++$(EXE_EXT) AR = xenon-ar$(EXE_EXT) CXXFLAGS += -D__LIBXENON__ -m32 -D__ppc__ STATIC_LINKING = 1 # Nintendo Wii else ifeq ($(platform), wii) TARGET := $(TARGET_NAME)_libretro_wii.a CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) CXXFLAGS += -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float -DBLARGG_BIG_ENDIAN=1 -D__ppc__ STATIC_LINKING = 1 # ARM else ifneq (,$(findstring armv,$(platform))) TARGET := $(TARGET_NAME)_libretro.so SHARED := -shared -Wl,--no-undefined fpic := -fPIC CC ?= gcc CXX ?= g++ ifneq (,$(findstring cortexa8,$(platform))) CXXFLAGS += -marm -mcpu=cortex-a8 else ifneq (,$(findstring cortexa9,$(platform))) CXXFLAGS += -marm -mcpu=cortex-a9 endif CXXFLAGS += -marm ifneq (,$(findstring neon,$(platform))) CXXFLAGS += -mfpu=neon HAVE_NEON = 1 endif ifneq (,$(findstring softfloat,$(platform))) CXXFLAGS += -mfloat-abi=softfp else ifneq (,$(findstring hardfloat,$(platform))) CXXFLAGS += -mfloat-abi=hard endif CXXFLAGS += -DARM # Windows else TARGET := $(TARGET_NAME)_libretro.dll CC = gcc CXX = g++ SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T CXXFLAGS += -D__WIN32__ -D__WIN32_LIBSNES__ endif CORE_DIR := .. ifeq ($(DEBUG), 1) CXXFLAGS += -O0 -g CFLAGS += -O0 -g else CXXFLAGS += -O3 -DNDEBUG CFLAGS += -O3 -DNDEBUG endif include Makefile.common OBJECTS := $(SOURCES_CXX:.cpp=.o) $(SOURCES_C:.c=.o) ifeq ($(platform), sncps3) WARNINGS_DEFINES = CODE_DEFINES = else WARNINGS_DEFINES = -Wall -W -Wno-unused-parameter CODE_DEFINES = -fomit-frame-pointer endif ifneq ($(HAVE_EXCEPTIONS), 1) CXXFLAGS += -fno-exceptions endif CXXFLAGS += $(CODE_DEFINES) -fno-rtti -pedantic $(WARNINGS_DEFINES) $(fpic) CXXFLAGS += -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR -D__LIBRETRO__ CFLAGS = $(CXXFLAGS) ifeq ($(platform), theos_ios) COMMON_FLAGS := -DIOS -DARM $(COMMON_DEFINES) $(INCFLAGS) -I$(THEOS_INCLUDE_PATH) -Wno-error $(LIBRARY_NAME)_CFLAGS += $(CFLAGS) $(COMMON_FLAGS) $(LIBRARY_NAME)_CXXFLAGS += $(CXXFLAGS) $(COMMON_FLAGS) ${LIBRARY_NAME}_FILES = $(SOURCES_CXX) $(SOURCES_C) include $(THEOS_MAKE_PATH)/library.mk else all: $(TARGET) $(TARGET): $(OBJECTS) ifeq ($(STATIC_LINKING), 1) $(AR) rcs $@ $(OBJECTS) else $(CXX) $(fpic) $(SHARED) $(INCFLAGS) -o $@ $(OBJECTS) $(LIBM) endif %.o: %.cpp $(CXX) $(INCFLAGS) $(CXXFLAGS) -c -o $@ $< %.o: %.c $(CC) $(INCFLAGS) $(CFLAGS) -c -o $@ $< clean: rm -f $(OBJECTS) $(TARGET) endif apu/bapu/smp/core/op_pc.b000664 001750 001750 00000006072 12720446475 016430 0ustar00sergiosergio000000 000000 bra(0x2f, 0), beq(0xf0, !regs.p.z), bne(0xd0, regs.p.z), bcs(0xb0, !regs.p.c), bcc(0x90, regs.p.c), bvs(0x70, !regs.p.v), bvc(0x50, regs.p.v), bmi(0x30, !regs.p.n), bpl(0x10, regs.p.n) { 1:rd = op_readpc(); if($1)end; 2:op_io(); 3:op_io(); regs.pc += (int8)rd; } bbs0(0x03, 0x01, !=), bbc0(0x13, 0x01, ==), bbs1(0x23, 0x02, !=), bbc1(0x33, 0x02, ==), bbs2(0x43, 0x04, !=), bbc2(0x53, 0x04, ==), bbs3(0x63, 0x08, !=), bbc3(0x73, 0x08, ==), bbs4(0x83, 0x10, !=), bbc4(0x93, 0x10, ==), bbs5(0xa3, 0x20, !=), bbc5(0xb3, 0x20, ==), bbs6(0xc3, 0x40, !=), bbc6(0xd3, 0x40, ==), bbs7(0xe3, 0x80, !=), bbc7(0xf3, 0x80, ==) { 1:dp = op_readpc(); 2:sp = op_readdp(dp); 3:rd = op_readpc(); 4:op_io(); if((sp & $1) $2 $1)end; 5:op_io(); 6:op_io(); regs.pc += (int8)rd; } cbne_dp(0x2e) { 1:dp = op_readpc(); 2:sp = op_readdp(dp); 3:rd = op_readpc(); 4:op_io(); if(regs.a == sp)end; 5:op_io(); 6:op_io(); regs.pc += (int8)rd; } cbne_dpx(0xde) { 1:dp = op_readpc(); 2:op_io(); 3:sp = op_readdp(dp + regs.x); 4:rd = op_readpc(); 5:op_io(); if(regs.a == sp)end; 6:op_io(); 7:op_io(); regs.pc += (int8)rd; } dbnz_dp(0x6e) { 1:dp = op_readpc(); 2:wr = op_readdp(dp); 3:op_writedp(dp, --wr); 4:rd = op_readpc(); if(wr == 0x00)end; 5:op_io(); 6:op_io(); regs.pc += (int8)rd; } dbnz_y(0xfe) { 1:rd = op_readpc(); 2:op_io(); regs.y--; 3:op_io(); if(regs.y == 0x00)end; 4:op_io(); 5:op_io(); regs.pc += (int8)rd; } jmp_addr(0x5f) { 1:rd = op_readpc(); 2:rd |= op_readpc() << 8; regs.pc = rd; } jmp_iaddrx(0x1f) { 1:dp = op_readpc(); 2:dp |= op_readpc() << 8; 3:op_io(); dp += regs.x; 4:rd = op_readaddr(dp); 5:rd |= op_readaddr(dp + 1) << 8; regs.pc = rd; } call(0x3f) { 1:rd = op_readpc(); 2:rd |= op_readpc() << 8; 3:op_io(); 4:op_io(); 5:op_io(); 6:op_writestack(regs.pc >> 8); 7:op_writestack(regs.pc); regs.pc = rd; } pcall(0x4f) { 1:rd = op_readpc(); 2:op_io(); 3:op_io(); 4:op_writestack(regs.pc >> 8); 5:op_writestack(regs.pc); regs.pc = 0xff00 | rd; } tcall_0(0x01, 0), tcall_1(0x11, 1), tcall_2(0x21, 2), tcall_3(0x31, 3), tcall_4(0x41, 4), tcall_5(0x51, 5), tcall_6(0x61, 6), tcall_7(0x71, 7), tcall_8(0x81, 8), tcall_9(0x91, 9), tcall_10(0xa1, 10), tcall_11(0xb1, 11), tcall_12(0xc1, 12), tcall_13(0xd1, 13), tcall_14(0xe1, 14), tcall_15(0xf1, 15) { 1:dp = 0xffde - ($1 << 1); rd = op_readaddr(dp); 2:rd |= op_readaddr(dp + 1) << 8; 3:op_io(); 4:op_io(); 5:op_io(); 6:op_writestack(regs.pc >> 8); 7:op_writestack(regs.pc); regs.pc = rd; } brk(0x0f) { 1:rd = op_readaddr(0xffde); 2:rd |= op_readaddr(0xffdf) << 8; 3:op_io(); 4:op_io(); 5:op_writestack(regs.pc >> 8); 6:op_writestack(regs.pc); 7:op_writestack(regs.p); regs.pc = rd; regs.p.b = 1; regs.p.i = 0; } ret(0x6f) { 1:rd = op_readstack(); 2:rd |= op_readstack() << 8; 3:op_io(); 4:op_io(); regs.pc = rd; } reti(0x7f) { 1:regs.p = op_readstack(); 2:rd = op_readstack(); 3:rd |= op_readstack() << 8; 4:op_io(); 5:op_io(); regs.pc = rd; } loadzip.cpp000664 001750 001750 00000021471 12720446475 014070 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef UNZIP_SUPPORT #include #include #include "unzip/unzip.h" #include "snes9x.h" #include "memmap.h" bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer) { *TotalFileSize = 0; unzFile file = unzOpen(zipname); if (file == NULL) return (FALSE); // find largest file in zip file (under MAX_ROM_SIZE) or a file with extension .1 char filename[132]; uint32 filesize = 0; int port = unzGoToFirstFile(file); unz_file_info info; while (port == UNZ_OK) { char name[132]; unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0); if (info.uncompressed_size > CMemory::MAX_ROM_SIZE + 512) { port = unzGoToNextFile(file); continue; } if (info.uncompressed_size > filesize) { strcpy(filename, name); filesize = info.uncompressed_size; } int len = strlen(name); if (len > 2 && name[len - 2] == '.' && name[len - 1] == '1') { strcpy(filename, name); filesize = info.uncompressed_size; break; } port = unzGoToNextFile(file); } if (!(port == UNZ_END_OF_LIST_OF_FILE || port == UNZ_OK) || filesize == 0) { assert(unzClose(file) == UNZ_OK); return (FALSE); } // find extension char tmp[2] = { 0, 0 }; char *ext = strrchr(filename, '.'); if (ext) ext++; else ext = tmp; uint8 *ptr = buffer; bool8 more = FALSE; unzLocateFile(file, filename, 1); unzGetCurrentFileInfo(file, &info, filename, 128, NULL, 0, NULL, 0); if (unzOpenCurrentFile(file) != UNZ_OK) { unzClose(file); return (FALSE); } do { assert(info.uncompressed_size <= CMemory::MAX_ROM_SIZE + 512); uint32 FileSize = info.uncompressed_size; int l = unzReadCurrentFile(file, ptr, FileSize); if (unzCloseCurrentFile(file) == UNZ_CRCERROR) { unzClose(file); return (FALSE); } if (l <= 0 || l != FileSize) { unzClose(file); return (FALSE); } FileSize = Memory.HeaderRemove(FileSize, ptr); ptr += FileSize; *TotalFileSize += FileSize; int len; if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 512 && (isdigit(ext[0]) && ext[1] == 0 && ext[0] < '9')) { more = TRUE; ext[0]++; } else if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 512) { if (ext == tmp) len = strlen(filename); else len = ext - filename - 1; if ((len == 7 || len == 8) && strncasecmp(filename, "sf", 2) == 0 && isdigit(filename[2]) && isdigit(filename[3]) && isdigit(filename[4]) && isdigit(filename[5]) && isalpha(filename[len - 1])) { more = TRUE; filename[len - 1]++; } } else more = FALSE; if (more) { if (unzLocateFile(file, filename, 1) != UNZ_OK || unzGetCurrentFileInfo(file, &info, filename, 128, NULL, 0, NULL, 0) != UNZ_OK || unzOpenCurrentFile(file) != UNZ_OK) break; } } while (more); unzClose(file); return (TRUE); } #endif movie.cpp000664 001750 001750 00000075201 12720446475 013545 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ // Input recording/playback code // (c) Copyright 2004 blip #ifndef __WIN32__ #include #endif #include "snes9x.h" #include "memmap.h" #include "controls.h" #include "snapshot.h" #include "movie.h" #include "language.h" #ifdef NETPLAY_SUPPORT #include "netplay.h" #endif #ifdef __WIN32__ #include #ifndef W_OK #define W_OK 2 #endif #define ftruncate chsize #endif #define SMV_MAGIC 0x1a564d53 // SMV0x1a #define SMV_VERSION 5 #define SMV_HEADER_SIZE 64 #define SMV_EXTRAROMINFO_SIZE 30 #define BUFFER_GROWTH_SIZE 4096 enum MovieState { MOVIE_STATE_NONE = 0, MOVIE_STATE_PLAY, MOVIE_STATE_RECORD }; struct SMovie { enum MovieState State; FILE *File; char Filename[PATH_MAX + 1]; char ROMName[23]; uint32 ROMCRC32; uint32 MovieId; uint32 Version; uint32 SaveStateOffset; uint32 ControllerDataOffset; uint8 ControllersMask; uint8 Opts; uint8 SyncFlags; uint32 MaxFrame; uint32 MaxSample; uint32 CurrentFrame; uint32 CurrentSample; uint32 BytesPerSample; uint32 RerecordCount; bool8 ReadOnly; uint8 PortType[2]; int8 PortIDs[2][4]; uint8 *InputBuffer; uint8 *InputBufferPtr; uint32 InputBufferSize; }; static struct SMovie Movie; static uint8 prevPortType[2]; static int8 prevPortIDs[2][4]; static bool8 prevMouseMaster, prevSuperScopeMaster, prevJustifierMaster, prevMultiPlayer5Master; static uint8 Read8 (uint8 *&); static uint16 Read16 (uint8 *&); static uint32 Read32 (uint8 *&); static void Write8 (uint8, uint8 *&); static void Write16 (uint16, uint8 *&); static void Write32 (uint32, uint8 *&); static void store_previous_settings (void); static void restore_previous_settings (void); static void store_movie_settings (void); static void restore_movie_settings (void); static int bytes_per_sample (void); static void reserve_buffer_space (uint32); static void reset_controllers (void); static void read_frame_controller_data (bool); static void write_frame_controller_data (void); static void flush_movie (void); static void truncate_movie (void); static int read_movie_header (FILE *, SMovie *); static int read_movie_extrarominfo (FILE *, SMovie *); static void write_movie_header (FILE *, SMovie *); static void write_movie_extrarominfo (FILE *, SMovie *); static void change_state (MovieState); // HACK: reduce movie size by not storing changes that can only affect polled input in the movie for these types, // because currently no port sets these types to polling #define SKIPPED_POLLING_PORT_TYPE(x) (((x) == CTL_NONE) || ((x) == CTL_JOYPAD) || ((x) == CTL_MP5)) #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif static uint8 Read8 (uint8 *&ptr) { uint8 v = *ptr++; return (v); } static uint16 Read16 (uint8 *&ptr) { uint16 v = READ_WORD(ptr); ptr += 2; return (v); } static uint32 Read32 (uint8 *&ptr) { uint32 v = READ_DWORD(ptr); ptr += 4; return (v); } static void Write8 (uint8 v, uint8 *&ptr) { *ptr++ = v; } static void Write16 (uint16 v, uint8 *&ptr) { WRITE_WORD(ptr, v); ptr += 2; } static void Write32 (uint32 v, uint8 *&ptr) { WRITE_DWORD(ptr, v); ptr += 4; } static void store_previous_settings (void) { for (int i = 0; i < 2; i++) { enum controllers pt; S9xGetController(i, &pt, &prevPortIDs[i][0], &prevPortIDs[i][1], &prevPortIDs[i][2], &prevPortIDs[i][3]); prevPortType[i] = (uint8) pt; } prevMouseMaster = Settings.MouseMaster; prevSuperScopeMaster = Settings.SuperScopeMaster; prevJustifierMaster = Settings.JustifierMaster; prevMultiPlayer5Master = Settings.MultiPlayer5Master; } static void restore_previous_settings (void) { Settings.MouseMaster = prevMouseMaster; Settings.SuperScopeMaster = prevSuperScopeMaster; Settings.JustifierMaster = prevJustifierMaster; Settings.MultiPlayer5Master = prevMultiPlayer5Master; S9xSetController(0, (enum controllers) prevPortType[0], prevPortIDs[0][0], prevPortIDs[0][1], prevPortIDs[0][2], prevPortIDs[0][3]); S9xSetController(1, (enum controllers) prevPortType[1], prevPortIDs[1][0], prevPortIDs[1][1], prevPortIDs[1][2], prevPortIDs[1][3]); } static void store_movie_settings (void) { for (int i = 0; i < 2; i++) { enum controllers pt; S9xGetController(i, &pt, &Movie.PortIDs[i][0], &Movie.PortIDs[i][1], &Movie.PortIDs[i][2], &Movie.PortIDs[i][3]); Movie.PortType[i] = (uint8) pt; } } static void restore_movie_settings (void) { Settings.MouseMaster = (Movie.PortType[0] == CTL_MOUSE || Movie.PortType[1] == CTL_MOUSE); Settings.SuperScopeMaster = (Movie.PortType[0] == CTL_SUPERSCOPE || Movie.PortType[1] == CTL_SUPERSCOPE); Settings.JustifierMaster = (Movie.PortType[0] == CTL_JUSTIFIER || Movie.PortType[1] == CTL_JUSTIFIER); Settings.MultiPlayer5Master = (Movie.PortType[0] == CTL_MP5 || Movie.PortType[1] == CTL_MP5); S9xSetController(0, (enum controllers) Movie.PortType[0], Movie.PortIDs[0][0], Movie.PortIDs[0][1], Movie.PortIDs[0][2], Movie.PortIDs[0][3]); S9xSetController(1, (enum controllers) Movie.PortType[1], Movie.PortIDs[1][0], Movie.PortIDs[1][1], Movie.PortIDs[1][2], Movie.PortIDs[1][3]); } static int bytes_per_sample (void) { int num_controllers = 0; for (int i = 0; i < 8; i++) { if (Movie.ControllersMask & (1 << i)) num_controllers++; } int bytes = CONTROLLER_DATA_SIZE * num_controllers; for (int p = 0; p < 2; p++) { if (Movie.PortType[p] == CTL_MOUSE) bytes += MOUSE_DATA_SIZE; else if (Movie.PortType[p] == CTL_SUPERSCOPE) bytes += SCOPE_DATA_SIZE; else if (Movie.PortType[p] == CTL_JUSTIFIER) bytes += JUSTIFIER_DATA_SIZE; } return (bytes); } static void reserve_buffer_space (uint32 space_needed) { if (space_needed > Movie.InputBufferSize) { uint32 ptr_offset = Movie.InputBufferPtr - Movie.InputBuffer; uint32 alloc_chunks = space_needed / BUFFER_GROWTH_SIZE; Movie.InputBufferSize = BUFFER_GROWTH_SIZE * (alloc_chunks + 1); Movie.InputBuffer = (uint8 *) realloc(Movie.InputBuffer, Movie.InputBufferSize); Movie.InputBufferPtr = Movie.InputBuffer + ptr_offset; } } static void reset_controllers (void) { for (int i = 0; i < 8; i++) MovieSetJoypad(i, 0); uint8 clearedMouse[MOUSE_DATA_SIZE]; memset(clearedMouse, 0, MOUSE_DATA_SIZE); clearedMouse[4] = 1; uint8 clearedScope[SCOPE_DATA_SIZE]; memset(clearedScope, 0, SCOPE_DATA_SIZE); uint8 clearedJustifier[JUSTIFIER_DATA_SIZE]; memset(clearedJustifier, 0, JUSTIFIER_DATA_SIZE); for (int p = 0; p < 2; p++) { MovieSetMouse(p, clearedMouse, true); MovieSetScope(p, clearedScope); MovieSetJustifier(p, clearedJustifier); } } static void read_frame_controller_data (bool addFrame) { // reset code check if (Movie.InputBufferPtr[0] == 0xff) { bool reset = true; for (int i = 1; i < (int) Movie.BytesPerSample; i++) { if (Movie.InputBufferPtr[i] != 0xff) { reset = false; break; } } if (reset) { Movie.InputBufferPtr += Movie.BytesPerSample; S9xSoftReset(); return; } } for (int i = 0; i < 8; i++) { if (Movie.ControllersMask & (1 << i)) MovieSetJoypad(i, Read16(Movie.InputBufferPtr)); else MovieSetJoypad(i, 0); // pretend the controller is disconnected } for (int p = 0; p < 2; p++) { if (Movie.PortType[p] == CTL_MOUSE) { uint8 buf[MOUSE_DATA_SIZE]; memcpy(buf, Movie.InputBufferPtr, MOUSE_DATA_SIZE); Movie.InputBufferPtr += MOUSE_DATA_SIZE; MovieSetMouse(p, buf, !addFrame); } else if (Movie.PortType[p] == CTL_SUPERSCOPE) { uint8 buf[SCOPE_DATA_SIZE]; memcpy(buf, Movie.InputBufferPtr, SCOPE_DATA_SIZE); Movie.InputBufferPtr += SCOPE_DATA_SIZE; MovieSetScope(p, buf); } else if (Movie.PortType[p] == CTL_JUSTIFIER) { uint8 buf[JUSTIFIER_DATA_SIZE]; memcpy(buf, Movie.InputBufferPtr, JUSTIFIER_DATA_SIZE); Movie.InputBufferPtr += JUSTIFIER_DATA_SIZE; MovieSetJustifier(p, buf); } } } static void write_frame_controller_data (void) { reserve_buffer_space((uint32) (Movie.InputBufferPtr + Movie.BytesPerSample - Movie.InputBuffer)); for (int i = 0; i < 8; i++) { if (Movie.ControllersMask & (1 << i)) Write16(MovieGetJoypad(i), Movie.InputBufferPtr); else MovieSetJoypad(i, 0); // pretend the controller is disconnected } for (int p = 0; p < 2; p++) { if (Movie.PortType[p] == CTL_MOUSE) { uint8 buf[MOUSE_DATA_SIZE]; MovieGetMouse(p, buf); memcpy(Movie.InputBufferPtr, buf, MOUSE_DATA_SIZE); Movie.InputBufferPtr += MOUSE_DATA_SIZE; } else if (Movie.PortType[p] == CTL_SUPERSCOPE) { uint8 buf[SCOPE_DATA_SIZE]; MovieGetScope(p, buf); memcpy(Movie.InputBufferPtr, buf, SCOPE_DATA_SIZE); Movie.InputBufferPtr += SCOPE_DATA_SIZE; } else if (Movie.PortType[p] == CTL_JUSTIFIER) { uint8 buf[JUSTIFIER_DATA_SIZE]; MovieGetJustifier(p, buf); memcpy(Movie.InputBufferPtr, buf, JUSTIFIER_DATA_SIZE); Movie.InputBufferPtr += JUSTIFIER_DATA_SIZE; } } } static void flush_movie (void) { if (!Movie.File) return; fseek(Movie.File, 0, SEEK_SET); write_movie_header(Movie.File, &Movie); fseek(Movie.File, Movie.ControllerDataOffset, SEEK_SET); size_t ignore; ignore = fwrite(Movie.InputBuffer, 1, Movie.BytesPerSample * (Movie.MaxSample + 1), Movie.File); } static void truncate_movie (void) { if (!Movie.File || !Settings.MovieTruncate) return; if (Movie.SaveStateOffset > Movie.ControllerDataOffset) return; int ignore; ignore = ftruncate(fileno(Movie.File), Movie.ControllerDataOffset + Movie.BytesPerSample * (Movie.MaxSample + 1)); } static int read_movie_header (FILE *fd, SMovie *movie) { uint32 value; uint8 buf[SMV_HEADER_SIZE], *ptr = buf; if (fread(buf, 1, SMV_HEADER_SIZE, fd) != SMV_HEADER_SIZE) return (WRONG_FORMAT); value = Read32(ptr); if (value != SMV_MAGIC) return (WRONG_FORMAT); value = Read32(ptr); if(value > SMV_VERSION || value < 4) return (WRONG_VERSION); movie->Version = value; movie->MovieId = Read32(ptr); movie->RerecordCount = Read32(ptr); movie->MaxFrame = Read32(ptr); movie->ControllersMask = Read8(ptr); movie->Opts = Read8(ptr); ptr++; movie->SyncFlags = Read8(ptr); movie->SaveStateOffset = Read32(ptr); movie->ControllerDataOffset = Read32(ptr); movie->MaxSample = Read32(ptr); movie->PortType[0] = Read8(ptr); movie->PortType[1] = Read8(ptr); for (int p = 0; p < 2; p++) { for (int i = 0; i < 4; i++) movie->PortIDs[p][i] = Read8(ptr); } if (movie->MaxSample < movie->MaxFrame) movie->MaxSample = movie->MaxFrame; return (SUCCESS); } static int read_movie_extrarominfo (FILE *fd, SMovie *movie) { uint8 buf[SMV_EXTRAROMINFO_SIZE], *ptr = buf; fseek(fd, movie->SaveStateOffset - SMV_EXTRAROMINFO_SIZE, SEEK_SET); if (fread(buf, 1, SMV_EXTRAROMINFO_SIZE, fd) != SMV_EXTRAROMINFO_SIZE) return (WRONG_FORMAT); ptr += 3; // zero bytes movie->ROMCRC32 = Read32(ptr); strncpy(movie->ROMName, (char *) ptr, 23); return (SUCCESS); } static void write_movie_header (FILE *fd, SMovie *movie) { uint8 buf[SMV_HEADER_SIZE], *ptr = buf; memset(buf, 0, sizeof(buf)); Write32(SMV_MAGIC, ptr); Write32(SMV_VERSION, ptr); Write32(movie->MovieId, ptr); Write32(movie->RerecordCount, ptr); Write32(movie->MaxFrame, ptr); Write8(movie->ControllersMask, ptr); Write8(movie->Opts, ptr); ptr++; Write8(movie->SyncFlags, ptr); Write32(movie->SaveStateOffset, ptr); Write32(movie->ControllerDataOffset, ptr); Write32(movie->MaxSample, ptr); Write8(movie->PortType[0], ptr); Write8(movie->PortType[1], ptr); for (int p = 0; p < 2; p++) { for (int i = 0; i < 4; i++) Write8(movie->PortIDs[p][i], ptr); } size_t ignore; ignore = fwrite(buf, 1, SMV_HEADER_SIZE, fd); } static void write_movie_extrarominfo (FILE *fd, SMovie *movie) { uint8 buf[SMV_EXTRAROMINFO_SIZE], *ptr = buf; Write8(0, ptr); Write8(0, ptr); Write8(0, ptr); Write32(movie->ROMCRC32, ptr); strncpy((char *) ptr, movie->ROMName, 23); size_t ignore; ignore = fwrite(buf, 1, SMV_EXTRAROMINFO_SIZE, fd); } static void change_state (MovieState new_state) { if (new_state == Movie.State) return; if (Movie.State == MOVIE_STATE_RECORD) flush_movie(); if (new_state == MOVIE_STATE_NONE) { truncate_movie(); fclose(Movie.File); Movie.File = NULL; if (S9xMoviePlaying() || S9xMovieRecording()) restore_previous_settings(); } Movie.State = new_state; } void S9xMovieFreeze (uint8 **buf, uint32 *size) { if (!S9xMovieActive()) return; uint32 size_needed; uint8 *ptr; size_needed = sizeof(Movie.MovieId) + sizeof(Movie.CurrentFrame) + sizeof(Movie.MaxFrame) + sizeof(Movie.CurrentSample) + sizeof(Movie.MaxSample); size_needed += (uint32) (Movie.BytesPerSample * (Movie.MaxSample + 1)); *size = size_needed; *buf = new uint8[size_needed]; ptr = *buf; if (!ptr) return; Write32(Movie.MovieId, ptr); Write32(Movie.CurrentFrame, ptr); Write32(Movie.MaxFrame, ptr); Write32(Movie.CurrentSample, ptr); Write32(Movie.MaxSample, ptr); memcpy(ptr, Movie.InputBuffer, Movie.BytesPerSample * (Movie.MaxSample + 1)); } int S9xMovieUnfreeze (uint8 *buf, uint32 size) { if (!S9xMovieActive()) return (FILE_NOT_FOUND); if (size < sizeof(Movie.MovieId) + sizeof(Movie.CurrentFrame) + sizeof(Movie.MaxFrame) + sizeof(Movie.CurrentSample) + sizeof(Movie.MaxSample)) return (WRONG_FORMAT); uint8 *ptr = buf; uint32 movie_id = Read32(ptr); uint32 current_frame = Read32(ptr); uint32 max_frame = Read32(ptr); uint32 current_sample = Read32(ptr); uint32 max_sample = Read32(ptr); uint32 space_needed = (Movie.BytesPerSample * (max_sample + 1)); if (current_frame > max_frame || current_sample > max_sample || space_needed > size) return (WRONG_MOVIE_SNAPSHOT); if (Settings.WrongMovieStateProtection) if (movie_id != Movie.MovieId) if (max_frame < Movie.MaxFrame || max_sample < Movie.MaxSample || memcmp(Movie.InputBuffer, ptr, space_needed)) return (WRONG_MOVIE_SNAPSHOT); if (!Movie.ReadOnly) { change_state(MOVIE_STATE_RECORD); Movie.CurrentFrame = current_frame; Movie.MaxFrame = max_frame; Movie.CurrentSample = current_sample; Movie.MaxSample = max_sample; Movie.RerecordCount++; store_movie_settings(); reserve_buffer_space(space_needed); memcpy(Movie.InputBuffer, ptr, space_needed); flush_movie(); fseek(Movie.File, Movie.ControllerDataOffset + (Movie.BytesPerSample * (Movie.CurrentSample + 1)), SEEK_SET); } else { uint32 space_processed = (Movie.BytesPerSample * (current_sample + 1)); if (current_frame > Movie.MaxFrame || current_sample > Movie.MaxSample || memcmp(Movie.InputBuffer, ptr, space_processed)) return (SNAPSHOT_INCONSISTENT); change_state(MOVIE_STATE_PLAY); Movie.CurrentFrame = current_frame; Movie.CurrentSample = current_sample; } Movie.InputBufferPtr = Movie.InputBuffer + (Movie.BytesPerSample * Movie.CurrentSample); read_frame_controller_data(true); return (SUCCESS); } int S9xMovieOpen (const char *filename, bool8 read_only) { FILE *fd; STREAM stream; int result; int fn; if (!(fd = fopen(filename, "rb+"))) { if (!(fd = fopen(filename, "rb"))) return (FILE_NOT_FOUND); else read_only = TRUE; } change_state(MOVIE_STATE_NONE); result = read_movie_header(fd, &Movie); if (result != SUCCESS) { fclose(fd); return (result); } read_movie_extrarominfo(fd, &Movie); fflush(fd); fn = fileno(fd); store_previous_settings(); restore_movie_settings(); lseek(fn, Movie.SaveStateOffset, SEEK_SET); stream = REOPEN_STREAM(fn, "rb"); if (!stream) return (FILE_NOT_FOUND); if (Movie.Opts & MOVIE_OPT_FROM_RESET) { S9xReset(); reset_controllers(); result = (READ_STREAM(Memory.SRAM, 0x20000, stream) == 0x20000) ? SUCCESS : WRONG_FORMAT; } else result = S9xUnfreezeFromStream(stream); CLOSE_STREAM(stream); if (result != SUCCESS) return (result); if (!(fd = fopen(filename, "rb+"))) { if (!(fd = fopen(filename, "rb"))) return (FILE_NOT_FOUND); else read_only = TRUE; } if (fseek(fd, Movie.ControllerDataOffset, SEEK_SET)) return (WRONG_FORMAT); Movie.File = fd; Movie.BytesPerSample = bytes_per_sample(); Movie.InputBufferPtr = Movie.InputBuffer; reserve_buffer_space(Movie.BytesPerSample * (Movie.MaxSample + 1)); size_t ignore; ignore = fread(Movie.InputBufferPtr, 1, Movie.BytesPerSample * (Movie.MaxSample + 1), fd); // read "baseline" controller data if (Movie.MaxSample && Movie.MaxFrame) read_frame_controller_data(true); Movie.CurrentFrame = 0; Movie.CurrentSample = 0; Movie.ReadOnly = read_only; strncpy(Movie.Filename, filename, PATH_MAX + 1); Movie.Filename[PATH_MAX] = 0; change_state(MOVIE_STATE_PLAY); S9xUpdateFrameCounter(-1); S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_REPLAY); return (SUCCESS); } int S9xMovieCreate (const char *filename, uint8 controllers_mask, uint8 opts, const wchar_t *metadata, int metadata_length) { FILE *fd; STREAM stream; if (controllers_mask == 0) return (WRONG_FORMAT); if (!(fd = fopen(filename, "wb"))) return (FILE_NOT_FOUND); if (metadata_length > MOVIE_MAX_METADATA) metadata_length = MOVIE_MAX_METADATA; change_state(MOVIE_STATE_NONE); store_previous_settings(); store_movie_settings(); Movie.MovieId = (uint32) time(NULL); Movie.RerecordCount = 0; Movie.MaxFrame = 0; Movie.MaxSample = 0; Movie.SaveStateOffset = SMV_HEADER_SIZE + (sizeof(uint16) * metadata_length) + SMV_EXTRAROMINFO_SIZE; Movie.ControllerDataOffset = 0; Movie.ControllersMask = controllers_mask; Movie.Opts = opts; Movie.SyncFlags = MOVIE_SYNC_DATA_EXISTS | MOVIE_SYNC_HASROMINFO; write_movie_header(fd, &Movie); // convert wchar_t metadata string/array to a uint16 array // XXX: UTF-8 is much better... if (metadata_length > 0) { uint8 meta_buf[sizeof(uint16) * MOVIE_MAX_METADATA]; for (int i = 0; i < metadata_length; i++) { uint16 c = (uint16) metadata[i]; meta_buf[i * 2] = (uint8) (c & 0xff); meta_buf[i * 2 + 1] = (uint8) ((c >> 8) & 0xff); } size_t ignore; ignore = fwrite(meta_buf, sizeof(uint16), metadata_length, fd); } Movie.ROMCRC32 = Memory.ROMCRC32; strncpy(Movie.ROMName, Memory.RawROMName, 23); write_movie_extrarominfo(fd, &Movie); fclose(fd); stream = OPEN_STREAM(filename, "ab"); if (!stream) return (FILE_NOT_FOUND); if (opts & MOVIE_OPT_FROM_RESET) { S9xReset(); reset_controllers(); WRITE_STREAM(Memory.SRAM, 0x20000, stream); } else S9xFreezeToStream(stream); CLOSE_STREAM(stream); if (!(fd = fopen(filename, "rb+"))) return (FILE_NOT_FOUND); fseek(fd, 0, SEEK_END); Movie.ControllerDataOffset = (uint32) ftell(fd); // 16-byte align the controller input, for hex-editing friendliness if nothing else while (Movie.ControllerDataOffset % 16) { fputc(0xcc, fd); // arbitrary Movie.ControllerDataOffset++; } // write "baseline" controller data Movie.File = fd; Movie.BytesPerSample = bytes_per_sample(); Movie.InputBufferPtr = Movie.InputBuffer; write_frame_controller_data(); Movie.CurrentFrame = 0; Movie.CurrentSample = 0; Movie.ReadOnly = false; strncpy(Movie.Filename, filename, PATH_MAX + 1); Movie.Filename[PATH_MAX] = 0; change_state(MOVIE_STATE_RECORD); S9xUpdateFrameCounter(-1); S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_RECORD); return (SUCCESS); } int S9xMovieGetInfo (const char *filename, struct MovieInfo *info) { FILE *fd; SMovie local_movie; int metadata_length; int result, i; flush_movie(); memset(info, 0, sizeof(*info)); if (!(fd = fopen(filename, "rb"))) return (FILE_NOT_FOUND); result = read_movie_header(fd, &local_movie); if (result != SUCCESS) return (result); info->TimeCreated = (time_t) local_movie.MovieId; info->Version = local_movie.Version; info->Opts = local_movie.Opts; info->SyncFlags = local_movie.SyncFlags; info->ControllersMask = local_movie.ControllersMask; info->RerecordCount = local_movie.RerecordCount; info->LengthFrames = local_movie.MaxFrame; info->LengthSamples = local_movie.MaxSample; info->PortType[0] = local_movie.PortType[0]; info->PortType[1] = local_movie.PortType[1]; if (local_movie.SaveStateOffset > SMV_HEADER_SIZE) { uint8 meta_buf[sizeof(uint16) * MOVIE_MAX_METADATA]; int curRomInfoSize = (local_movie.SyncFlags & MOVIE_SYNC_HASROMINFO) ? SMV_EXTRAROMINFO_SIZE : 0; metadata_length = ((int) local_movie.SaveStateOffset - SMV_HEADER_SIZE - curRomInfoSize) / sizeof(uint16); metadata_length = (metadata_length >= MOVIE_MAX_METADATA) ? MOVIE_MAX_METADATA - 1 : metadata_length; metadata_length = (int) fread(meta_buf, sizeof(uint16), metadata_length, fd); for (i = 0; i < metadata_length; i++) { uint16 c = meta_buf[i * 2] | (meta_buf[i * 2 + 1] << 8); info->Metadata[i] = (wchar_t) c; } info->Metadata[i] = '\0'; } else info->Metadata[0] = '\0'; read_movie_extrarominfo(fd, &local_movie); info->ROMCRC32 = local_movie.ROMCRC32; strncpy(info->ROMName, local_movie.ROMName, 23); fclose(fd); if ((fd = fopen(filename, "r+")) == NULL) info->ReadOnly = true; else fclose(fd); return (SUCCESS); } void S9xMovieUpdate (bool addFrame) { switch (Movie.State) { case MOVIE_STATE_PLAY: { if (Movie.CurrentFrame >= Movie.MaxFrame || Movie.CurrentSample >= Movie.MaxSample) { change_state(MOVIE_STATE_NONE); S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_END); return; } else { if (addFrame) S9xUpdateFrameCounter(); else if (SKIPPED_POLLING_PORT_TYPE(Movie.PortType[0]) && SKIPPED_POLLING_PORT_TYPE(Movie.PortType[1])) return; read_frame_controller_data(addFrame); Movie.CurrentSample++; if (addFrame) Movie.CurrentFrame++; } break; } case MOVIE_STATE_RECORD: { if (addFrame) S9xUpdateFrameCounter(); else if (SKIPPED_POLLING_PORT_TYPE(Movie.PortType[0]) && SKIPPED_POLLING_PORT_TYPE(Movie.PortType[1])) return; write_frame_controller_data(); Movie.MaxSample = ++Movie.CurrentSample; if (addFrame) Movie.MaxFrame = ++Movie.CurrentFrame; size_t ignore; ignore = fwrite((Movie.InputBufferPtr - Movie.BytesPerSample), 1, Movie.BytesPerSample, Movie.File); break; } default: { if (addFrame) S9xUpdateFrameCounter(); break; } } } void S9xMovieUpdateOnReset (void) { if (Movie.State == MOVIE_STATE_RECORD) { reserve_buffer_space((uint32) (Movie.InputBufferPtr + Movie.BytesPerSample - Movie.InputBuffer)); memset(Movie.InputBufferPtr, 0xFF, Movie.BytesPerSample); Movie.InputBufferPtr += Movie.BytesPerSample; Movie.MaxSample = ++Movie.CurrentSample; Movie.MaxFrame = ++Movie.CurrentFrame; size_t ignore; ignore = fwrite((Movie.InputBufferPtr - Movie.BytesPerSample), 1, Movie.BytesPerSample, Movie.File); } } void S9xMovieInit (void) { memset(&Movie, 0, sizeof(Movie)); Movie.State = MOVIE_STATE_NONE; } void S9xMovieStop (bool8 suppress_message) { if (Movie.State != MOVIE_STATE_NONE) { change_state(MOVIE_STATE_NONE); if (!suppress_message) S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_STOP); } } void S9xMovieShutdown (void) { if (S9xMovieActive()) S9xMovieStop(TRUE); } bool8 S9xMovieActive (void) { return (Movie.State != MOVIE_STATE_NONE); } bool8 S9xMoviePlaying (void) { return (Movie.State == MOVIE_STATE_PLAY); } bool8 S9xMovieRecording (void) { return (Movie.State == MOVIE_STATE_RECORD); } uint8 S9xMovieControllers (void) { return (Movie.ControllersMask); } bool8 S9xMovieReadOnly (void) { if (!S9xMovieActive()) return (FALSE); return (Movie.ReadOnly); } uint32 S9xMovieGetId (void) { if (!S9xMovieActive()) return (0); return (Movie.MovieId); } uint32 S9xMovieGetLength (void) { if (!S9xMovieActive()) return (0); return (Movie.MaxFrame); } uint32 S9xMovieGetFrameCounter (void) { if (!S9xMovieActive()) return (0); return (Movie.CurrentFrame); } void S9xMovieToggleRecState (void) { Movie.ReadOnly = !Movie.ReadOnly; if (Movie.ReadOnly) S9xMessage(S9X_INFO, S9X_MOVIE_INFO, "Movie is now read-only."); else S9xMessage(S9X_INFO, S9X_MOVIE_INFO, "Movie is now read+write."); } void S9xMovieToggleFrameDisplay (void) { Settings.DisplayMovieFrame = !Settings.DisplayMovieFrame; S9xReRefresh(); } void S9xUpdateFrameCounter (int offset) { extern bool8 pad_read; offset++; if (!Settings.DisplayMovieFrame) *GFX.FrameDisplayString = 0; else if (Movie.State == MOVIE_STATE_RECORD) sprintf(GFX.FrameDisplayString, "Recording frame: %d%s", max(0, (int) (Movie.CurrentFrame + offset)), pad_read || !Settings.MovieNotifyIgnored ? "" : " (ignored)"); else if (Movie.State == MOVIE_STATE_PLAY) sprintf(GFX.FrameDisplayString, "Playing frame: %d / %d", max(0, (int) (Movie.CurrentFrame + offset)), Movie.MaxFrame); #ifdef NETPLAY_SUPPORT else if (Settings.NetPlay) sprintf(GFX.FrameDisplayString, "%s frame: %d", Settings.NetPlayServer ? "Server" : "Client", max(0, (int) (NetPlay.FrameCount + offset))); #endif } dsp.cpp000664 001750 001750 00000015753 12720446475 013222 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #ifdef DEBUGGER #include "missing.h" #endif uint8 (*GetDSP) (uint16) = NULL; void (*SetDSP) (uint8, uint16) = NULL; void S9xResetDSP (void) { memset(&DSP1, 0, sizeof(DSP1)); DSP1.waiting4command = TRUE; DSP1.first_parameter = TRUE; memset(&DSP2, 0, sizeof(DSP2)); DSP2.waiting4command = TRUE; memset(&DSP3, 0, sizeof(DSP3)); DSP3_Reset(); memset(&DSP4, 0, sizeof(DSP4)); DSP4.waiting4command = TRUE; } uint8 S9xGetDSP (uint16 address) { #ifdef DEBUGGER if (Settings.TraceDSP) { sprintf(String, "DSP read: 0x%04X", address); S9xMessage(S9X_TRACE, S9X_TRACE_DSP1, String); } #endif return ((*GetDSP)(address)); } void S9xSetDSP (uint8 byte, uint16 address) { #ifdef DEBUGGER missing.unknowndsp_write = address; if (Settings.TraceDSP) { sprintf(String, "DSP write: 0x%04X=0x%02X", address, byte); S9xMessage(S9X_TRACE, S9X_TRACE_DSP1, String); } #endif (*SetDSP)(byte, address); } cpu.cpp000664 001750 001750 00000022366 12720446475 013221 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "dma.h" #include "apu/apu.h" #include "fxemu.h" #include "sdd1.h" #include "srtc.h" #include "snapshot.h" #include "cheats.h" #include "logger.h" #ifdef DEBUGGER #include "debug.h" #endif static void S9xResetCPU (void); static void S9xSoftResetCPU (void); static void S9xResetCPU (void) { S9xSoftResetCPU(); Registers.SL = 0xff; Registers.P.W = 0; Registers.A.W = 0; Registers.X.W = 0; Registers.Y.W = 0; SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); ClearFlags(Decimal); } static void S9xSoftResetCPU (void) { CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector. CPU.PrevCycles = CPU.Cycles; CPU.V_Counter = 0; CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG); CPU.PCBase = NULL; CPU.NMILine = FALSE; CPU.IRQLine = FALSE; CPU.IRQTransition = FALSE; CPU.IRQLastState = FALSE; CPU.IRQExternal = FALSE; CPU.IRQPending = Timings.IRQPendCount; CPU.MemSpeed = SLOW_ONE_CYCLE; CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2; CPU.FastROMSpeed = SLOW_ONE_CYCLE; CPU.InDMA = FALSE; CPU.InHDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.InWRAMDMAorHDMA = FALSE; CPU.HDMARanInDMA = 0; CPU.CurrentDMAorHDMAChannel = -1; CPU.WhichEvent = HC_RENDER_EVENT; CPU.NextEvent = Timings.RenderPos; CPU.WaitingForInterrupt = FALSE; CPU.AutoSaveTimer = 0; CPU.SRAMModified = FALSE; Registers.PBPC = 0; Registers.PB = 0; Registers.PCw = S9xGetWord(0xfffc); OpenBus = Registers.PCh; Registers.D.W = 0; Registers.DB = 0; Registers.SH = 1; Registers.SL -= 3; Registers.XH = 0; Registers.YH = 0; ICPU.ShiftedPB = 0; ICPU.ShiftedDB = 0; SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation); ClearFlags(Decimal); Timings.InterlaceField = FALSE; Timings.H_Max = Timings.H_Max_Master; Timings.V_Max = Timings.V_Max_Master; Timings.NMITriggerPos = 0xffff; if (Model->_5A22 == 2) Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; else Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; S9xSetPCBase(Registers.PBPC); ICPU.S9xOpcodes = S9xOpcodesE1; ICPU.S9xOpLengths = S9xOpLengthsM1X1; S9xUnpackStatus(); } void S9xReset (void) { S9xResetSaveTimer(FALSE); S9xResetLogger(); memset(Memory.RAM, 0x55, 0x20000); memset(Memory.VRAM, 0x00, 0x10000); memset(Memory.FillRAM, 0, 0x8000); if (Settings.BS) S9xResetBSX(); S9xResetCPU(); S9xResetPPU(); S9xResetDMA(); S9xResetAPU(); if (Settings.DSP) S9xResetDSP(); if (Settings.SuperFX) S9xResetSuperFX(); if (Settings.SA1) S9xSA1Init(); if (Settings.SDD1) S9xResetSDD1(); if (Settings.SPC7110) S9xResetSPC7110(); if (Settings.C4) S9xInitC4(); if (Settings.OBC1) S9xResetOBC1(); if (Settings.SRTC) S9xResetSRTC(); S9xInitCheatData(); } void S9xSoftReset (void) { S9xResetSaveTimer(FALSE); memset(Memory.FillRAM, 0, 0x8000); if (Settings.BS) S9xResetBSX(); S9xSoftResetCPU(); S9xSoftResetPPU(); S9xResetDMA(); S9xSoftResetAPU(); if (Settings.DSP) S9xResetDSP(); if (Settings.SuperFX) S9xResetSuperFX(); if (Settings.SA1) S9xSA1Init(); if (Settings.SDD1) S9xResetSDD1(); if (Settings.SPC7110) S9xResetSPC7110(); if (Settings.C4) S9xInitC4(); if (Settings.OBC1) S9xResetOBC1(); if (Settings.SRTC) S9xResetSRTC(); S9xInitCheatData(); } apu/bapu/smp/algorithms.cpp000664 001750 001750 00000004204 12720446475 017105 0ustar00sergiosergio000000 000000 uint8 SMP::op_adc(uint8 x, uint8 y) { int r = x + y + regs.p.c; regs.p.n = r & 0x80; regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; regs.p.h = (x ^ y ^ r) & 0x10; regs.p.z = (uint8)r == 0; regs.p.c = r > 0xff; return r; } uint16 SMP::op_addw(uint16 x, uint16 y) { uint16 r; regs.p.c = 0; r = op_adc(x, y); r |= op_adc(x >> 8, y >> 8) << 8; regs.p.z = r == 0; return r; } uint8 SMP::op_and(uint8 x, uint8 y) { x &= y; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_cmp(uint8 x, uint8 y) { int r = x - y; regs.p.n = r & 0x80; regs.p.z = (uint8)r == 0; regs.p.c = r >= 0; return x; } uint16 SMP::op_cmpw(uint16 x, uint16 y) { int r = x - y; regs.p.n = r & 0x8000; regs.p.z = (uint16)r == 0; regs.p.c = r >= 0; return x; } uint8 SMP::op_eor(uint8 x, uint8 y) { x ^= y; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_or(uint8 x, uint8 y) { x |= y; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_sbc(uint8 x, uint8 y) { int r = x - y - !regs.p.c; regs.p.n = r & 0x80; regs.p.v = (x ^ y) & (x ^ r) & 0x80; regs.p.h = !((x ^ y ^ r) & 0x10); regs.p.z = (uint8)r == 0; regs.p.c = r >= 0; return r; } uint16 SMP::op_subw(uint16 x, uint16 y) { uint16 r; regs.p.c = 1; r = op_sbc(x, y); r |= op_sbc(x >> 8, y >> 8) << 8; regs.p.z = r == 0; return r; } uint8 SMP::op_inc(uint8 x) { x++; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_dec(uint8 x) { x--; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_asl(uint8 x) { regs.p.c = x & 0x80; x <<= 1; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_lsr(uint8 x) { regs.p.c = x & 0x01; x >>= 1; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_rol(uint8 x) { unsigned carry = (unsigned)regs.p.c; regs.p.c = x & 0x80; x = (x << 1) | carry; regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } uint8 SMP::op_ror(uint8 x) { unsigned carry = (unsigned)regs.p.c << 7; regs.p.c = x & 0x01; x = carry | (x >> 1); regs.p.n = x & 0x80; regs.p.z = x == 0; return x; } sar.h000664 001750 001750 00000015462 12720446475 012663 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SAR_H_ #define _SAR_H_ #ifdef RIGHTSHIFT_IS_SAR #define SAR(b, n) ((b) >> (n)) #else static inline int8 SAR (const int8 b, const int n) { #ifndef RIGHTSHIFT_int8_IS_SAR if (b < 0) return ((b >> n) | (-1 << (8 - n))); #endif return (b >> n); } static inline int16 SAR (const int16 b, const int n) { #ifndef RIGHTSHIFT_int16_IS_SAR if (b < 0) return ((b >> n) | (-1 << (16 - n))); #endif return (b >> n); } static inline int32 SAR (const int32 b, const int n) { #ifndef RIGHTSHIFT_int32_IS_SAR if (b < 0) return ((b >> n) | (-1 << (32 - n))); #endif return (b >> n); } static inline int64 SAR (const int64 b, const int n) { #ifndef RIGHTSHIFT_int64_IS_SAR if (b < 0) return ((b >> n) | (-1 << (64 - n))); #endif return (b >> n); } #endif #endif apu/bapu/smp/core/op_misc.b000664 001750 001750 00000005724 12720446475 016764 0ustar00sergiosergio000000 000000 nop(0x00) { 1:op_io(); } sleep(0xef), stop(0xff) { 1:op_io(); 2:op_io(); regs.pc--; } xcn(0x9f) { 1:op_io(); 2:op_io(); 3:op_io(); 4:op_io(); regs.a = (regs.a >> 4) | (regs.a << 4); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } daa(0xdf) { 1:op_io(); 2:op_io(); if(regs.p.c || (regs.a) > 0x99) { regs.a += 0x60; regs.p.c = 1; } if(regs.p.h || (regs.a & 15) > 0x09) { regs.a += 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } das(0xbe) { 1:op_io(); 2:op_io(); if(!regs.p.c || (regs.a) > 0x99) { regs.a -= 0x60; regs.p.c = 0; } if(!regs.p.h || (regs.a & 15) > 0x09) { regs.a -= 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } clrc(0x60, regs.p.c = 0), clrp(0x20, regs.p.p = 0), setc(0x80, regs.p.c = 1), setp(0x40, regs.p.p = 1) { 1:op_io(); $1; } clrv(0xe0) { 1:op_io(); regs.p.v = 0; regs.p.h = 0; } notc(0xed) { 1:op_io(); 2:op_io(); regs.p.c = !regs.p.c; } ei(0xa0, 1), di(0xc0, 0) { 1:op_io(); 2:op_io(); regs.p.i = $1; } set0_dp(0x02, rd |= 0x01), clr0_dp(0x12, rd &= ~0x01), set1_dp(0x22, rd |= 0x02), clr1_dp(0x32, rd &= ~0x02), set2_dp(0x42, rd |= 0x04), clr2_dp(0x52, rd &= ~0x04), set3_dp(0x62, rd |= 0x08), clr3_dp(0x72, rd &= ~0x08), set4_dp(0x82, rd |= 0x10), clr4_dp(0x92, rd &= ~0x10), set5_dp(0xa2, rd |= 0x20), clr5_dp(0xb2, rd &= ~0x20), set6_dp(0xc2, rd |= 0x40), clr6_dp(0xd2, rd &= ~0x40), set7_dp(0xe2, rd |= 0x80), clr7_dp(0xf2, rd &= ~0x80) { 1:dp = op_readpc(); 2:rd = op_readdp(dp); 3:$1; op_writedp(dp, rd); } push_a(0x2d, a), push_x(0x4d, x), push_y(0x6d, y), push_p(0x0d, p) { 1:op_io(); 2:op_io(); 3:op_writestack(regs.$1); } pop_a(0xae, a), pop_x(0xce, x), pop_y(0xee, y), pop_p(0x8e, p) { 1:op_io(); 2:op_io(); 3:regs.$1 = op_readstack(); } mul_ya(0xcf) { 1:op_io(); 2:op_io(); 3:op_io(); 4:op_io(); 5:op_io(); 6:op_io(); 7:op_io(); 8:op_io(); ya = regs.y * regs.a; regs.a = ya; regs.y = ya >> 8; //result is set based on y (high-byte) only regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); } div_ya_x(0x9e) { 1:op_io(); 2:op_io(); 3:op_io(); 4:op_io(); 5:op_io(); 6:op_io(); 7:op_io(); 8:op_io(); 9:op_io(); 10:op_io(); 11:op_io(); ya = regs.ya; //overflow set if quotient >= 256 regs.p.v = !!(regs.y >= regs.x); regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); if(regs.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) regs.a = ya / regs.x; regs.y = ya % regs.x; } else { //otherwise, the quotient won't fit into regs.p.v + regs.a //this emulates the odd behavior of the S-SMP in this case regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); } apu/bapu/smp/smp.cpp000664 001750 001750 00000006017 12720446475 015537 0ustar00sergiosergio000000 000000 #define CYCLE_ACCURATE #define PSEUDO_CYCLE #include #define SMP_CPP namespace SNES { #if defined(DEBUGGER) #include "debugger/debugger.cpp" #include "debugger/disassembler.cpp" SMPDebugger smp; #else SMP smp; #endif #include "algorithms.cpp" #include "core.cpp" #include "iplrom.cpp" #include "memory.cpp" #include "timing.cpp" void SMP::synchronize_cpu() { #ifndef SNES9X if(CPU::Threaded == true) { //if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); } else { while(clock >= 0) cpu.enter(); } #endif } void SMP::synchronize_dsp() { #ifndef SNES9X if(DSP::Threaded == true) { //if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); } else { while(dsp.clock < 0) dsp.enter(); } #endif } void SMP::enter() { while(clock < 0) op_step(); } void SMP::power() { #ifndef SNES9X Processor::frequency = system.apu_frequency(); #endif Processor::clock = 0; timer0.target = 0; timer1.target = 0; timer2.target = 0; for(unsigned n = 0; n < 256; n++) { cycle_table_dsp[n] = (cycle_count_table[n] * 24); cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency; } cycle_step_cpu = 24 * cpu.frequency; reset(); } void SMP::reset() { for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; opcode_number = 0; opcode_cycle = 0; regs.pc = 0xffc0; regs.sp = 0xef; regs.B.a = 0x00; regs.x = 0x00; regs.B.y = 0x00; regs.p = 0x02; //$00f1 status.iplrom_enable = true; //$00f2 status.dsp_addr = 0x00; //$00f8,$00f9 status.ram00f8 = 0x00; status.ram00f9 = 0x00; //timers timer0.enable = timer1.enable = timer2.enable = false; timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0; timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0; timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0; } #ifndef SNES9X void SMP::serialize(serializer &s) { Processor::serialize(s); s.array(apuram, 64 * 1024); s.integer(opcode_number); s.integer(opcode_cycle); s.integer(regs.pc); s.integer(regs.sp); s.integer(regs.a); s.integer(regs.x); s.integer(regs.y); s.integer(regs.p.n); s.integer(regs.p.v); s.integer(regs.p.p); s.integer(regs.p.b); s.integer(regs.p.h); s.integer(regs.p.i); s.integer(regs.p.z); s.integer(regs.p.c); s.integer(status.iplrom_enable); s.integer(status.dsp_addr); s.integer(status.ram00f8); s.integer(status.ram00f9); s.integer(timer0.enable); s.integer(timer0.target); s.integer(timer0.stage1_ticks); s.integer(timer0.stage2_ticks); s.integer(timer0.stage3_ticks); s.integer(timer1.enable); s.integer(timer1.target); s.integer(timer1.stage1_ticks); s.integer(timer1.stage2_ticks); s.integer(timer1.stage3_ticks); s.integer(timer2.enable); s.integer(timer2.target); s.integer(timer2.stage1_ticks); s.integer(timer2.stage2_ticks); s.integer(timer2.stage3_ticks); } #endif SMP::SMP() { apuram = new uint8[64 * 1024]; } SMP::~SMP() { } } fxinst.h000664 001750 001750 00000040676 12720446475 013416 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _FXINST_H_ #define _FXINST_H_ /* * FxChip(GSU) register space specification * (Register address space 3000-32ff) * * The 16 generic 16 bit registers: * (Some have a special function in special circumstances) * 3000 - R0 default source/destination register * 3002 - R1 pixel plot X position register * 3004 - R2 pixel plot Y position register * 3006 - R3 * 3008 - R4 lower 16 bit result of lmult * 300a - R5 * 300c - R6 multiplier for fmult and lmult * 300e - R7 fixed point texel X position for merge * 3010 - R8 fixed point texel Y position for merge * 3012 - R9 * 3014 - R10 * 3016 - R11 return address set by link * 3018 - R12 loop counter * 301a - R13 loop point address * 301c - R14 rom address for getb, getbh, getbl, getbs * 301e - R15 program counter * * 3020-302f - unused * * Other internal registers * 3030 - SFR status flag register (16bit) * 3032 - unused * 3033 - BRAMR Backup RAM register (8bit) * 3034 - PBR program bank register (8bit) * 3035 - unused * 3036 - ROMBR rom bank register (8bit) * 3037 - CFGR control flags register (8bit) * 3038 - SCBR screen base register (8bit) * 3039 - CLSR clock speed register (8bit) * 303a - SCMR screen mode register (8bit) * 303b - VCR version code register (8bit) (read only) * 303c - RAMBR ram bank register (8bit) * 303d - unused * 303e - CBR cache base register (16bit) * * 3040-30ff - unused * * 3100-32ff - CACHERAM 512 bytes of GSU cache memory * * SFR status flag register bits: * 0 - * 1 Z Zero flag * 2 CY Carry flag * 3 S Sign flag * 4 OV Overflow flag * 5 G Go flag (set to 1 when the GSU is running) * 6 R Set to 1 when reading ROM using R14 address * 7 - * 8 ALT1 Mode set-up flag for the next instruction * 9 ALT2 Mode set-up flag for the next instruction * 10 IL Immediate lower 8-bit flag * 11 IH Immediate higher 8-bit flag * 12 B Set to 1 when the WITH instruction is executed * 13 - * 14 - * 15 IRQ Set to 1 when GSU caused an interrupt * Set to 0 when read by 658c16 * * BRAMR = 0, BackupRAM is disabled * BRAMR = 1, BackupRAM is enabled * * CFGR control flags register bits: * 0 - * 1 - * 2 - * 3 - * 4 - * 5 MS0 Multiplier speed, 0=standard, 1=high speed * 6 - * 7 IRQ Set to 1 when GSU interrupt request is masked * * CLSR clock speed register bits: * 0 CLSR clock speed, 0 = 10.7Mhz, 1 = 21.4Mhz * * SCMR screen mode register bits: * 0 MD0 color depth mode bit 0 * 1 MD1 color depth mode bit 1 * 2 HT0 screen height bit 1 * 3 RAN RAM access control * 4 RON ROM access control * 5 HT1 screen height bit 2 * 6 - * 7 - * * RON = 0 SNES CPU has ROM access * RON = 1 GSU has ROM access * * RAN = 0 SNES has game pak RAM access * RAN = 1 GSU has game pak RAM access * * HT1 HT0 Screen height mode * 0 0 128 pixels high * 0 1 160 pixels high * 1 0 192 pixels high * 1 1 OBJ mode * * MD1 MD0 Color depth mode * 0 0 4 color mode * 0 1 16 color mode * 1 0 not used * 1 1 256 color mode * * CBR cache base register bits: * 15-4 Specify base address for data to cache from ROM or RAM * 3-0 Are 0 when address is read * * Write access to the program counter (301e) from * the SNES-CPU will start the GSU, and it will not * stop until it reaches a stop instruction. * */ // Number of banks in GSU RAM #define FX_RAM_BANKS 4 // Emulate proper R14 ROM access (slower, but safer) #define FX_DO_ROMBUFFER // Address checking (definately slow) //#define FX_ADDRESS_CHECK struct FxRegs_s { // FxChip registers uint32 avReg[16]; // 16 Generic registers uint32 vColorReg; // Internal color register uint32 vPlotOptionReg; // Plot option register uint32 vStatusReg; // Status register uint32 vPrgBankReg; // Program bank index register uint32 vRomBankReg; // Rom bank index register uint32 vRamBankReg; // Ram bank index register uint32 vCacheBaseReg; // Cache base address register uint32 vCacheFlags; // Saying what parts of the cache was written to uint32 vLastRamAdr; // Last RAM address accessed uint32 *pvDreg; // Pointer to current destination register uint32 *pvSreg; // Pointer to current source register uint8 vRomBuffer; // Current byte read by R14 uint8 vPipe; // Instructionset pipe uint32 vPipeAdr; // The address of where the pipe was read from // Status register optimization stuff uint32 vSign; // v & 0x8000 uint32 vZero; // v == 0 uint32 vCarry; // a value of 1 or 0 int32 vOverflow; // (v >= 0x8000 || v < -0x8000) // Other emulator variables int32 vErrorCode; uint32 vIllegalAddress; uint8 bBreakPoint; uint32 vBreakPoint; uint32 vStepPoint; uint8 *pvRegisters; // 768 bytes located in the memory at address 0x3000 uint32 nRamBanks; // Number of 64kb-banks in FxRam (Don't confuse it with SNES-Ram!!!) uint8 *pvRam; // Pointer to FxRam uint32 nRomBanks; // Number of 32kb-banks in Cart-ROM uint8 *pvRom; // Pointer to Cart-ROM uint32 vMode; // Color depth/mode uint32 vPrevMode; // Previous depth uint8 *pvScreenBase; uint8 *apvScreen[32]; // Pointer to each of the 32 screen colums int32 x[32]; uint32 vScreenHeight; // 128, 160, 192 or 256 (could be overriden by cmode) uint32 vScreenRealHeight; // 128, 160, 192 or 256 uint32 vPrevScreenHeight; uint32 vScreenSize; void (*pfPlot) (void); void (*pfRpix) (void); uint8 *pvRamBank; // Pointer to current RAM-bank uint8 *pvRomBank; // Pointer to current ROM-bank uint8 *pvPrgBank; // Pointer to current program ROM-bank uint8 *apvRamBank[FX_RAM_BANKS]; // Ram bank table (max 256kb) uint8 *apvRomBank[256]; // Rom bank table uint8 bCacheActive; uint8 *pvCache; // Pointer to the GSU cache uint8 avCacheBackup[512]; // Backup of ROM when the cache has replaced it uint32 vCounter; uint32 vInstCount; uint32 vSCBRDirty; // If SCBR is written, our cached screen pointers need updating uint8 *avRegAddr; // To reference avReg in snapshot.cpp }; extern struct FxRegs_s GSU; // GSU registers #define GSU_R0 0x000 #define GSU_R1 0x002 #define GSU_R2 0x004 #define GSU_R3 0x006 #define GSU_R4 0x008 #define GSU_R5 0x00a #define GSU_R6 0x00c #define GSU_R7 0x00e #define GSU_R8 0x010 #define GSU_R9 0x012 #define GSU_R10 0x014 #define GSU_R11 0x016 #define GSU_R12 0x018 #define GSU_R13 0x01a #define GSU_R14 0x01c #define GSU_R15 0x01e #define GSU_SFR 0x030 #define GSU_BRAMR 0x033 #define GSU_PBR 0x034 #define GSU_ROMBR 0x036 #define GSU_CFGR 0x037 #define GSU_SCBR 0x038 #define GSU_CLSR 0x039 #define GSU_SCMR 0x03a #define GSU_VCR 0x03b #define GSU_RAMBR 0x03c #define GSU_CBR 0x03e #define GSU_CACHERAM 0x100 // SFR flags #define FLG_Z (1 << 1) #define FLG_CY (1 << 2) #define FLG_S (1 << 3) #define FLG_OV (1 << 4) #define FLG_G (1 << 5) #define FLG_R (1 << 6) #define FLG_ALT1 (1 << 8) #define FLG_ALT2 (1 << 9) #define FLG_IL (1 << 10) #define FLG_IH (1 << 11) #define FLG_B (1 << 12) #define FLG_IRQ (1 << 15) // Test flag #define TF(a) (GSU.vStatusReg & FLG_##a) #define CF(a) (GSU.vStatusReg &= ~FLG_##a) #define SF(a) (GSU.vStatusReg |= FLG_##a) // Test and set flag if condition, clear if not #define TS(a, b) GSU.vStatusReg = ((GSU.vStatusReg & (~FLG_##a)) | ((!!(##b)) * FLG_##a)) // Testing ALT1 & ALT2 bits #define ALT0 (!TF(ALT1) && !TF(ALT2)) #define ALT1 ( TF(ALT1) && !TF(ALT2)) #define ALT2 (!TF(ALT1) && TF(ALT2)) #define ALT3 ( TF(ALT1) && TF(ALT2)) // Sign extend from 8/16 bit to 32 bit #define SEX8(a) ((int32) ((int8) (a))) #define SEX16(a) ((int32) ((int16) (a))) // Unsign extend from 8/16 bit to 32 bit #define USEX8(a) ((uint32) ((uint8) (a))) #define USEX16(a) ((uint32) ((uint16) (a))) #define SUSEX16(a) ((int32) ((uint16) (a))) // Set/Clr Sign and Zero flag #define TSZ(num) TS(S, ((num) & 0x8000)); TS(Z, (!USEX16(num))) // Clear flags #define CLRFLAGS GSU.vStatusReg &= ~(FLG_ALT1 | FLG_ALT2 | FLG_B); GSU.pvDreg = GSU.pvSreg = &R0 // Read current RAM-Bank #define RAM(adr) GSU.pvRamBank[USEX16(adr)] // Read current ROM-Bank #define ROM(idx) GSU.pvRomBank[USEX16(idx)] // Access the current value in the pipe #define PIPE GSU.vPipe // Access data in the current program bank #define PRGBANK(idx) GSU.pvPrgBank[USEX16(idx)] // Update pipe from ROM #if 0 #define FETCHPIPE { PIPE = PRGBANK(R15); GSU.vPipeAdr = (GSU.vPrgBankReg << 16) + R15; } #else #define FETCHPIPE { PIPE = PRGBANK(R15); } #endif // ABS #define ABS(x) ((x) < 0 ? -(x) : (x)) // Access source register #define SREG (*GSU.pvSreg) // Access destination register #define DREG (*GSU.pvDreg) #ifndef FX_DO_ROMBUFFER // Don't read R14 #define READR14 // Don't test and/or read R14 #define TESTR14 #else // Read R14 #define READR14 GSU.vRomBuffer = ROM(R14) // Test and/or read R14 #define TESTR14 if (GSU.pvDreg == &R14) READR14 #endif // Access to registers #define R0 GSU.avReg[0] #define R1 GSU.avReg[1] #define R2 GSU.avReg[2] #define R3 GSU.avReg[3] #define R4 GSU.avReg[4] #define R5 GSU.avReg[5] #define R6 GSU.avReg[6] #define R7 GSU.avReg[7] #define R8 GSU.avReg[8] #define R9 GSU.avReg[9] #define R10 GSU.avReg[10] #define R11 GSU.avReg[11] #define R12 GSU.avReg[12] #define R13 GSU.avReg[13] #define R14 GSU.avReg[14] #define R15 GSU.avReg[15] #define SFR GSU.vStatusReg #define PBR GSU.vPrgBankReg #define ROMBR GSU.vRomBankReg #define RAMBR GSU.vRamBankReg #define CBR GSU.vCacheBaseReg #define SCBR USEX8(GSU.pvRegisters[GSU_SCBR]) #define SCMR USEX8(GSU.pvRegisters[GSU_SCMR]) #define COLR GSU.vColorReg #define POR GSU.vPlotOptionReg #define BRAMR USEX8(GSU.pvRegisters[GSU_BRAMR]) #define VCR USEX8(GSU.pvRegisters[GSU_VCR]) #define CFGR USEX8(GSU.pvRegisters[GSU_CFGR]) #define CLSR USEX8(GSU.pvRegisters[GSU_CLSR]) // Execute instruction from the pipe, and fetch next byte to the pipe #define FX_STEP \ { \ uint32 vOpcode = (uint32) PIPE; \ FETCHPIPE; \ (*fx_OpcodeTable[(GSU.vStatusReg & 0x300) | vOpcode])(); \ } extern void (*fx_PlotTable[]) (void); extern void (*fx_OpcodeTable[]) (void); // Set this define if branches are relative to the instruction in the delay slot (I think they are) #define BRANCH_DELAY_RELATIVE #endif spc7110.h000664 001750 001750 00000017302 12720446475 013167 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SPC7110_H_ #define _SPC7110_H_ #define SPC7110_DECOMP_BUFFER_SIZE 64 // for snapshot only struct SSPC7110Snapshot { uint8 r4801; uint8 r4802; uint8 r4803; uint8 r4804; uint8 r4805; uint8 r4806; uint8 r4807; uint8 r4808; uint8 r4809; uint8 r480a; uint8 r480b; uint8 r480c; uint8 r4811; uint8 r4812; uint8 r4813; uint8 r4814; uint8 r4815; uint8 r4816; uint8 r4817; uint8 r4818; uint8 r481x; bool8 r4814_latch; // bool bool8 r4815_latch; // bool uint8 r4820; uint8 r4821; uint8 r4822; uint8 r4823; uint8 r4824; uint8 r4825; uint8 r4826; uint8 r4827; uint8 r4828; uint8 r4829; uint8 r482a; uint8 r482b; uint8 r482c; uint8 r482d; uint8 r482e; uint8 r482f; uint8 r4830; uint8 r4831; uint8 r4832; uint8 r4833; uint8 r4834; uint32 dx_offset; // unsigned uint32 ex_offset; // unsigned uint32 fx_offset; // unsigned uint8 r4840; uint8 r4841; uint8 r4842; int32 rtc_state; // enum RTC_State int32 rtc_mode; // enum RTC_Mode uint32 rtc_index; // unsigned uint32 decomp_mode; // unsigned uint32 decomp_offset; // unsigned uint8 decomp_buffer[SPC7110_DECOMP_BUFFER_SIZE]; uint32 decomp_buffer_rdoffset; // unsigned uint32 decomp_buffer_wroffset; // unsigned uint32 decomp_buffer_length; // unsigned struct ContextState { uint8 index; uint8 invert; } context[32]; }; extern struct SSPC7110Snapshot s7snap; void S9xInitSPC7110 (void); void S9xResetSPC7110 (void); void S9xSPC7110PreSaveState (void); void S9xSPC7110PostLoadState (int); void S9xSetSPC7110 (uint8, uint16); uint8 S9xGetSPC7110 (uint16); uint8 S9xGetSPC7110Byte (uint32); uint8 * S9xGetBasePointerSPC7110 (uint32); #endif obc1.h000664 001750 001750 00000014531 12720446475 012716 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _OBC1_H_ #define _OBC1_H_ struct SOBC1 { uint16 address; uint16 basePtr; uint16 shift; }; extern struct SOBC1 OBC1; void S9xSetOBC1 (uint8, uint16); uint8 S9xGetOBC1 (uint16); void S9xResetOBC1 (void); uint8 * S9xGetBasePointerOBC1 (uint16); uint8 * S9xGetMemPointerOBC1 (uint16); #endif sa1.h000664 001750 001750 00000022430 12720446475 012553 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SA1_H_ #define _SA1_H_ struct SSA1Registers { uint8 DB; pair P; pair A; pair D; pair S; pair X; pair Y; PC_t PC; }; struct SSA1 { struct SOpcodes *S9xOpcodes; uint8 *S9xOpLengths; uint8 _Carry; uint8 _Zero; uint8 _Negative; uint8 _Overflow; uint32 ShiftedPB; uint32 ShiftedDB; uint32 Flags; int32 Cycles; int32 PrevCycles; uint8 *PCBase; bool8 WaitingForInterrupt; uint8 *Map[MEMMAP_NUM_BLOCKS]; uint8 *WriteMap[MEMMAP_NUM_BLOCKS]; uint8 *BWRAM; bool8 in_char_dma; bool8 TimerIRQLastState; uint16 HTimerIRQPos; uint16 VTimerIRQPos; int16 HCounter; int16 VCounter; int16 PrevHCounter; int32 MemSpeed; int32 MemSpeedx2; int32 arithmetic_op; uint16 op1; uint16 op2; uint64 sum; bool8 overflow; uint8 VirtualBitmapFormat; uint8 variable_bit_pos; }; #define SA1CheckCarry() (SA1._Carry) #define SA1CheckZero() (SA1._Zero == 0) #define SA1CheckIRQ() (SA1Registers.PL & IRQ) #define SA1CheckDecimal() (SA1Registers.PL & Decimal) #define SA1CheckIndex() (SA1Registers.PL & IndexFlag) #define SA1CheckMemory() (SA1Registers.PL & MemoryFlag) #define SA1CheckOverflow() (SA1._Overflow) #define SA1CheckNegative() (SA1._Negative & 0x80) #define SA1CheckEmulation() (SA1Registers.P.W & Emulation) #define SA1SetFlags(f) (SA1Registers.P.W |= (f)) #define SA1ClearFlags(f) (SA1Registers.P.W &= ~(f)) #define SA1CheckFlag(f) (SA1Registers.PL & (f)) extern struct SSA1Registers SA1Registers; extern struct SSA1 SA1; extern uint8 SA1OpenBus; extern struct SOpcodes S9xSA1OpcodesM1X1[256]; extern struct SOpcodes S9xSA1OpcodesM1X0[256]; extern struct SOpcodes S9xSA1OpcodesM0X1[256]; extern struct SOpcodes S9xSA1OpcodesM0X0[256]; extern uint8 S9xOpLengthsM1X1[256]; extern uint8 S9xOpLengthsM1X0[256]; extern uint8 S9xOpLengthsM0X1[256]; extern uint8 S9xOpLengthsM0X0[256]; uint8 S9xSA1GetByte (uint32); void S9xSA1SetByte (uint8, uint32); uint16 S9xSA1GetWord (uint32, enum s9xwrap_t w = WRAP_NONE); void S9xSA1SetWord (uint16, uint32, enum s9xwrap_t w = WRAP_NONE, enum s9xwriteorder_t o = WRITE_01); void S9xSA1SetPCBase (uint32); uint8 S9xGetSA1 (uint32); void S9xSetSA1 (uint8, uint32); void S9xSA1Init (void); void S9xSA1MainLoop (void); void S9xSA1PostLoadState (void); static inline void S9xSA1UnpackStatus (void) { SA1._Zero = (SA1Registers.PL & Zero) == 0; SA1._Negative = (SA1Registers.PL & Negative); SA1._Carry = (SA1Registers.PL & Carry); SA1._Overflow = (SA1Registers.PL & Overflow) >> 6; } static inline void S9xSA1PackStatus (void) { SA1Registers.PL &= ~(Zero | Negative | Carry | Overflow); SA1Registers.PL |= SA1._Carry | ((SA1._Zero == 0) << 1) | (SA1._Negative & 0x80) | (SA1._Overflow << 6); } static inline void S9xSA1FixCycles (void) { if (SA1CheckEmulation()) { SA1.S9xOpcodes = S9xSA1OpcodesM1X1; SA1.S9xOpLengths = S9xOpLengthsM1X1; } else if (SA1CheckMemory()) { if (SA1CheckIndex()) { SA1.S9xOpcodes = S9xSA1OpcodesM1X1; SA1.S9xOpLengths = S9xOpLengthsM1X1; } else { SA1.S9xOpcodes = S9xSA1OpcodesM1X0; SA1.S9xOpLengths = S9xOpLengthsM1X0; } } else { if (SA1CheckIndex()) { SA1.S9xOpcodes = S9xSA1OpcodesM0X1; SA1.S9xOpLengths = S9xOpLengthsM0X1; } else { SA1.S9xOpcodes = S9xSA1OpcodesM0X0; SA1.S9xOpLengths = S9xOpLengthsM0X0; } } } #endif crosshairs.h000664 001750 001750 00000020367 12720446475 014256 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CROSSHAIRS_H_ #define _CROSSHAIRS_H_ // Read in the specified crosshair file, replacing whatever data might be in that slot. // Available slots are 1-31. // The input file must be a PNG or a text file. // PNG: 15x15 pixels, palettized, with 3 colors (white, black, and transparent). // text: 15 lines of 16 characters (counting the \n), consisting of ' ', '#', or '.'. bool S9xLoadCrosshairFile (int idx, const char *filename); // Return the specified crosshair. Woo-hoo. // char * to a 225-byte string, with '#' marking foreground, '.' marking background, // and anything else transparent. const char * S9xGetCrosshair (int idx); // In controls.cpp. Sets the crosshair for the specified device. Defaults are: // cross fgcolor bgcolor // Mouse 1: 1 White Black // Mouse 2: 1 Purple White // Superscope: 2 White Black // Justifier 1: 4 Blue Black // Justifier 2: 4 MagicPink Black // // Available colors are: Trans, Black, 25Grey, 50Grey, 75Grey, White, Red, Orange, // Yellow, Green, Cyan, Sky, Blue, Violet, MagicPink, and Purple. // You may also prefix a 't' (e.g. tBlue) for a 50%-transparent version. // Use idx = -1 or fg/bg = NULL to keep the current setting. enum crosscontrols { X_MOUSE1, X_MOUSE2, X_SUPERSCOPE, X_JUSTIFIER1, X_JUSTIFIER2 }; void S9xSetControllerCrosshair (enum crosscontrols ctl, int8 idx, const char *fg, const char *bg); void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg); // In gfx.cpp, much like S9xDisplayChar() except it takes the parameters // listed and looks up GFX.Screen. // The 'crosshair' arg is a 15x15 image, with '#' meaning fgcolor, // '.' meaning bgcolor, and anything else meaning transparent. // Color values should be (RGB): // 0 = transparent 4 = 23 23 23 8 = 31 31 0 12 = 0 0 31 // 1 = 0 0 0 5 = 31 31 31 9 = 0 31 0 13 = 23 0 31 // 2 = 8 8 8 6 = 31 0 0 10 = 0 31 31 14 = 31 0 31 // 3 = 16 16 16 7 = 31 16 0 11 = 0 23 31 15 = 31 0 16 // 16-31 are 50% transparent versions of 0-15. void S9xDrawCrosshair (const char *crosshair, uint8 fgcolor, uint8 bgcolor, int16 x, int16 y); #endif apu/bapu/dsp/blargg_common.h000664 001750 001750 00000012125 12720446475 017177 0ustar00sergiosergio000000 000000 // Sets up common environment for Shay Green's libraries. // To change configuration options, modify blargg_config.h, not this file. // snes_spc 0.9.0 #ifndef BLARGG_COMMON_H #define BLARGG_COMMON_H #include #include #include #include #undef BLARGG_COMMON_H // allow blargg_config.h to #include blargg_common.h #include "blargg_config.h" #ifndef BLARGG_COMMON_H #define BLARGG_COMMON_H // BLARGG_RESTRICT: equivalent to restrict, where supported #if defined (__GNUC__) || _MSC_VER >= 1100 #define BLARGG_RESTRICT __restrict #else #define BLARGG_RESTRICT #endif // STATIC_CAST(T,expr): Used in place of static_cast (expr) #ifndef STATIC_CAST #define STATIC_CAST(T,expr) ((T) (expr)) #endif // blargg_err_t (0 on success, otherwise error string) #ifndef blargg_err_t typedef const char* blargg_err_t; #endif // blargg_vector - very lightweight vector of POD types (no constructor/destructor) template class blargg_vector { T* begin_; size_t size_; public: blargg_vector() : begin_( 0 ), size_( 0 ) { } ~blargg_vector() { free( begin_ ); } size_t size() const { return size_; } T* begin() const { return begin_; } T* end() const { return begin_ + size_; } blargg_err_t resize( size_t n ) { // TODO: blargg_common.cpp to hold this as an outline function, ugh void* p = realloc( begin_, n * sizeof (T) ); if ( p ) begin_ = (T*) p; else if ( n > size_ ) // realloc failure only a problem if expanding return "Out of memory"; size_ = n; return 0; } void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } T& operator [] ( size_t n ) const { assert( n <= size_ ); // <= to allow past-the-end value return begin_ [n]; } }; #ifndef BLARGG_DISABLE_NOTHROW // throw spec mandatory in ISO C++ if operator new can return NULL #if __cplusplus >= 199711 || defined (__GNUC__) #define BLARGG_THROWS( spec ) throw spec #else #define BLARGG_THROWS( spec ) #endif #define BLARGG_DISABLE_NOTHROW \ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ void operator delete ( void* p ) { free( p ); } #define BLARGG_NEW new #else #include #define BLARGG_NEW new (std::nothrow) #endif // BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) #define BLARGG_4CHAR( a, b, c, d ) \ ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) // BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. #ifndef BOOST_STATIC_ASSERT #ifdef _MSC_VER // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified #define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) #else // Some other compilers fail when declaring same function multiple times in class, // so differentiate them by line #define BOOST_STATIC_ASSERT( expr ) \ void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) #endif #endif // BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, // compiler is assumed to support bool. If undefined, availability is determined. #ifndef BLARGG_COMPILER_HAS_BOOL #if defined (__MWERKS__) #if !__option(bool) #define BLARGG_COMPILER_HAS_BOOL 0 #endif #elif defined (_MSC_VER) #if _MSC_VER < 1100 #define BLARGG_COMPILER_HAS_BOOL 0 #endif #elif defined (__GNUC__) // supports bool #elif __cplusplus < 199711 #define BLARGG_COMPILER_HAS_BOOL 0 #endif #endif #if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL // If you get errors here, modify your blargg_config.h file typedef int bool; const bool true = 1; const bool false = 0; #endif // blargg_long/blargg_ulong = at least 32 bits, int if it's big enough #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF typedef long blargg_long; #else typedef int blargg_long; #endif #if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF typedef unsigned long blargg_ulong; #else typedef unsigned blargg_ulong; #endif // BOOST::int8_t etc. // HAVE_STDINT_H: If defined, use for int8_t etc. #if defined (HAVE_STDINT_H) #include #define BOOST // HAVE_INTTYPES_H: If defined, use for int8_t etc. #elif defined (HAVE_INTTYPES_H) #include #define BOOST #else struct BOOST { #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F typedef signed char int8_t; typedef unsigned char uint8_t; #else // No suitable 8-bit type available typedef struct see_blargg_common_h int8_t; typedef struct see_blargg_common_h uint8_t; #endif #if USHRT_MAX == 0xFFFF typedef short int16_t; typedef unsigned short uint16_t; #else // No suitable 16-bit type available typedef struct see_blargg_common_h int16_t; typedef struct see_blargg_common_h uint16_t; #endif #if ULONG_MAX == 0xFFFFFFFF typedef long int32_t; typedef unsigned long uint32_t; #elif UINT_MAX == 0xFFFFFFFF typedef int int32_t; typedef unsigned int uint32_t; #else // No suitable 32-bit type available typedef struct see_blargg_common_h int32_t; typedef struct see_blargg_common_h uint32_t; #endif }; #endif #endif #endif apu/bapu/dsp/blargg_config.h000664 001750 001750 00000001152 12720446475 017152 0ustar00sergiosergio000000 000000 // snes_spc 0.9.0 user configuration file. Don't replace when updating library. // snes_spc 0.9.0 #ifndef BLARGG_CONFIG_H #define BLARGG_CONFIG_H // Uncomment to disable debugging checks #define NDEBUG 1 // Uncomment to enable platform-specific (and possibly non-portable) optimizations //#define BLARGG_NONPORTABLE 1 // Uncomment if automatic byte-order determination doesn't work //#define BLARGG_BIG_ENDIAN 1 // Uncomment if you get errors in the bool section of blargg_common.h //#define BLARGG_COMPILER_HAS_BOOL 1 // Use standard config.h if present #ifdef HAVE_CONFIG_H #include "config.h" #endif #endif apu/bapu/smp/core/opcycle_misc.cpp000664 001750 001750 00000022467 12720446475 020350 0ustar00sergiosergio000000 000000 case 0x00: { switch(opcode_cycle++) { case 1: op_io(); opcode_cycle = 0; break; } break; } case 0xef: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); regs.pc--; opcode_cycle = 0; break; } break; } case 0xff: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); regs.pc--; opcode_cycle = 0; break; } break; } case 0x9f: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_io(); break; case 4: op_io(); regs.a = (regs.a >> 4) | (regs.a << 4); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xdf: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); if(regs.p.c || (regs.a) > 0x99) { regs.a += 0x60; regs.p.c = 1; } if(regs.p.h || (regs.a & 15) > 0x09) { regs.a += 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xbe: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); if(!regs.p.c || (regs.a) > 0x99) { regs.a -= 0x60; regs.p.c = 0; } if(!regs.p.h || (regs.a & 15) > 0x09) { regs.a -= 0x06; } regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0x60: { switch(opcode_cycle++) { case 1: op_io(); regs.p.c = 0; opcode_cycle = 0; break; } break; } case 0x20: { switch(opcode_cycle++) { case 1: op_io(); regs.p.p = 0; opcode_cycle = 0; break; } break; } case 0x80: { switch(opcode_cycle++) { case 1: op_io(); regs.p.c = 1; opcode_cycle = 0; break; } break; } case 0x40: { switch(opcode_cycle++) { case 1: op_io(); regs.p.p = 1; opcode_cycle = 0; break; } break; } case 0xe0: { switch(opcode_cycle++) { case 1: op_io(); regs.p.v = 0; regs.p.h = 0; opcode_cycle = 0; break; } break; } case 0xed: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); regs.p.c = !regs.p.c; opcode_cycle = 0; break; } break; } case 0xa0: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); regs.p.i = 1; opcode_cycle = 0; break; } break; } case 0xc0: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); regs.p.i = 0; opcode_cycle = 0; break; } break; } case 0x02: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x01; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x12: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x01; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x22: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x02; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x32: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x02; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x42: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x04; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x52: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x04; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x62: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x08; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x72: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x08; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x82: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x10; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x92: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x10; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xa2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x20; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xb2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x20; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xc2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x40; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xd2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x40; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xe2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= 0x80; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xf2: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd &= ~0x80; op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x2d: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_writestack(regs.a); opcode_cycle = 0; break; } break; } case 0x4d: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_writestack(regs.x); opcode_cycle = 0; break; } break; } case 0x6d: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_writestack(regs.y); opcode_cycle = 0; break; } break; } case 0x0d: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_writestack(regs.p); opcode_cycle = 0; break; } break; } case 0xae: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: regs.a = op_readstack(); opcode_cycle = 0; break; } break; } case 0xce: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: regs.x = op_readstack(); opcode_cycle = 0; break; } break; } case 0xee: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: regs.y = op_readstack(); opcode_cycle = 0; break; } break; } case 0x8e: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: regs.p = op_readstack(); opcode_cycle = 0; break; } break; } case 0xcf: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_io(); break; case 7: op_io(); break; case 8: op_io(); ya = regs.y * regs.a; regs.a = ya; regs.y = ya >> 8; //result is set based on y (high-byte) only regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0x9e: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_io(); break; case 4: op_io(); break; case 5: op_io(); break; case 6: op_io(); break; case 7: op_io(); break; case 8: op_io(); break; case 9: op_io(); break; case 10: op_io(); break; case 11: op_io(); ya = regs.ya; //overflow set if quotient >= 256 regs.p.v = !!(regs.y >= regs.x); regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); if(regs.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) regs.a = ya / regs.x; regs.y = ya % regs.x; } else { //otherwise, the quotient won't fit into regs.p.v + regs.a //this emulates the odd behavior of the S-SMP in this case regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } apu/000700 001750 001750 00000000000 12724164663 012466 5ustar00sergiosergio000000 000000 apu/bapu/dsp/000700 001750 001750 00000000000 12724164663 014203 5ustar00sergiosergio000000 000000 srtcemu.cpp000664 001750 001750 00000013637 12720446475 014115 0ustar00sergiosergio000000 000000 /***** * S-RTC emulation code * Copyright (c) byuu *****/ #define _SRTCEMU_CPP_ const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; void SRTC::power() { reset(); } void SRTC::reset() { rtc_mode = RTCM_Read; rtc_index = -1; update_time(); } void SRTC::update_time() { time_t rtc_time = (memory_cartrtc_read(16) << 0) | (memory_cartrtc_read(17) << 8) | (memory_cartrtc_read(18) << 16) | (memory_cartrtc_read(19) << 24); time_t current_time = time(0); //sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic. //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow //memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if //time_t overflows. calculation should be valid regardless of number representation, time_t size, //or whether time_t is signed or unsigned. time_t diff = (current_time >= rtc_time) ? (current_time - rtc_time) : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow if(diff > 0) { unsigned second = memory_cartrtc_read( 0) + memory_cartrtc_read( 1) * 10; unsigned minute = memory_cartrtc_read( 2) + memory_cartrtc_read( 3) * 10; unsigned hour = memory_cartrtc_read( 4) + memory_cartrtc_read( 5) * 10; unsigned day = memory_cartrtc_read( 6) + memory_cartrtc_read( 7) * 10; unsigned month = memory_cartrtc_read( 8); unsigned year = memory_cartrtc_read( 9) + memory_cartrtc_read(10) * 10 + memory_cartrtc_read(11) * 100; unsigned weekday = memory_cartrtc_read(12); day--; month--; year += 1000; second += diff; while(second >= 60) { second -= 60; minute++; if(minute < 60) continue; minute = 0; hour++; if(hour < 24) continue; hour = 0; day++; weekday = (weekday + 1) % 7; unsigned days = months[month % 12]; if(days == 28) { bool leapyear = false; if((year % 4) == 0) { leapyear = true; if((year % 100) == 0 && (year % 400) != 0) leapyear = false; } if(leapyear) days++; } if(day < days) continue; day = 0; month++; if(month < 12) continue; month = 0; year++; } day++; month++; year -= 1000; memory_cartrtc_write( 0, second % 10); memory_cartrtc_write( 1, second / 10); memory_cartrtc_write( 2, minute % 10); memory_cartrtc_write( 3, minute / 10); memory_cartrtc_write( 4, hour % 10); memory_cartrtc_write( 5, hour / 10); memory_cartrtc_write( 6, day % 10); memory_cartrtc_write( 7, day / 10); memory_cartrtc_write( 8, month); memory_cartrtc_write( 9, year % 10); memory_cartrtc_write(10, (year / 10) % 10); memory_cartrtc_write(11, year / 100); memory_cartrtc_write(12, weekday % 7); } memory_cartrtc_write(16, current_time >> 0); memory_cartrtc_write(17, current_time >> 8); memory_cartrtc_write(18, current_time >> 16); memory_cartrtc_write(19, current_time >> 24); } //returns day of week for specified date //eg 0 = Sunday, 1 = Monday, ... 6 = Saturday //usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008 unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) { unsigned y = 1900, m = 1; //epoch is 1900-01-01 unsigned sum = 0; //number of days passed since epoch year = max(1900, year); month = max(1, min(12, month)); day = max(1, min(31, day)); while(y < year) { bool leapyear = false; if((y % 4) == 0) { leapyear = true; if((y % 100) == 0 && (y % 400) != 0) leapyear = false; } sum += leapyear ? 366 : 365; y++; } while(m < month) { unsigned days = months[m - 1]; if(days == 28) { bool leapyear = false; if((y % 4) == 0) { leapyear = true; if((y % 100) == 0 && (y % 400) != 0) leapyear = false; } if(leapyear) days++; } sum += days; m++; } sum += day - 1; return (sum + 1) % 7; //1900-01-01 was a Monday } uint8 SRTC::mmio_read(unsigned addr) { addr &= 0xffff; if(addr == 0x2800) { if(rtc_mode != RTCM_Read) return 0x00; if(rtc_index < 0) { update_time(); rtc_index++; return 0x0f; } else if(rtc_index > 12) { rtc_index = -1; return 0x0f; } else { return memory_cartrtc_read(rtc_index++); } } return cpu_regs_mdr; } void SRTC::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; if(addr == 0x2801) { data &= 0x0f; //only the low four bits are used if(data == 0x0d) { rtc_mode = RTCM_Read; rtc_index = -1; return; } if(data == 0x0e) { rtc_mode = RTCM_Command; return; } if(data == 0x0f) return; //unknown behavior if(rtc_mode == RTCM_Write) { if(rtc_index >= 0 && rtc_index < 12) { memory_cartrtc_write(rtc_index++, data); if(rtc_index == 12) { //day of week is automatically calculated and written unsigned day = memory_cartrtc_read( 6) + memory_cartrtc_read( 7) * 10; unsigned month = memory_cartrtc_read( 8); unsigned year = memory_cartrtc_read( 9) + memory_cartrtc_read(10) * 10 + memory_cartrtc_read(11) * 100; year += 1000; memory_cartrtc_write(rtc_index++, weekday(year, month, day)); } } } else if(rtc_mode == RTCM_Command) { if(data == 0) { rtc_mode = RTCM_Write; rtc_index = 0; } else if(data == 4) { rtc_mode = RTCM_Ready; rtc_index = -1; for(unsigned i = 0; i < 13; i++) memory_cartrtc_write(i, 0); } else { //unknown behavior rtc_mode = RTCM_Ready; } } } } SRTC::SRTC() { } libretro/Makefile.common000664 001750 001750 00000003071 12720446475 016467 0ustar00sergiosergio000000 000000 INCFLAGS = -I$(CORE_DIR)/libretro -I$(CORE_DIR) -I$(CORE_DIR)/apu/ -I$(CORE_DIR)/apu/bapu SOURCES_C := SOURCES_CXX := $(CORE_DIR)/apu/apu.cpp \ $(CORE_DIR)/apu/bapu/dsp/sdsp.cpp \ $(CORE_DIR)/apu/bapu/dsp/SPC_DSP.cpp \ $(CORE_DIR)/apu/bapu/smp/smp.cpp \ $(CORE_DIR)/apu/bapu/smp/smp_state.cpp \ $(CORE_DIR)/bsx.cpp \ $(CORE_DIR)/c4.cpp \ $(CORE_DIR)/c4emu.cpp \ $(CORE_DIR)/cheats.cpp \ $(CORE_DIR)/cheats2.cpp \ $(CORE_DIR)/clip.cpp \ $(CORE_DIR)/conffile.cpp \ $(CORE_DIR)/controls.cpp \ $(CORE_DIR)/cpu.cpp \ $(CORE_DIR)/cpuexec.cpp \ $(CORE_DIR)/cpuops.cpp \ $(CORE_DIR)/crosshairs.cpp \ $(CORE_DIR)/dma.cpp \ $(CORE_DIR)/dsp.cpp \ $(CORE_DIR)/dsp1.cpp \ $(CORE_DIR)/dsp2.cpp \ $(CORE_DIR)/dsp3.cpp \ $(CORE_DIR)/dsp4.cpp \ $(CORE_DIR)/fxinst.cpp \ $(CORE_DIR)/fxemu.cpp \ $(CORE_DIR)/gfx.cpp \ $(CORE_DIR)/globals.cpp \ $(CORE_DIR)/logger.cpp \ $(CORE_DIR)/memmap.cpp \ $(CORE_DIR)/movie.cpp \ $(CORE_DIR)/obc1.cpp \ $(CORE_DIR)/ppu.cpp \ $(CORE_DIR)/stream.cpp \ $(CORE_DIR)/sa1.cpp \ $(CORE_DIR)/sa1cpu.cpp \ $(CORE_DIR)/screenshot.cpp \ $(CORE_DIR)/sdd1.cpp \ $(CORE_DIR)/sdd1emu.cpp \ $(CORE_DIR)/seta.cpp \ $(CORE_DIR)/seta010.cpp \ $(CORE_DIR)/seta011.cpp \ $(CORE_DIR)/seta018.cpp \ $(CORE_DIR)/snapshot.cpp \ $(CORE_DIR)/snes9x.cpp \ $(CORE_DIR)/spc7110.cpp \ $(CORE_DIR)/srtc.cpp \ $(CORE_DIR)/tile.cpp \ $(CORE_DIR)/libretro/libretro.cpp apu/apu.h000664 001750 001750 00000016131 12720446475 013442 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _APU_H_ #define _APU_H_ #include "snes9x.h" typedef void (*apu_callback) (void *); #define SPC_SAVE_STATE_BLOCK_SIZE (1024 * 65) #define SPC_FILE_SIZE (66048) bool8 S9xInitAPU (void); void S9xDeinitAPU (void); void S9xResetAPU (void); void S9xSoftResetAPU (void); uint8 S9xAPUReadPort (int); void S9xAPUWritePort (int, uint8); void S9xAPUExecute (void); void S9xAPUEndScanline (void); void S9xAPUSetReferenceTime (int32); void S9xAPUTimingSetSpeedup (int); void S9xAPUAllowTimeOverflow (bool); void S9xAPULoadState (uint8 *); void S9xAPULoadBlarggState(uint8 *oldblock); void S9xAPUSaveState (uint8 *); void S9xDumpSPCSnapshot (void); bool8 S9xSPCDump (const char *); bool8 S9xInitSound (int, int); bool8 S9xOpenSoundDevice (void); bool8 S9xSyncSound (void); int S9xGetSampleCount (void); void S9xSetSoundControl (uint8); void S9xSetSoundMute (bool8); void S9xLandSamples (void); void S9xFinalizeSamples (void); void S9xClearSamples (void); bool8 S9xMixSamples (uint8 *, int); void S9xSetSamplesAvailableCallback (apu_callback, void *); #endif apu/bapu/smp/core/op_mov.cpp000664 001750 001750 00000013571 12720446475 017172 0ustar00sergiosergio000000 000000 case 0x7d: { op_io(); regs.a = regs.x; regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xdd: { op_io(); regs.a = regs.y; regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0x5d: { op_io(); regs.x = regs.a; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xfd: { op_io(); regs.y = regs.a; regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0x9d: { op_io(); regs.x = regs.sp; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xbd: { op_io(); regs.sp = regs.x; break; } case 0xe8: { regs.a = op_readpc(); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xcd: { regs.x = op_readpc(); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0x8d: { regs.y = op_readpc(); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0xe6: { op_io(); regs.a = op_readdp(regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xbf: { op_io(); regs.a = op_readdp(regs.x++); op_io(); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xe4: { sp = op_readpc(); regs.a = op_readdp(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xf8: { sp = op_readpc(); regs.x = op_readdp(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xeb: { sp = op_readpc(); regs.y = op_readdp(sp); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0xf4: { sp = op_readpc(); op_io(); regs.a = op_readdp(sp + regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xf9: { sp = op_readpc(); op_io(); regs.x = op_readdp(sp + regs.y); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xfb: { sp = op_readpc(); op_io(); regs.y = op_readdp(sp + regs.x); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0xe5: { sp = op_readpc(); sp |= op_readpc() << 8; regs.a = op_readaddr(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xe9: { sp = op_readpc(); sp |= op_readpc() << 8; regs.x = op_readaddr(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xec: { sp = op_readpc(); sp |= op_readpc() << 8; regs.y = op_readaddr(sp); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); break; } case 0xf5: { sp = op_readpc(); sp |= op_readpc() << 8; op_io(); regs.a = op_readaddr(sp + regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xf6: { sp = op_readpc(); sp |= op_readpc() << 8; op_io(); regs.a = op_readaddr(sp + regs.y); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xe7: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; regs.a = op_readaddr(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xf7: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; regs.a = op_readaddr(sp + regs.y); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); break; } case 0xfa: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); op_writedp(dp, rd); break; } case 0x8f: { rd = op_readpc(); dp = op_readpc(); op_readdp(dp); op_writedp(dp, rd); break; } case 0xc6: { op_io(); op_readdp(regs.x); op_writedp(regs.x, regs.a); break; } case 0xaf: { op_io(); op_io(); op_writedp(regs.x++, regs.a); break; } case 0xc4: { dp = op_readpc(); op_readdp(dp); op_writedp(dp, regs.a); break; } case 0xd8: { dp = op_readpc(); op_readdp(dp); op_writedp(dp, regs.x); break; } case 0xcb: { dp = op_readpc(); op_readdp(dp); op_writedp(dp, regs.y); break; } case 0xd4: { dp = op_readpc(); op_io(); dp += regs.x; op_readdp(dp); op_writedp(dp, regs.a); break; } case 0xd9: { dp = op_readpc(); op_io(); dp += regs.y; op_readdp(dp); op_writedp(dp, regs.x); break; } case 0xdb: { dp = op_readpc(); op_io(); dp += regs.x; op_readdp(dp); op_writedp(dp, regs.y); break; } case 0xc5: { dp = op_readpc(); dp |= op_readpc() << 8; op_readaddr(dp); op_writeaddr(dp, regs.a); break; } case 0xc9: { dp = op_readpc(); dp |= op_readpc() << 8; op_readaddr(dp); op_writeaddr(dp, regs.x); break; } case 0xcc: { dp = op_readpc(); dp |= op_readpc() << 8; op_readaddr(dp); op_writeaddr(dp, regs.y); break; } case 0xd5: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.x; op_readaddr(dp); op_writeaddr(dp, regs.a); break; } case 0xd6: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.y; op_readaddr(dp); op_writeaddr(dp, regs.a); break; } case 0xc7: { sp = op_readpc(); op_io(); sp += regs.x; dp = op_readdp(sp); dp |= op_readdp(sp + 1) << 8; op_readaddr(dp); op_writeaddr(dp, regs.a); break; } case 0xd7: { sp = op_readpc(); dp = op_readdp(sp); dp |= op_readdp(sp + 1) << 8; op_io(); dp += regs.y; op_readaddr(dp); op_writeaddr(dp, regs.a); break; } case 0xba: { sp = op_readpc(); regs.a = op_readdp(sp); op_io(); regs.y = op_readdp(sp + 1); regs.p.n = !!(regs.ya & 0x8000); regs.p.z = (regs.ya == 0); break; } case 0xda: { dp = op_readpc(); op_readdp(dp); op_writedp(dp, regs.a); op_writedp(dp + 1, regs.y); break; } case 0xaa: { sp = op_readpc(); sp |= op_readpc() << 8; bit = sp >> 13; sp &= 0x1fff; rd = op_readaddr(sp); regs.p.c = !!(rd & (1 << bit)); break; } case 0xca: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); if(regs.p.c)rd |= (1 << bit); else rd &= ~(1 << bit); op_io(); op_writeaddr(dp, rd); break; } seta010.cpp000664 001750 001750 00000072510 12720446475 013603 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "memmap.h" #include "seta.h" static const int16 ST010_SinTable[256] = { 0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2, 0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504, 0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3, 0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5, 0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d, 0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b, 0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23, 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3, 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df, 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b, 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324, 0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2, -0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, -0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a, -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, -0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6, -0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504, -0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3, -0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5, -0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d, -0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b, -0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23, -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3, -0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3, -0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de, -0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b, -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 }; static const uint8 ST010_ArcTan[32][32] = { { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, { 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf }, { 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd }, { 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc }, { 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb }, { 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9 }, { 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8 }, { 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7 }, { 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5 }, { 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4 }, { 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3 }, { 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6, 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2 }, { 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1 }, { 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3, 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0 }, { 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf }, { 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae }, { 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad }, { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac }, { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab }, { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa }, { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9 }, { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8 }, { 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7 }, { 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6 }, { 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5 }, { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4 }, { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95, 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4 }, { 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3 }, { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2 }, { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1 }, { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1 }, { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0 } }; // Mode 7 scaling constants for all raster lines static const int16 ST010_M7Scale[176] = { 0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3, 0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b, 0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8, 0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6, 0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5, 0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d, 0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c, 0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e, 0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063, 0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a, 0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052, 0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c, 0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047, 0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042, 0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e, 0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a, 0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037, 0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034, 0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031, 0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f, 0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d, 0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b }; #ifndef PI #define PI 3.1415926535897932384626433832795 #endif #define ST010_WORD(offset) (Memory.SRAM[offset + 1] << 8) | Memory.SRAM[offset] static int16 ST010_Sin (int16 Theta) { return (ST010_SinTable[(Theta >> 8) & 0xff]); } static int16 ST010_Cos (int16 Theta) { return (ST010_SinTable[((Theta + 0x4000) >> 8) & 0xff]); } static void ST010_OP01 (int16 x0, int16 y0, int16 &x1, int16 &y1, int16 &Quadrant, int16 &Theta) { if ((x0 < 0) && (y0 < 0)) { x1 = -x0; y1 = -y0; Quadrant = -0x8000; } else if (x0 < 0) { x1 = y0; y1 = -x0; Quadrant = -0x4000; } else if (y0 < 0) { x1 = -y0; y1 = x0; Quadrant = 0x4000; } else { x1 = x0; y1 = y0; Quadrant = 0x0000; } while ((x1 > 0x1f) || (y1 > 0x1f)) { if (x1 > 1) x1 >>= 1; if (y1 > 1) y1 >>= 1; } if (y1 == 0) Quadrant += 0x4000; Theta = (ST010_ArcTan[y1][x1] << 8) ^ Quadrant; } static void ST010_Scale (int16 Multiplier, int16 X0, int16 Y0, int32 &X1, int32 &Y1) { X1 = X0 * Multiplier << 1; Y1 = Y0 * Multiplier << 1; } static void ST010_Multiply (int16 Multiplicand, int16 Multiplier, int32 &Product) { Product = Multiplicand * Multiplier << 1; } static void ST010_Rotate (int16 Theta, int16 X0, int16 Y0, int16 &X1, int16 &Y1) { X1 = (Y0 * ST010_Sin(Theta) >> 15) + (X0 * ST010_Cos(Theta) >> 15); Y1 = (Y0 * ST010_Cos(Theta) >> 15) - (X0 * ST010_Sin(Theta) >> 15); } static void ST010_SortDrivers (uint16 Positions, uint16 Places[32], uint16 Drivers[32]) { bool Sorted; uint16 Temp; if (Positions > 1) { do { Sorted = true; for (int i = 0; i < Positions - 1; i++) { if (Places[i] < Places[i + 1]) { Temp = Places[i + 1]; Places[i + 1] = Places[i]; Places[i] = Temp; Temp = Drivers[i + 1]; Drivers[i + 1] = Drivers[i]; Drivers[i] = Temp; Sorted = false; } } Positions--; } while (!Sorted); } } /* static void SETA_Distance (int16 Y0, int16 X0, int16 &Distance) { if (X0 < 0) X0 = -X0; if (Y0 < 0) Y0 = -Y0; Distance = ((X0 * 0x7af0) + 0x4000) >> 15; } */ uint8 S9xGetST010 (uint32 Address) { if (!(Address & 0x80000)) return (0x80); if ((Address & 0xFFF) == 0x20) return (ST010.op_reg); if ((Address & 0xFFF) == 0x21) return (ST010.execute); return (Memory.SRAM[Address & Memory.SRAMMask]); } void S9xSetST010 (uint32 Address, uint8 Byte) { if (!(Address & 0x80000)) { ST010.control_enable = TRUE; return; } #ifdef DEBUGGER printf("Write %06X:%02X\n", Address, Byte); #endif if ((Address & 0xFFF) == 0x20 && ST010.control_enable) ST010.op_reg = Byte; if ((Address & 0xFFF) == 0x21 && ST010.control_enable) ST010.execute = Byte; else Memory.SRAM[Address & Memory.SRAMMask] = Byte; if (ST010.execute & 0x80) { switch (ST010.op_reg) { // Sorts Driver Placements // // Input // 0x0024-0x0025 : Positions // 0x0040-0x007f : Places // 0x0080-0x00ff : Drivers // Output // 0x0040-0x007f : Places // 0x0080-0x00ff : Drivers // case 0x02: { #ifdef FAST_LSB_WORD_ACCESS ST010_SortDrivers(*(uint16 *) (Memory.SRAM + 0x0024), (uint16 *) (Memory.SRAM + 0x0040), (uint16 *) (Memory.SRAM + 0x0080)); #else uint16 Places[32]; uint16 Positions = ST010_WORD(0x0024); int Pos, Offset; Offset = 0; for (Pos = 0; Pos < Positions; Pos++) { Places[Pos] = ST010_WORD(0x0040 + Offset); Offset += 2; } ST010_SortDrivers(Positions, Places, (uint16 *) (Memory.SRAM + 0x0080)); Offset = 0; for (Pos = 0; Pos < Positions; Pos++) { Memory.SRAM[0x0040 + Offset] = (uint8) (Places[Pos]); Memory.SRAM[0x0041 + Offset] = (uint8) (Places[Pos] >> 8); Offset += 2; } #endif break; } // Two Dimensional Coordinate Scale // // Input // 0x0000-0x0001 : X0 (signed) // 0x0002-0x0003 : Y0 (signed) // 0x0004-0x0005 : Multiplier (signed) // Output // 0x0010-0x0013 : X1 (signed) // 0x0014-0x0017 : Y1 (signed) // case 0x03: { #ifdef FAST_LSB_WORD_ACCESS ST010_Scale(*(int16 *) &Memory.SRAM[0x0004], *(int16 *) &Memory.SRAM[0x0000], *(int16 *) &Memory.SRAM[0x0002], (int32 &) Memory.SRAM[0x0010], (int32 &) Memory.SRAM[0x0014]); #else int32 x1, y1; ST010_Scale(ST010_WORD(0x0004), ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1); Memory.SRAM[0x0010] = (uint8) (x1); Memory.SRAM[0x0011] = (uint8) (x1 >> 8); Memory.SRAM[0x0012] = (uint8) (x1 >> 16); Memory.SRAM[0x0013] = (uint8) (x1 >> 24); Memory.SRAM[0x0014] = (uint8) (y1); Memory.SRAM[0x0015] = (uint8) (y1 >> 8); Memory.SRAM[0x0016] = (uint8) (y1 >> 16); Memory.SRAM[0x0017] = (uint8) (y1 >> 24); #endif break; } // 16-bit Multiplication // // Input // 0x0000-0x0001 : Multiplcand (signed) // 0x0002-0x0003 : Multiplier (signed) // Output // 0x0010-0x0013 : Product (signed) // case 0x06: { #ifdef FAST_LSB_WORD_ACCESS ST010_Multiply(*(int16 *) &Memory.SRAM[0x0000], *(int16 *) &Memory.SRAM[0x0002], (int32 &) Memory.SRAM[0x0010]); #else int32 Product; ST010_Multiply(ST010_WORD(0x0000), ST010_WORD(0x0002), Product); Memory.SRAM[0x0010] = (uint8) (Product); Memory.SRAM[0x0011] = (uint8) (Product >> 8); Memory.SRAM[0x0012] = (uint8) (Product >> 16); Memory.SRAM[0x0013] = (uint8) (Product >> 24); #endif break; } // Mode 7 Raster Data Calculation // // Input // 0x0000-0x0001 : Angle (signed) // Output // 0x00f0-0x024f : Mode 7 Matrix A // 0x0250-0x03af : Mode 7 Matrix B // 0x03b0-0x050f : Mode 7 Matrix C // 0x0510-0x066f : Mode 7 Matrix D // case 0x07: { int16 data; int32 offset = 0; int16 Theta = ST010_WORD(0x0000); for (int32 line = 0; line < 176; line++) { // Calculate Mode 7 Matrix A/D data data = ST010_M7Scale[line] * ST010_Cos(Theta) >> 15; Memory.SRAM[0x00f0 + offset] = (uint8) (data); Memory.SRAM[0x00f1 + offset] = (uint8) (data >> 8); Memory.SRAM[0x0510 + offset] = (uint8) (data); Memory.SRAM[0x0511 + offset] = (uint8) (data >> 8); // Calculate Mode 7 Matrix B/C data data = ST010_M7Scale[line] * ST010_Sin(Theta) >> 15; Memory.SRAM[0x0250 + offset] = (uint8) (data); Memory.SRAM[0x0251 + offset] = (uint8) (data >> 8); if (data) data = ~data; Memory.SRAM[0x03b0 + offset] = (uint8) (data); Memory.SRAM[0x03b1 + offset] = (uint8) (data >> 8); offset += 2; } // Shift Angle for use with Lookup table Memory.SRAM[0x00] = Memory.SRAM[0x01]; Memory.SRAM[0x01] = 0x00; break; } // Two dimensional Coordinate Rotation // // Input // 0x0000-0x0001 : X0 (signed) // 0x0002-0x0003 : Y0 (signed) // 0x0004-0x0005 : Angle (signed) // Output // 0x0010-0x0011 : X1 (signed) // 0x0012-0x0013 : Y1 (signed) // case 0x08: { #ifdef FAST_LSB_WORD_ACCESS ST010_Rotate(*(int16 *) &Memory.SRAM[0x0004], *(int16 *) &Memory.SRAM[0x0000], *(int16 *) &Memory.SRAM[0x0002], (int16 &) Memory.SRAM[0x0010], (int16 &) Memory.SRAM[0x0012]); #else int16 x1, y1; ST010_Rotate(ST010_WORD(0x0004), ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1); Memory.SRAM[0x0010] = (uint8) (x1); Memory.SRAM[0x0011] = (uint8) (x1 >> 8); Memory.SRAM[0x0012] = (uint8) (y1); Memory.SRAM[0x0013] = (uint8) (y1 >> 8); #endif break; } // Input // 0x0000-0x0001 : DX (signed) // 0x0002-0x0003 : DY (signed) // Output // 0x0010-0x0011 : Angle (signed) // case 0x01: { Memory.SRAM[0x0006] = Memory.SRAM[0x0002]; Memory.SRAM[0x0007] = Memory.SRAM[0x0003]; #ifdef FAST_LSB_WORD_ACCESS ST010_OP01(*(int16 *) &Memory.SRAM[0x0000], *(int16 *) &Memory.SRAM[0x0002], (int16 &) Memory.SRAM[0x0000], (int16 &) Memory.SRAM[0x0002], (int16 &) Memory.SRAM[0x0004], (int16 &) Memory.SRAM[0x0010]); #else int16 x1, y1, Quadrant, Theta; ST010_OP01(ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1, Quadrant, Theta); Memory.SRAM[0x0000] = (uint8) (x1); Memory.SRAM[0x0001] = (uint8) (x1 >> 8); Memory.SRAM[0x0002] = (uint8) (y1); Memory.SRAM[0x0003] = (uint8) (y1 >> 8); Memory.SRAM[0x0004] = (uint8) (Quadrant); Memory.SRAM[0x0005] = (uint8) (Quadrant >> 8); Memory.SRAM[0x0010] = (uint8) (Theta); Memory.SRAM[0x0011] = (uint8) (Theta >> 8); #endif break; } // calculate the vector length of (x, y) case 0x04: { int16 square, x, y; #ifdef FAST_LSB_WORD_ACCESS x = *((int16 *) Memory.SRAM); y = *((int16 *) &Memory.SRAM[2]); #else x = Memory.SRAM[0] | (Memory.SRAM[1] << 8); y = Memory.SRAM[2] | (Memory.SRAM[3] << 8); #endif square = (int16) sqrt((double) (y * y + x * x)); //SETA_Distance(x, y, square); #ifdef FAST_LSB_WORD_ACCESS *((int16 *) &Memory.SRAM[0x10]) = square; #else Memory.SRAM[0x10] = (uint8) (square); Memory.SRAM[0x11] = (uint8) (square >> 8); #endif break; } // calculate AI orientation based on specific guidelines case 0x05: { int32 dx, dy; int16 a1, b1, c1; uint16 o1; bool wrap = false; // target (x, y) coordinates int16 ypos_max = ST010_WORD(0x00C0); int16 xpos_max = ST010_WORD(0x00C2); // current coordinates and direction int32 ypos = Memory.SRAM[0xC4] | (Memory.SRAM[0xC5] << 8) | (Memory.SRAM[0xC6] << 16) | (Memory.SRAM[0xC7] << 24); int32 xpos = Memory.SRAM[0xC8] | (Memory.SRAM[0xC9] << 8) | (Memory.SRAM[0xCA] << 16) | (Memory.SRAM[0xCB] << 24); uint16 rot = Memory.SRAM[0xCC] | (Memory.SRAM[0xCD] << 8); // physics uint16 speed = ST010_WORD(0x00D4); uint16 accel = ST010_WORD(0x00D6); uint16 speed_max = ST010_WORD(0x00D8); // special condition acknowledgment int16 system = ST010_WORD(0x00DA); int16 flags = ST010_WORD(0x00DC); // new target coordinates int16 ypos_new = ST010_WORD(0x00DE); int16 xpos_new = ST010_WORD(0x00E0); // mask upper bit xpos_new &= 0x7FFF; // get the current distance dx = xpos_max - (xpos >> 16); dy = ypos_max - (ypos >> 16); // quirk: clear and move in9 Memory.SRAM[0xD2] = 0xFF; Memory.SRAM[0xD3] = 0xFF; Memory.SRAM[0xDA] = 0; Memory.SRAM[0xDB] = 0; // grab the target angle ST010_OP01(dy, dx, a1, b1, c1, (int16 &) o1); // check for wrapping //if ((o1 < 0x6000 && rot > 0xA000) || (rot < 0x6000 && o1 > 0xA000)) //if (o1 < rot) if (abs(o1 - rot) > 0x8000) { o1 += 0x8000; rot += 0x8000; wrap = true; } //o1 = 0x0000; //rot = 0xFF00; uint16 old_speed; old_speed = speed; // special case if (abs(o1 - rot) == 0x8000) speed = 0x100; // slow down for sharp curves else if (abs(o1 - rot) >= 0x1000) { uint32 slow = abs(o1 - rot); slow >>= 4; // scaling speed -= slow; } // otherwise accelerate else { speed += accel; if (speed > speed_max) { // clip speed speed = speed_max; } } // prevent negative/positive overflow if (abs(old_speed - speed) > 0x8000) { if (old_speed < speed) speed = 0; else speed = 0xff00; } // adjust direction by so many degrees // be careful of negative adjustments if ((o1 > rot && (o1 - rot) > 0x80) || (o1 < rot && (rot - o1) >= 0x80)) { if (o1 < rot) rot -= 0x280; else if (o1 > rot) rot += 0x280; } // turn off wrapping if (wrap) rot -= 0x8000; // now check the distances (store for later) dx = (xpos_max << 16) - xpos; dy = (ypos_max << 16) - ypos; dx >>= 16; dy >>= 16; // if we're in so many units of the target, signal it if ((system && (dy <= 6 && dy >= -8) && (dx <= 126 && dx >= -128)) || (!system && (dx <= 6 && dx >= -8) && (dy <= 126 && dy >= -128))) { // announce our new destination and flag it xpos_max = xpos_new & 0x7FFF; ypos_max = ypos_new; flags |= 0x08; } // update position xpos -= (ST010_Cos(rot) * 0x400 >> 15) * (speed >> 8) << 1; ypos -= (ST010_Sin(rot) * 0x400 >> 15) * (speed >> 8) << 1; // quirk: mask upper byte xpos &= 0x1FFFFFFF; ypos &= 0x1FFFFFFF; Memory.SRAM[0x00C0] = (uint8) (ypos_max); Memory.SRAM[0x00C1] = (uint8) (ypos_max >> 8); Memory.SRAM[0x00C2] = (uint8) (xpos_max); Memory.SRAM[0x00C3] = (uint8) (xpos_max >> 8); Memory.SRAM[0x00C4] = (uint8) (ypos); Memory.SRAM[0x00C5] = (uint8) (ypos >> 8); Memory.SRAM[0x00C6] = (uint8) (ypos >> 16); Memory.SRAM[0x00C7] = (uint8) (ypos >> 24); Memory.SRAM[0x00C8] = (uint8) (xpos); Memory.SRAM[0x00C9] = (uint8) (xpos >> 8); Memory.SRAM[0x00CA] = (uint8) (xpos >> 16); Memory.SRAM[0x00CB] = (uint8) (xpos >> 24); Memory.SRAM[0x00CC] = (uint8) (rot); Memory.SRAM[0x00CD] = (uint8) (rot >> 8); Memory.SRAM[0x00D4] = (uint8) (speed); Memory.SRAM[0x00D5] = (uint8) (speed >> 8); Memory.SRAM[0x00DC] = (uint8) (flags); Memory.SRAM[0x00DD] = (uint8) (flags >> 8); break; } default: #ifdef DEBUGGER printf("Unknown Op\n"); #endif break; } // lower signal: op processed ST010.op_reg = 0; ST010.execute = 0; } } apu/bapu/smp/debugger/000700 001750 001750 00000000000 12724164663 016000 5ustar00sergiosergio000000 000000 screenshot.h000664 001750 001750 00000014203 12720446475 014243 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _SCREENSHOT_H_ #define _SCREENSHOT_H_ bool8 S9xDoScreenshot (int, int); #endif cpumacro.h000664 001750 001750 00000046447 12720446475 013716 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CPUMACRO_H_ #define _CPUMACRO_H_ #define rOP8(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \ FUNC(val); \ } #define rOP16(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ uint16 val = S9xGetWord(ADDR(READ), WRAP); \ OpenBus = (uint8) (val >> 8); \ FUNC(val); \ } #define rOPC(OP, COND, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ if (Check##COND()) \ { \ uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \ FUNC(val); \ } \ else \ { \ uint16 val = S9xGetWord(ADDR(READ), WRAP); \ OpenBus = (uint8) (val >> 8); \ FUNC(val); \ } \ } #define rOPM(OP, ADDR, WRAP, FUNC) \ rOPC(OP, Memory, ADDR, WRAP, FUNC) #define rOPX(OP, ADDR, WRAP, FUNC) \ rOPC(OP, Index, ADDR, WRAP, FUNC) #define wOP8(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ FUNC##8(ADDR(WRITE)); \ } #define wOP16(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ FUNC##16(ADDR(WRITE), WRAP); \ } #define wOPC(OP, COND, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ if (Check##COND()) \ FUNC##8(ADDR(WRITE)); \ else \ FUNC##16(ADDR(WRITE), WRAP); \ } #define wOPM(OP, ADDR, WRAP, FUNC) \ wOPC(OP, Memory, ADDR, WRAP, FUNC) #define wOPX(OP, ADDR, WRAP, FUNC) \ wOPC(OP, Index, ADDR, WRAP, FUNC) #define mOP8(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ FUNC##8(ADDR(MODIFY)); \ } #define mOP16(OP, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ FUNC##16(ADDR(MODIFY), WRAP); \ } #define mOPC(OP, COND, ADDR, WRAP, FUNC) \ static void Op##OP (void) \ { \ if (Check##COND()) \ FUNC##8(ADDR(MODIFY)); \ else \ FUNC##16(ADDR(MODIFY), WRAP); \ } #define mOPM(OP, ADDR, WRAP, FUNC) \ mOPC(OP, Memory, ADDR, WRAP, FUNC) #define bOP(OP, REL, COND, CHK, E) \ static void Op##OP (void) \ { \ pair newPC; \ newPC.W = REL(JUMP); \ if (COND) \ { \ AddCycles(ONE_CYCLE); \ if (E && Registers.PCh != newPC.B.h) \ AddCycles(ONE_CYCLE); \ if ((Registers.PCw & ~MEMMAP_MASK) != (newPC.W & ~MEMMAP_MASK)) \ S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \ else \ Registers.PCw = newPC.W; \ } \ } static inline void SetZN (uint16 Work16) { ICPU._Zero = Work16 != 0; ICPU._Negative = (uint8) (Work16 >> 8); } static inline void SetZN (uint8 Work8) { ICPU._Zero = Work8; ICPU._Negative = Work8; } static inline void ADC (uint16 Work16) { if (CheckDecimal()) { uint16 A1 = Registers.A.W & 0x000F; uint16 A2 = Registers.A.W & 0x00F0; uint16 A3 = Registers.A.W & 0x0F00; uint32 A4 = Registers.A.W & 0xF000; uint16 W1 = Work16 & 0x000F; uint16 W2 = Work16 & 0x00F0; uint16 W3 = Work16 & 0x0F00; uint16 W4 = Work16 & 0xF000; A1 += W1 + CheckCarry(); if (A1 > 0x0009) { A1 -= 0x000A; A1 &= 0x000F; A2 += 0x0010; } A2 += W2; if (A2 > 0x0090) { A2 -= 0x00A0; A2 &= 0x00F0; A3 += 0x0100; } A3 += W3; if (A3 > 0x0900) { A3 -= 0x0A00; A3 &= 0x0F00; A4 += 0x1000; } A4 += W4; if (A4 > 0x9000) { A4 -= 0xA000; A4 &= 0xF000; SetCarry(); } else ClearCarry(); uint16 Ans16 = A4 | A3 | A2 | A1; if (~(Registers.A.W ^ Work16) & (Work16 ^ Ans16) & 0x8000) SetOverflow(); else ClearOverflow(); Registers.A.W = Ans16; SetZN(Registers.A.W); } else { uint32 Ans32 = Registers.A.W + Work16 + CheckCarry(); ICPU._Carry = Ans32 >= 0x10000; if (~(Registers.A.W ^ Work16) & (Work16 ^ (uint16) Ans32) & 0x8000) SetOverflow(); else ClearOverflow(); Registers.A.W = (uint16) Ans32; SetZN(Registers.A.W); } } static inline void ADC (uint8 Work8) { if (CheckDecimal()) { uint8 A1 = Registers.A.W & 0x0F; uint16 A2 = Registers.A.W & 0xF0; uint8 W1 = Work8 & 0x0F; uint8 W2 = Work8 & 0xF0; A1 += W1 + CheckCarry(); if (A1 > 0x09) { A1 -= 0x0A; A1 &= 0x0F; A2 += 0x10; } A2 += W2; if (A2 > 0x90) { A2 -= 0xA0; A2 &= 0xF0; SetCarry(); } else ClearCarry(); uint8 Ans8 = A2 | A1; if (~(Registers.AL ^ Work8) & (Work8 ^ Ans8) & 0x80) SetOverflow(); else ClearOverflow(); Registers.AL = Ans8; SetZN(Registers.AL); } else { uint16 Ans16 = Registers.AL + Work8 + CheckCarry(); ICPU._Carry = Ans16 >= 0x100; if (~(Registers.AL ^ Work8) & (Work8 ^ (uint8) Ans16) & 0x80) SetOverflow(); else ClearOverflow(); Registers.AL = (uint8) Ans16; SetZN(Registers.AL); } } static inline void AND (uint16 Work16) { Registers.A.W &= Work16; SetZN(Registers.A.W); } static inline void AND (uint8 Work8) { Registers.AL &= Work8; SetZN(Registers.AL); } static inline void ASL16 (uint32 OpAddress, s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w); ICPU._Carry = (Work16 & 0x8000) != 0; Work16 <<= 1; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; SetZN(Work16); } static inline void ASL8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress); ICPU._Carry = (Work8 & 0x80) != 0; Work8 <<= 1; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; SetZN(Work8); } static inline void BIT (uint16 Work16) { ICPU._Overflow = (Work16 & 0x4000) != 0; ICPU._Negative = (uint8) (Work16 >> 8); ICPU._Zero = (Work16 & Registers.A.W) != 0; } static inline void BIT (uint8 Work8) { ICPU._Overflow = (Work8 & 0x40) != 0; ICPU._Negative = Work8; ICPU._Zero = Work8 & Registers.AL; } static inline void CMP (uint16 val) { int32 Int32 = (int32) Registers.A.W - (int32) val; ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static inline void CMP (uint8 val) { int16 Int16 = (int16) Registers.AL - (int16) val; ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static inline void CPX (uint16 val) { int32 Int32 = (int32) Registers.X.W - (int32) val; ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static inline void CPX (uint8 val) { int16 Int16 = (int16) Registers.XL - (int16) val; ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static inline void CPY (uint16 val) { int32 Int32 = (int32) Registers.Y.W - (int32) val; ICPU._Carry = Int32 >= 0; SetZN((uint16) Int32); } static inline void CPY (uint8 val) { int16 Int16 = (int16) Registers.YL - (int16) val; ICPU._Carry = Int16 >= 0; SetZN((uint8) Int16); } static inline void DEC16 (uint32 OpAddress, s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w) - 1; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; SetZN(Work16); } static inline void DEC8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress) - 1; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; SetZN(Work8); } static inline void EOR (uint16 val) { Registers.A.W ^= val; SetZN(Registers.A.W); } static inline void EOR (uint8 val) { Registers.AL ^= val; SetZN(Registers.AL); } static inline void INC16 (uint32 OpAddress, s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w) + 1; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; SetZN(Work16); } static inline void INC8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress) + 1; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; SetZN(Work8); } static inline void LDA (uint16 val) { Registers.A.W = val; SetZN(Registers.A.W); } static inline void LDA (uint8 val) { Registers.AL = val; SetZN(Registers.AL); } static inline void LDX (uint16 val) { Registers.X.W = val; SetZN(Registers.X.W); } static inline void LDX (uint8 val) { Registers.XL = val; SetZN(Registers.XL); } static inline void LDY (uint16 val) { Registers.Y.W = val; SetZN(Registers.Y.W); } static inline void LDY (uint8 val) { Registers.YL = val; SetZN(Registers.YL); } static inline void LSR16 (uint32 OpAddress, s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w); ICPU._Carry = Work16 & 1; Work16 >>= 1; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; SetZN(Work16); } static inline void LSR8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress); ICPU._Carry = Work8 & 1; Work8 >>= 1; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; SetZN(Work8); } static inline void ORA (uint16 val) { Registers.A.W |= val; SetZN(Registers.A.W); } static inline void ORA (uint8 val) { Registers.AL |= val; SetZN(Registers.AL); } static inline void ROL16 (uint32 OpAddress, s9xwrap_t w) { uint32 Work32 = (((uint32) S9xGetWord(OpAddress, w)) << 1) | CheckCarry(); ICPU._Carry = Work32 >= 0x10000; AddCycles(ONE_CYCLE); S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10); OpenBus = Work32 & 0xff; SetZN((uint16) Work32); } static inline void ROL8 (uint32 OpAddress) { uint16 Work16 = (((uint16) S9xGetByte(OpAddress)) << 1) | CheckCarry(); ICPU._Carry = Work16 >= 0x100; AddCycles(ONE_CYCLE); S9xSetByte((uint8) Work16, OpAddress); OpenBus = Work16 & 0xff; SetZN((uint8) Work16); } static inline void ROR16 (uint32 OpAddress, s9xwrap_t w) { uint32 Work32 = ((uint32) S9xGetWord(OpAddress, w)) | (((uint32) CheckCarry()) << 16); ICPU._Carry = Work32 & 1; Work32 >>= 1; AddCycles(ONE_CYCLE); S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10); OpenBus = Work32 & 0xff; SetZN((uint16) Work32); } static inline void ROR8 (uint32 OpAddress) { uint16 Work16 = ((uint16) S9xGetByte(OpAddress)) | (((uint16) CheckCarry()) << 8); ICPU._Carry = Work16 & 1; Work16 >>= 1; AddCycles(ONE_CYCLE); S9xSetByte((uint8) Work16, OpAddress); OpenBus = Work16 & 0xff; SetZN((uint8) Work16); } static inline void SBC (uint16 Work16) { if (CheckDecimal()) { uint16 A1 = Registers.A.W & 0x000F; uint16 A2 = Registers.A.W & 0x00F0; uint16 A3 = Registers.A.W & 0x0F00; uint32 A4 = Registers.A.W & 0xF000; uint16 W1 = Work16 & 0x000F; uint16 W2 = Work16 & 0x00F0; uint16 W3 = Work16 & 0x0F00; uint16 W4 = Work16 & 0xF000; A1 -= W1 + !CheckCarry(); A2 -= W2; A3 -= W3; A4 -= W4; if (A1 > 0x000F) { A1 += 0x000A; A1 &= 0x000F; A2 -= 0x0010; } if (A2 > 0x00F0) { A2 += 0x00A0; A2 &= 0x00F0; A3 -= 0x0100; } if (A3 > 0x0F00) { A3 += 0x0A00; A3 &= 0x0F00; A4 -= 0x1000; } if (A4 > 0xF000) { A4 += 0xA000; A4 &= 0xF000; ClearCarry(); } else SetCarry(); uint16 Ans16 = A4 | A3 | A2 | A1; if ((Registers.A.W ^ Work16) & (Registers.A.W ^ Ans16) & 0x8000) SetOverflow(); else ClearOverflow(); Registers.A.W = Ans16; SetZN(Registers.A.W); } else { int32 Int32 = (int32) Registers.A.W - (int32) Work16 + (int32) CheckCarry() - 1; ICPU._Carry = Int32 >= 0; if ((Registers.A.W ^ Work16) & (Registers.A.W ^ (uint16) Int32) & 0x8000) SetOverflow(); else ClearOverflow(); Registers.A.W = (uint16) Int32; SetZN(Registers.A.W); } } static inline void SBC (uint8 Work8) { if (CheckDecimal()) { uint8 A1 = Registers.A.W & 0x0F; uint16 A2 = Registers.A.W & 0xF0; uint8 W1 = Work8 & 0x0F; uint8 W2 = Work8 & 0xF0; A1 -= W1 + !CheckCarry(); A2 -= W2; if (A1 > 0x0F) { A1 += 0x0A; A1 &= 0x0F; A2 -= 0x10; } if (A2 > 0xF0) { A2 += 0xA0; A2 &= 0xF0; ClearCarry(); } else SetCarry(); uint8 Ans8 = A2 | A1; if ((Registers.AL ^ Work8) & (Registers.AL ^ Ans8) & 0x80) SetOverflow(); else ClearOverflow(); Registers.AL = Ans8; SetZN(Registers.AL); } else { int16 Int16 = (int16) Registers.AL - (int16) Work8 + (int16) CheckCarry() - 1; ICPU._Carry = Int16 >= 0; if ((Registers.AL ^ Work8) & (Registers.AL ^ (uint8) Int16) & 0x80) SetOverflow(); else ClearOverflow(); Registers.AL = (uint8) Int16; SetZN(Registers.AL); } } static inline void STA16 (uint32 OpAddress, enum s9xwrap_t w) { S9xSetWord(Registers.A.W, OpAddress, w); OpenBus = Registers.AH; } static inline void STA8 (uint32 OpAddress) { S9xSetByte(Registers.AL, OpAddress); OpenBus = Registers.AL; } static inline void STX16 (uint32 OpAddress, enum s9xwrap_t w) { S9xSetWord(Registers.X.W, OpAddress, w); OpenBus = Registers.XH; } static inline void STX8 (uint32 OpAddress) { S9xSetByte(Registers.XL, OpAddress); OpenBus = Registers.XL; } static inline void STY16 (uint32 OpAddress, enum s9xwrap_t w) { S9xSetWord(Registers.Y.W, OpAddress, w); OpenBus = Registers.YH; } static inline void STY8 (uint32 OpAddress) { S9xSetByte(Registers.YL, OpAddress); OpenBus = Registers.YL; } static inline void STZ16 (uint32 OpAddress, enum s9xwrap_t w) { S9xSetWord(0, OpAddress, w); OpenBus = 0; } static inline void STZ8 (uint32 OpAddress) { S9xSetByte(0, OpAddress); OpenBus = 0; } static inline void TSB16 (uint32 OpAddress, enum s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w); ICPU._Zero = (Work16 & Registers.A.W) != 0; Work16 |= Registers.A.W; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; } static inline void TSB8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress); ICPU._Zero = Work8 & Registers.AL; Work8 |= Registers.AL; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; } static inline void TRB16 (uint32 OpAddress, enum s9xwrap_t w) { uint16 Work16 = S9xGetWord(OpAddress, w); ICPU._Zero = (Work16 & Registers.A.W) != 0; Work16 &= ~Registers.A.W; AddCycles(ONE_CYCLE); S9xSetWord(Work16, OpAddress, w, WRITE_10); OpenBus = Work16 & 0xff; } static inline void TRB8 (uint32 OpAddress) { uint8 Work8 = S9xGetByte(OpAddress); ICPU._Zero = Work8 & Registers.AL; Work8 &= ~Registers.AL; AddCycles(ONE_CYCLE); S9xSetByte(Work8, OpAddress); OpenBus = Work8; } #endif c4.cpp000664 001750 001750 00000022614 12720446475 012734 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include "snes9x.h" #include "memmap.h" #define C4_PI 3.14159265 int16 C4WFXVal; int16 C4WFYVal; int16 C4WFZVal; int16 C4WFX2Val; int16 C4WFY2Val; int16 C4WFDist; int16 C4WFScale; int16 C41FXVal; int16 C41FYVal; int16 C41FAngleRes; int16 C41FDist; int16 C41FDistVal; static double tanval; static double c4x, c4y, c4z; static double c4x2, c4y2, c4z2; void C4TransfWireFrame (void) { c4x = (double) C4WFXVal; c4y = (double) C4WFYVal; c4z = (double) C4WFZVal - 0x95; // Rotate X tanval = -(double) C4WFX2Val * C4_PI * 2 / 128; c4y2 = c4y * cos(tanval) - c4z * sin(tanval); c4z2 = c4y * sin(tanval) + c4z * cos(tanval); // Rotate Y tanval = -(double) C4WFY2Val * C4_PI * 2 / 128; c4x2 = c4x * cos(tanval) + c4z2 * sin(tanval); c4z = c4x * -sin(tanval) + c4z2 * cos(tanval); // Rotate Z tanval = -(double) C4WFDist * C4_PI * 2 / 128; c4x = c4x2 * cos(tanval) - c4y2 * sin(tanval); c4y = c4x2 * sin(tanval) + c4y2 * cos(tanval); // Scale C4WFXVal = (int16) (c4x * (double) C4WFScale / (0x90 * (c4z + 0x95)) * 0x95); C4WFYVal = (int16) (c4y * (double) C4WFScale / (0x90 * (c4z + 0x95)) * 0x95); } void C4TransfWireFrame2 (void) { c4x = (double) C4WFXVal; c4y = (double) C4WFYVal; c4z = (double) C4WFZVal; // Rotate X tanval = -(double) C4WFX2Val * C4_PI * 2 / 128; c4y2 = c4y * cos(tanval) - c4z * sin(tanval); c4z2 = c4y * sin(tanval) + c4z * cos(tanval); // Rotate Y tanval = -(double) C4WFY2Val * C4_PI * 2 / 128; c4x2 = c4x * cos(tanval) + c4z2 * sin(tanval); c4z = c4x * -sin(tanval) + c4z2 * cos(tanval); // Rotate Z tanval = -(double) C4WFDist * C4_PI * 2 / 128; c4x = c4x2 * cos(tanval) - c4y2 * sin(tanval); c4y = c4x2 * sin(tanval) + c4y2 * cos(tanval); // Scale C4WFXVal = (int16) (c4x * (double) C4WFScale / 0x100); C4WFYVal = (int16) (c4y * (double) C4WFScale / 0x100); } void C4CalcWireFrame (void) { C4WFXVal = C4WFX2Val - C4WFXVal; C4WFYVal = C4WFY2Val - C4WFYVal; if (abs(C4WFXVal) > abs(C4WFYVal)) { C4WFDist = abs(C4WFXVal) + 1; C4WFYVal = (int16) (256 * (double) C4WFYVal / abs(C4WFXVal)); if (C4WFXVal < 0) C4WFXVal = -256; else C4WFXVal = 256; } else { if (C4WFYVal != 0) { C4WFDist = abs(C4WFYVal) + 1; C4WFXVal = (int16) (256 * (double) C4WFXVal / abs(C4WFYVal)); if (C4WFYVal < 0) C4WFYVal = -256; else C4WFYVal = 256; } else C4WFDist = 0; } } void C4Op1F (void) { if (C41FXVal == 0) { if (C41FYVal > 0) C41FAngleRes = 0x80; else C41FAngleRes = 0x180; } else { tanval = (double) C41FYVal / C41FXVal; C41FAngleRes = (int16) (atan(tanval) / (C4_PI * 2) * 512); C41FAngleRes = C41FAngleRes; if (C41FXVal< 0) C41FAngleRes += 0x100; C41FAngleRes &= 0x1FF; } } void C4Op15 (void) { tanval = sqrt((double) C41FYVal * C41FYVal + (double) C41FXVal * C41FXVal); C41FDist = (int16) tanval; } void C4Op0D (void) { tanval = sqrt((double) C41FYVal * C41FYVal + (double) C41FXVal * C41FXVal); tanval = C41FDistVal / tanval; C41FYVal = (int16) (C41FYVal * tanval * 0.99); C41FXVal = (int16) (C41FXVal * tanval * 0.98); } uint8 * S9xGetBasePointerC4 (uint16 Address) { if (Address >= 0x7f40 && Address <= 0x7f5e) return (NULL); return (Memory.C4RAM - 0x6000); } uint8 * S9xGetMemPointerC4 (uint16 Address) { if (Address >= 0x7f40 && Address <= 0x7f5e) return (NULL); return (Memory.C4RAM - 0x6000 + (Address & 0xffff)); } dsp1.cpp000664 001750 001750 00000200366 12720446475 013277 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ /* Copyright (C) 1997-2006 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach ) http://www.zsnes.com http://sourceforge.net/projects/zsnes This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "snes9x.h" #include "memmap.h" #ifdef DEBUGGER //#define DebugDSP1 #endif #ifdef DebugDSP1 #include static FILE *LogFile = NULL; #endif static const uint16 DSP1ROM[1024] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; static const int16 DSP1_MulTable[256] = { 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321 }; static const int16 DSP1_SinTable[256] = { 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 }; #ifdef DebugDSP1 static void Log_Message (const char *Message, ...) { char Msg[400]; va_list ap; size_t ignore; va_start(ap, Message); vsprintf(Msg, Message, ap); va_end(ap); strcat(Msg, "\r\n\0"); ignore = fwrite(Msg, strlen(Msg), 1, LogFile); fflush(LogFile); } static void Start_Log (void) { LogFile = fopen("dsp1emu.log", "wb"); } static void Stop_Log (void) { if (LogFile) { fclose(LogFile); LogFile = NULL; } } #endif static void DSP1_Op00 (void) { DSP1.Op00Result = DSP1.Op00Multiplicand * DSP1.Op00Multiplier >> 15; #ifdef DebugDSP1 Log_Message("OP00 MULT %d*%d/32768=%d", DSP1.Op00Multiplicand, DSP1.Op00Multiplier, DSP1.Op00Result); #endif } static void DSP1_Op20 (void) { DSP1.Op20Result = DSP1.Op20Multiplicand * DSP1.Op20Multiplier >> 15; DSP1.Op20Result++; #ifdef DebugDSP1 Log_Message("OP20 MULT %d*%d/32768=%d", DSP1.Op20Multiplicand, DSP1.Op20Multiplier, DSP1.Op20Result); #endif } static void DSP1_Inverse (int16 Coefficient, int16 Exponent, int16 *iCoefficient, int16 *iExponent) { // Step One: Division by Zero if (Coefficient == 0x0000) { *iCoefficient = 0x7fff; *iExponent = 0x002f; } else { int16 Sign = 1; // Step Two: Remove Sign if (Coefficient < 0) { if (Coefficient < -32767) Coefficient = -32767; Coefficient = -Coefficient; Sign = -1; } // Step Three: Normalize while (Coefficient < 0x4000) { Coefficient <<= 1; Exponent--; } // Step Four: Special Case if (Coefficient == 0x4000) { if (Sign == 1) *iCoefficient = 0x7fff; else { *iCoefficient = -0x4000; Exponent--; } } else { // Step Five: Initial Guess int16 i = DSP1ROM[((Coefficient - 0x4000) >> 7) + 0x0065]; // Step Six: Iterate "estimated" Newton's Method i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; *iCoefficient = i * Sign; } *iExponent = 1 - Exponent; } } static void DSP1_Op10 (void) { DSP1_Inverse(DSP1.Op10Coefficient, DSP1.Op10Exponent, &DSP1.Op10CoefficientR, &DSP1.Op10ExponentR); #ifdef DebugDSP1 Log_Message("OP10 INV %d*2^%d = %d*2^%d", DSP1.Op10Coefficient, DSP1.Op10Exponent, DSP1.Op10CoefficientR, DSP1.Op10ExponentR); #endif } static int16 DSP1_Sin (int16 Angle) { int32 S; if (Angle < 0) { if (Angle == -32768) return (0); return (-DSP1_Sin(-Angle)); } S = DSP1_SinTable[Angle >> 8] + (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[0x40 + (Angle >> 8)] >> 15); if (S > 32767) S = 32767; return ((int16) S); } static int16 DSP1_Cos (int16 Angle) { int32 S; if (Angle < 0) { if (Angle == -32768) return (-32768); Angle = -Angle; } S = DSP1_SinTable[0x40 + (Angle >> 8)] - (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[Angle >> 8] >> 15); if (S < -32768) S = -32767; return ((int16) S); } static void DSP1_Normalize (int16 m, int16 *Coefficient, int16 *Exponent) { int16 i = 0x4000; int16 e = 0; if (m < 0) { while ((m & i) && i) { i >>= 1; e++; } } else { while (!(m & i) && i) { i >>= 1; e++; } } if (e > 0) *Coefficient = m * DSP1ROM[0x21 + e] << 1; else *Coefficient = m; *Exponent -= e; } static void DSP1_NormalizeDouble (int32 Product, int16 *Coefficient, int16 *Exponent) { int16 n = Product & 0x7fff; int16 m = Product >> 15; int16 i = 0x4000; int16 e = 0; if (m < 0) { while ((m & i) && i) { i >>= 1; e++; } } else { while (!(m & i) && i) { i >>= 1; e++; } } if (e > 0) { *Coefficient = m * DSP1ROM[0x0021 + e] << 1; if (e < 15) *Coefficient += n * DSP1ROM[0x0040 - e] >> 15; else { i = 0x4000; if (m < 0) { while ((n & i) && i) { i >>= 1; e++; } } else { while (!(n & i) && i) { i >>= 1; e++; } } if (e > 15) *Coefficient = n * DSP1ROM[0x0012 + e] << 1; else *Coefficient += n; } } else *Coefficient = m; *Exponent = e; } static int16 DSP1_Truncate (int16 C, int16 E) { if (E > 0) { if (C > 0) return (32767); else if (C < 0) return (-32767); } else { if (E < 0) return (C * DSP1ROM[0x0031 + E] >> 15); } return (C); } static void DSP1_Op04 (void) { DSP1.Op04Sin = DSP1_Sin(DSP1.Op04Angle) * DSP1.Op04Radius >> 15; DSP1.Op04Cos = DSP1_Cos(DSP1.Op04Angle) * DSP1.Op04Radius >> 15; } static void DSP1_Op0C (void) { DSP1.Op0CX2 = (DSP1.Op0CY1 * DSP1_Sin(DSP1.Op0CA) >> 15) + (DSP1.Op0CX1 * DSP1_Cos(DSP1.Op0CA) >> 15); DSP1.Op0CY2 = (DSP1.Op0CY1 * DSP1_Cos(DSP1.Op0CA) >> 15) - (DSP1.Op0CX1 * DSP1_Sin(DSP1.Op0CA) >> 15); } static void DSP1_Parameter (int16 Fx, int16 Fy, int16 Fz, int16 Lfe, int16 Les, int16 Aas, int16 Azs, int16 *Vof, int16 *Vva, int16 *Cx, int16 *Cy) { const int16 MaxAZS_Exp[16] = { 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 }; int16 CSec, C, E, MaxAZS, Aux; int16 LfeNx, LfeNy, LfeNz; int16 LesNx, LesNy, LesNz; int16 CentreZ; // Copy Zenith angle for clipping int16 AZS = Azs; // Store Sine and Cosine of Azimuth and Zenith angle DSP1.SinAas = DSP1_Sin(Aas); DSP1.CosAas = DSP1_Cos(Aas); DSP1.SinAzs = DSP1_Sin(Azs); DSP1.CosAzs = DSP1_Cos(Azs); DSP1.Nx = DSP1.SinAzs * -DSP1.SinAas >> 15; DSP1.Ny = DSP1.SinAzs * DSP1.CosAas >> 15; DSP1.Nz = DSP1.CosAzs * 0x7fff >> 15; LfeNx = Lfe * DSP1.Nx >> 15; LfeNy = Lfe * DSP1.Ny >> 15; LfeNz = Lfe * DSP1.Nz >> 15; // Center of Projection DSP1.CentreX = Fx + LfeNx; DSP1.CentreY = Fy + LfeNy; CentreZ = Fz + LfeNz; LesNx = Les * DSP1.Nx >> 15; LesNy = Les * DSP1.Ny >> 15; LesNz = Les * DSP1.Nz >> 15; DSP1.Gx = DSP1.CentreX - LesNx; DSP1.Gy = DSP1.CentreY - LesNy; DSP1.Gz = CentreZ - LesNz; DSP1.E_Les = 0; DSP1_Normalize(Les, &DSP1.C_Les, &DSP1.E_Les); DSP1.G_Les = Les; E = 0; DSP1_Normalize(CentreZ, &C, &E); DSP1.VPlane_C = C; DSP1.VPlane_E = E; // Determine clip boundary and clip Zenith angle if necessary MaxAZS = MaxAZS_Exp[-E]; if (AZS < 0) { MaxAZS = -MaxAZS; if (AZS < MaxAZS + 1) AZS = MaxAZS + 1; } else { if (AZS > MaxAZS) AZS = MaxAZS; } // Store Sine and Cosine of clipped Zenith angle DSP1.SinAZS = DSP1_Sin(AZS); DSP1.CosAZS = DSP1_Cos(AZS); DSP1_Inverse(DSP1.CosAZS, 0, &DSP1.SecAZS_C1, &DSP1.SecAZS_E1); DSP1_Normalize(C * DSP1.SecAZS_C1 >> 15, &C, &E); E += DSP1.SecAZS_E1; C = DSP1_Truncate(C, E) * DSP1.SinAZS >> 15; DSP1.CentreX += C * DSP1.SinAas >> 15; DSP1.CentreY -= C * DSP1.CosAas >> 15; *Cx = DSP1.CentreX; *Cy = DSP1.CentreY; // Raster number of imaginary center and horizontal line *Vof = 0; if ((Azs != AZS) || (Azs == MaxAZS)) { if (Azs == -32768) Azs = -32767; C = Azs - MaxAZS; if (C >= 0) C--; Aux = ~(C << 2); C = Aux * DSP1ROM[0x0328] >> 15; C = (C * Aux >> 15) + DSP1ROM[0x0327]; *Vof -= (C * Aux >> 15) * Les >> 15; C = Aux * Aux >> 15; Aux = (C * DSP1ROM[0x0324] >> 15) + DSP1ROM[0x0325]; DSP1.CosAZS += (C * Aux >> 15) * DSP1.CosAZS >> 15; } DSP1.VOffset = Les * DSP1.CosAZS >> 15; DSP1_Inverse(DSP1.SinAZS, 0, &CSec, &E); DSP1_Normalize(DSP1.VOffset, &C, &E); DSP1_Normalize(C * CSec >> 15, &C, &E); if (C == -32768) { C >>= 1; E++; } *Vva = DSP1_Truncate(-C, E); // Store Secant of clipped Zenith angle DSP1_Inverse(DSP1.CosAZS, 0, &DSP1.SecAZS_C2, &DSP1.SecAZS_E2); } static void DSP1_Raster (int16 Vs, int16 *An, int16 *Bn, int16 *Cn, int16 *Dn) { int16 C, E, C1, E1; DSP1_Inverse((Vs * DSP1.SinAzs >> 15) + DSP1.VOffset, 7, &C, &E); E += DSP1.VPlane_E; C1 = C * DSP1.VPlane_C >> 15; E1 = E + DSP1.SecAZS_E2; DSP1_Normalize(C1, &C, &E); C = DSP1_Truncate(C, E); *An = C * DSP1.CosAas >> 15; *Cn = C * DSP1.SinAas >> 15; DSP1_Normalize(C1 * DSP1.SecAZS_C2 >> 15, &C, &E1); C = DSP1_Truncate(C, E1); *Bn = C * -DSP1.SinAas >> 15; *Dn = C * DSP1.CosAas >> 15; } static void DSP1_Op02 (void) { DSP1_Parameter(DSP1.Op02FX, DSP1.Op02FY, DSP1.Op02FZ, DSP1.Op02LFE, DSP1.Op02LES, DSP1.Op02AAS, DSP1.Op02AZS, &DSP1.Op02VOF, &DSP1.Op02VVA, &DSP1.Op02CX, &DSP1.Op02CY); } static void DSP1_Op0A (void) { DSP1_Raster(DSP1.Op0AVS, &DSP1.Op0AA, &DSP1.Op0AB, &DSP1.Op0AC, &DSP1.Op0AD); DSP1.Op0AVS++; } static int16 DSP1_ShiftR (int16 C, int16 E) { return (C * DSP1ROM[0x0031 + E] >> 15); } static void DSP1_Project (int16 X, int16 Y, int16 Z, int16 *H, int16 *V, int16 *M) { int32 aux, aux4; int16 E, E2, E3, E4, E5, refE, E6, E7; int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; int16 Px, Py, Pz; E4 = E3 = E2 = E = E5 = 0; DSP1_NormalizeDouble((int32) X - DSP1.Gx, &Px, &E4); DSP1_NormalizeDouble((int32) Y - DSP1.Gy, &Py, &E ); DSP1_NormalizeDouble((int32) Z - DSP1.Gz, &Pz, &E3); Px >>= 1; // to avoid overflows when calculating the scalar products E4--; Py >>= 1; E--; Pz >>= 1; E3--; refE = (E < E3) ? E : E3; refE = (refE < E4) ? refE : E4; Px = DSP1_ShiftR(Px, E4 - refE); // normalize them to the same exponent Py = DSP1_ShiftR(Py, E - refE); Pz = DSP1_ShiftR(Pz, E3 - refE); C11 =- (Px * DSP1.Nx >> 15); C8 =- (Py * DSP1.Ny >> 15); C9 =- (Pz * DSP1.Nz >> 15); C12 = C11 + C8 + C9; // this cannot overflow! aux4 = C12; // de-normalization with 32-bits arithmetic refE = 16 - refE; // refE can be up to 3 if (refE >= 0) aux4 <<= (refE); else aux4 >>= -(refE); if (aux4 == -1) aux4 = 0; // why? aux4 >>= 1; aux = ((uint16) DSP1.G_Les) + aux4; // Les - the scalar product of P with the normal vector of the screen DSP1_NormalizeDouble(aux, &C10, &E2); E2 = 15 - E2; DSP1_Inverse(C10, 0, &C4, &E4); C2 = C4 * DSP1.C_Les >> 15; // scale factor // H E7 = 0; C16 = Px * ( DSP1.CosAas * 0x7fff >> 15) >> 15; C20 = Py * ( DSP1.SinAas * 0x7fff >> 15) >> 15; C17 = C16 + C20; // scalar product of P with the normalized horizontal vector of the screen... C18 = C17 * C2 >> 15; // ... multiplied by the scale factor DSP1_Normalize(C18, &C19, &E7); *H = DSP1_Truncate(C19, DSP1.E_Les - E2 + refE + E7); // V E6 = 0; C21 = Px * ( DSP1.CosAzs * -DSP1.SinAas >> 15) >> 15; C22 = Py * ( DSP1.CosAzs * DSP1.CosAas >> 15) >> 15; C23 = Pz * (-DSP1.SinAzs * 0x7fff >> 15) >> 15; C24 = C21 + C22 + C23; // scalar product of P with the normalized vertical vector of the screen... C26 = C24 * C2 >> 15; // ... multiplied by the scale factor DSP1_Normalize(C26, &C25, &E6); *V = DSP1_Truncate(C25, DSP1.E_Les - E2 + refE + E6); // M DSP1_Normalize(C2, &C6, &E4); *M = DSP1_Truncate(C6, E4 + DSP1.E_Les - E2 - 7); // M is the scale factor divided by 2^7 } static void DSP1_Op06 (void) { DSP1_Project(DSP1.Op06X, DSP1.Op06Y, DSP1.Op06Z, &DSP1.Op06H, &DSP1.Op06V, &DSP1.Op06M); } static void DSP1_Op01 (void) { int16 SinAz = DSP1_Sin(DSP1.Op01Zr); int16 CosAz = DSP1_Cos(DSP1.Op01Zr); int16 SinAy = DSP1_Sin(DSP1.Op01Yr); int16 CosAy = DSP1_Cos(DSP1.Op01Yr); int16 SinAx = DSP1_Sin(DSP1.Op01Xr); int16 CosAx = DSP1_Cos(DSP1.Op01Xr); DSP1.Op01m >>= 1; DSP1.matrixA[0][0] = (DSP1.Op01m * CosAz >> 15) * CosAy >> 15; DSP1.matrixA[0][1] = -((DSP1.Op01m * SinAz >> 15) * CosAy >> 15); DSP1.matrixA[0][2] = DSP1.Op01m * SinAy >> 15; DSP1.matrixA[1][0] = ((DSP1.Op01m * SinAz >> 15) * CosAx >> 15) + (((DSP1.Op01m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixA[1][1] = ((DSP1.Op01m * CosAz >> 15) * CosAx >> 15) - (((DSP1.Op01m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixA[1][2] = -((DSP1.Op01m * SinAx >> 15) * CosAy >> 15); DSP1.matrixA[2][0] = ((DSP1.Op01m * SinAz >> 15) * SinAx >> 15) - (((DSP1.Op01m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixA[2][1] = ((DSP1.Op01m * CosAz >> 15) * SinAx >> 15) + (((DSP1.Op01m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixA[2][2] = (DSP1.Op01m * CosAx >> 15) * CosAy >> 15; } static void DSP1_Op11 (void) { int16 SinAz = DSP1_Sin(DSP1.Op11Zr); int16 CosAz = DSP1_Cos(DSP1.Op11Zr); int16 SinAy = DSP1_Sin(DSP1.Op11Yr); int16 CosAy = DSP1_Cos(DSP1.Op11Yr); int16 SinAx = DSP1_Sin(DSP1.Op11Xr); int16 CosAx = DSP1_Cos(DSP1.Op11Xr); DSP1.Op11m >>= 1; DSP1.matrixB[0][0] = (DSP1.Op11m * CosAz >> 15) * CosAy >> 15; DSP1.matrixB[0][1] = -((DSP1.Op11m * SinAz >> 15) * CosAy >> 15); DSP1.matrixB[0][2] = DSP1.Op11m * SinAy >> 15; DSP1.matrixB[1][0] = ((DSP1.Op11m * SinAz >> 15) * CosAx >> 15) + (((DSP1.Op11m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixB[1][1] = ((DSP1.Op11m * CosAz >> 15) * CosAx >> 15) - (((DSP1.Op11m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixB[1][2] = -((DSP1.Op11m * SinAx >> 15) * CosAy >> 15); DSP1.matrixB[2][0] = ((DSP1.Op11m * SinAz >> 15) * SinAx >> 15) - (((DSP1.Op11m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixB[2][1] = ((DSP1.Op11m * CosAz >> 15) * SinAx >> 15) + (((DSP1.Op11m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixB[2][2] = (DSP1.Op11m * CosAx >> 15) * CosAy >> 15; } static void DSP1_Op21 (void) { int16 SinAz = DSP1_Sin(DSP1.Op21Zr); int16 CosAz = DSP1_Cos(DSP1.Op21Zr); int16 SinAy = DSP1_Sin(DSP1.Op21Yr); int16 CosAy = DSP1_Cos(DSP1.Op21Yr); int16 SinAx = DSP1_Sin(DSP1.Op21Xr); int16 CosAx = DSP1_Cos(DSP1.Op21Xr); DSP1.Op21m >>= 1; DSP1.matrixC[0][0] = (DSP1.Op21m * CosAz >> 15) * CosAy >> 15; DSP1.matrixC[0][1] = -((DSP1.Op21m * SinAz >> 15) * CosAy >> 15); DSP1.matrixC[0][2] = DSP1.Op21m * SinAy >> 15; DSP1.matrixC[1][0] = ((DSP1.Op21m * SinAz >> 15) * CosAx >> 15) + (((DSP1.Op21m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixC[1][1] = ((DSP1.Op21m * CosAz >> 15) * CosAx >> 15) - (((DSP1.Op21m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); DSP1.matrixC[1][2] = -((DSP1.Op21m * SinAx >> 15) * CosAy >> 15); DSP1.matrixC[2][0] = ((DSP1.Op21m * SinAz >> 15) * SinAx >> 15) - (((DSP1.Op21m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixC[2][1] = ((DSP1.Op21m * CosAz >> 15) * SinAx >> 15) + (((DSP1.Op21m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); DSP1.matrixC[2][2] = (DSP1.Op21m * CosAx >> 15) * CosAy >> 15; } static void DSP1_Op0D (void) { DSP1.Op0DF = (DSP1.Op0DX * DSP1.matrixA[0][0] >> 15) + (DSP1.Op0DY * DSP1.matrixA[0][1] >> 15) + (DSP1.Op0DZ * DSP1.matrixA[0][2] >> 15); DSP1.Op0DL = (DSP1.Op0DX * DSP1.matrixA[1][0] >> 15) + (DSP1.Op0DY * DSP1.matrixA[1][1] >> 15) + (DSP1.Op0DZ * DSP1.matrixA[1][2] >> 15); DSP1.Op0DU = (DSP1.Op0DX * DSP1.matrixA[2][0] >> 15) + (DSP1.Op0DY * DSP1.matrixA[2][1] >> 15) + (DSP1.Op0DZ * DSP1.matrixA[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP0D X: %d Y: %d Z: %d / F: %d L: %d U: %d", DSP1.Op0DX, DSP1.Op0DY, DSP1.Op0DZ, DSP1.Op0DF, DSP1.Op0DL, DSP1.Op0DU); #endif } static void DSP1_Op1D (void) { DSP1.Op1DF = (DSP1.Op1DX * DSP1.matrixB[0][0] >> 15) + (DSP1.Op1DY * DSP1.matrixB[0][1] >> 15) + (DSP1.Op1DZ * DSP1.matrixB[0][2] >> 15); DSP1.Op1DL = (DSP1.Op1DX * DSP1.matrixB[1][0] >> 15) + (DSP1.Op1DY * DSP1.matrixB[1][1] >> 15) + (DSP1.Op1DZ * DSP1.matrixB[1][2] >> 15); DSP1.Op1DU = (DSP1.Op1DX * DSP1.matrixB[2][0] >> 15) + (DSP1.Op1DY * DSP1.matrixB[2][1] >> 15) + (DSP1.Op1DZ * DSP1.matrixB[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP1D X: %d Y: %d Z: %d / F: %d L: %d U: %d", DSP1.Op1DX, DSP1.Op1DY, DSP1.Op1DZ, DSP1.Op1DF, DSP1.Op1DL, DSP1.Op1DU); #endif } static void DSP1_Op2D (void) { DSP1.Op2DF = (DSP1.Op2DX * DSP1.matrixC[0][0] >> 15) + (DSP1.Op2DY * DSP1.matrixC[0][1] >> 15) + (DSP1.Op2DZ * DSP1.matrixC[0][2] >> 15); DSP1.Op2DL = (DSP1.Op2DX * DSP1.matrixC[1][0] >> 15) + (DSP1.Op2DY * DSP1.matrixC[1][1] >> 15) + (DSP1.Op2DZ * DSP1.matrixC[1][2] >> 15); DSP1.Op2DU = (DSP1.Op2DX * DSP1.matrixC[2][0] >> 15) + (DSP1.Op2DY * DSP1.matrixC[2][1] >> 15) + (DSP1.Op2DZ * DSP1.matrixC[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP2D X: %d Y: %d Z: %d / F: %d L: %d U: %d", DSP1.Op2DX, DSP1.Op2DY, DSP1.Op2DZ, DSP1.Op2DF, DSP1.Op2DL, DSP1.Op2DU); #endif } static void DSP1_Op03 (void) { DSP1.Op03X = (DSP1.Op03F * DSP1.matrixA[0][0] >> 15) + (DSP1.Op03L * DSP1.matrixA[1][0] >> 15) + (DSP1.Op03U * DSP1.matrixA[2][0] >> 15); DSP1.Op03Y = (DSP1.Op03F * DSP1.matrixA[0][1] >> 15) + (DSP1.Op03L * DSP1.matrixA[1][1] >> 15) + (DSP1.Op03U * DSP1.matrixA[2][1] >> 15); DSP1.Op03Z = (DSP1.Op03F * DSP1.matrixA[0][2] >> 15) + (DSP1.Op03L * DSP1.matrixA[1][2] >> 15) + (DSP1.Op03U * DSP1.matrixA[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP03 F: %d L: %d U: %d / X: %d Y: %d Z: %d", DSP1.Op03F, DSP1.Op03L, DSP1.Op03U, DSP1.Op03X, DSP1.Op03Y, DSP1.Op03Z); #endif } static void DSP1_Op13 (void) { DSP1.Op13X = (DSP1.Op13F * DSP1.matrixB[0][0] >> 15) + (DSP1.Op13L * DSP1.matrixB[1][0] >> 15) + (DSP1.Op13U * DSP1.matrixB[2][0] >> 15); DSP1.Op13Y = (DSP1.Op13F * DSP1.matrixB[0][1] >> 15) + (DSP1.Op13L * DSP1.matrixB[1][1] >> 15) + (DSP1.Op13U * DSP1.matrixB[2][1] >> 15); DSP1.Op13Z = (DSP1.Op13F * DSP1.matrixB[0][2] >> 15) + (DSP1.Op13L * DSP1.matrixB[1][2] >> 15) + (DSP1.Op13U * DSP1.matrixB[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP13 F: %d L: %d U: %d / X: %d Y: %d Z: %d", DSP1.Op13F, DSP1.Op13L, DSP1.Op13U, DSP1.Op13X, DSP1.Op13Y, DSP1.Op13Z); #endif } static void DSP1_Op23 (void) { DSP1.Op23X = (DSP1.Op23F * DSP1.matrixC[0][0] >> 15) + (DSP1.Op23L * DSP1.matrixC[1][0] >> 15) + (DSP1.Op23U * DSP1.matrixC[2][0] >> 15); DSP1.Op23Y = (DSP1.Op23F * DSP1.matrixC[0][1] >> 15) + (DSP1.Op23L * DSP1.matrixC[1][1] >> 15) + (DSP1.Op23U * DSP1.matrixC[2][1] >> 15); DSP1.Op23Z = (DSP1.Op23F * DSP1.matrixC[0][2] >> 15) + (DSP1.Op23L * DSP1.matrixC[1][2] >> 15) + (DSP1.Op23U * DSP1.matrixC[2][2] >> 15); #ifdef DebugDSP1 Log_Message("OP23 F: %d L: %d U: %d / X: %d Y: %d Z: %d", DSP1.Op23F, DSP1.Op23L, DSP1.Op23U, DSP1.Op23X, DSP1.Op23Y, DSP1.Op23Z); #endif } static void DSP1_Op14 (void) { int16 CSec, ESec, CTan, CSin, C, E; DSP1_Inverse(DSP1_Cos(DSP1.Op14Xr), 0, &CSec, &ESec); // Rotation Around Z DSP1_NormalizeDouble(DSP1.Op14U * DSP1_Cos(DSP1.Op14Yr) - DSP1.Op14F * DSP1_Sin(DSP1.Op14Yr), &C, &E); E = ESec - E; DSP1_Normalize(C * CSec >> 15, &C, &E); DSP1.Op14Zrr = DSP1.Op14Zr + DSP1_Truncate(C, E); // Rotation Around X DSP1.Op14Xrr = DSP1.Op14Xr + (DSP1.Op14U * DSP1_Sin(DSP1.Op14Yr) >> 15) + (DSP1.Op14F * DSP1_Cos(DSP1.Op14Yr) >> 15); // Rotation Around Y DSP1_NormalizeDouble(DSP1.Op14U * DSP1_Cos(DSP1.Op14Yr) + DSP1.Op14F * DSP1_Sin(DSP1.Op14Yr), &C, &E); E = ESec - E; DSP1_Normalize(DSP1_Sin(DSP1.Op14Xr), &CSin, &E); CTan = CSec * CSin >> 15; DSP1_Normalize(-(C * CTan >> 15), &C, &E); DSP1.Op14Yrr = DSP1.Op14Yr + DSP1_Truncate(C, E) + DSP1.Op14L; } static void DSP1_Target (int16 H, int16 V, int16 *X, int16 *Y) { int16 C, E, C1, E1; DSP1_Inverse((V * DSP1.SinAzs >> 15) + DSP1.VOffset, 8, &C, &E); E += DSP1.VPlane_E; C1 = C * DSP1.VPlane_C >> 15; E1 = E + DSP1.SecAZS_E1; H <<= 8; DSP1_Normalize(C1, &C, &E); C = DSP1_Truncate(C, E) * H >> 15; *X = DSP1.CentreX + (C * DSP1.CosAas >> 15); *Y = DSP1.CentreY - (C * DSP1.SinAas >> 15); V <<= 8; DSP1_Normalize(C1 * DSP1.SecAZS_C1 >> 15, &C, &E1); C = DSP1_Truncate(C, E1) * V >> 15; *X += C * -DSP1.SinAas >> 15; *Y += C * DSP1.CosAas >> 15; } static void DSP1_Op0E (void) { DSP1_Target(DSP1.Op0EH, DSP1.Op0EV, &DSP1.Op0EX, &DSP1.Op0EY); } static void DSP1_Op0B (void) { DSP1.Op0BS = (DSP1.Op0BX * DSP1.matrixA[0][0] + DSP1.Op0BY * DSP1.matrixA[0][1] + DSP1.Op0BZ * DSP1.matrixA[0][2]) >> 15; #ifdef DebugDSP1 Log_Message("OP0B"); #endif } static void DSP1_Op1B (void) { DSP1.Op1BS = (DSP1.Op1BX * DSP1.matrixB[0][0] + DSP1.Op1BY * DSP1.matrixB[0][1] + DSP1.Op1BZ * DSP1.matrixB[0][2]) >> 15; #ifdef DebugDSP1 Log_Message("OP1B X: %d Y: %d Z: %d S: %d", DSP1.Op1BX, DSP1.Op1BY, DSP1.Op1BZ, DSP1.Op1BS); Log_Message(" MX: %d MY: %d MZ: %d Scale: %d", (int16) (DSP1.matrixB[0][0] * 100), (int16) (DSP1.matrixB[0][1] * 100), (int16) (DSP1.matrixB[0][2] * 100), (int16) (DSP1.Op1BS * 100)); #endif } static void DSP1_Op2B (void) { DSP1.Op2BS = (DSP1.Op2BX * DSP1.matrixC[0][0] + DSP1.Op2BY * DSP1.matrixC[0][1] + DSP1.Op2BZ * DSP1.matrixC[0][2]) >> 15; #ifdef DebugDSP1 Log_Message("OP2B"); #endif } static void DSP1_Op08 (void) { int32 op08Size = (DSP1.Op08X * DSP1.Op08X + DSP1.Op08Y * DSP1.Op08Y + DSP1.Op08Z * DSP1.Op08Z) << 1; DSP1.Op08Ll = op08Size & 0xffff; DSP1.Op08Lh = (op08Size >> 16) & 0xffff; #ifdef DebugDSP1 Log_Message("OP08 %d,%d,%d", DSP1.Op08X, DSP1.Op08Y, DSP1.Op08Z); Log_Message("OP08 ((OP08X^2)+(OP08Y^2)+(OP08Z^2))=%x", op08Size); #endif } static void DSP1_Op18 (void) { DSP1.Op18D = (DSP1.Op18X * DSP1.Op18X + DSP1.Op18Y * DSP1.Op18Y + DSP1.Op18Z * DSP1.Op18Z - DSP1.Op18R * DSP1.Op18R) >> 15; #ifdef DebugDSP1 Log_Message("OP18 X: %d Y: %d Z: %d R: %D DIFF %d", DSP1.Op18X, DSP1.Op18Y, DSP1.Op38Z, DSP1.Op18D); #endif } static void DSP1_Op38 (void) { DSP1.Op38D = (DSP1.Op38X * DSP1.Op38X + DSP1.Op38Y * DSP1.Op38Y + DSP1.Op38Z * DSP1.Op38Z - DSP1.Op38R * DSP1.Op38R) >> 15; DSP1.Op38D++; #ifdef DebugDSP1 Log_Message("OP38 X: %d Y: %d Z: %d R: %D DIFF %d", DSP1.Op38X, DSP1.Op38Y, DSP1.Op38Z, DSP1.Op38D); #endif } static void DSP1_Op28 (void) { int32 Radius = DSP1.Op28X * DSP1.Op28X + DSP1.Op28Y * DSP1.Op28Y + DSP1.Op28Z * DSP1.Op28Z; if (Radius == 0) DSP1.Op28R = 0; else { int16 C, E, Pos, Node1, Node2; DSP1_NormalizeDouble(Radius, &C, &E); if (E & 1) C = C * 0x4000 >> 15; Pos = C * 0x0040 >> 15; Node1 = DSP1ROM[0x00d5 + Pos]; Node2 = DSP1ROM[0x00d6 + Pos]; DSP1.Op28R = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; DSP1.Op28R >>= (E >> 1); } #ifdef DebugDSP1 Log_Message("OP28 X:%d Y:%d Z:%d", DSP1.Op28X, DSP1.Op28Y, DSP1.Op28Z); Log_Message("OP28 Vector Length %d", DSP1.Op28R); #endif } static void DSP1_Op1C (void) { // Rotate Around Op1CZ1 DSP1.Op1CX1 = (DSP1.Op1CYBR * DSP1_Sin(DSP1.Op1CZ) >> 15) + (DSP1.Op1CXBR * DSP1_Cos(DSP1.Op1CZ) >> 15); DSP1.Op1CY1 = (DSP1.Op1CYBR * DSP1_Cos(DSP1.Op1CZ) >> 15) - (DSP1.Op1CXBR * DSP1_Sin(DSP1.Op1CZ) >> 15); DSP1.Op1CXBR = DSP1.Op1CX1; DSP1.Op1CYBR = DSP1.Op1CY1; // Rotate Around Op1CY1 DSP1.Op1CZ1 = (DSP1.Op1CXBR * DSP1_Sin(DSP1.Op1CY) >> 15) + (DSP1.Op1CZBR * DSP1_Cos(DSP1.Op1CY) >> 15); DSP1.Op1CX1 = (DSP1.Op1CXBR * DSP1_Cos(DSP1.Op1CY) >> 15) - (DSP1.Op1CZBR * DSP1_Sin(DSP1.Op1CY) >> 15); DSP1.Op1CXAR = DSP1.Op1CX1; DSP1.Op1CZBR = DSP1.Op1CZ1; // Rotate Around Op1CX1 DSP1.Op1CY1 = (DSP1.Op1CZBR * DSP1_Sin(DSP1.Op1CX) >> 15) + (DSP1.Op1CYBR * DSP1_Cos(DSP1.Op1CX) >> 15); DSP1.Op1CZ1 = (DSP1.Op1CZBR * DSP1_Cos(DSP1.Op1CX) >> 15) - (DSP1.Op1CYBR * DSP1_Sin(DSP1.Op1CX) >> 15); DSP1.Op1CYAR = DSP1.Op1CY1; DSP1.Op1CZAR = DSP1.Op1CZ1; #ifdef DebugDSP1 Log_Message("OP1C Apply Matrix CX:%d CY:%d CZ", DSP1.Op1CXAR, DSP1.Op1CYAR, DSP1.Op1CZAR); #endif } static void DSP1_Op0F (void) { DSP1.Op0FPass = 0x0000; #ifdef DebugDSP1 Log_Message("OP0F RAM Test Pass:%d", DSP1.Op0FPass); #endif } static void DSP1_Op2F (void) { DSP1.Op2FSize = 0x100; } void DSP1SetByte (uint8 byte, uint16 address) { if (address < DSP0.boundary) { if ((DSP1.command == 0x0A || DSP1.command == 0x1A) && DSP1.out_count != 0) { DSP1.out_count--; DSP1.out_index++; return; } else if (DSP1.waiting4command) { DSP1.command = byte; DSP1.in_index = 0; DSP1.waiting4command = FALSE; DSP1.first_parameter = TRUE; #ifdef DEBUGGER //printf("OP%02X\n",byte); #endif switch (byte) { case 0x00: DSP1.in_count = 2; break; case 0x30: case 0x10: DSP1.in_count = 2; break; case 0x20: DSP1.in_count = 2; break; case 0x24: case 0x04: DSP1.in_count = 2; break; case 0x08: DSP1.in_count = 3; break; case 0x18: DSP1.in_count = 4; break; case 0x28: DSP1.in_count = 3; break; case 0x38: DSP1.in_count = 4; break; case 0x2c: case 0x0c: DSP1.in_count = 3; break; case 0x3c: case 0x1c: DSP1.in_count = 6; break; case 0x32: case 0x22: case 0x12: case 0x02: DSP1.in_count = 7; break; case 0x0a: DSP1.in_count = 1; break; case 0x3a: case 0x2a: case 0x1a: DSP1.command = 0x1a; DSP1.in_count = 1; break; case 0x16: case 0x26: case 0x36: case 0x06: DSP1.in_count = 3; break; case 0x1e: case 0x2e: case 0x3e: case 0x0e: DSP1.in_count = 2; break; case 0x05: case 0x35: case 0x31: case 0x01: DSP1.in_count = 4; break; case 0x15: case 0x11: DSP1.in_count = 4; break; case 0x25: case 0x21: DSP1.in_count = 4; break; case 0x09: case 0x39: case 0x3d: case 0x0d: DSP1.in_count = 3; break; case 0x19: case 0x1d: DSP1.in_count = 3; break; case 0x29: case 0x2d: DSP1.in_count = 3; break; case 0x33: case 0x03: DSP1.in_count = 3; break; case 0x13: DSP1.in_count = 3; break; case 0x23: DSP1.in_count = 3; break; case 0x3b: case 0x0b: DSP1.in_count = 3; break; case 0x1b: DSP1.in_count = 3; break; case 0x2b: DSP1.in_count = 3; break; case 0x34: case 0x14: DSP1.in_count = 6; break; case 0x07: case 0x0f: DSP1.in_count = 1; break; case 0x27: case 0x2F: DSP1.in_count = 1; break; case 0x17: case 0x37: case 0x3F: DSP1.command = 0x1f; case 0x1f: DSP1.in_count = 1; break; default: #ifdef DEBUGGER //printf("OP%02X\n", byte); #endif case 0x80: DSP1.in_count = 0; DSP1.waiting4command = TRUE; DSP1.first_parameter = TRUE; break; } DSP1.in_count <<= 1; } else { DSP1.parameters[DSP1.in_index] = byte; DSP1.first_parameter = FALSE; DSP1.in_index++; } if (DSP1.waiting4command || (DSP1.first_parameter && byte == 0x80)) { DSP1.waiting4command = TRUE; DSP1.first_parameter = FALSE; } else if (DSP1.first_parameter && (DSP1.in_count != 0 || (DSP1.in_count == 0 && DSP1.in_index == 0))) ; else { if (DSP1.in_count) { if (--DSP1.in_count == 0) { // Actually execute the command DSP1.waiting4command = TRUE; DSP1.out_index = 0; switch (DSP1.command) { case 0x1f: DSP1.out_count = 2048; break; case 0x00: // Multiple DSP1.Op00Multiplicand = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op00Multiplier = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1_Op00(); DSP1.out_count = 2; DSP1.output[0] = DSP1.Op00Result & 0xFF; DSP1.output[1] = (DSP1.Op00Result >> 8) & 0xFF; break; case 0x20: // Multiple DSP1.Op20Multiplicand = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op20Multiplier = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1_Op20(); DSP1.out_count = 2; DSP1.output[0] = DSP1.Op20Result & 0xFF; DSP1.output[1] = (DSP1.Op20Result >> 8) & 0xFF; break; case 0x30: case 0x10: // Inverse DSP1.Op10Coefficient = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op10Exponent = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1_Op10(); DSP1.out_count = 4; DSP1.output[0] = (uint8) ( ((int16) DSP1.Op10CoefficientR) & 0xFF); DSP1.output[1] = (uint8) ((((int16) DSP1.Op10CoefficientR) >> 8) & 0xFF); DSP1.output[2] = (uint8) ( ((int16) DSP1.Op10ExponentR ) & 0xFF); DSP1.output[3] = (uint8) ((((int16) DSP1.Op10ExponentR ) >> 8) & 0xFF); break; case 0x24: case 0x04: // Sin and Cos of angle DSP1.Op04Angle = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op04Radius = (uint16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1_Op04(); DSP1.out_count = 4; DSP1.output[0] = (uint8) (DSP1.Op04Sin & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op04Sin >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op04Cos & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op04Cos >> 8) & 0xFF); break; case 0x08: // Radius DSP1.Op08X = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op08Y = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op08Z = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op08(); DSP1.out_count = 4; DSP1.output[0] = (uint8) ( ((int16) DSP1.Op08Ll) & 0xFF); DSP1.output[1] = (uint8) ((((int16) DSP1.Op08Ll) >> 8) & 0xFF); DSP1.output[2] = (uint8) ( ((int16) DSP1.Op08Lh) & 0xFF); DSP1.output[3] = (uint8) ((((int16) DSP1.Op08Lh) >> 8) & 0xFF); break; case 0x18: // Range DSP1.Op18X = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op18Y = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op18Z = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1.Op18R = (int16) (DSP1.parameters[6] | (DSP1.parameters[7] << 8)); DSP1_Op18(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op18D & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op18D >> 8) & 0xFF); break; case 0x38: // Range DSP1.Op38X = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op38Y = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op38Z = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1.Op38R = (int16) (DSP1.parameters[6] | (DSP1.parameters[7] << 8)); DSP1_Op38(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op38D & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op38D >> 8) & 0xFF); break; case 0x28: // Distance (vector length) DSP1.Op28X = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op28Y = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op28Z = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op28(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op28R & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op28R >> 8) & 0xFF); break; case 0x2c: case 0x0c: // Rotate (2D rotate) DSP1.Op0CA = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op0CX1 = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op0CY1 = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op0C(); DSP1.out_count = 4; DSP1.output[0] = (uint8) (DSP1.Op0CX2 & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op0CX2 >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op0CY2 & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op0CY2 >> 8) & 0xFF); break; case 0x3c: case 0x1c: // Polar (3D rotate) DSP1.Op1CZ = (DSP1.parameters[ 0] | (DSP1.parameters[ 1] << 8)); //MK: reversed X and Y on neviksti and John's advice. DSP1.Op1CY = (DSP1.parameters[ 2] | (DSP1.parameters[ 3] << 8)); DSP1.Op1CX = (DSP1.parameters[ 4] | (DSP1.parameters[ 5] << 8)); DSP1.Op1CXBR = (DSP1.parameters[ 6] | (DSP1.parameters[ 7] << 8)); DSP1.Op1CYBR = (DSP1.parameters[ 8] | (DSP1.parameters[ 9] << 8)); DSP1.Op1CZBR = (DSP1.parameters[10] | (DSP1.parameters[11] << 8)); DSP1_Op1C(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op1CXAR & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op1CXAR >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op1CYAR & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op1CYAR >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op1CZAR & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op1CZAR >> 8) & 0xFF); break; case 0x32: case 0x22: case 0x12: case 0x02: // Parameter (Projection) DSP1.Op02FX = (int16) (DSP1.parameters[ 0] | (DSP1.parameters[ 1] << 8)); DSP1.Op02FY = (int16) (DSP1.parameters[ 2] | (DSP1.parameters[ 3] << 8)); DSP1.Op02FZ = (int16) (DSP1.parameters[ 4] | (DSP1.parameters[ 5] << 8)); DSP1.Op02LFE = (int16) (DSP1.parameters[ 6] | (DSP1.parameters[ 7] << 8)); DSP1.Op02LES = (int16) (DSP1.parameters[ 8] | (DSP1.parameters[ 9] << 8)); DSP1.Op02AAS = (uint16) (DSP1.parameters[10] | (DSP1.parameters[11] << 8)); DSP1.Op02AZS = (uint16) (DSP1.parameters[12] | (DSP1.parameters[13] << 8)); DSP1_Op02(); DSP1.out_count = 8; DSP1.output[0] = (uint8) (DSP1.Op02VOF & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op02VOF >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op02VVA & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op02VVA >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op02CX & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op02CX >> 8) & 0xFF); DSP1.output[6] = (uint8) (DSP1.Op02CY & 0xFF); DSP1.output[7] = (uint8) ((DSP1.Op02CY >> 8) & 0xFF); break; case 0x3a: case 0x2a: case 0x1a: // Raster mode 7 matrix data case 0x0a: DSP1.Op0AVS = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1_Op0A(); DSP1.out_count = 8; DSP1.output[0] = (uint8) (DSP1.Op0AA & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op0AA >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op0AB & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op0AB >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op0AC & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op0AC >> 8) & 0xFF); DSP1.output[6] = (uint8) (DSP1.Op0AD & 0xFF); DSP1.output[7] = (uint8) ((DSP1.Op0AD >> 8) & 0xFF); DSP1.in_index = 0; break; case 0x16: case 0x26: case 0x36: case 0x06: // Project object DSP1.Op06X = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op06Y = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op06Z = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op06(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op06H & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op06H >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op06V & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op06V >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op06M & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op06M >> 8) & 0xFF); break; case 0x1e: case 0x2e: case 0x3e: case 0x0e: // Target DSP1.Op0EH = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op0EV = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1_Op0E(); DSP1.out_count = 4; DSP1.output[0] = (uint8) (DSP1.Op0EX & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op0EX >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op0EY & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op0EY >> 8) & 0xFF); break; // Extra commands used by Pilot Wings case 0x05: case 0x35: case 0x31: case 0x01: // Set attitude matrix A DSP1.Op01m = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op01Zr = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op01Yr = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1.Op01Xr = (int16) (DSP1.parameters[6] | (DSP1.parameters[7] << 8)); DSP1_Op01(); break; case 0x15: case 0x11: // Set attitude matrix B DSP1.Op11m = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op11Zr = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op11Yr = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1.Op11Xr = (int16) (DSP1.parameters[7] | (DSP1.parameters[7] << 8)); DSP1_Op11(); break; case 0x25: case 0x21: // Set attitude matrix C DSP1.Op21m = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op21Zr = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op21Yr = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1.Op21Xr = (int16) (DSP1.parameters[6] | (DSP1.parameters[7] << 8)); DSP1_Op21(); break; case 0x09: case 0x39: case 0x3d: case 0x0d: // Objective matrix A DSP1.Op0DX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op0DY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op0DZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op0D(); DSP1.out_count = 6; DSP1.output [0] = (uint8) (DSP1.Op0DF & 0xFF); DSP1.output [1] = (uint8) ((DSP1.Op0DF >> 8) & 0xFF); DSP1.output [2] = (uint8) (DSP1.Op0DL & 0xFF); DSP1.output [3] = (uint8) ((DSP1.Op0DL >> 8) & 0xFF); DSP1.output [4] = (uint8) (DSP1.Op0DU & 0xFF); DSP1.output [5] = (uint8) ((DSP1.Op0DU >> 8) & 0xFF); break; case 0x19: case 0x1d: // Objective matrix B DSP1.Op1DX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op1DY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op1DZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op1D(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op1DF & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op1DF >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op1DL & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op1DL >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op1DU & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op1DU >> 8) & 0xFF); break; case 0x29: case 0x2d: // Objective matrix C DSP1.Op2DX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op2DY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op2DZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op2D(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op2DF & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op2DF >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op2DL & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op2DL >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op2DU & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op2DU >> 8) & 0xFF); break; case 0x33: case 0x03: // Subjective matrix A DSP1.Op03F = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op03L = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op03U = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op03(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op03X & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op03X >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op03Y & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op03Y >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op03Z & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op03Z >> 8) & 0xFF); break; case 0x13: // Subjective matrix B DSP1.Op13F = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op13L = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op13U = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op13(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op13X & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op13X >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op13Y & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op13Y >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op13Z & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op13Z >> 8) & 0xFF); break; case 0x23: // Subjective matrix C DSP1.Op23F = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op23L = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op23U = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op23(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op23X & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op23X >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op23Y & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op23Y >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op23Z & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op23Z >> 8) & 0xFF); break; case 0x3b: case 0x0b: DSP1.Op0BX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op0BY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op0BZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op0B(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op0BS & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op0BS >> 8) & 0xFF); break; case 0x1b: DSP1.Op1BX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op1BY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op1BZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op1B(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op1BS & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op1BS >> 8) & 0xFF); break; case 0x2b: DSP1.Op2BX = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1.Op2BY = (int16) (DSP1.parameters[2] | (DSP1.parameters[3] << 8)); DSP1.Op2BZ = (int16) (DSP1.parameters[4] | (DSP1.parameters[5] << 8)); DSP1_Op2B(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op2BS & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op2BS >> 8) & 0xFF); break; case 0x34: case 0x14: DSP1.Op14Zr = (int16) (DSP1.parameters[ 0] | (DSP1.parameters[ 1] << 8)); DSP1.Op14Xr = (int16) (DSP1.parameters[ 2] | (DSP1.parameters[ 3] << 8)); DSP1.Op14Yr = (int16) (DSP1.parameters[ 4] | (DSP1.parameters[ 5] << 8)); DSP1.Op14U = (int16) (DSP1.parameters[ 6] | (DSP1.parameters[ 7] << 8)); DSP1.Op14F = (int16) (DSP1.parameters[ 8] | (DSP1.parameters[ 9] << 8)); DSP1.Op14L = (int16) (DSP1.parameters[10] | (DSP1.parameters[11] << 8)); DSP1_Op14(); DSP1.out_count = 6; DSP1.output[0] = (uint8) (DSP1.Op14Zrr & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op14Zrr >> 8) & 0xFF); DSP1.output[2] = (uint8) (DSP1.Op14Xrr & 0xFF); DSP1.output[3] = (uint8) ((DSP1.Op14Xrr >> 8) & 0xFF); DSP1.output[4] = (uint8) (DSP1.Op14Yrr & 0xFF); DSP1.output[5] = (uint8) ((DSP1.Op14Yrr >> 8) & 0xFF); break; case 0x27: case 0x2F: DSP1.Op2FUnknown = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1_Op2F(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op2FSize & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op2FSize >> 8) & 0xFF); break; case 0x07: case 0x0F: DSP1.Op0FRamsize = (int16) (DSP1.parameters[0] | (DSP1.parameters[1] << 8)); DSP1_Op0F(); DSP1.out_count = 2; DSP1.output[0] = (uint8) (DSP1.Op0FPass & 0xFF); DSP1.output[1] = (uint8) ((DSP1.Op0FPass >> 8) & 0xFF); break; default: break; } } } } } } uint8 DSP1GetByte (uint16 address) { uint8 t; if (address < DSP0.boundary) { if (DSP1.out_count) { t = (uint8) DSP1.output[DSP1.out_index]; DSP1.out_index++; if (--DSP1.out_count == 0) { if (DSP1.command == 0x1a || DSP1.command == 0x0a) { DSP1_Op0A(); DSP1.out_count = 8; DSP1.out_index = 0; DSP1.output[0] = DSP1.Op0AA & 0xFF; DSP1.output[1] = (DSP1.Op0AA >> 8) & 0xFF; DSP1.output[2] = DSP1.Op0AB & 0xFF; DSP1.output[3] = (DSP1.Op0AB >> 8) & 0xFF; DSP1.output[4] = DSP1.Op0AC & 0xFF; DSP1.output[5] = (DSP1.Op0AC >> 8) & 0xFF; DSP1.output[6] = DSP1.Op0AD & 0xFF; DSP1.output[7] = (DSP1.Op0AD >> 8) & 0xFF; } if (DSP1.command == 0x1f) { if ((DSP1.out_index % 2) != 0) t = (uint8) DSP1ROM[DSP1.out_index >> 1]; else t = DSP1ROM[DSP1.out_index >> 1] >> 8; } } DSP1.waiting4command = TRUE; } else t = 0xff; } else t = 0x80; return (t); } libretro/libretro.def000664 001750 001750 00000001026 12720446475 016040 0ustar00sergiosergio000000 000000 LIBRARY libretro EXPORTS retro_api_version retro_get_system_info retro_get_system_av_info retro_set_video_refresh retro_set_audio_sample retro_set_audio_sample_batch retro_set_input_poll retro_set_input_state retro_set_environment retro_set_controller_port_device retro_init retro_deinit retro_reset retro_run retro_serialize_size retro_serialize retro_unserialize retro_cheat_reset retro_cheat_set retro_load_game retro_unload_game retro_load_game_special retro_get_region retro_get_memory_data retro_get_memory_sizec4.h000664 001750 001750 00000015447 12720446475 012407 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _C4_H_ #define _C4_H_ extern int16 C4WFXVal; extern int16 C4WFYVal; extern int16 C4WFZVal; extern int16 C4WFX2Val; extern int16 C4WFY2Val; extern int16 C4WFDist; extern int16 C4WFScale; extern int16 C41FXVal; extern int16 C41FYVal; extern int16 C41FAngleRes; extern int16 C41FDist; extern int16 C41FDistVal; void C4TransfWireFrame (void); void C4TransfWireFrame2 (void); void C4CalcWireFrame (void); void C4Op0D (void); void C4Op15 (void); void C4Op1F (void); void S9xInitC4 (void); void S9xSetC4 (uint8, uint16); uint8 S9xGetC4 (uint16); uint8 * S9xGetBasePointerC4 (uint16); uint8 * S9xGetMemPointerC4 (uint16); static inline uint8 * C4GetMemPointer (uint32 Address) { return (Memory.ROM + ((Address & 0xff0000) >> 1) + (Address & 0x7fff)); } #endif apu/bapu/smp/core/oppseudo_mov.cpp000664 001750 001750 00000024557 12720446475 020420 0ustar00sergiosergio000000 000000 case 0x7d: { op_io(); regs.B.a = regs.x; regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0xdd: { op_io(); regs.B.a = regs.B.y; regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0x5d: { op_io(); regs.x = regs.B.a; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xfd: { op_io(); regs.B.y = regs.B.a; regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); break; } case 0x9d: { op_io(); regs.x = regs.sp; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0xbd: { op_io(); regs.sp = regs.x; break; } case 0xe8: { regs.B.a = op_readpc(); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0xcd: { regs.x = op_readpc(); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); break; } case 0x8d: { regs.B.y = op_readpc(); regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); break; } case 0xe6: { switch(++opcode_cycle) { case 1: op_io(); break; case 2: regs.B.a = op_readdp(regs.x); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xbf: { switch(++opcode_cycle) { case 1: op_io(); break; case 2: regs.B.a = op_readdp(regs.x++); op_io(); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xe4: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: regs.B.a = op_readdp(sp); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xf8: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: regs.x = op_readdp(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xeb: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: regs.B.y = op_readdp(sp); regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } break; } case 0xf4: { switch(++opcode_cycle) { case 1: sp = op_readpc(); op_io(); break; case 2: regs.B.a = op_readdp(sp + regs.x); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xf9: { switch(++opcode_cycle) { case 1: sp = op_readpc(); op_io(); break; case 2: regs.x = op_readdp(sp + regs.B.y); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xfb: { switch(++opcode_cycle) { case 1: sp = op_readpc(); op_io(); break; case 2: regs.B.y = op_readdp(sp + regs.x); regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } break; } case 0xe5: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: regs.B.a = op_readaddr(sp); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xe9: { switch(++opcode_cycle) { case 1: sp = op_readpc(); sp |= op_readpc() << 8; break; case 2: regs.x = op_readaddr(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xec: { switch(++opcode_cycle) { case 1: sp = op_readpc(); sp |= op_readpc() << 8; break; case 2: regs.B.y = op_readaddr(sp); regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); opcode_cycle = 0; break; } break; } case 0xf5: { switch(++opcode_cycle) { case 1: sp = op_readpc(); sp |= op_readpc() << 8; op_io(); break; case 2: regs.B.a = op_readaddr(sp + regs.x); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xf6: { switch(++opcode_cycle) { case 1: sp = op_readpc(); sp |= op_readpc() << 8; op_io(); break; case 2: regs.B.a = op_readaddr(sp + regs.B.y); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xe7: { switch(++opcode_cycle) { case 1: dp = op_readpc() + regs.x; op_io(); break; case 2: sp = op_readdp(dp); break; case 3: sp |= op_readdp(dp + 1) << 8; break; case 4: regs.B.a = op_readaddr(sp); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xf7: { switch(++opcode_cycle) { case 1: dp = op_readpc(); op_io(); break; case 2: sp = op_readdp(dp); break; case 3: sp |= op_readdp(dp + 1) << 8; break; case 4: regs.B.a = op_readaddr(sp + regs.B.y); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); opcode_cycle = 0; break; } break; } case 0xfa: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x8f: { switch(++opcode_cycle) { case 1: rd = op_readpc(); dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xc6: { switch(++opcode_cycle) { case 1: op_io(); break; case 2: op_readdp(regs.x); break; case 3: op_writedp(regs.x, regs.B.a); opcode_cycle = 0; break; } break; } case 0xaf: { switch(++opcode_cycle) { case 1: op_io(2); case 2: op_writedp(regs.x++, regs.B.a); opcode_cycle = 0; break; } break; } case 0xc4: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xd8: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xcb: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.B.y); opcode_cycle = 0; break; } break; } case 0xd4: { switch(++opcode_cycle) { case 1: dp = op_readpc(); op_io(); dp += regs.x; break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xd9: { switch(++opcode_cycle) { case 1: dp = op_readpc(); op_io(); dp += regs.B.y; break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xdb: { switch(++opcode_cycle) { case 1: dp = op_readpc(); op_io(); dp += regs.x; break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.B.y); opcode_cycle = 0; break; } break; } case 0xc5: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xc9: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xcc: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.B.y); opcode_cycle = 0; break; } break; } case 0xd5: { switch(++opcode_cycle) { case 1: dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.x; break; case 2: op_readaddr(dp); break; case 3: op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xd6: { switch(++opcode_cycle) { case 1: dp = op_readpc(); dp |= op_readpc() << 8; op_io(); dp += regs.B.y; break; case 2: op_readaddr(dp); break; case 3: op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xc7: { switch(++opcode_cycle) { case 1: sp = op_readpc(); op_io(); sp += regs.x; break; case 2: dp = op_readdp(sp); break; case 3: dp |= op_readdp(sp + 1) << 8; break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xd7: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: dp = op_readdp(sp); break; case 3: dp |= op_readdp(sp + 1) << 8; op_io(); dp += regs.B.y; break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, regs.B.a); opcode_cycle = 0; break; } break; } case 0xba: { switch(++opcode_cycle) { case 1: sp = op_readpc(); break; case 2: regs.B.a = op_readdp(sp); op_io(); break; case 3: regs.B.y = op_readdp(sp + 1); regs.p.n = !!(regs.ya & 0x8000); regs.p.z = (regs.ya == 0); opcode_cycle = 0; break; } break; } case 0xda: { switch(++opcode_cycle) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.B.a); break; case 4: op_writedp(dp + 1, regs.B.y); opcode_cycle = 0; break; } break; } case 0xaa: { switch(++opcode_cycle) { case 1: sp = op_readpc(); sp |= op_readpc() << 8; break; case 2: bit = sp >> 13; sp &= 0x1fff; rd = op_readaddr(sp); regs.p.c = !!(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0xca: { switch(++opcode_cycle) { case 1: dp = op_readpc(); dp |= op_readpc() << 8; break; case 2: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); if(regs.p.c)rd |= (1 << bit); else rd &= ~(1 << bit); op_io(); break; case 3: op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } apu/bapu/smp/core.cpp000664 001750 001750 00000006675 12720446475 015702 0ustar00sergiosergio000000 000000 void SMP::tick() { timer0.tick(); timer1.tick(); timer2.tick(); #ifndef SNES9X clock += cycle_step_cpu; dsp.clock -= 24; synchronize_dsp(); #else clock++; dsp.clock++; #endif } void SMP::tick(unsigned clocks) { timer0.tick(clocks); timer1.tick(clocks); timer2.tick(clocks); clock += clocks; dsp.clock += clocks; } void SMP::op_io() { #if defined(CYCLE_ACCURATE) tick(); #endif } void SMP::op_io(unsigned clocks) { tick(clocks); } uint8 SMP::op_read(uint16 addr) { #if defined(CYCLE_ACCURATE) tick(); #endif if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; return apuram[addr]; } void SMP::op_write(uint16 addr, uint8 data) { #if defined(CYCLE_ACCURATE) tick(); #endif if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); apuram[addr] = data; //all writes go to RAM, even MMIO writes } void SMP::op_step() { #define op_readpc() op_read(regs.pc++) #define op_readdp(addr) op_read((regs.p.p << 8) + addr) #define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) #define op_readaddr(addr) op_read(addr) #define op_writeaddr(addr, data) op_write(addr, data) #define op_readstack() op_read(0x0100 | ++regs.sp) #define op_writestack(data) op_write(0x0100 | regs.sp--, data) #if defined(CYCLE_ACCURATE) #if defined(PSEUDO_CYCLE) if(opcode_cycle == 0) opcode_number = op_readpc(); switch(opcode_number) { #include "core/oppseudo_misc.cpp" #include "core/oppseudo_mov.cpp" #include "core/oppseudo_pc.cpp" #include "core/oppseudo_read.cpp" #include "core/oppseudo_rmw.cpp" } #else if(opcode_cycle == 0) { opcode_number = op_readpc(); opcode_cycle++; } else switch(opcode_number) { #include "core/opcycle_misc.cpp" #include "core/opcycle_mov.cpp" #include "core/opcycle_pc.cpp" #include "core/opcycle_read.cpp" #include "core/opcycle_rmw.cpp" } #endif // defined(PSEUDO_CYCLE) #else unsigned opcode = op_readpc(); switch(opcode) { #include "core/op_misc.cpp" #include "core/op_mov.cpp" #include "core/op_pc.cpp" #include "core/op_read.cpp" #include "core/op_rmw.cpp" } //TODO: untaken branches should consume less cycles timer0.tick(cycle_count_table[opcode]); timer1.tick(cycle_count_table[opcode]); timer2.tick(cycle_count_table[opcode]); #ifndef SNES9X clock += cycle_table_cpu[opcode]; dsp.clock -= cycle_table_dsp[opcode]; synchronize_dsp(); #else clock += cycle_count_table[opcode]; dsp.clock += cycle_count_table[opcode]; #endif #endif // defined(CYCLE_ACCURATE) } const unsigned SMP::cycle_count_table[256] = { #define c 12 //0 1 2 3 4 5 6 7 8 9 A B C D E F 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4 4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9 3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B 3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C 4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D 2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E 4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F #undef c }; sdd1.cpp000664 001750 001750 00000015262 12720446475 013262 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "sdd1.h" #include "display.h" void S9xSetSDD1MemoryMap (uint32 bank, uint32 value) { bank = 0xc00 + bank * 0x100; value = value * 1024 * 1024; for (int c = 0; c < 0x100; c += 16) { uint8 *block = &Memory.ROM[value + (c << 12)]; for (int i = c; i < c + 16; i++) Memory.Map[i + bank] = block; } } void S9xResetSDD1 (void) { memset(&Memory.FillRAM[0x4800], 0, 4); for (int i = 0; i < 4; i++) { Memory.FillRAM[0x4804 + i] = i; S9xSetSDD1MemoryMap(i, i); } } void S9xSDD1PostLoadState (void) { for (int i = 0; i < 4; i++) S9xSetSDD1MemoryMap(i, Memory.FillRAM[0x4804 + i]); } dma.cpp000664 001750 001750 00000127747 12720446475 013204 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "dma.h" #include "apu/apu.h" #include "sdd1emu.h" #include "spc7110emu.h" #ifdef DEBUGGER #include "missing.h" #endif #define ADD_CYCLES(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); } extern uint8 *HDMAMemPointers[8]; extern int HDMA_ModeByteCounts[8]; extern SPC7110 s7emu; static uint8 sdd1_decode_buffer[0x10000]; static inline bool8 addCyclesInDMA (uint8); static inline bool8 HDMAReadLineCount (int); static inline bool8 addCyclesInDMA (uint8 dma_channel) { // Add 8 cycles per byte, sync APU, and do HC related events. // If HDMA was done in S9xDoHEventProcessing(), check if it used the same channel as DMA. ADD_CYCLES(SLOW_ONE_CYCLE); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); if (CPU.HDMARanInDMA & (1 << dma_channel)) { CPU.HDMARanInDMA = 0; #ifdef DEBUGGER printf("HDMA and DMA use the same channel %d!\n", dma_channel); #endif // If HDMA triggers in the middle of DMA transfer and it uses the same channel, // it kills the DMA transfer immediately. $43x2 and $43x5 stop updating. return (FALSE); } CPU.HDMARanInDMA = 0; return (TRUE); } bool8 S9xDoDMA (uint8 Channel) { CPU.InDMA = TRUE; CPU.InDMAorHDMA = TRUE; CPU.CurrentDMAorHDMAChannel = Channel; SDMA *d = &DMA[Channel]; // Check invalid DMA first if ((d->ABank == 0x7E || d->ABank == 0x7F) && d->BAddress == 0x80 && !d->ReverseTransfer) { // Attempting a DMA from WRAM to $2180 will not work, WRAM will not be written. // Attempting a DMA from $2180 to WRAM will similarly not work, // the value written is (initially) the OpenBus value. // In either case, the address in $2181-3 is not incremented. // Does an invalid DMA actually take time? // I'd say yes, since 'invalid' is probably just the WRAM chip // not being able to read and write itself at the same time // And no, PPU.WRAM should not be updated. int32 c = d->TransferBytes; // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0. if (c == 0) c = 0x10000; // 8 cycles per channel ADD_CYCLES(SLOW_ONE_CYCLE); // 8 cycles per byte while (c) { d->TransferBytes--; d->AAddress++; c--; if (!addCyclesInDMA(Channel)) { CPU.InDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = -1; return (FALSE); } } #ifdef DEBUGGER if (Settings.TraceDMA) { sprintf(String, "DMA[%d]: WRAM Bank:%02X->$2180", Channel, d->ABank); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); } #endif CPU.InDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = -1; return (TRUE); } // Prepare for accessing $2118-2119 switch (d->BAddress) { case 0x18: case 0x19: if (IPPU.RenderThisFrame) FLUSH_REDRAW(); break; } int32 inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1); int32 count = d->TransferBytes; // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0. if (count == 0) count = 0x10000; // Prepare for custom chip DMA // S-DD1 uint8 *in_sdd1_dma = NULL; if (Settings.SDD1) { if (d->AAddressFixed && Memory.FillRAM[0x4801] > 0) { // XXX: Should probably verify that we're DMAing from ROM? // And somewhere we should make sure we're not running across a mapping boundary too. // Hacky support for pre-decompressed S-DD1 data inc = !d->AAddressDecrement ? 1 : -1; uint8 *in_ptr = S9xGetBasePointer(((d->ABank << 16) | d->AAddress)); if (in_ptr) { in_ptr += d->AAddress; SDD1_decompress(sdd1_decode_buffer, in_ptr, d->TransferBytes); } #ifdef DEBUGGER else { sprintf(String, "S-DD1: DMA from non-block address $%02X:%04X", d->ABank, d->AAddress); S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String); } #endif in_sdd1_dma = sdd1_decode_buffer; } Memory.FillRAM[0x4801] = 0; } // SPC7110 uint8 *spc7110_dma = NULL; if (Settings.SPC7110) { if (d->AAddress == 0x4800 || d->ABank == 0x50) { spc7110_dma = new uint8[d->TransferBytes]; for (int i = 0; i < d->TransferBytes; i++) spc7110_dma[i] = s7emu.decomp.read(); int32 icount = s7emu.r4809 | (s7emu.r480a << 8); icount -= d->TransferBytes; s7emu.r4809 = icount & 0x00ff; s7emu.r480a = (icount & 0xff00) >> 8; inc = 1; d->AAddress -= count; } } // SA-1 bool8 in_sa1_dma = FALSE; if (Settings.SA1) { if (SA1.in_char_dma && d->BAddress == 0x18 && (d->ABank & 0xf0) == 0x40) { // Perform packed bitmap to PPU character format conversion on the data // before transmitting it to V-RAM via-DMA. int32 num_chars = 1 << ((Memory.FillRAM[0x2231] >> 2) & 7); int32 depth = (Memory.FillRAM[0x2231] & 3) == 0 ? 8 : (Memory.FillRAM[0x2231] & 3) == 1 ? 4 : 2; int32 bytes_per_char = 8 * depth; int32 bytes_per_line = depth * num_chars; int32 char_line_bytes = bytes_per_char * num_chars; uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes; uint8 *base = S9xGetBasePointer((d->ABank << 16) + addr); if (!base) { sprintf(String, "SA-1: DMA from non-block address $%02X:%04X", d->ABank, addr); S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String); base = Memory.ROM; } base += addr; uint8 *buffer = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000]; uint8 *p = buffer; uint32 inc_sa1 = char_line_bytes - (d->AAddress % char_line_bytes); uint32 char_count = inc_sa1 / bytes_per_char; in_sa1_dma = TRUE; #if 0 printf("SA-1 DMA: %08x,", base); printf("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n", depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes); #endif switch (depth) { case 2: for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars) { uint8 *line = base + (num_chars - char_count) * 2; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 2) { uint8 *q = line; for (int32 l = 0; l < 8; l++, q += bytes_per_line) { for (int32 b = 0; b < 2; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1); } p += 2; } } } break; case 4: for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars) { uint8 *line = base + (num_chars - char_count) * 4; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 4) { uint8 *q = line; for (int32 l = 0; l < 8; l++, q += bytes_per_line) { for (int32 b = 0; b < 4; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1); } p += 2; } p += 32 - 16; } } break; case 8: for (int32 i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars) { uint8 *line = base + (num_chars - char_count) * 8; for (uint32 j = 0; j < char_count && p - buffer < count; j++, line += 8) { uint8 *q = line; for (int32 l = 0; l < 8; l++, q += bytes_per_line) { for (int32 b = 0; b < 8; b++) { uint8 r = *(q + b); *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1); *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1); *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1); *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1); } p += 2; } p += 64 - 16; } } break; } } } #ifdef DEBUGGER if (Settings.TraceDMA) { sprintf(String, "DMA[%d]: %s Mode:%d 0x%02X%04X->0x21%02X Bytes:%d (%s) V:%03d", Channel, d->ReverseTransfer ? "PPU->CPU" : "CPU->PPU", d->TransferMode, d->ABank, d->AAddress, d->BAddress, d->TransferBytes, d->AAddressFixed ? "fixed" : (d->AAddressDecrement ? "dec" : "inc"), CPU.V_Counter); if (d->BAddress == 0x18 || d->BAddress == 0x19 || d->BAddress == 0x39 || d->BAddress == 0x3a) sprintf(String, "%s VRAM: %04X (%d,%d) %s", String, PPU.VMA.Address, PPU.VMA.Increment, PPU.VMA.FullGraphicCount, PPU.VMA.High ? "word" : "byte"); else if (d->BAddress == 0x22 || d->BAddress == 0x3b) sprintf(String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, PPU.CGFLIP); else if (d->BAddress == 0x04 || d->BAddress == 0x38) sprintf(String, "%s OBJADDR: %04X", String, PPU.OAMAddr); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); } #endif // Do Transfer uint8 Work; // 8 cycles per channel ADD_CYCLES(SLOW_ONE_CYCLE); if (!d->ReverseTransfer) { // CPU -> PPU int32 b = 0; uint16 p = d->AAddress; uint8 *base = S9xGetBasePointer((d->ABank << 16) + d->AAddress); bool8 inWRAM_DMA; int32 rem = count; // Transfer per block if d->AAdressFixed is FALSE count = d->AAddressFixed ? rem : (d->AAddressDecrement ? ((p & MEMMAP_MASK) + 1) : (MEMMAP_BLOCK_SIZE - (p & MEMMAP_MASK))); // Settings for custom chip DMA if (in_sa1_dma) { base = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000]; p = 0; count = rem; } else if (in_sdd1_dma) { base = in_sdd1_dma; p = 0; count = rem; } else if (spc7110_dma) { base = spc7110_dma; p = 0; count = rem; } inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) && (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000))); // 8 cycles per byte #define UPDATE_COUNTERS \ d->TransferBytes--; \ d->AAddress += inc; \ p += inc; \ if (!addCyclesInDMA(Channel)) \ { \ CPU.InDMA = FALSE; \ CPU.InDMAorHDMA = FALSE; \ CPU.InWRAMDMAorHDMA = FALSE; \ CPU.CurrentDMAorHDMAChannel = -1; \ return (FALSE); \ } while (1) { if (count > rem) count = rem; rem -= count; CPU.InWRAMDMAorHDMA = inWRAM_DMA; if (!base) { // DMA SLOW PATH if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6) { do { Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; } while (--count > 0); } else if (d->TransferMode == 1 || d->TransferMode == 5) { // This is a variation on Duff's Device. It is legal C/C++. switch (b) { default: while (count > 1) { Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; count--; case 1: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; count--; } } if (count == 1) { Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; b = 1; } else b = 0; } else if (d->TransferMode == 3 || d->TransferMode == 7) { switch (b) { default: do { Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 1; break; } case 1: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 2; break; } case 2: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 3; break; } case 3: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 0; break; } } while (1); } } else if (d->TransferMode == 4) { switch (b) { default: do { Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 1; break; } case 1: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 2; break; } case 2: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2102 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 3; break; } case 3: Work = S9xGetByte((d->ABank << 16) + p); S9xSetPPU(Work, 0x2103 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 0; break; } } while (1); } } #ifdef DEBUGGER else { sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); } #endif } else { // DMA FAST PATH if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6) { switch (d->BAddress) { case 0x04: // OAMDATA do { Work = *(base + p); REGISTER_2104(Work); UPDATE_COUNTERS; } while (--count > 0); break; case 0x18: // VMDATAL if (!PPU.VMA.FullGraphicCount) { do { Work = *(base + p); REGISTER_2118_linear(Work); UPDATE_COUNTERS; } while (--count > 0); } else { do { Work = *(base + p); REGISTER_2118_tile(Work); UPDATE_COUNTERS; } while (--count > 0); } break; case 0x19: // VMDATAH if (!PPU.VMA.FullGraphicCount) { do { Work = *(base + p); REGISTER_2119_linear(Work); UPDATE_COUNTERS; } while (--count > 0); } else { do { Work = *(base + p); REGISTER_2119_tile(Work); UPDATE_COUNTERS; } while (--count > 0); } break; case 0x22: // CGDATA do { Work = *(base + p); REGISTER_2122(Work); UPDATE_COUNTERS; } while (--count > 0); break; case 0x80: // WMDATA if (!CPU.InWRAMDMAorHDMA) { do { Work = *(base + p); REGISTER_2180(Work); UPDATE_COUNTERS; } while (--count > 0); } else { do { UPDATE_COUNTERS; } while (--count > 0); } break; default: do { Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; } while (--count > 0); break; } } else if (d->TransferMode == 1 || d->TransferMode == 5) { if (d->BAddress == 0x18) { // VMDATAL if (!PPU.VMA.FullGraphicCount) { switch (b) { default: while (count > 1) { Work = *(base + p); REGISTER_2118_linear(Work); UPDATE_COUNTERS; count--; case 1: Work = *(base + p); REGISTER_2119_linear(Work); UPDATE_COUNTERS; count--; } } if (count == 1) { Work = *(base + p); REGISTER_2118_linear(Work); UPDATE_COUNTERS; b = 1; } else b = 0; } else { switch (b) { default: while (count > 1) { Work = *(base + p); REGISTER_2118_tile(Work); UPDATE_COUNTERS; count--; case 1: Work = *(base + p); REGISTER_2119_tile(Work); UPDATE_COUNTERS; count--; } } if (count == 1) { Work = *(base + p); REGISTER_2118_tile(Work); UPDATE_COUNTERS; b = 1; } else b = 0; } } else { // DMA mode 1 general case switch (b) { default: while (count > 1) { Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; count--; case 1: Work = *(base + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; count--; } } if (count == 1) { Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; b = 1; } else b = 0; } } else if (d->TransferMode == 3 || d->TransferMode == 7) { switch (b) { default: do { Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 1; break; } case 1: Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 2; break; } case 2: Work = *(base + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 3; break; } case 3: Work = *(base + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 0; break; } } while (1); } } else if (d->TransferMode == 4) { switch (b) { default: do { Work = *(base + p); S9xSetPPU(Work, 0x2100 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 1; break; } case 1: Work = *(base + p); S9xSetPPU(Work, 0x2101 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 2; break; } case 2: Work = *(base + p); S9xSetPPU(Work, 0x2102 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 3; break; } case 3: Work = *(base + p); S9xSetPPU(Work, 0x2103 + d->BAddress); UPDATE_COUNTERS; if (--count <= 0) { b = 0; break; } } while (1); } } #ifdef DEBUGGER else { sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); } #endif } if (rem <= 0) break; base = S9xGetBasePointer((d->ABank << 16) + d->AAddress); count = MEMMAP_BLOCK_SIZE; inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) && (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000))); } #undef UPDATE_COUNTERS } else { // PPU -> CPU // 8 cycles per byte #define UPDATE_COUNTERS \ d->TransferBytes--; \ d->AAddress += inc; \ if (!addCyclesInDMA(Channel)) \ { \ CPU.InDMA = FALSE; \ CPU.InDMAorHDMA = FALSE; \ CPU.InWRAMDMAorHDMA = FALSE; \ CPU.CurrentDMAorHDMAChannel = -1; \ return (FALSE); \ } if (d->BAddress > 0x80 - 4 && d->BAddress <= 0x83 && !(d->ABank & 0x40)) { // REVERSE-DMA REALLY-SLOW PATH do { switch (d->TransferMode) { case 0: case 2: case 6: CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 1: case 5: CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 3: case 7: CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 4: CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2102 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000); Work = S9xGetPPU(0x2103 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; default: #ifdef DEBUGGER sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); #endif while (count) { UPDATE_COUNTERS; count--; } break; } } while (count); } else { // REVERSE-DMA FASTER PATH CPU.InWRAMDMAorHDMA = (d->ABank == 0x7e || d->ABank == 0x7f); do { switch (d->TransferMode) { case 0: case 2: case 6: Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 1: case 5: Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 3: case 7: Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; case 4: Work = S9xGetPPU(0x2100 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2101 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2102 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; if (!--count) break; Work = S9xGetPPU(0x2103 + d->BAddress); S9xSetByte(Work, (d->ABank << 16) + d->AAddress); UPDATE_COUNTERS; count--; break; default: #ifdef DEBUGGER sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel); S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String); #endif while (count) { UPDATE_COUNTERS; count--; } break; } } while (count); } } if (CPU.NMILine && (Timings.NMITriggerPos != 0xffff)) { Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay; if (Timings.NMITriggerPos >= Timings.H_Max) Timings.NMITriggerPos -= Timings.H_Max; } // Release the memory used in SPC7110 DMA if (Settings.SPC7110) { if (spc7110_dma) delete [] spc7110_dma; } #if 0 // sanity check if (d->TransferBytes != 0) fprintf(stderr,"DMA[%d] TransferBytes not 0! $21%02x Reverse:%d %04x\n", Channel, d->BAddress, d->ReverseTransfer, d->TransferBytes); #endif CPU.InDMA = FALSE; CPU.InDMAorHDMA = FALSE; CPU.InWRAMDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = -1; return (TRUE); } static inline bool8 HDMAReadLineCount (int d) { // CPU.InDMA is set, so S9xGetXXX() / S9xSetXXX() incur no charges. uint8 line; line = S9xGetByte((DMA[d].ABank << 16) + DMA[d].Address); ADD_CYCLES(SLOW_ONE_CYCLE); if (!line) { DMA[d].Repeat = FALSE; DMA[d].LineCount = 128; if (DMA[d].HDMAIndirectAddressing) { if (PPU.HDMA & (0xfe << d)) { DMA[d].Address++; ADD_CYCLES(SLOW_ONE_CYCLE << 1); } else ADD_CYCLES(SLOW_ONE_CYCLE); DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address); DMA[d].Address++; } DMA[d].Address++; HDMAMemPointers[d] = NULL; return (FALSE); } else if (line == 0x80) { DMA[d].Repeat = TRUE; DMA[d].LineCount = 128; } else { DMA[d].Repeat = !(line & 0x80); DMA[d].LineCount = line & 0x7f; } DMA[d].Address++; DMA[d].DoTransfer = TRUE; if (DMA[d].HDMAIndirectAddressing) { ADD_CYCLES(SLOW_ONE_CYCLE << 1); DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address); DMA[d].Address += 2; HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].IndirectBank << 16) + DMA[d].IndirectAddress); } else HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].ABank << 16) + DMA[d].Address); return (TRUE); } void S9xStartHDMA (void) { PPU.HDMA = Memory.FillRAM[0x420c]; #ifdef DEBUGGER missing.hdma_this_frame = PPU.HDMA; #endif PPU.HDMAEnded = 0; int32 tmpch; CPU.InHDMA = TRUE; CPU.InDMAorHDMA = TRUE; tmpch = CPU.CurrentDMAorHDMAChannel; // XXX: Not quite right... if (PPU.HDMA != 0) ADD_CYCLES(Timings.DMACPUSync); for (uint8 i = 0; i < 8; i++) { if (PPU.HDMA & (1 << i)) { CPU.CurrentDMAorHDMAChannel = i; DMA[i].Address = DMA[i].AAddress; if (!HDMAReadLineCount(i)) { PPU.HDMA &= ~(1 << i); PPU.HDMAEnded |= (1 << i); } } else DMA[i].DoTransfer = FALSE; } CPU.InHDMA = FALSE; CPU.InDMAorHDMA = CPU.InDMA; CPU.HDMARanInDMA = CPU.InDMA ? PPU.HDMA : 0; CPU.CurrentDMAorHDMAChannel = tmpch; } uint8 S9xDoHDMA (uint8 byte) { struct SDMA *p = &DMA[0]; uint32 ShiftedIBank; uint16 IAddr; bool8 temp; int32 tmpch; int d = 0; CPU.InHDMA = TRUE; CPU.InDMAorHDMA = TRUE; CPU.HDMARanInDMA = CPU.InDMA ? byte : 0; temp = CPU.InWRAMDMAorHDMA; tmpch = CPU.CurrentDMAorHDMAChannel; // XXX: Not quite right... ADD_CYCLES(Timings.DMACPUSync); for (uint8 mask = 1; mask; mask <<= 1, p++, d++) { if (byte & mask) { CPU.InWRAMDMAorHDMA = FALSE; CPU.CurrentDMAorHDMAChannel = d; if (p->HDMAIndirectAddressing) { ShiftedIBank = (p->IndirectBank << 16); IAddr = p->IndirectAddress; } else { ShiftedIBank = (p->ABank << 16); IAddr = p->Address; } if (!HDMAMemPointers[d]) HDMAMemPointers[d] = S9xGetMemPointer(ShiftedIBank + IAddr); if (p->DoTransfer) { // XXX: Hack for Uniracers, because we don't understand // OAM Address Invalidation if (p->BAddress == 0x04) { if (SNESGameFixes.Uniracers) { PPU.OAMAddr = 0x10c; PPU.OAMFlip = 0; } } #ifdef DEBUGGER if (Settings.TraceHDMA && p->DoTransfer) { sprintf(String, "H-DMA[%d] %s (%d) 0x%06X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X", p-DMA, p->ReverseTransfer? "read" : "write", p->TransferMode, ShiftedIBank+IAddr, p->BAddress, p->HDMAIndirectAddressing ? "ind" : "abs", p->LineCount, p->Repeat ? "yes" : "no ", (long) CPU.V_Counter, p->ABank, p->Address); S9xMessage(S9X_TRACE, S9X_HDMA_TRACE, String); } #endif if (!p->ReverseTransfer) { if ((IAddr & MEMMAP_MASK) + HDMA_ModeByteCounts[p->TransferMode] >= MEMMAP_BLOCK_SIZE) { // HDMA REALLY-SLOW PATH HDMAMemPointers[d] = NULL; #define DOBYTE(Addr, RegOff) \ CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \ (!(ShiftedIBank & 0x400000) && ((uint16) (Addr)) < 0x2000)); \ S9xSetPPU(S9xGetByte(ShiftedIBank + ((uint16) (Addr))), 0x2100 + p->BAddress + (RegOff)); switch (p->TransferMode) { case 0: DOBYTE(IAddr, 0); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 1: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 2); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 3); ADD_CYCLES(SLOW_ONE_CYCLE); break; } #undef DOBYTE } else { CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || (!(ShiftedIBank & 0x400000) && IAddr < 0x2000)); if (!HDMAMemPointers[d]) { // HDMA SLOW PATH uint32 Addr = ShiftedIBank + IAddr; switch (p->TransferMode) { case 0: S9xSetPPU(S9xGetByte(Addr), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); Addr += 2; /* fall through */ case 1: S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 2), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 3), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 2), 0x2102 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(S9xGetByte(Addr + 3), 0x2103 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; } } else { // HDMA FAST PATH switch (p->TransferMode) { case 0: S9xSetPPU(*HDMAMemPointers[d]++, 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; /* fall through */ case 1: S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; break; case 2: case 6: S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 2; break; case 3: case 7: S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 4; break; case 4: S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2102 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2103 + p->BAddress); ADD_CYCLES(SLOW_ONE_CYCLE); HDMAMemPointers[d] += 4; break; } } } } else { // REVERSE HDMA REALLY-SLOW PATH // anomie says: Since this is apparently never used // (otherwise we would have noticed before now), let's not bother with faster paths. HDMAMemPointers[d] = NULL; #define DOBYTE(Addr, RegOff) \ CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \ (!(ShiftedIBank & 0x400000) && ((uint16) (Addr)) < 0x2000)); \ S9xSetByte(S9xGetPPU(0x2100 + p->BAddress + (RegOff)), ShiftedIBank + ((uint16) (Addr))); switch (p->TransferMode) { case 0: DOBYTE(IAddr, 0); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 5: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 1: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 2: case 6: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 3: case 7: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 1); ADD_CYCLES(SLOW_ONE_CYCLE); break; case 4: DOBYTE(IAddr + 0, 0); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 1, 1); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 2, 2); ADD_CYCLES(SLOW_ONE_CYCLE); DOBYTE(IAddr + 3, 3); ADD_CYCLES(SLOW_ONE_CYCLE); break; } #undef DOBYTE } if (p->HDMAIndirectAddressing) p->IndirectAddress += HDMA_ModeByteCounts[p->TransferMode]; else p->Address += HDMA_ModeByteCounts[p->TransferMode]; } p->DoTransfer = !p->Repeat; if (!--p->LineCount) { if (!HDMAReadLineCount(d)) { byte &= ~mask; PPU.HDMAEnded |= mask; p->DoTransfer = FALSE; continue; } } else ADD_CYCLES(SLOW_ONE_CYCLE); } } CPU.InHDMA = FALSE; CPU.InDMAorHDMA = CPU.InDMA; CPU.InWRAMDMAorHDMA = temp; CPU.CurrentDMAorHDMAChannel = tmpch; return (byte); } void S9xResetDMA (void) { for (int d = 0; d < 8; d++) { DMA[d].ReverseTransfer = TRUE; DMA[d].HDMAIndirectAddressing = TRUE; DMA[d].AAddressFixed = TRUE; DMA[d].AAddressDecrement = TRUE; DMA[d].TransferMode = 7; DMA[d].BAddress = 0xff; DMA[d].AAddress = 0xffff; DMA[d].ABank = 0xff; DMA[d].DMACount_Or_HDMAIndirectAddress = 0xffff; DMA[d].IndirectBank = 0xff; DMA[d].Address = 0xffff; DMA[d].Repeat = FALSE; DMA[d].LineCount = 0x7f; DMA[d].UnknownByte = 0xff; DMA[d].DoTransfer = FALSE; DMA[d].UnusedBit43x0 = 1; } } libretro/000700 001750 001750 00000000000 12724164663 013523 5ustar00sergiosergio000000 000000 movie.h000664 001750 001750 00000020263 12720446475 013210 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _MOVIE_H_ #define _MOVIE_H_ #define MOVIE_OPT_FROM_SNAPSHOT 0 #define MOVIE_OPT_FROM_RESET (1 << 0) #define MOVIE_OPT_PAL (1 << 1) #define MOVIE_OPT_NOSAVEDATA (1 << 2) #define MOVIE_SYNC_DATA_EXISTS 0x01 #define MOVIE_SYNC_OBSOLETE 0x02 #define MOVIE_SYNC_VOLUMEENVX 0x08 #define MOVIE_SYNC_FAKEMUTE 0x10 #define MOVIE_SYNC_HASROMINFO 0x40 #define MOVIE_SYNC_NOCPUSHUTDOWN 0x80 #define MOVIE_MAX_METADATA 512 #define CONTROLLER_DATA_SIZE 2 #define MOUSE_DATA_SIZE 5 #define SCOPE_DATA_SIZE 6 #define JUSTIFIER_DATA_SIZE 11 struct MovieInfo { time_t TimeCreated; uint32 Version; uint32 LengthFrames; uint32 LengthSamples; uint32 RerecordCount; uint8 Opts; uint8 ControllersMask; uint8 SyncFlags; bool8 ReadOnly; uint8 PortType[2]; wchar_t Metadata[MOVIE_MAX_METADATA]; uint32 ROMCRC32; char ROMName[23]; }; // methods used by the user-interface code int S9xMovieOpen (const char *, bool8); int S9xMovieCreate (const char *, uint8, uint8, const wchar_t *, int); int S9xMovieGetInfo (const char *, struct MovieInfo *); void S9xMovieStop (bool8); void S9xMovieToggleRecState (void); void S9xMovieToggleFrameDisplay (void); const char * S9xChooseMovieFilename (bool8); // methods used by the emulation void S9xMovieInit (void); void S9xMovieShutdown (void); void S9xMovieUpdate (bool a = true); void S9xMovieUpdateOnReset (void); void S9xUpdateFrameCounter (int o = 0); void S9xMovieFreeze (uint8 **, uint32 *); int S9xMovieUnfreeze (uint8 *, uint32); // accessor functions bool8 S9xMovieActive (void); bool8 S9xMoviePlaying (void); bool8 S9xMovieRecording (void); bool8 S9xMovieReadOnly (void); uint8 S9xMovieControllers (void); uint32 S9xMovieGetId (void); uint32 S9xMovieGetLength (void); uint32 S9xMovieGetFrameCounter (void); uint16 MovieGetJoypad (int); void MovieSetJoypad (int, uint16); bool MovieGetMouse (int, uint8 d[MOUSE_DATA_SIZE]); void MovieSetMouse (int, uint8 d[MOUSE_DATA_SIZE], bool); bool MovieGetScope (int, uint8 d[SCOPE_DATA_SIZE]); void MovieSetScope (int, uint8 d[SCOPE_DATA_SIZE]); bool MovieGetJustifier (int, uint8 d[JUSTIFIER_DATA_SIZE]); void MovieSetJustifier (int, uint8 d[JUSTIFIER_DATA_SIZE]); #endif fxinst.cpp000664 001750 001750 00000215276 12720446475 013751 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "fxinst.h" #include "fxemu.h" // Set this define if you wish the plot instruction to check for y-pos limits (I don't think it's nessecary) #define CHECK_LIMITS /* Codes used: rn = a GSU register (r0 - r15) #n = 4 bit immediate value #pp = 8 bit immediate value (yy) = 8 bit word address (0x0000 - 0x01fe) #xx = 16 bit immediate value (xx) = 16 bit address (0x0000 - 0xffff) */ // 00 - stop - stop GSU execution (and maybe generate an IRQ) static void fx_stop (void) { CF(G); GSU.vCounter = 0; GSU.vInstCount = GSU.vCounter; // Check if we need to generate an IRQ if (!(GSU.pvRegisters[GSU_CFGR] & 0x80)) SF(IRQ); GSU.vPlotOptionReg = 0; GSU.vPipe = 1; CLRFLAGS; R15++; } // 01 - nop - no operation static void fx_nop (void) { CLRFLAGS; R15++; } // 02 - cache - reintialize GSU cache static void fx_cache (void) { uint32 c = R15 & 0xfff0; if (GSU.vCacheBaseReg != c || !GSU.bCacheActive) { fx_flushCache(); GSU.vCacheBaseReg = c; GSU.bCacheActive = TRUE; #if 0 if (c < (0x10000 - 512)) { const uint8 *t = &ROM(c); memcpy(GSU.pvCache, t, 512); } else { const uint8 *t1, t2; uint32 i = 0x10000 - c; t1 = &ROM(c); t2 = &ROM(0); memcpy(GSU.pvCache, t1, i); memcpy(&GSU.pvCache[i], t2, 512 - i); } #endif } CLRFLAGS; R15++; } // 03 - lsr - logic shift right static void fx_lsr (void) { uint32 v; GSU.vCarry = SREG & 1; v = USEX16(SREG) >> 1; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 04 - rol - rotate left static void fx_rol (void) { uint32 v = USEX16((SREG << 1) + GSU.vCarry); GSU.vCarry = (SREG >> 15) & 1; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 05 - bra - branch always static void fx_bra (void) { uint8 v = PIPE; R15++; FETCHPIPE; R15 += SEX8(v); } // Branch on condition #define BRA_COND(cond) \ uint8 v = PIPE; \ R15++; \ FETCHPIPE; \ if (cond) \ R15 += SEX8(v); \ else \ R15++ #define TEST_S (GSU.vSign & 0x8000) #define TEST_Z (USEX16(GSU.vZero) == 0) #define TEST_OV (GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000) #define TEST_CY (GSU.vCarry & 1) // 06 - blt - branch on less than static void fx_blt (void) { BRA_COND((TEST_S != 0) != (TEST_OV != 0)); } // 07 - bge - branch on greater or equals static void fx_bge (void) { BRA_COND((TEST_S != 0) == (TEST_OV != 0)); } // 08 - bne - branch on not equal static void fx_bne (void) { BRA_COND(!TEST_Z); } // 09 - beq - branch on equal static void fx_beq (void) { BRA_COND(TEST_Z); } // 0a - bpl - branch on plus static void fx_bpl (void) { BRA_COND(!TEST_S); } // 0b - bmi - branch on minus static void fx_bmi (void) { BRA_COND(TEST_S); } // 0c - bcc - branch on carry clear static void fx_bcc (void) { BRA_COND(!TEST_CY); } // 0d - bcs - branch on carry set static void fx_bcs (void) { BRA_COND(TEST_CY); } // 0e - bvc - branch on overflow clear static void fx_bvc (void) { BRA_COND(!TEST_OV); } // 0f - bvs - branch on overflow set static void fx_bvs (void) { BRA_COND(TEST_OV); } // 10-1f - to rn - set register n as destination register // 10-1f (B) - move rn - move one register to another (if B flag is set) #define FX_TO(reg) \ if (TF(B)) \ { \ GSU.avReg[(reg)] = SREG; \ CLRFLAGS; \ } \ else \ GSU.pvDreg = &GSU.avReg[reg]; \ R15++ #define FX_TO_R14(reg) \ if (TF(B)) \ { \ GSU.avReg[(reg)] = SREG; \ CLRFLAGS; \ READR14; \ } \ else \ GSU.pvDreg = &GSU.avReg[reg]; \ R15++ #define FX_TO_R15(reg) \ if (TF(B)) \ { \ GSU.avReg[(reg)] = SREG; \ CLRFLAGS; \ } \ else \ { \ GSU.pvDreg = &GSU.avReg[reg]; \ R15++; \ } static void fx_to_r0 (void) { FX_TO(0); } static void fx_to_r1 (void) { FX_TO(1); } static void fx_to_r2 (void) { FX_TO(2); } static void fx_to_r3 (void) { FX_TO(3); } static void fx_to_r4 (void) { FX_TO(4); } static void fx_to_r5 (void) { FX_TO(5); } static void fx_to_r6 (void) { FX_TO(6); } static void fx_to_r7 (void) { FX_TO(7); } static void fx_to_r8 (void) { FX_TO(8); } static void fx_to_r9 (void) { FX_TO(9); } static void fx_to_r10 (void) { FX_TO(10); } static void fx_to_r11 (void) { FX_TO(11); } static void fx_to_r12 (void) { FX_TO(12); } static void fx_to_r13 (void) { FX_TO(13); } static void fx_to_r14 (void) { FX_TO_R14(14); } static void fx_to_r15 (void) { FX_TO_R15(15); } // 20-2f - to rn - set register n as source and destination register #define FX_WITH(reg) \ SF(B); \ GSU.pvSreg = GSU.pvDreg = &GSU.avReg[reg]; \ R15++ static void fx_with_r0 (void) { FX_WITH(0); } static void fx_with_r1 (void) { FX_WITH(1); } static void fx_with_r2 (void) { FX_WITH(2); } static void fx_with_r3 (void) { FX_WITH(3); } static void fx_with_r4 (void) { FX_WITH(4); } static void fx_with_r5 (void) { FX_WITH(5); } static void fx_with_r6 (void) { FX_WITH(6); } static void fx_with_r7 (void) { FX_WITH(7); } static void fx_with_r8 (void) { FX_WITH(8); } static void fx_with_r9 (void) { FX_WITH(9); } static void fx_with_r10 (void) { FX_WITH(10); } static void fx_with_r11 (void) { FX_WITH(11); } static void fx_with_r12 (void) { FX_WITH(12); } static void fx_with_r13 (void) { FX_WITH(13); } static void fx_with_r14 (void) { FX_WITH(14); } static void fx_with_r15 (void) { FX_WITH(15); } // 30-3b - stw (rn) - store word #define FX_STW(reg) \ GSU.vLastRamAdr = GSU.avReg[reg]; \ RAM(GSU.avReg[reg]) = (uint8) SREG; \ RAM(GSU.avReg[reg] ^ 1) = (uint8) (SREG >> 8); \ CLRFLAGS; \ R15++ static void fx_stw_r0 (void) { FX_STW(0); } static void fx_stw_r1 (void) { FX_STW(1); } static void fx_stw_r2 (void) { FX_STW(2); } static void fx_stw_r3 (void) { FX_STW(3); } static void fx_stw_r4 (void) { FX_STW(4); } static void fx_stw_r5 (void) { FX_STW(5); } static void fx_stw_r6 (void) { FX_STW(6); } static void fx_stw_r7 (void) { FX_STW(7); } static void fx_stw_r8 (void) { FX_STW(8); } static void fx_stw_r9 (void) { FX_STW(9); } static void fx_stw_r10 (void) { FX_STW(10); } static void fx_stw_r11 (void) { FX_STW(11); } // 30-3b (ALT1) - stb (rn) - store byte #define FX_STB(reg) \ GSU.vLastRamAdr = GSU.avReg[reg]; \ RAM(GSU.avReg[reg]) = (uint8) SREG; \ CLRFLAGS; \ R15++ static void fx_stb_r0 (void) { FX_STB(0); } static void fx_stb_r1 (void) { FX_STB(1); } static void fx_stb_r2 (void) { FX_STB(2); } static void fx_stb_r3 (void) { FX_STB(3); } static void fx_stb_r4 (void) { FX_STB(4); } static void fx_stb_r5 (void) { FX_STB(5); } static void fx_stb_r6 (void) { FX_STB(6); } static void fx_stb_r7 (void) { FX_STB(7); } static void fx_stb_r8 (void) { FX_STB(8); } static void fx_stb_r9 (void) { FX_STB(9); } static void fx_stb_r10 (void) { FX_STB(10); } static void fx_stb_r11 (void) { FX_STB(11); } // 3c - loop - decrement loop counter, and branch on not zero static void fx_loop (void) { GSU.vSign = GSU.vZero = --R12; if ((uint16) R12 != 0) R15 = R13; else R15++; CLRFLAGS; } // 3d - alt1 - set alt1 mode static void fx_alt1 (void) { SF(ALT1); CF(B); R15++; } // 3e - alt2 - set alt2 mode static void fx_alt2 (void) { SF(ALT2); CF(B); R15++; } // 3f - alt3 - set alt3 mode static void fx_alt3 (void) { SF(ALT1); SF(ALT2); CF(B); R15++; } // 40-4b - ldw (rn) - load word from RAM #define FX_LDW(reg) \ uint32 v; \ GSU.vLastRamAdr = GSU.avReg[reg]; \ v = (uint32) RAM(GSU.avReg[reg]); \ v |= ((uint32) RAM(GSU.avReg[reg] ^ 1)) << 8; \ R15++; \ DREG = v; \ TESTR14; \ CLRFLAGS static void fx_ldw_r0 (void) { FX_LDW(0); } static void fx_ldw_r1 (void) { FX_LDW(1); } static void fx_ldw_r2 (void) { FX_LDW(2); } static void fx_ldw_r3 (void) { FX_LDW(3); } static void fx_ldw_r4 (void) { FX_LDW(4); } static void fx_ldw_r5 (void) { FX_LDW(5); } static void fx_ldw_r6 (void) { FX_LDW(6); } static void fx_ldw_r7 (void) { FX_LDW(7); } static void fx_ldw_r8 (void) { FX_LDW(8); } static void fx_ldw_r9 (void) { FX_LDW(9); } static void fx_ldw_r10 (void) { FX_LDW(10); } static void fx_ldw_r11 (void) { FX_LDW(11); } // 40-4b (ALT1) - ldb (rn) - load byte #define FX_LDB(reg) \ uint32 v; \ GSU.vLastRamAdr = GSU.avReg[reg]; \ v = (uint32) RAM(GSU.avReg[reg]); \ R15++; \ DREG = v; \ TESTR14; \ CLRFLAGS static void fx_ldb_r0 (void) { FX_LDB(0); } static void fx_ldb_r1 (void) { FX_LDB(1); } static void fx_ldb_r2 (void) { FX_LDB(2); } static void fx_ldb_r3 (void) { FX_LDB(3); } static void fx_ldb_r4 (void) { FX_LDB(4); } static void fx_ldb_r5 (void) { FX_LDB(5); } static void fx_ldb_r6 (void) { FX_LDB(6); } static void fx_ldb_r7 (void) { FX_LDB(7); } static void fx_ldb_r8 (void) { FX_LDB(8); } static void fx_ldb_r9 (void) { FX_LDB(9); } static void fx_ldb_r10 (void) { FX_LDB(10); } static void fx_ldb_r11 (void) { FX_LDB(11); } // 4c - plot - plot pixel with R1, R2 as x, y and the color register as the color static void fx_plot_2bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v, c; R15++; CLRFLAGS; R1++; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif if (GSU.vPlotOptionReg & 0x02) c = (x ^ y) & 1 ? (uint8) (GSU.vColorReg >> 4) : (uint8) GSU.vColorReg; else c = (uint8) GSU.vColorReg; if (!(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return; a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); if (c & 0x01) a[0] |= v; else a[0] &= ~v; if (c & 0x02) a[1] |= v; else a[1] &= ~v; } // 4c (ALT1) - rpix - read color of the pixel with R1, R2 as x, y static void fx_rpix_2bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v; R15++; CLRFLAGS; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); DREG = 0; DREG |= ((uint32) ((a[0] & v) != 0)) << 0; DREG |= ((uint32) ((a[1] & v) != 0)) << 1; TESTR14; } // 4c - plot - plot pixel with R1, R2 as x, y and the color register as the color static void fx_plot_4bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v, c; R15++; CLRFLAGS; R1++; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif if (GSU.vPlotOptionReg & 0x02) c = (x ^ y) & 1 ? (uint8) (GSU.vColorReg >> 4) : (uint8) GSU.vColorReg; else c = (uint8) GSU.vColorReg; if (!(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return; a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); if (c & 0x01) a[0x00] |= v; else a[0x00] &= ~v; if (c & 0x02) a[0x01] |= v; else a[0x01] &= ~v; if (c & 0x04) a[0x10] |= v; else a[0x10] &= ~v; if (c & 0x08) a[0x11] |= v; else a[0x11] &= ~v; } // 4c (ALT1) - rpix - read color of the pixel with R1, R2 as x, y static void fx_rpix_4bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v; R15++; CLRFLAGS; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); DREG = 0; DREG |= ((uint32) ((a[0x00] & v) != 0)) << 0; DREG |= ((uint32) ((a[0x01] & v) != 0)) << 1; DREG |= ((uint32) ((a[0x10] & v) != 0)) << 2; DREG |= ((uint32) ((a[0x11] & v) != 0)) << 3; TESTR14; } // 4c - plot - plot pixel with R1, R2 as x, y and the color register as the color static void fx_plot_8bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v, c; R15++; CLRFLAGS; R1++; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif c = (uint8) GSU.vColorReg; if (!(GSU.vPlotOptionReg & 0x10)) { if (!(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return; } else if (!(GSU.vPlotOptionReg & 0x01) && !c) return; a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); if (c & 0x01) a[0x00] |= v; else a[0x00] &= ~v; if (c & 0x02) a[0x01] |= v; else a[0x01] &= ~v; if (c & 0x04) a[0x10] |= v; else a[0x10] &= ~v; if (c & 0x08) a[0x11] |= v; else a[0x11] &= ~v; if (c & 0x10) a[0x20] |= v; else a[0x20] &= ~v; if (c & 0x20) a[0x21] |= v; else a[0x21] &= ~v; if (c & 0x40) a[0x30] |= v; else a[0x30] &= ~v; if (c & 0x80) a[0x31] |= v; else a[0x31] &= ~v; } // 4c (ALT1) - rpix - read color of the pixel with R1, R2 as x, y static void fx_rpix_8bit (void) { uint32 x = USEX8(R1); uint32 y = USEX8(R2); uint8 *a; uint8 v; R15++; CLRFLAGS; #ifdef CHECK_LIMITS if (y >= GSU.vScreenHeight) return; #endif a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); v = 128 >> (x & 7); DREG = 0; DREG |= ((uint32) ((a[0x00] & v) != 0)) << 0; DREG |= ((uint32) ((a[0x01] & v) != 0)) << 1; DREG |= ((uint32) ((a[0x10] & v) != 0)) << 2; DREG |= ((uint32) ((a[0x11] & v) != 0)) << 3; DREG |= ((uint32) ((a[0x20] & v) != 0)) << 4; DREG |= ((uint32) ((a[0x21] & v) != 0)) << 5; DREG |= ((uint32) ((a[0x30] & v) != 0)) << 6; DREG |= ((uint32) ((a[0x31] & v) != 0)) << 7; GSU.vZero = DREG; TESTR14; } // 4c - plot - plot pixel with R1, R2 as x, y and the color register as the color static void fx_plot_obj (void) { #ifdef DEBUGGER fprintf(stderr, "ERROR fx_plot_obj called\n"); #endif } // 4c (ALT1) - rpix - read color of the pixel with R1, R2 as x, y static void fx_rpix_obj (void) { #ifdef DEBUGGER fprintf(stderr, "ERROR fx_rpix_obj called\n"); #endif } // 4d - swap - swap upper and lower byte of a register static void fx_swap (void) { uint8 c = (uint8) SREG; uint8 d = (uint8) (SREG >> 8); uint32 v = (((uint32) c) << 8) | ((uint32) d); R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 4e - color - copy source register to color register static void fx_color (void) { uint8 c = (uint8) SREG; if (GSU.vPlotOptionReg & 0x04) c = (c & 0xf0) | (c >> 4); if (GSU.vPlotOptionReg & 0x08) { GSU.vColorReg &= 0xf0; GSU.vColorReg |= c & 0x0f; } else GSU.vColorReg = USEX8(c); CLRFLAGS; R15++; } // 4e (ALT1) - cmode - set plot option register static void fx_cmode (void) { GSU.vPlotOptionReg = SREG; if (GSU.vPlotOptionReg & 0x10) GSU.vScreenHeight = 256; // OBJ Mode (for drawing into sprites) else GSU.vScreenHeight = GSU.vScreenRealHeight; fx_computeScreenPointers(); CLRFLAGS; R15++; } // 4f - not - perform exclusive exor with 1 on all bits static void fx_not (void) { uint32 v = ~SREG; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 50-5f - add rn - add, register + register #define FX_ADD(reg) \ int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]); \ GSU.vCarry = s >= 0x10000; \ GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_add_r0 (void) { FX_ADD(0); } static void fx_add_r1 (void) { FX_ADD(1); } static void fx_add_r2 (void) { FX_ADD(2); } static void fx_add_r3 (void) { FX_ADD(3); } static void fx_add_r4 (void) { FX_ADD(4); } static void fx_add_r5 (void) { FX_ADD(5); } static void fx_add_r6 (void) { FX_ADD(6); } static void fx_add_r7 (void) { FX_ADD(7); } static void fx_add_r8 (void) { FX_ADD(8); } static void fx_add_r9 (void) { FX_ADD(9); } static void fx_add_r10 (void) { FX_ADD(10); } static void fx_add_r11 (void) { FX_ADD(11); } static void fx_add_r12 (void) { FX_ADD(12); } static void fx_add_r13 (void) { FX_ADD(13); } static void fx_add_r14 (void) { FX_ADD(14); } static void fx_add_r15 (void) { FX_ADD(15); } // 50-5f (ALT1) - adc rn - add with carry, register + register #define FX_ADC(reg) \ int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]) + SEX16(GSU.vCarry); \ GSU.vCarry = s >= 0x10000; \ GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_adc_r0 (void) { FX_ADC(0); } static void fx_adc_r1 (void) { FX_ADC(1); } static void fx_adc_r2 (void) { FX_ADC(2); } static void fx_adc_r3 (void) { FX_ADC(3); } static void fx_adc_r4 (void) { FX_ADC(4); } static void fx_adc_r5 (void) { FX_ADC(5); } static void fx_adc_r6 (void) { FX_ADC(6); } static void fx_adc_r7 (void) { FX_ADC(7); } static void fx_adc_r8 (void) { FX_ADC(8); } static void fx_adc_r9 (void) { FX_ADC(9); } static void fx_adc_r10 (void) { FX_ADC(10); } static void fx_adc_r11 (void) { FX_ADC(11); } static void fx_adc_r12 (void) { FX_ADC(12); } static void fx_adc_r13 (void) { FX_ADC(13); } static void fx_adc_r14 (void) { FX_ADC(14); } static void fx_adc_r15 (void) { FX_ADC(15); } // 50-5f (ALT2) - add #n - add, register + immediate #define FX_ADD_I(imm) \ int32 s = SUSEX16(SREG) + imm; \ GSU.vCarry = s >= 0x10000; \ GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_add_i0 (void) { FX_ADD_I(0); } static void fx_add_i1 (void) { FX_ADD_I(1); } static void fx_add_i2 (void) { FX_ADD_I(2); } static void fx_add_i3 (void) { FX_ADD_I(3); } static void fx_add_i4 (void) { FX_ADD_I(4); } static void fx_add_i5 (void) { FX_ADD_I(5); } static void fx_add_i6 (void) { FX_ADD_I(6); } static void fx_add_i7 (void) { FX_ADD_I(7); } static void fx_add_i8 (void) { FX_ADD_I(8); } static void fx_add_i9 (void) { FX_ADD_I(9); } static void fx_add_i10 (void) { FX_ADD_I(10); } static void fx_add_i11 (void) { FX_ADD_I(11); } static void fx_add_i12 (void) { FX_ADD_I(12); } static void fx_add_i13 (void) { FX_ADD_I(13); } static void fx_add_i14 (void) { FX_ADD_I(14); } static void fx_add_i15 (void) { FX_ADD_I(15); } // 50-5f (ALT3) - adc #n - add with carry, register + immediate #define FX_ADC_I(imm) \ int32 s = SUSEX16(SREG) + imm + SUSEX16(GSU.vCarry); \ GSU.vCarry = s >= 0x10000; \ GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_adc_i0 (void) { FX_ADC_I(0); } static void fx_adc_i1 (void) { FX_ADC_I(1); } static void fx_adc_i2 (void) { FX_ADC_I(2); } static void fx_adc_i3 (void) { FX_ADC_I(3); } static void fx_adc_i4 (void) { FX_ADC_I(4); } static void fx_adc_i5 (void) { FX_ADC_I(5); } static void fx_adc_i6 (void) { FX_ADC_I(6); } static void fx_adc_i7 (void) { FX_ADC_I(7); } static void fx_adc_i8 (void) { FX_ADC_I(8); } static void fx_adc_i9 (void) { FX_ADC_I(9); } static void fx_adc_i10 (void) { FX_ADC_I(10); } static void fx_adc_i11 (void) { FX_ADC_I(11); } static void fx_adc_i12 (void) { FX_ADC_I(12); } static void fx_adc_i13 (void) { FX_ADC_I(13); } static void fx_adc_i14 (void) { FX_ADC_I(14); } static void fx_adc_i15 (void) { FX_ADC_I(15); } // 60-6f - sub rn - subtract, register - register #define FX_SUB(reg) \ int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \ GSU.vCarry = s >= 0; \ GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_sub_r0 (void) { FX_SUB(0); } static void fx_sub_r1 (void) { FX_SUB(1); } static void fx_sub_r2 (void) { FX_SUB(2); } static void fx_sub_r3 (void) { FX_SUB(3); } static void fx_sub_r4 (void) { FX_SUB(4); } static void fx_sub_r5 (void) { FX_SUB(5); } static void fx_sub_r6 (void) { FX_SUB(6); } static void fx_sub_r7 (void) { FX_SUB(7); } static void fx_sub_r8 (void) { FX_SUB(8); } static void fx_sub_r9 (void) { FX_SUB(9); } static void fx_sub_r10 (void) { FX_SUB(10); } static void fx_sub_r11 (void) { FX_SUB(11); } static void fx_sub_r12 (void) { FX_SUB(12); } static void fx_sub_r13 (void) { FX_SUB(13); } static void fx_sub_r14 (void) { FX_SUB(14); } static void fx_sub_r15 (void) { FX_SUB(15); } // 60-6f (ALT1) - sbc rn - subtract with carry, register - register #define FX_SBC(reg) \ int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]) - (SUSEX16(GSU.vCarry ^ 1)); \ GSU.vCarry = s >= 0; \ GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_sbc_r0 (void) { FX_SBC(0); } static void fx_sbc_r1 (void) { FX_SBC(1); } static void fx_sbc_r2 (void) { FX_SBC(2); } static void fx_sbc_r3 (void) { FX_SBC(3); } static void fx_sbc_r4 (void) { FX_SBC(4); } static void fx_sbc_r5 (void) { FX_SBC(5); } static void fx_sbc_r6 (void) { FX_SBC(6); } static void fx_sbc_r7 (void) { FX_SBC(7); } static void fx_sbc_r8 (void) { FX_SBC(8); } static void fx_sbc_r9 (void) { FX_SBC(9); } static void fx_sbc_r10 (void) { FX_SBC(10); } static void fx_sbc_r11 (void) { FX_SBC(11); } static void fx_sbc_r12 (void) { FX_SBC(12); } static void fx_sbc_r13 (void) { FX_SBC(13); } static void fx_sbc_r14 (void) { FX_SBC(14); } static void fx_sbc_r15 (void) { FX_SBC(15); } // 60-6f (ALT2) - sub #n - subtract, register - immediate #define FX_SUB_I(imm) \ int32 s = SUSEX16(SREG) - imm; \ GSU.vCarry = s >= 0; \ GSU.vOverflow = (SREG ^ imm) & (SREG ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ DREG = s; \ TESTR14; \ CLRFLAGS static void fx_sub_i0 (void) { FX_SUB_I(0); } static void fx_sub_i1 (void) { FX_SUB_I(1); } static void fx_sub_i2 (void) { FX_SUB_I(2); } static void fx_sub_i3 (void) { FX_SUB_I(3); } static void fx_sub_i4 (void) { FX_SUB_I(4); } static void fx_sub_i5 (void) { FX_SUB_I(5); } static void fx_sub_i6 (void) { FX_SUB_I(6); } static void fx_sub_i7 (void) { FX_SUB_I(7); } static void fx_sub_i8 (void) { FX_SUB_I(8); } static void fx_sub_i9 (void) { FX_SUB_I(9); } static void fx_sub_i10 (void) { FX_SUB_I(10); } static void fx_sub_i11 (void) { FX_SUB_I(11); } static void fx_sub_i12 (void) { FX_SUB_I(12); } static void fx_sub_i13 (void) { FX_SUB_I(13); } static void fx_sub_i14 (void) { FX_SUB_I(14); } static void fx_sub_i15 (void) { FX_SUB_I(15); } // 60-6f (ALT3) - cmp rn - compare, register, register #define FX_CMP(reg) \ int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \ GSU.vCarry = s >= 0; \ GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ GSU.vSign = s; \ GSU.vZero = s; \ R15++; \ CLRFLAGS static void fx_cmp_r0 (void) { FX_CMP(0); } static void fx_cmp_r1 (void) { FX_CMP(1); } static void fx_cmp_r2 (void) { FX_CMP(2); } static void fx_cmp_r3 (void) { FX_CMP(3); } static void fx_cmp_r4 (void) { FX_CMP(4); } static void fx_cmp_r5 (void) { FX_CMP(5); } static void fx_cmp_r6 (void) { FX_CMP(6); } static void fx_cmp_r7 (void) { FX_CMP(7); } static void fx_cmp_r8 (void) { FX_CMP(8); } static void fx_cmp_r9 (void) { FX_CMP(9); } static void fx_cmp_r10 (void) { FX_CMP(10); } static void fx_cmp_r11 (void) { FX_CMP(11); } static void fx_cmp_r12 (void) { FX_CMP(12); } static void fx_cmp_r13 (void) { FX_CMP(13); } static void fx_cmp_r14 (void) { FX_CMP(14); } static void fx_cmp_r15 (void) { FX_CMP(15); } // 70 - merge - R7 as upper byte, R8 as lower byte (used for texture-mapping) static void fx_merge (void) { uint32 v = (R7 & 0xff00) | ((R8 & 0xff00) >> 8); R15++; DREG = v; GSU.vOverflow = (v & 0xc0c0) << 16; GSU.vZero = !(v & 0xf0f0); GSU.vSign = ((v | (v << 8)) & 0x8000); GSU.vCarry = (v & 0xe0e0) != 0; TESTR14; CLRFLAGS; } // 71-7f - and rn - reister & register #define FX_AND(reg) \ uint32 v = SREG & GSU.avReg[reg]; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_and_r1 (void) { FX_AND(1); } static void fx_and_r2 (void) { FX_AND(2); } static void fx_and_r3 (void) { FX_AND(3); } static void fx_and_r4 (void) { FX_AND(4); } static void fx_and_r5 (void) { FX_AND(5); } static void fx_and_r6 (void) { FX_AND(6); } static void fx_and_r7 (void) { FX_AND(7); } static void fx_and_r8 (void) { FX_AND(8); } static void fx_and_r9 (void) { FX_AND(9); } static void fx_and_r10 (void) { FX_AND(10); } static void fx_and_r11 (void) { FX_AND(11); } static void fx_and_r12 (void) { FX_AND(12); } static void fx_and_r13 (void) { FX_AND(13); } static void fx_and_r14 (void) { FX_AND(14); } static void fx_and_r15 (void) { FX_AND(15); } // 71-7f (ALT1) - bic rn - reister & ~register #define FX_BIC(reg) \ uint32 v = SREG & ~GSU.avReg[reg]; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_bic_r1 (void) { FX_BIC(1); } static void fx_bic_r2 (void) { FX_BIC(2); } static void fx_bic_r3 (void) { FX_BIC(3); } static void fx_bic_r4 (void) { FX_BIC(4); } static void fx_bic_r5 (void) { FX_BIC(5); } static void fx_bic_r6 (void) { FX_BIC(6); } static void fx_bic_r7 (void) { FX_BIC(7); } static void fx_bic_r8 (void) { FX_BIC(8); } static void fx_bic_r9 (void) { FX_BIC(9); } static void fx_bic_r10 (void) { FX_BIC(10); } static void fx_bic_r11 (void) { FX_BIC(11); } static void fx_bic_r12 (void) { FX_BIC(12); } static void fx_bic_r13 (void) { FX_BIC(13); } static void fx_bic_r14 (void) { FX_BIC(14); } static void fx_bic_r15 (void) { FX_BIC(15); } // 71-7f (ALT2) - and #n - reister & immediate #define FX_AND_I(imm) \ uint32 v = SREG & imm; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_and_i1 (void) { FX_AND_I(1); } static void fx_and_i2 (void) { FX_AND_I(2); } static void fx_and_i3 (void) { FX_AND_I(3); } static void fx_and_i4 (void) { FX_AND_I(4); } static void fx_and_i5 (void) { FX_AND_I(5); } static void fx_and_i6 (void) { FX_AND_I(6); } static void fx_and_i7 (void) { FX_AND_I(7); } static void fx_and_i8 (void) { FX_AND_I(8); } static void fx_and_i9 (void) { FX_AND_I(9); } static void fx_and_i10 (void) { FX_AND_I(10); } static void fx_and_i11 (void) { FX_AND_I(11); } static void fx_and_i12 (void) { FX_AND_I(12); } static void fx_and_i13 (void) { FX_AND_I(13); } static void fx_and_i14 (void) { FX_AND_I(14); } static void fx_and_i15 (void) { FX_AND_I(15); } // 71-7f (ALT3) - bic #n - reister & ~immediate #define FX_BIC_I(imm) \ uint32 v = SREG & ~imm; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_bic_i1 (void) { FX_BIC_I(1); } static void fx_bic_i2 (void) { FX_BIC_I(2); } static void fx_bic_i3 (void) { FX_BIC_I(3); } static void fx_bic_i4 (void) { FX_BIC_I(4); } static void fx_bic_i5 (void) { FX_BIC_I(5); } static void fx_bic_i6 (void) { FX_BIC_I(6); } static void fx_bic_i7 (void) { FX_BIC_I(7); } static void fx_bic_i8 (void) { FX_BIC_I(8); } static void fx_bic_i9 (void) { FX_BIC_I(9); } static void fx_bic_i10 (void) { FX_BIC_I(10); } static void fx_bic_i11 (void) { FX_BIC_I(11); } static void fx_bic_i12 (void) { FX_BIC_I(12); } static void fx_bic_i13 (void) { FX_BIC_I(13); } static void fx_bic_i14 (void) { FX_BIC_I(14); } static void fx_bic_i15 (void) { FX_BIC_I(15); } // 80-8f - mult rn - 8 bit to 16 bit signed multiply, register * register #define FX_MULT(reg) \ uint32 v = (uint32) (SEX8(SREG) * SEX8(GSU.avReg[reg])); \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_mult_r0 (void) { FX_MULT(0); } static void fx_mult_r1 (void) { FX_MULT(1); } static void fx_mult_r2 (void) { FX_MULT(2); } static void fx_mult_r3 (void) { FX_MULT(3); } static void fx_mult_r4 (void) { FX_MULT(4); } static void fx_mult_r5 (void) { FX_MULT(5); } static void fx_mult_r6 (void) { FX_MULT(6); } static void fx_mult_r7 (void) { FX_MULT(7); } static void fx_mult_r8 (void) { FX_MULT(8); } static void fx_mult_r9 (void) { FX_MULT(9); } static void fx_mult_r10 (void) { FX_MULT(10); } static void fx_mult_r11 (void) { FX_MULT(11); } static void fx_mult_r12 (void) { FX_MULT(12); } static void fx_mult_r13 (void) { FX_MULT(13); } static void fx_mult_r14 (void) { FX_MULT(14); } static void fx_mult_r15 (void) { FX_MULT(15); } // 80-8f (ALT1) - umult rn - 8 bit to 16 bit unsigned multiply, register * register #define FX_UMULT(reg) \ uint32 v = USEX8(SREG) * USEX8(GSU.avReg[reg]); \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_umult_r0 (void) { FX_UMULT(0); } static void fx_umult_r1 (void) { FX_UMULT(1); } static void fx_umult_r2 (void) { FX_UMULT(2); } static void fx_umult_r3 (void) { FX_UMULT(3); } static void fx_umult_r4 (void) { FX_UMULT(4); } static void fx_umult_r5 (void) { FX_UMULT(5); } static void fx_umult_r6 (void) { FX_UMULT(6); } static void fx_umult_r7 (void) { FX_UMULT(7); } static void fx_umult_r8 (void) { FX_UMULT(8); } static void fx_umult_r9 (void) { FX_UMULT(9); } static void fx_umult_r10 (void) { FX_UMULT(10); } static void fx_umult_r11 (void) { FX_UMULT(11); } static void fx_umult_r12 (void) { FX_UMULT(12); } static void fx_umult_r13 (void) { FX_UMULT(13); } static void fx_umult_r14 (void) { FX_UMULT(14); } static void fx_umult_r15 (void) { FX_UMULT(15); } // 80-8f (ALT2) - mult #n - 8 bit to 16 bit signed multiply, register * immediate #define FX_MULT_I(imm) \ uint32 v = (uint32) (SEX8(SREG) * ((int32) imm)); \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_mult_i0 (void) { FX_MULT_I(0); } static void fx_mult_i1 (void) { FX_MULT_I(1); } static void fx_mult_i2 (void) { FX_MULT_I(2); } static void fx_mult_i3 (void) { FX_MULT_I(3); } static void fx_mult_i4 (void) { FX_MULT_I(4); } static void fx_mult_i5 (void) { FX_MULT_I(5); } static void fx_mult_i6 (void) { FX_MULT_I(6); } static void fx_mult_i7 (void) { FX_MULT_I(7); } static void fx_mult_i8 (void) { FX_MULT_I(8); } static void fx_mult_i9 (void) { FX_MULT_I(9); } static void fx_mult_i10 (void) { FX_MULT_I(10); } static void fx_mult_i11 (void) { FX_MULT_I(11); } static void fx_mult_i12 (void) { FX_MULT_I(12); } static void fx_mult_i13 (void) { FX_MULT_I(13); } static void fx_mult_i14 (void) { FX_MULT_I(14); } static void fx_mult_i15 (void) { FX_MULT_I(15); } // 80-8f (ALT3) - umult #n - 8 bit to 16 bit unsigned multiply, register * immediate #define FX_UMULT_I(imm) \ uint32 v = USEX8(SREG) * ((uint32) imm); \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_umult_i0 (void) { FX_UMULT_I(0); } static void fx_umult_i1 (void) { FX_UMULT_I(1); } static void fx_umult_i2 (void) { FX_UMULT_I(2); } static void fx_umult_i3 (void) { FX_UMULT_I(3); } static void fx_umult_i4 (void) { FX_UMULT_I(4); } static void fx_umult_i5 (void) { FX_UMULT_I(5); } static void fx_umult_i6 (void) { FX_UMULT_I(6); } static void fx_umult_i7 (void) { FX_UMULT_I(7); } static void fx_umult_i8 (void) { FX_UMULT_I(8); } static void fx_umult_i9 (void) { FX_UMULT_I(9); } static void fx_umult_i10 (void) { FX_UMULT_I(10); } static void fx_umult_i11 (void) { FX_UMULT_I(11); } static void fx_umult_i12 (void) { FX_UMULT_I(12); } static void fx_umult_i13 (void) { FX_UMULT_I(13); } static void fx_umult_i14 (void) { FX_UMULT_I(14); } static void fx_umult_i15 (void) { FX_UMULT_I(15); } // 90 - sbk - store word to last accessed RAM address static void fx_sbk (void) { RAM(GSU.vLastRamAdr) = (uint8) SREG; RAM(GSU.vLastRamAdr ^ 1) = (uint8) (SREG >> 8); CLRFLAGS; R15++; } // 91-94 - link #n - R11 = R15 + immediate #define FX_LINK_I(lkn) \ R11 = R15 + lkn; \ CLRFLAGS; \ R15++ static void fx_link_i1 (void) { FX_LINK_I(1); } static void fx_link_i2 (void) { FX_LINK_I(2); } static void fx_link_i3 (void) { FX_LINK_I(3); } static void fx_link_i4 (void) { FX_LINK_I(4); } // 95 - sex - sign extend 8 bit to 16 bit static void fx_sex (void) { uint32 v = (uint32) SEX8(SREG); R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 96 - asr - aritmetric shift right by one static void fx_asr (void) { uint32 v; GSU.vCarry = SREG & 1; v = (uint32) (SEX16(SREG) >> 1); R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 96 (ALT1) - div2 - aritmetric shift right by one static void fx_div2 (void) { uint32 v; int32 s = SEX16(SREG); GSU.vCarry = s & 1; if (s == -1) v = 0; else v = (uint32) (s >> 1); R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 97 - ror - rotate right by one static void fx_ror (void) { uint32 v = (USEX16(SREG) >> 1) | (GSU.vCarry << 15); GSU.vCarry = SREG & 1; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } // 98-9d - jmp rn - jump to address of register #define FX_JMP(reg) \ R15 = GSU.avReg[reg]; \ CLRFLAGS static void fx_jmp_r8 (void) { FX_JMP(8); } static void fx_jmp_r9 (void) { FX_JMP(9); } static void fx_jmp_r10 (void) { FX_JMP(10); } static void fx_jmp_r11 (void) { FX_JMP(11); } static void fx_jmp_r12 (void) { FX_JMP(12); } static void fx_jmp_r13 (void) { FX_JMP(13); } // 98-9d (ALT1) - ljmp rn - set program bank to source register and jump to address of register #define FX_LJMP(reg) \ GSU.vPrgBankReg = GSU.avReg[reg] & 0x7f; \ GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg]; \ R15 = SREG; \ GSU.bCacheActive = FALSE; \ fx_cache(); \ R15-- static void fx_ljmp_r8 (void) { FX_LJMP(8); } static void fx_ljmp_r9 (void) { FX_LJMP(9); } static void fx_ljmp_r10 (void) { FX_LJMP(10); } static void fx_ljmp_r11 (void) { FX_LJMP(11); } static void fx_ljmp_r12 (void) { FX_LJMP(12); } static void fx_ljmp_r13 (void) { FX_LJMP(13); } // 9e - lob - set upper byte to zero (keep low byte) static void fx_lob (void) { uint32 v = USEX8(SREG); R15++; DREG = v; GSU.vSign = v << 8; GSU.vZero = v << 8; TESTR14; CLRFLAGS; } // 9f - fmult - 16 bit to 32 bit signed multiplication, upper 16 bits only static void fx_fmult (void) { uint32 v; uint32 c = (uint32) (SEX16(SREG) * SEX16(R6)); v = c >> 16; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; GSU.vCarry = (c >> 15) & 1; TESTR14; CLRFLAGS; } // 9f (ALT1) - lmult - 16 bit to 32 bit signed multiplication static void fx_lmult (void) { uint32 v; uint32 c = (uint32) (SEX16(SREG) * SEX16(R6)); R4 = c; v = c >> 16; R15++; DREG = v; GSU.vSign = v; GSU.vZero = v; // XXX: R6 or R4? GSU.vCarry = (R4 >> 15) & 1; // should it be bit 15 of R4 instead ? TESTR14; CLRFLAGS; } // a0-af - ibt rn, #pp - immediate byte transfer #define FX_IBT(reg) \ uint8 v = PIPE; \ R15++; \ FETCHPIPE; \ R15++; \ GSU.avReg[reg] = SEX8(v); \ CLRFLAGS static void fx_ibt_r0 (void) { FX_IBT(0); } static void fx_ibt_r1 (void) { FX_IBT(1); } static void fx_ibt_r2 (void) { FX_IBT(2); } static void fx_ibt_r3 (void) { FX_IBT(3); } static void fx_ibt_r4 (void) { FX_IBT(4); } static void fx_ibt_r5 (void) { FX_IBT(5); } static void fx_ibt_r6 (void) { FX_IBT(6); } static void fx_ibt_r7 (void) { FX_IBT(7); } static void fx_ibt_r8 (void) { FX_IBT(8); } static void fx_ibt_r9 (void) { FX_IBT(9); } static void fx_ibt_r10 (void) { FX_IBT(10); } static void fx_ibt_r11 (void) { FX_IBT(11); } static void fx_ibt_r12 (void) { FX_IBT(12); } static void fx_ibt_r13 (void) { FX_IBT(13); } static void fx_ibt_r14 (void) { FX_IBT(14); READR14; } static void fx_ibt_r15 (void) { FX_IBT(15); } // a0-af (ALT1) - lms rn, (yy) - load word from RAM (short address) #define FX_LMS(reg) \ GSU.vLastRamAdr = ((uint32) PIPE) << 1; \ R15++; \ FETCHPIPE; \ R15++; \ GSU.avReg[reg] = (uint32) RAM(GSU.vLastRamAdr); \ GSU.avReg[reg] |= ((uint32) RAM(GSU.vLastRamAdr + 1)) << 8; \ CLRFLAGS static void fx_lms_r0 (void) { FX_LMS(0); } static void fx_lms_r1 (void) { FX_LMS(1); } static void fx_lms_r2 (void) { FX_LMS(2); } static void fx_lms_r3 (void) { FX_LMS(3); } static void fx_lms_r4 (void) { FX_LMS(4); } static void fx_lms_r5 (void) { FX_LMS(5); } static void fx_lms_r6 (void) { FX_LMS(6); } static void fx_lms_r7 (void) { FX_LMS(7); } static void fx_lms_r8 (void) { FX_LMS(8); } static void fx_lms_r9 (void) { FX_LMS(9); } static void fx_lms_r10 (void) { FX_LMS(10); } static void fx_lms_r11 (void) { FX_LMS(11); } static void fx_lms_r12 (void) { FX_LMS(12); } static void fx_lms_r13 (void) { FX_LMS(13); } static void fx_lms_r14 (void) { FX_LMS(14); READR14; } static void fx_lms_r15 (void) { FX_LMS(15); } // a0-af (ALT2) - sms (yy), rn - store word in RAM (short address) // XXX: If rn == r15, is the value of r15 before or after the extra byte is read ? #define FX_SMS(reg) \ uint32 v = GSU.avReg[reg]; \ GSU.vLastRamAdr = ((uint32) PIPE) << 1; \ R15++; \ FETCHPIPE; \ RAM(GSU.vLastRamAdr) = (uint8) v; \ RAM(GSU.vLastRamAdr + 1) = (uint8) (v >> 8); \ CLRFLAGS; \ R15++ static void fx_sms_r0 (void) { FX_SMS(0); } static void fx_sms_r1 (void) { FX_SMS(1); } static void fx_sms_r2 (void) { FX_SMS(2); } static void fx_sms_r3 (void) { FX_SMS(3); } static void fx_sms_r4 (void) { FX_SMS(4); } static void fx_sms_r5 (void) { FX_SMS(5); } static void fx_sms_r6 (void) { FX_SMS(6); } static void fx_sms_r7 (void) { FX_SMS(7); } static void fx_sms_r8 (void) { FX_SMS(8); } static void fx_sms_r9 (void) { FX_SMS(9); } static void fx_sms_r10 (void) { FX_SMS(10); } static void fx_sms_r11 (void) { FX_SMS(11); } static void fx_sms_r12 (void) { FX_SMS(12); } static void fx_sms_r13 (void) { FX_SMS(13); } static void fx_sms_r14 (void) { FX_SMS(14); } static void fx_sms_r15 (void) { FX_SMS(15); } // b0-bf - from rn - set source register // b0-bf (B) - moves rn - move register to register, and set flags, (if B flag is set) #define FX_FROM(reg) \ if (TF(B)) \ { \ uint32 v = GSU.avReg[reg]; \ R15++; \ DREG = v; \ GSU.vOverflow = (v & 0x80) << 16; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS; \ } \ else \ { \ GSU.pvSreg = &GSU.avReg[reg]; \ R15++; \ } static void fx_from_r0 (void) { FX_FROM(0); } static void fx_from_r1 (void) { FX_FROM(1); } static void fx_from_r2 (void) { FX_FROM(2); } static void fx_from_r3 (void) { FX_FROM(3); } static void fx_from_r4 (void) { FX_FROM(4); } static void fx_from_r5 (void) { FX_FROM(5); } static void fx_from_r6 (void) { FX_FROM(6); } static void fx_from_r7 (void) { FX_FROM(7); } static void fx_from_r8 (void) { FX_FROM(8); } static void fx_from_r9 (void) { FX_FROM(9); } static void fx_from_r10 (void) { FX_FROM(10); } static void fx_from_r11 (void) { FX_FROM(11); } static void fx_from_r12 (void) { FX_FROM(12); } static void fx_from_r13 (void) { FX_FROM(13); } static void fx_from_r14 (void) { FX_FROM(14); } static void fx_from_r15 (void) { FX_FROM(15); } // c0 - hib - move high-byte to low-byte static void fx_hib (void) { uint32 v = USEX8(SREG >> 8); R15++; DREG = v; GSU.vSign = v << 8; GSU.vZero = v << 8; TESTR14; CLRFLAGS; } // c1-cf - or rn #define FX_OR(reg) \ uint32 v = SREG | GSU.avReg[reg]; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_or_r1 (void) { FX_OR(1); } static void fx_or_r2 (void) { FX_OR(2); } static void fx_or_r3 (void) { FX_OR(3); } static void fx_or_r4 (void) { FX_OR(4); } static void fx_or_r5 (void) { FX_OR(5); } static void fx_or_r6 (void) { FX_OR(6); } static void fx_or_r7 (void) { FX_OR(7); } static void fx_or_r8 (void) { FX_OR(8); } static void fx_or_r9 (void) { FX_OR(9); } static void fx_or_r10 (void) { FX_OR(10); } static void fx_or_r11 (void) { FX_OR(11); } static void fx_or_r12 (void) { FX_OR(12); } static void fx_or_r13 (void) { FX_OR(13); } static void fx_or_r14 (void) { FX_OR(14); } static void fx_or_r15 (void) { FX_OR(15); } // c1-cf (ALT1) - xor rn #define FX_XOR(reg) \ uint32 v = SREG ^ GSU.avReg[reg]; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_xor_r1 (void) { FX_XOR(1); } static void fx_xor_r2 (void) { FX_XOR(2); } static void fx_xor_r3 (void) { FX_XOR(3); } static void fx_xor_r4 (void) { FX_XOR(4); } static void fx_xor_r5 (void) { FX_XOR(5); } static void fx_xor_r6 (void) { FX_XOR(6); } static void fx_xor_r7 (void) { FX_XOR(7); } static void fx_xor_r8 (void) { FX_XOR(8); } static void fx_xor_r9 (void) { FX_XOR(9); } static void fx_xor_r10 (void) { FX_XOR(10); } static void fx_xor_r11 (void) { FX_XOR(11); } static void fx_xor_r12 (void) { FX_XOR(12); } static void fx_xor_r13 (void) { FX_XOR(13); } static void fx_xor_r14 (void) { FX_XOR(14); } static void fx_xor_r15 (void) { FX_XOR(15); } // c1-cf (ALT2) - or #n #define FX_OR_I(imm) \ uint32 v = SREG | imm; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_or_i1 (void) { FX_OR_I(1); } static void fx_or_i2 (void) { FX_OR_I(2); } static void fx_or_i3 (void) { FX_OR_I(3); } static void fx_or_i4 (void) { FX_OR_I(4); } static void fx_or_i5 (void) { FX_OR_I(5); } static void fx_or_i6 (void) { FX_OR_I(6); } static void fx_or_i7 (void) { FX_OR_I(7); } static void fx_or_i8 (void) { FX_OR_I(8); } static void fx_or_i9 (void) { FX_OR_I(9); } static void fx_or_i10 (void) { FX_OR_I(10); } static void fx_or_i11 (void) { FX_OR_I(11); } static void fx_or_i12 (void) { FX_OR_I(12); } static void fx_or_i13 (void) { FX_OR_I(13); } static void fx_or_i14 (void) { FX_OR_I(14); } static void fx_or_i15 (void) { FX_OR_I(15); } // c1-cf (ALT3) - xor #n #define FX_XOR_I(imm) \ uint32 v = SREG ^ imm; \ R15++; \ DREG = v; \ GSU.vSign = v; \ GSU.vZero = v; \ TESTR14; \ CLRFLAGS static void fx_xor_i1 (void) { FX_XOR_I(1); } static void fx_xor_i2 (void) { FX_XOR_I(2); } static void fx_xor_i3 (void) { FX_XOR_I(3); } static void fx_xor_i4 (void) { FX_XOR_I(4); } static void fx_xor_i5 (void) { FX_XOR_I(5); } static void fx_xor_i6 (void) { FX_XOR_I(6); } static void fx_xor_i7 (void) { FX_XOR_I(7); } static void fx_xor_i8 (void) { FX_XOR_I(8); } static void fx_xor_i9 (void) { FX_XOR_I(9); } static void fx_xor_i10 (void) { FX_XOR_I(10); } static void fx_xor_i11 (void) { FX_XOR_I(11); } static void fx_xor_i12 (void) { FX_XOR_I(12); } static void fx_xor_i13 (void) { FX_XOR_I(13); } static void fx_xor_i14 (void) { FX_XOR_I(14); } static void fx_xor_i15 (void) { FX_XOR_I(15); } // d0-de - inc rn - increase by one #define FX_INC(reg) \ GSU.avReg[reg] += 1; \ GSU.vSign = GSU.avReg[reg]; \ GSU.vZero = GSU.avReg[reg]; \ CLRFLAGS; \ R15++ static void fx_inc_r0 (void) { FX_INC(0); } static void fx_inc_r1 (void) { FX_INC(1); } static void fx_inc_r2 (void) { FX_INC(2); } static void fx_inc_r3 (void) { FX_INC(3); } static void fx_inc_r4 (void) { FX_INC(4); } static void fx_inc_r5 (void) { FX_INC(5); } static void fx_inc_r6 (void) { FX_INC(6); } static void fx_inc_r7 (void) { FX_INC(7); } static void fx_inc_r8 (void) { FX_INC(8); } static void fx_inc_r9 (void) { FX_INC(9); } static void fx_inc_r10 (void) { FX_INC(10); } static void fx_inc_r11 (void) { FX_INC(11); } static void fx_inc_r12 (void) { FX_INC(12); } static void fx_inc_r13 (void) { FX_INC(13); } static void fx_inc_r14 (void) { FX_INC(14); READR14; } // df - getc - transfer ROM buffer to color register static void fx_getc (void) { #ifndef FX_DO_ROMBUFFER uint8 c = ROM(R14); #else uint8 c = GSU.vRomBuffer; #endif if (GSU.vPlotOptionReg & 0x04) c = (c & 0xf0) | (c >> 4); if (GSU.vPlotOptionReg & 0x08) { GSU.vColorReg &= 0xf0; GSU.vColorReg |= c & 0x0f; } else GSU.vColorReg = USEX8(c); CLRFLAGS; R15++; } // df (ALT2) - ramb - set current RAM bank static void fx_ramb (void) { GSU.vRamBankReg = SREG & (FX_RAM_BANKS - 1); GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3]; CLRFLAGS; R15++; } // df (ALT3) - romb - set current ROM bank static void fx_romb (void) { GSU.vRomBankReg = USEX8(SREG) & 0x7f; GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg]; CLRFLAGS; R15++; } // e0-ee - dec rn - decrement by one #define FX_DEC(reg) \ GSU.avReg[reg] -= 1; \ GSU.vSign = GSU.avReg[reg]; \ GSU.vZero = GSU.avReg[reg]; \ CLRFLAGS; \ R15++ static void fx_dec_r0 (void) { FX_DEC(0); } static void fx_dec_r1 (void) { FX_DEC(1); } static void fx_dec_r2 (void) { FX_DEC(2); } static void fx_dec_r3 (void) { FX_DEC(3); } static void fx_dec_r4 (void) { FX_DEC(4); } static void fx_dec_r5 (void) { FX_DEC(5); } static void fx_dec_r6 (void) { FX_DEC(6); } static void fx_dec_r7 (void) { FX_DEC(7); } static void fx_dec_r8 (void) { FX_DEC(8); } static void fx_dec_r9 (void) { FX_DEC(9); } static void fx_dec_r10 (void) { FX_DEC(10); } static void fx_dec_r11 (void) { FX_DEC(11); } static void fx_dec_r12 (void) { FX_DEC(12); } static void fx_dec_r13 (void) { FX_DEC(13); } static void fx_dec_r14 (void) { FX_DEC(14); READR14; } // ef - getb - get byte from ROM at address R14 static void fx_getb (void) { uint32 v; #ifndef FX_DO_ROMBUFFER v = (uint32) ROM(R14); #else v = (uint32) GSU.vRomBuffer; #endif R15++; DREG = v; TESTR14; CLRFLAGS; } // ef (ALT1) - getbh - get high-byte from ROM at address R14 static void fx_getbh (void) { uint32 v; #ifndef FX_DO_ROMBUFFER uint32 c = (uint32) ROM(R14); #else uint32 c = USEX8(GSU.vRomBuffer); #endif v = USEX8(SREG) | (c << 8); R15++; DREG = v; TESTR14; CLRFLAGS; } // ef (ALT2) - getbl - get low-byte from ROM at address R14 static void fx_getbl (void) { uint32 v; #ifndef FX_DO_ROMBUFFER uint32 c = (uint32) ROM(R14); #else uint32 c = USEX8(GSU.vRomBuffer); #endif v = (SREG & 0xff00) | c; R15++; DREG = v; TESTR14; CLRFLAGS; } // ef (ALT3) - getbs - get sign extended byte from ROM at address R14 static void fx_getbs (void) { uint32 v; #ifndef FX_DO_ROMBUFFER int8 c; c = ROM(R14); v = SEX8(c); #else v = SEX8(GSU.vRomBuffer); #endif R15++; DREG = v; TESTR14; CLRFLAGS; } // f0-ff - iwt rn, #xx - immediate word transfer to register #define FX_IWT(reg) \ uint32 v = PIPE; \ R15++; \ FETCHPIPE; \ R15++; \ v |= USEX8(PIPE) << 8; \ FETCHPIPE; \ R15++; \ GSU.avReg[reg] = v; \ CLRFLAGS static void fx_iwt_r0 (void) { FX_IWT(0); } static void fx_iwt_r1 (void) { FX_IWT(1); } static void fx_iwt_r2 (void) { FX_IWT(2); } static void fx_iwt_r3 (void) { FX_IWT(3); } static void fx_iwt_r4 (void) { FX_IWT(4); } static void fx_iwt_r5 (void) { FX_IWT(5); } static void fx_iwt_r6 (void) { FX_IWT(6); } static void fx_iwt_r7 (void) { FX_IWT(7); } static void fx_iwt_r8 (void) { FX_IWT(8); } static void fx_iwt_r9 (void) { FX_IWT(9); } static void fx_iwt_r10 (void) { FX_IWT(10); } static void fx_iwt_r11 (void) { FX_IWT(11); } static void fx_iwt_r12 (void) { FX_IWT(12); } static void fx_iwt_r13 (void) { FX_IWT(13); } static void fx_iwt_r14 (void) { FX_IWT(14); READR14; } static void fx_iwt_r15 (void) { FX_IWT(15); } // f0-ff (ALT1) - lm rn, (xx) - load word from RAM #define FX_LM(reg) \ GSU.vLastRamAdr = PIPE; \ R15++; \ FETCHPIPE; \ R15++; \ GSU.vLastRamAdr |= USEX8(PIPE) << 8; \ FETCHPIPE; \ R15++; \ GSU.avReg[reg] = RAM(GSU.vLastRamAdr); \ GSU.avReg[reg] |= USEX8(RAM(GSU.vLastRamAdr ^ 1)) << 8; \ CLRFLAGS static void fx_lm_r0 (void) { FX_LM(0); } static void fx_lm_r1 (void) { FX_LM(1); } static void fx_lm_r2 (void) { FX_LM(2); } static void fx_lm_r3 (void) { FX_LM(3); } static void fx_lm_r4 (void) { FX_LM(4); } static void fx_lm_r5 (void) { FX_LM(5); } static void fx_lm_r6 (void) { FX_LM(6); } static void fx_lm_r7 (void) { FX_LM(7); } static void fx_lm_r8 (void) { FX_LM(8); } static void fx_lm_r9 (void) { FX_LM(9); } static void fx_lm_r10 (void) { FX_LM(10); } static void fx_lm_r11 (void) { FX_LM(11); } static void fx_lm_r12 (void) { FX_LM(12); } static void fx_lm_r13 (void) { FX_LM(13); } static void fx_lm_r14 (void) { FX_LM(14); READR14; } static void fx_lm_r15 (void) { FX_LM(15); } // f0-ff (ALT2) - sm (xx), rn - store word in RAM // XXX: If rn == r15, is the value of r15 before or after the extra bytes are read ? #define FX_SM(reg) \ uint32 v = GSU.avReg[reg]; \ GSU.vLastRamAdr = PIPE; \ R15++; \ FETCHPIPE; \ R15++; \ GSU.vLastRamAdr |= USEX8(PIPE) << 8; \ FETCHPIPE; \ RAM(GSU.vLastRamAdr) = (uint8) v; \ RAM(GSU.vLastRamAdr ^ 1) = (uint8) (v >> 8); \ CLRFLAGS; \ R15++ static void fx_sm_r0 (void) { FX_SM(0); } static void fx_sm_r1 (void) { FX_SM(1); } static void fx_sm_r2 (void) { FX_SM(2); } static void fx_sm_r3 (void) { FX_SM(3); } static void fx_sm_r4 (void) { FX_SM(4); } static void fx_sm_r5 (void) { FX_SM(5); } static void fx_sm_r6 (void) { FX_SM(6); } static void fx_sm_r7 (void) { FX_SM(7); } static void fx_sm_r8 (void) { FX_SM(8); } static void fx_sm_r9 (void) { FX_SM(9); } static void fx_sm_r10 (void) { FX_SM(10); } static void fx_sm_r11 (void) { FX_SM(11); } static void fx_sm_r12 (void) { FX_SM(12); } static void fx_sm_r13 (void) { FX_SM(13); } static void fx_sm_r14 (void) { FX_SM(14); } static void fx_sm_r15 (void) { FX_SM(15); } // GSU executions functions uint32 fx_run (uint32 nInstructions) { GSU.vCounter = nInstructions; READR14; while (TF(G) && (GSU.vCounter-- > 0)) FX_STEP; #if 0 #ifndef FX_ADDRESS_CHECK GSU.vPipeAdr = USEX16(R15 - 1) | (USEX8(GSU.vPrgBankReg) << 16); #endif #endif return (nInstructions - GSU.vInstCount); } /* uint32 fx_run_to_breakpoint (uint32 nInstructions) { uint32 vCounter = 0; while (TF(G) && vCounter < nInstructions) { vCounter++; FX_STEP; if (USEX16(R15) == GSU.vBreakPoint) { GSU.vErrorCode = FX_BREAKPOINT; break; } } #if 0 #ifndef FX_ADDRESS_CHECK GSU.vPipeAdr = USEX16(R15 - 1) | (USEX8(GSU.vPrgBankReg) << 16); #endif #endif return (vCounter); } */ /* uint32 fx_step_over (uint32 nInstructions) { uint32 vCounter = 0; while (TF(G) && vCounter < nInstructions) { vCounter++; FX_STEP; if (USEX16(R15) == GSU.vBreakPoint) { GSU.vErrorCode = FX_BREAKPOINT; break; } if (USEX16(R15) == GSU.vStepPoint) break; } #if 0 #ifndef FX_ADDRESS_CHECK GSU.vPipeAdr = USEX16(R15 - 1) | (USEX8(GSU.vPrgBankReg) << 16); #endif #endif return (vCounter); } */ // Special table for the different plot configurations void (*fx_PlotTable[]) (void) = { &fx_plot_2bit, &fx_plot_4bit, &fx_plot_4bit, &fx_plot_8bit, &fx_plot_obj, &fx_rpix_2bit, &fx_rpix_4bit, &fx_rpix_4bit, &fx_rpix_8bit, &fx_rpix_obj }; // Opcode table void (*fx_OpcodeTable[]) (void) = { // ALT0 Table // 00 - 0f &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, // 10 - 1f &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, // 20 - 2f &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, // 30 - 3f &fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7, &fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, // 40 - 4f &fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7, &fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit, &fx_swap, &fx_color, &fx_not, // 50 - 5f &fx_add_r0, &fx_add_r1, &fx_add_r2, &fx_add_r3, &fx_add_r4, &fx_add_r5, &fx_add_r6, &fx_add_r7, &fx_add_r8, &fx_add_r9, &fx_add_r10, &fx_add_r11, &fx_add_r12, &fx_add_r13, &fx_add_r14, &fx_add_r15, // 60 - 6f &fx_sub_r0, &fx_sub_r1, &fx_sub_r2, &fx_sub_r3, &fx_sub_r4, &fx_sub_r5, &fx_sub_r6, &fx_sub_r7, &fx_sub_r8, &fx_sub_r9, &fx_sub_r10, &fx_sub_r11, &fx_sub_r12, &fx_sub_r13, &fx_sub_r14, &fx_sub_r15, // 70 - 7f &fx_merge, &fx_and_r1, &fx_and_r2, &fx_and_r3, &fx_and_r4, &fx_and_r5, &fx_and_r6, &fx_and_r7, &fx_and_r8, &fx_and_r9, &fx_and_r10, &fx_and_r11, &fx_and_r12, &fx_and_r13, &fx_and_r14, &fx_and_r15, // 80 - 8f &fx_mult_r0, &fx_mult_r1, &fx_mult_r2, &fx_mult_r3, &fx_mult_r4, &fx_mult_r5, &fx_mult_r6, &fx_mult_r7, &fx_mult_r8, &fx_mult_r9, &fx_mult_r10, &fx_mult_r11, &fx_mult_r12, &fx_mult_r13, &fx_mult_r14, &fx_mult_r15, // 90 - 9f &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror, &fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult, // a0 - af &fx_ibt_r0, &fx_ibt_r1, &fx_ibt_r2, &fx_ibt_r3, &fx_ibt_r4, &fx_ibt_r5, &fx_ibt_r6, &fx_ibt_r7, &fx_ibt_r8, &fx_ibt_r9, &fx_ibt_r10, &fx_ibt_r11, &fx_ibt_r12, &fx_ibt_r13, &fx_ibt_r14, &fx_ibt_r15, // b0 - bf &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, // c0 - cf &fx_hib, &fx_or_r1, &fx_or_r2, &fx_or_r3, &fx_or_r4, &fx_or_r5, &fx_or_r6, &fx_or_r7, &fx_or_r8, &fx_or_r9, &fx_or_r10, &fx_or_r11, &fx_or_r12, &fx_or_r13, &fx_or_r14, &fx_or_r15, // d0 - df &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc, // e0 - ef &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getb, // f0 - ff &fx_iwt_r0, &fx_iwt_r1, &fx_iwt_r2, &fx_iwt_r3, &fx_iwt_r4, &fx_iwt_r5, &fx_iwt_r6, &fx_iwt_r7, &fx_iwt_r8, &fx_iwt_r9, &fx_iwt_r10, &fx_iwt_r11, &fx_iwt_r12, &fx_iwt_r13, &fx_iwt_r14, &fx_iwt_r15, // ALT1 Table // 00 - 0f &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, // 10 - 1f &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, // 20 - 2f &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, // 30 - 3f &fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7, &fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, // 40 - 4f &fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7, &fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit, &fx_swap, &fx_cmode, &fx_not, // 50 - 5f &fx_adc_r0, &fx_adc_r1, &fx_adc_r2, &fx_adc_r3, &fx_adc_r4, &fx_adc_r5, &fx_adc_r6, &fx_adc_r7, &fx_adc_r8, &fx_adc_r9, &fx_adc_r10, &fx_adc_r11, &fx_adc_r12, &fx_adc_r13, &fx_adc_r14, &fx_adc_r15, // 60 - 6f &fx_sbc_r0, &fx_sbc_r1, &fx_sbc_r2, &fx_sbc_r3, &fx_sbc_r4, &fx_sbc_r5, &fx_sbc_r6, &fx_sbc_r7, &fx_sbc_r8, &fx_sbc_r9, &fx_sbc_r10, &fx_sbc_r11, &fx_sbc_r12, &fx_sbc_r13, &fx_sbc_r14, &fx_sbc_r15, // 70 - 7f &fx_merge, &fx_bic_r1, &fx_bic_r2, &fx_bic_r3, &fx_bic_r4, &fx_bic_r5, &fx_bic_r6, &fx_bic_r7, &fx_bic_r8, &fx_bic_r9, &fx_bic_r10, &fx_bic_r11, &fx_bic_r12, &fx_bic_r13, &fx_bic_r14, &fx_bic_r15, // 80 - 8f &fx_umult_r0, &fx_umult_r1, &fx_umult_r2, &fx_umult_r3, &fx_umult_r4, &fx_umult_r5, &fx_umult_r6, &fx_umult_r7, &fx_umult_r8, &fx_umult_r9, &fx_umult_r10, &fx_umult_r11, &fx_umult_r12, &fx_umult_r13, &fx_umult_r14, &fx_umult_r15, // 90 - 9f &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_div2, &fx_ror, &fx_ljmp_r8, &fx_ljmp_r9, &fx_ljmp_r10, &fx_ljmp_r11, &fx_ljmp_r12, &fx_ljmp_r13, &fx_lob, &fx_lmult, // a0 - af &fx_lms_r0, &fx_lms_r1, &fx_lms_r2, &fx_lms_r3, &fx_lms_r4, &fx_lms_r5, &fx_lms_r6, &fx_lms_r7, &fx_lms_r8, &fx_lms_r9, &fx_lms_r10, &fx_lms_r11, &fx_lms_r12, &fx_lms_r13, &fx_lms_r14, &fx_lms_r15, // b0 - bf &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, // c0 - cf &fx_hib, &fx_xor_r1, &fx_xor_r2, &fx_xor_r3, &fx_xor_r4, &fx_xor_r5, &fx_xor_r6, &fx_xor_r7, &fx_xor_r8, &fx_xor_r9, &fx_xor_r10, &fx_xor_r11, &fx_xor_r12, &fx_xor_r13, &fx_xor_r14, &fx_xor_r15, // d0 - df &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc, // e0 - ef &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbh, // f0 - ff &fx_lm_r0, &fx_lm_r1, &fx_lm_r2, &fx_lm_r3, &fx_lm_r4, &fx_lm_r5, &fx_lm_r6, &fx_lm_r7, &fx_lm_r8, &fx_lm_r9, &fx_lm_r10, &fx_lm_r11, &fx_lm_r12, &fx_lm_r13, &fx_lm_r14, &fx_lm_r15, // ALT2 Table // 00 - 0f &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, // 10 - 1f &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, // 20 - 2f &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, // 30 - 3f &fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7, &fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, // 40 - 4f &fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7, &fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit, &fx_swap, &fx_color, &fx_not, // 50 - 5f &fx_add_i0, &fx_add_i1, &fx_add_i2, &fx_add_i3, &fx_add_i4, &fx_add_i5, &fx_add_i6, &fx_add_i7, &fx_add_i8, &fx_add_i9, &fx_add_i10, &fx_add_i11, &fx_add_i12, &fx_add_i13, &fx_add_i14, &fx_add_i15, // 60 - 6f &fx_sub_i0, &fx_sub_i1, &fx_sub_i2, &fx_sub_i3, &fx_sub_i4, &fx_sub_i5, &fx_sub_i6, &fx_sub_i7, &fx_sub_i8, &fx_sub_i9, &fx_sub_i10, &fx_sub_i11, &fx_sub_i12, &fx_sub_i13, &fx_sub_i14, &fx_sub_i15, // 70 - 7f &fx_merge, &fx_and_i1, &fx_and_i2, &fx_and_i3, &fx_and_i4, &fx_and_i5, &fx_and_i6, &fx_and_i7, &fx_and_i8, &fx_and_i9, &fx_and_i10, &fx_and_i11, &fx_and_i12, &fx_and_i13, &fx_and_i14, &fx_and_i15, // 80 - 8f &fx_mult_i0, &fx_mult_i1, &fx_mult_i2, &fx_mult_i3, &fx_mult_i4, &fx_mult_i5, &fx_mult_i6, &fx_mult_i7, &fx_mult_i8, &fx_mult_i9, &fx_mult_i10, &fx_mult_i11, &fx_mult_i12, &fx_mult_i13, &fx_mult_i14, &fx_mult_i15, // 90 - 9f &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror, &fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult, // a0 - af &fx_sms_r0, &fx_sms_r1, &fx_sms_r2, &fx_sms_r3, &fx_sms_r4, &fx_sms_r5, &fx_sms_r6, &fx_sms_r7, &fx_sms_r8, &fx_sms_r9, &fx_sms_r10, &fx_sms_r11, &fx_sms_r12, &fx_sms_r13, &fx_sms_r14, &fx_sms_r15, // b0 - bf &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, // c0 - cf &fx_hib, &fx_or_i1, &fx_or_i2, &fx_or_i3, &fx_or_i4, &fx_or_i5, &fx_or_i6, &fx_or_i7, &fx_or_i8, &fx_or_i9, &fx_or_i10, &fx_or_i11, &fx_or_i12, &fx_or_i13, &fx_or_i14, &fx_or_i15, // d0 - df &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_ramb, // e0 - ef &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbl, // f0 - ff &fx_sm_r0, &fx_sm_r1, &fx_sm_r2, &fx_sm_r3, &fx_sm_r4, &fx_sm_r5, &fx_sm_r6, &fx_sm_r7, &fx_sm_r8, &fx_sm_r9, &fx_sm_r10, &fx_sm_r11, &fx_sm_r12, &fx_sm_r13, &fx_sm_r14, &fx_sm_r15, // ALT3 Table // 00 - 0f &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, // 10 - 1f &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, // 20 - 2f &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, // 30 - 3f &fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7, &fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, // 40 - 4f &fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7, &fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit, &fx_swap, &fx_cmode, &fx_not, // 50 - 5f &fx_adc_i0, &fx_adc_i1, &fx_adc_i2, &fx_adc_i3, &fx_adc_i4, &fx_adc_i5, &fx_adc_i6, &fx_adc_i7, &fx_adc_i8, &fx_adc_i9, &fx_adc_i10, &fx_adc_i11, &fx_adc_i12, &fx_adc_i13, &fx_adc_i14, &fx_adc_i15, // 60 - 6f &fx_cmp_r0, &fx_cmp_r1, &fx_cmp_r2, &fx_cmp_r3, &fx_cmp_r4, &fx_cmp_r5, &fx_cmp_r6, &fx_cmp_r7, &fx_cmp_r8, &fx_cmp_r9, &fx_cmp_r10, &fx_cmp_r11, &fx_cmp_r12, &fx_cmp_r13, &fx_cmp_r14, &fx_cmp_r15, // 70 - 7f &fx_merge, &fx_bic_i1, &fx_bic_i2, &fx_bic_i3, &fx_bic_i4, &fx_bic_i5, &fx_bic_i6, &fx_bic_i7, &fx_bic_i8, &fx_bic_i9, &fx_bic_i10, &fx_bic_i11, &fx_bic_i12, &fx_bic_i13, &fx_bic_i14, &fx_bic_i15, // 80 - 8f &fx_umult_i0, &fx_umult_i1, &fx_umult_i2, &fx_umult_i3, &fx_umult_i4, &fx_umult_i5, &fx_umult_i6, &fx_umult_i7, &fx_umult_i8, &fx_umult_i9, &fx_umult_i10, &fx_umult_i11, &fx_umult_i12, &fx_umult_i13, &fx_umult_i14, &fx_umult_i15, // 90 - 9f &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_div2, &fx_ror, &fx_ljmp_r8, &fx_ljmp_r9, &fx_ljmp_r10, &fx_ljmp_r11, &fx_ljmp_r12, &fx_ljmp_r13, &fx_lob, &fx_lmult, // a0 - af &fx_lms_r0, &fx_lms_r1, &fx_lms_r2, &fx_lms_r3, &fx_lms_r4, &fx_lms_r5, &fx_lms_r6, &fx_lms_r7, &fx_lms_r8, &fx_lms_r9, &fx_lms_r10, &fx_lms_r11, &fx_lms_r12, &fx_lms_r13, &fx_lms_r14, &fx_lms_r15, // b0 - bf &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, // c0 - cf &fx_hib, &fx_xor_i1, &fx_xor_i2, &fx_xor_i3, &fx_xor_i4, &fx_xor_i5, &fx_xor_i6, &fx_xor_i7, &fx_xor_i8, &fx_xor_i9, &fx_xor_i10, &fx_xor_i11, &fx_xor_i12, &fx_xor_i13, &fx_xor_i14, &fx_xor_i15, // d0 - df &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_romb, // e0 - ef &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbs, // f0 - ff &fx_lm_r0, &fx_lm_r1, &fx_lm_r2, &fx_lm_r3, &fx_lm_r4, &fx_lm_r5, &fx_lm_r6, &fx_lm_r7, &fx_lm_r8, &fx_lm_r9, &fx_lm_r10, &fx_lm_r11, &fx_lm_r12, &fx_lm_r13, &fx_lm_r14, &fx_lm_r15 }; statemanager.h000664 001750 001750 00000001315 12720446475 014541 0ustar00sergiosergio000000 000000 #ifndef STATEMANAGER_H #define STATEMANAGER_H /* State Manager Class that records snapshot data for rewinding mostly based on SSNES's rewind code by Themaister */ #include "snes9x.h" class StateManager { private: uint64_t *buffer; size_t buf_size; size_t buf_size_mask; uint32_t *tmp_state; uint32_t *in_state; size_t top_ptr; size_t bottom_ptr; size_t state_size; size_t real_state_size; bool init_done; bool first_pop; void reassign_bottom(); void generate_delta(const void *data); void deallocate(); public: StateManager(); ~StateManager(); bool init(size_t buffer_size); int pop(); bool push(); }; #endif // STATEMANAGER_H stream.h000664 001750 001750 00000021574 12720446475 013372 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _STREAM_H_ #define _STREAM_H_ #include class Stream { public: Stream (void); virtual ~Stream (void); virtual int get_char (void) = 0; virtual char * gets (char *, size_t) = 0; virtual char * getline (void); // free() when done virtual std::string getline (bool &); virtual size_t read (void *, size_t) = 0; virtual size_t write (void *, size_t) = 0; virtual size_t pos (void) = 0; virtual size_t size (void) = 0; virtual int revert (size_t from, size_t offset) = 0; virtual void closeStream() = 0; }; class fStream : public Stream { public: fStream (FSTREAM); virtual ~fStream (void); virtual int get_char (void); virtual char * gets (char *, size_t); virtual size_t read (void *, size_t); virtual size_t write (void *, size_t); virtual size_t pos (void); virtual size_t size (void); virtual int revert (size_t from, size_t offset); virtual void closeStream(); private: FSTREAM fp; }; #ifdef UNZIP_SUPPORT #include "unzip.h" #define unz_BUFFSIZ 1024 class unzStream : public Stream { public: unzStream (unzFile &); virtual ~unzStream (void); virtual int get_char (void); virtual char * gets (char *, size_t); virtual size_t read (void *, size_t); virtual size_t write (void *, size_t); virtual size_t pos (void); virtual size_t size (void); virtual int revert (size_t from, size_t offset); virtual void closeStream(); private: unzFile file; char buffer[unz_BUFFSIZ]; char *head; size_t numbytes; }; #endif class memStream : public Stream { public: memStream (uint8 *,size_t); memStream (const uint8 *,size_t); virtual ~memStream (void); virtual int get_char (void); virtual char * gets (char *, size_t); virtual size_t read (void *, size_t); virtual size_t write (void *, size_t); virtual size_t pos (void); virtual size_t size (void); virtual int revert (size_t from, size_t offset); virtual void closeStream(); private: uint8 *mem; size_t msize; size_t remaining; uint8 *head; bool readonly; }; /* dummy stream that always reads 0 and writes nowhere but counts bytes written */ class nulStream : public Stream { public: nulStream (void); virtual ~nulStream (void); virtual int get_char (void); virtual char * gets (char *, size_t); virtual size_t read (void *, size_t); virtual size_t write (void *, size_t); virtual size_t pos (void); virtual size_t size (void); virtual int revert (size_t from, size_t offset); virtual void closeStream(); private: size_t bytes_written; }; Stream *openStreamFromFSTREAM(const char* filename, const char* mode); Stream *reopenStreamFromFd(int fd, const char* mode); #endif conffile.h000664 001750 001750 00000035351 12720446475 013662 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CONFIG_H_ #define _CONFIG_H_ #include #include #include #include #ifdef UNZIP_SUPPORT #include "unzip/unzip.h" #endif #include "snes9x.h" #ifndef MAX # define MAX(a,b) ((a) > (b)? (a) : (b)) # define MIN(a,b) ((a) < (b)? (a) : (b)) #endif class ConfigFile { public: ConfigFile(void); void Clear(void); // return false on failure bool LoadFile(const char *filename); void LoadFile(Stream *r, const char *name=NULL); // return false if key does not exist or is empty bool Exists(const char *key); // return the value / default std::string GetString(const char *key, std::string def); char *GetString(const char *key, char *out, uint32 outlen); // return NULL if it doesn't exist, out not affected const char *GetString(const char *key, const char *def=NULL); // NOTE: returned pointer becomes invalid when key is deleted/modified, or the ConfigFile is Clear()ed or deleted. char *GetStringDup(const char *key, const char *def=NULL); // Much like "strdup(GetString(key, def))" int32 GetInt(const char *key, int32 def=-1, bool *bad=NULL); uint32 GetUInt(const char *key, uint32 def=0, int base=0, bool *bad=NULL); // base = 0, 8, 10, or 16 bool GetBool(const char *key, bool def=false, bool *bad=NULL); const char* GetComment(const char *key); // NOTE: returned pointer becomes invalid when key is deleted/modified, or the ConfigFile is Clear()ed or deleted. // return true if the key existed prior to setting bool SetString(const char *key, std::string val, const char *comment=""); bool SetInt(const char *key, int32 val, const char *comment=""); bool SetUInt(const char *key, uint32 val, int base=10, const char *comment=""); // base = 8, 10, or 16 bool SetBool(const char *key, bool val, const char *true_val="TRUE", const char *false_val="FALSE", const char *comment=""); bool DeleteKey(const char *key); // Operation on entire sections bool DeleteSection(const char *section); typedef std::vector > secvec_t; secvec_t GetSection(const char *section); int GetSectionSize(const std::string section); // Clears all key-value pairs that didn't receive a Set command, or a Get command with autoAdd on void ClearUnused(void); // Clears all stored line numbers void ClearLines(void); bool SaveTo(const char *filename); static void SetDefaultAutoAdd(bool autoAdd); static void SetNiceAlignment(bool align); static void SetShowComments(bool show); static void SetAlphaSort(bool sort); static void SetTimeSort(bool sort); private: std::string Get(const char *key); bool Has(const char *key); class ConfigEntry { protected: int line; std::string section; std::string key; std::string val; std::string comment; mutable bool used; struct section_then_key_less { bool operator()(const ConfigEntry &a, const ConfigEntry &b); }; struct key_less { bool operator()(const ConfigEntry &a, const ConfigEntry &b) const{ if(a.section!=b.section) return a.section0) s.erase(0, i); // erase leading whitespace i=s.find_last_not_of(" \f\n\r\t\v"); if(i!=-1) s.erase(i+1); // erase trailing whitespace return; } // trims comments and leading/trailing whitespace from s, and returns any trimmed comments // make sure not to call this more than once on the same string static std::string trimCommented(std::string &s){ std::string cmt; int i; i=s.find_first_not_of(" \f\n\r\t\v"); if(i==-1){ s.clear(); return cmt; } if(i>0) s.erase(0, i); // erase leading whitespace int off=0; for(;;){ i=s.find('#',off); // find trailing comment if(i>=0) { if((int)s.length()>i+1 && s.at(i+1) == '#') { s.erase(i,1); // ignore ## and change to # off = i+1; continue; } else { int j=s.find_first_not_of(" \f\n\r\t\v",i+1); if(j!=-1) cmt = s.substr(j); // store s.erase(i); // erase trailing comment } } break; } i=s.find_last_not_of(" \f\n\r\t\v"); if(i!=-1) s.erase(i+1); // erase trailing whitespace return cmt; } public: ConfigEntry(int l, const std::string &s, const std::string &k, const std::string &v) : line(l), section(s), key(k), val(v) { trim(section); trim(key); used=false; } void parse_key(const std::string &k){ int i=k.find("::"); if(i==-1){ section="Uncategorized"; key=k; } else { section=k.substr(0,i); key=k.substr(i+2); } trim(section); trim(key); used=false; } ConfigEntry(const std::string k){ parse_key(k); } ConfigEntry(const std::string k, const std::string &v) : line(-1), val(v) { parse_key(k); } friend class ConfigFile; friend struct key_less; friend struct line_less; }; class SectionSizes { protected: std::map sections; public: uint32 GetSectionSize(const std::string section) { uint32 count=0; uint32 seclen; std::map::iterator it; for(it=sections.begin(); it!=sections.end(); it++) { seclen = MIN(section.size(),it->first.size()); if(it->first==section || !section.compare(0,seclen,it->first,0,seclen)) count+=it->second; } return count; } void IncreaseSectionSize(const std::string section) { std::map::iterator it=sections.find(section); if(it!=sections.end()) it->second++; else sections.insert(std::pair(section,1)); } void DecreaseSectionSize(const std::string section) { std::map::iterator it=sections.find(section); if(it!=sections.end()) it->second--; } void ClearSections() { sections.clear(); } void DeleteSection(const std::string section) { sections.erase(section); } }; std::set data; SectionSizes sectionSizes; int linectr; static bool defaultAutoAdd; static bool niceAlignment; static bool showComments; static bool alphaSort; static bool timeSort; }; /* Config file format: * * Comments are any lines whose first non-whitespace character is ';' or '#'. * Note that comments can also follow a value, on the same line. * To intentionally have a '#' character in the value, use ## * * All parameters fall into sections. To name a section, the first * non-whitespace character on the line will be '[', and the last will be ']'. * * Parameters are simple key=value pairs. Whitespace around the '=', and at the * beginning or end of the line is ignored. Key names may not contain '=' nor * begin with '[', however values can. If the last character of the value is * '\', the next line (sans leading/trailing whitespace) is considered part of * the value as well. Programmatically, the key "K" in section "S" is referred * to as "S::K", much like C++ namespaces. For example: * [Section1] * # this is a comment * foo = bar \ * baz\ * quux \ * ## this is not a comment! # this IS a comment * means the value of "Section1::foo" is "bar bazquux # this is not a comment!" * * Parameters may be of several types: * String - Bare characters. If the first and last characters are both '"', * they are removed (so just double them if you really want quotes * there) * Int - A decimal number from -2147483648 to 2147483647 * UInt - A number in decimal, hex, or octal from 0 to 4294967295 (or * 0xffffffff, or 037777777777) * Bool - true/false, 0/1, on/off, yes/no * * Of course, the actual accepted values for a parameter may be further * restricted ;) */ /* You must write this for your port */ void S9xParsePortConfig(ConfigFile &, int pass); /* This may or may not be useful to you */ const char *S9xParseDisplayConfig(ConfigFile &, int pass); #endif cpuexec.h000664 001750 001750 00000021773 12720446475 013534 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CPUEXEC_H_ #define _CPUEXEC_H_ #include "ppu.h" #ifdef DEBUGGER #include "debug.h" #endif struct SOpcodes { void (*S9xOpcode) (void); }; struct SICPU { struct SOpcodes *S9xOpcodes; uint8 *S9xOpLengths; uint8 _Carry; uint8 _Zero; uint8 _Negative; uint8 _Overflow; uint32 ShiftedPB; uint32 ShiftedDB; uint32 Frame; uint32 FrameAdvanceCount; }; extern struct SICPU ICPU; extern struct SOpcodes S9xOpcodesE1[256]; extern struct SOpcodes S9xOpcodesM1X1[256]; extern struct SOpcodes S9xOpcodesM1X0[256]; extern struct SOpcodes S9xOpcodesM0X1[256]; extern struct SOpcodes S9xOpcodesM0X0[256]; extern struct SOpcodes S9xOpcodesSlow[256]; extern uint8 S9xOpLengthsM1X1[256]; extern uint8 S9xOpLengthsM1X0[256]; extern uint8 S9xOpLengthsM0X1[256]; extern uint8 S9xOpLengthsM0X0[256]; void S9xMainLoop (void); void S9xReset (void); void S9xSoftReset (void); void S9xDoHEventProcessing (void); static inline void S9xUnpackStatus (void) { ICPU._Zero = (Registers.PL & Zero) == 0; ICPU._Negative = (Registers.PL & Negative); ICPU._Carry = (Registers.PL & Carry); ICPU._Overflow = (Registers.PL & Overflow) >> 6; } static inline void S9xPackStatus (void) { Registers.PL &= ~(Zero | Negative | Carry | Overflow); Registers.PL |= ICPU._Carry | ((ICPU._Zero == 0) << 1) | (ICPU._Negative & 0x80) | (ICPU._Overflow << 6); } static inline void S9xFixCycles (void) { if (CheckEmulation()) { ICPU.S9xOpcodes = S9xOpcodesE1; ICPU.S9xOpLengths = S9xOpLengthsM1X1; } else if (CheckMemory()) { if (CheckIndex()) { ICPU.S9xOpcodes = S9xOpcodesM1X1; ICPU.S9xOpLengths = S9xOpLengthsM1X1; } else { ICPU.S9xOpcodes = S9xOpcodesM1X0; ICPU.S9xOpLengths = S9xOpLengthsM1X0; } } else { if (CheckIndex()) { ICPU.S9xOpcodes = S9xOpcodesM0X1; ICPU.S9xOpLengths = S9xOpLengthsM0X1; } else { ICPU.S9xOpcodes = S9xOpcodesM0X0; ICPU.S9xOpLengths = S9xOpLengthsM0X0; } } } static inline void S9xCheckInterrupts (void) { bool8 thisIRQ = PPU.HTimerEnabled || PPU.VTimerEnabled; if (CPU.IRQLine && thisIRQ) CPU.IRQTransition = TRUE; if (PPU.HTimerEnabled) { int32 htimepos = PPU.HTimerPosition; if (CPU.Cycles >= Timings.H_Max && htimepos < CPU.PrevCycles) htimepos += Timings.H_Max; if (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos) thisIRQ = FALSE; } if (PPU.VTimerEnabled) { int32 vcounter = CPU.V_Counter; if (CPU.Cycles >= Timings.H_Max && (!PPU.HTimerEnabled || PPU.HTimerPosition < CPU.PrevCycles)) { vcounter++; if(vcounter >= Timings.V_Max) vcounter = 0; } if (vcounter != PPU.VTimerPosition) thisIRQ = FALSE; } if (!CPU.IRQLastState && thisIRQ) { #ifdef DEBUGGER S9xTraceFormattedMessage("--- /IRQ High->Low prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d", CPU.PrevCycles, CPU.Cycles, PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); #endif CPU.IRQLine = TRUE; } CPU.IRQLastState = thisIRQ; } #endif apu/bapu/smp/memory.cpp000664 001750 001750 00000004334 12720446475 016250 0ustar00sergiosergio000000 000000 unsigned SMP::port_read(unsigned addr) { return apuram[0xf4 + (addr & 3)]; } void SMP::port_write(unsigned addr, unsigned data) { apuram[0xf4 + (addr & 3)] = data; } unsigned SMP::mmio_read(unsigned addr) { switch(addr) { case 0xf2: return status.dsp_addr; case 0xf3: return dsp.read(status.dsp_addr & 0x7f); case 0xf4: case 0xf5: case 0xf6: case 0xf7: synchronize_cpu(); return cpu.port_read(addr); case 0xf8: return status.ram00f8; case 0xf9: return status.ram00f9; case 0xfd: { unsigned result = timer0.stage3_ticks & 15; timer0.stage3_ticks = 0; return result; } case 0xfe: { unsigned result = timer1.stage3_ticks & 15; timer1.stage3_ticks = 0; return result; } case 0xff: { unsigned result = timer2.stage3_ticks & 15; timer2.stage3_ticks = 0; return result; } } return 0x00; } void SMP::mmio_write(unsigned addr, unsigned data) { switch(addr) { case 0xf1: status.iplrom_enable = data & 0x80; if(data & 0x30) { synchronize_cpu(); if(data & 0x20) { cpu.port_write(3, 0x00); cpu.port_write(2, 0x00); } if(data & 0x10) { cpu.port_write(1, 0x00); cpu.port_write(0, 0x00); } } if(timer2.enable == false && (data & 0x04)) { timer2.stage2_ticks = 0; timer2.stage3_ticks = 0; } timer2.enable = data & 0x04; if(timer1.enable == false && (data & 0x02)) { timer1.stage2_ticks = 0; timer1.stage3_ticks = 0; } timer1.enable = data & 0x02; if(timer0.enable == false && (data & 0x01)) { timer0.stage2_ticks = 0; timer0.stage3_ticks = 0; } timer0.enable = data & 0x01; break; case 0xf2: status.dsp_addr = data; break; case 0xf3: if(status.dsp_addr & 0x80) break; dsp.write(status.dsp_addr, data); break; case 0xf4: case 0xf5: case 0xf6: case 0xf7: synchronize_cpu(); port_write(addr, data); break; case 0xf8: status.ram00f8 = data; break; case 0xf9: status.ram00f9 = data; break; case 0xfa: timer0.target = data; break; case 0xfb: timer1.target = data; break; case 0xfc: timer2.target = data; break; } } docs/snes9x.conf.default000664 001750 001750 00000012432 12720446475 016372 0ustar00sergiosergio000000 000000 #----------------------------------------- # snes9x.conf : Snes9x Configuration file #----------------------------------------- [ROM] # Filename = LoROM = FALSE HiROM = FALSE PAL = FALSE NTSC = FALSE # Header = TRUE/FALSE to ForceHeader or ForceNoHeader # Interleaved = TRUE/FALSE to ForceInterleaved or ForceNoInterleaved Interleaved2 = FALSE InterleaveGD24 = FALSE Cheat = FALSE Patch = TRUE [Sound] Sync = FALSE 16BitSound = TRUE Stereo = TRUE ReverseStereo = FALSE Rate = 32000 InputRate = 32000 Mute = FALSE [Display] HiRes = TRUE Transparency = TRUE GraphicWindows = TRUE DisplayFrameRate = FALSE DisplayWatchedAddresses = FALSE DisplayInput = FALSE DisplayFrameCount = FALSE MessagesInImage = TRUE MessageDisplayTime = 120 [Settings] BSXBootup = FALSE # FrameTime = FrameSkip = Auto TurboMode = FALSE TurboFrameSkip = 15 MovieTruncateAtEnd = FALSE MovieNotifyIgnored = FALSE WrongMovieStateProtection = TRUE StretchScreenshots = 1 SnapshotScreenshots = TRUE DontSaveOopsSnapshot = FALSE AutoSaveDelay = 0 [Controls] MouseMaster = TRUE SuperscopeMaster = TRUE JustifierMaster = TRUE MP5Master = TRUE AllowLeftRight = FALSE Port1 = pad1 Port2 = none Mouse1Crosshair = 1 White/Black Mouse2Crosshair = 1 White/Black SuperscopeCrosshair = 2 White/Black Justifier1Crosshair = 4 Blue/Black Justifier2Crosshair = 4 MagicPink/Black [Hack] EnableGameSpecificHacks = TRUE AllowInvalidVRAMAccess = FALSE SpeedHacks = FALSE HDMATiming = 100 [Netplay] Enable = FALSE Port = 6096 Server = "" [DEBUG] Debugger = FALSE Trace = FALSE [Unix] # BaseDir = ~/.snes9x # SnapshotFilename = # PlayMovieFilename = # RecordMovieFilename = EnableGamePad = TRUE PadDevice1 = (null) PadDevice2 = (null) PadDevice3 = (null) PadDevice4 = (null) PadDevice5 = (null) PadDevice6 = (null) PadDevice7 = (null) PadDevice8 = (null) ThreadSound = FALSE SoundBufferSize = 100 SoundFragmentSize = 2048 # SoundDevice = ClearAllControls = FALSE [Unix/X11] SetKeyRepeat = TRUE VideoMode = 1 [Unix/X11 Controls] J00:Axis1 = Joypad1 Axis Up/Down T=50% J00:Axis0 = Joypad1 Axis Left/Right T=50% J00:B1 = Joypad1 A J00:B2 = Joypad1 B J00:B0 = Joypad1 X J00:B3 = Joypad1 Y J00:B6 = Joypad1 L J00:B7 = Joypad1 R J00:B8 = Joypad1 Select J00:B11 = Joypad1 Start K00:u = Joypad1 Up K00:Up = Joypad1 Up K00:j = Joypad1 Down K00:n = Joypad1 Down K00:Down = Joypad1 Down K00:h = Joypad1 Left K00:Left = Joypad1 Left K00:k = Joypad1 Right K00:Right = Joypad1 Right K00:d = Joypad1 A K00:S+d = Joypad1 ToggleTurbo A K00:C+d = Joypad1 ToggleSticky A K00:c = Joypad1 B K00:S+c = Joypad1 ToggleTurbo B K00:C+c = Joypad1 ToggleSticky B K00:s = Joypad1 X K00:S+s = Joypad1 ToggleTurbo X K00:C+s = Joypad1 ToggleSticky X K00:x = Joypad1 Y K00:S+x = Joypad1 ToggleTurbo Y K00:C+x = Joypad1 ToggleSticky Y K00:a = Joypad1 L K00:v = Joypad1 L K00:S+a = Joypad1 ToggleTurbo L K00:S+v = Joypad1 ToggleTurbo L K00:C+a = Joypad1 ToggleSticky L K00:C+v = Joypad1 ToggleSticky L K00:z = Joypad1 R K00:S+z = Joypad1 ToggleTurbo R K00:C+z = Joypad1 ToggleSticky R K00:space = Joypad1 Select K00:Return = Joypad1 Start K00:KP_Up = Joypad2 Up K00:KP_Down = Joypad2 Down K00:KP_Left = Joypad2 Left K00:KP_Right = Joypad2 Right K00:Prior = Joypad2 A K00:Next = Joypad2 B K00:Home = Joypad2 X K00:End = Joypad2 Y K00:Insert = Joypad2 L K00:Delete = Joypad2 R K00:KP_Add = Joypad2 Select K00:KP_Enter = Joypad2 Start K00:Escape = ExitEmu K00:Pause = Pause K00:Scroll_Lock = Pause K00:CS+Escape = Reset K00:S+Escape = SoftReset K00:F12 = SaveFreezeFile K00:A+F3 = SaveFreezeFile K00:C+F3 = SaveFreezeFile K00:F11 = LoadFreezeFile K00:A+F2 = LoadFreezeFile K00:C+F2 = LoadFreezeFile K00:S+F1 = QuickSave000 K00:S+F2 = QuickSave001 K00:S+F3 = QuickSave002 K00:S+F4 = QuickSave003 K00:S+F5 = QuickSave004 K00:S+F6 = QuickSave005 K00:S+F7 = QuickSave006 K00:S+F8 = QuickSave007 K00:S+F9 = QuickSave008 K00:F1 = QuickLoad000 K00:F2 = QuickLoad001 K00:F3 = QuickLoad002 K00:F4 = QuickLoad003 K00:F5 = QuickLoad004 K00:F6 = QuickLoad005 K00:F7 = QuickLoad006 K00:F8 = QuickLoad007 K00:F9 = QuickLoad008 K00:F10 = LoadOopsFile K00:A+F1 = SaveSPC K00:C+F1 = SaveSPC K00:Print = Screenshot K00:S+1 = BeginRecordingMovie K00:S+2 = EndRecordingMovie K00:S+3 = LoadMovie K00:Tab = EmuTurbo K00:S+Tab = ToggleEmuTurbo K00:equal = IncFrameRate K00:minus = DecFrameRate K00:S+equal = IncFrameTime K00:S+minus = DecFrameTime K00:A+equal = IncEmuTurbo K00:A+minus = DecEmuTurbo K00:C+equal = IncTurboSpeed K00:C+minus = DecTurboSpeed K00:6 = SwapJoypads K00:A+F4 = SoundChannel0 K00:C+F4 = SoundChannel0 K00:A+F5 = SoundChannel1 K00:C+F5 = SoundChannel1 K00:A+F6 = SoundChannel2 K00:C+F6 = SoundChannel2 K00:A+F7 = SoundChannel3 K00:C+F7 = SoundChannel3 K00:A+F8 = SoundChannel4 K00:C+F8 = SoundChannel4 K00:A+F9 = SoundChannel5 K00:C+F9 = SoundChannel5 K00:A+F10 = SoundChannel6 K00:C+F10 = SoundChannel6 K00:A+F11 = SoundChannel7 K00:C+F11 = SoundChannel7 K00:A+F12 = SoundChannelsOn K00:C+F12 = SoundChannelsOn K00:1 = ToggleBG0 K00:2 = ToggleBG1 K00:3 = ToggleBG2 K00:4 = ToggleBG3 K00:5 = ToggleSprites K00:9 = ToggleTransparency K00:BackSpace = ClipWindows K00:A+Escape = Debugger M00:Pointer = Pointer Mouse1+Superscope+Justifier1 M00:B0 = {Mouse1 L,Superscope Fire,Justifier1 Trigger} M00:B2 = {Mouse1 R,Superscope Cursor,Justifier1 Start} M00:B1 = {Justifier1 AimOffscreen Trigger,Superscope AimOffscreen} K00:grave = Superscope ToggleTurbo K00:slash = Superscope Pause bsx.h000664 001750 001750 00000015561 12720446475 012672 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _BSX_H_ #define _BSX_H_ struct SBSX { bool8 dirty; // Changed register values bool8 dirty2; // Changed register values bool8 bootup; // Start in bios mapping bool8 flash_enable; // Flash state bool8 write_enable; // ROM write protection bool8 read_enable; // Allow card vendor reading uint32 flash_command; // Flash command uint32 old_write; // Previous flash write address uint32 new_write; // Current flash write address uint8 out_index; uint8 output[32]; uint8 PPU[32]; uint8 MMC[16]; uint8 prevMMC[16]; uint8 test2192[32]; }; extern struct SBSX BSX; uint8 S9xGetBSX (uint32); void S9xSetBSX (uint8, uint32); uint8 S9xGetBSXPPU (uint16); void S9xSetBSXPPU (uint8, uint16); uint8 * S9xGetBasePointerBSX (uint32); void S9xInitBSX (void); void S9xResetBSX (void); void S9xBSXPostLoadState (void); #endif apu/bapu/smp/core/opcycle_read.cpp000664 001750 001750 00000055707 12720446475 020333 0ustar00sergiosergio000000 000000 case 0x88: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x28: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x68: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xc8: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.x = op_cmp(regs.x, rd); opcode_cycle = 0; break; } break; } case 0xad: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.y = op_cmp(regs.y, rd); opcode_cycle = 0; break; } break; } case 0x48: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x08: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xa8: { switch(opcode_cycle++) { case 1: rd = op_readpc(); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x86: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x26: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x66: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x46: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x06: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xa6: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.x); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x84: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x24: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x64: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x3e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.x = op_cmp(regs.x, rd); opcode_cycle = 0; break; } break; } case 0x7e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.y = op_cmp(regs.y, rd); opcode_cycle = 0; break; } break; } case 0x44: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x04: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xa4: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x94: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x34: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x74: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x54: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x14: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xb4: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x85: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x25: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x65: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x1e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.x = op_cmp(regs.x, rd); opcode_cycle = 0; break; } break; } case 0x5e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.y = op_cmp(regs.y, rd); opcode_cycle = 0; break; } break; } case 0x45: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x05: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xa5: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x95: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x96: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x35: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x36: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x75: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x76: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x55: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x56: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x15: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x16: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xb5: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.x); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xb6: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: rd = op_readaddr(dp + regs.y); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x87: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x27: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x67: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x47: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x07: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xa7: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x97: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_adc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x37: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_and(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x77: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_cmp(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x57: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_eor(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x17: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_or(regs.a, rd); opcode_cycle = 0; break; } break; } case 0xb7: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: rd = op_readaddr(sp + regs.y); regs.a = op_sbc(regs.a, rd); opcode_cycle = 0; break; } break; } case 0x99: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_adc(wr, rd); break; case 4: (1) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x39: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_and(wr, rd); break; case 4: (1) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x79: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_cmp(wr, rd); break; case 4: (0) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x59: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_eor(wr, rd); break; case 4: (1) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x19: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_or(wr, rd); break; case 4: (1) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0xb9: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: rd = op_readdp(regs.y); break; case 3: wr = op_readdp(regs.x); wr = op_sbc(wr, rd); break; case 4: (1) ? op_writedp(regs.x, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x89: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x29: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x69: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x49: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x09: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0xa9: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: wr = op_readdp(dp); break; case 5: wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x98: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x38: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x78: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x58: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x18: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0xb8: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: wr = op_readdp(dp); break; case 4: wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); opcode_cycle = 0; break; } break; } case 0x7a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: op_io(); break; case 4: rd |= op_readdp(dp + 1) << 8; regs.ya = op_addw(regs.ya, rd); opcode_cycle = 0; break; } break; } case 0x9a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: op_io(); break; case 4: rd |= op_readdp(dp + 1) << 8; regs.ya = op_subw(regs.ya, rd); opcode_cycle = 0; break; } break; } case 0x5a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd |= op_readdp(dp + 1) << 8; op_cmpw(regs.ya, rd); opcode_cycle = 0; break; } break; } case 0x4a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !!(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0x6a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0x8a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); break; case 4: op_io(); regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0xea: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); rd ^= (1 << bit); break; case 4: op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x0a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); break; case 4: op_io(); regs.p.c = regs.p.c | !!(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0x2a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); break; case 4: op_io(); regs.p.c = regs.p.c | !(rd & (1 << bit)); opcode_cycle = 0; break; } break; } apu/bapu/dsp/blargg_endian.h000664 001750 001750 00000014334 12720446475 017151 0ustar00sergiosergio000000 000000 // CPU Byte Order Utilities // snes_spc 0.9.0 #ifndef BLARGG_ENDIAN #define BLARGG_ENDIAN #include "blargg_common.h" // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ defined (__x86_64__) || defined (__ia64__) || defined (__i386__) #define BLARGG_CPU_X86 1 #define BLARGG_CPU_CISC 1 #endif #if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) #define BLARGG_CPU_POWERPC 1 #define BLARGG_CPU_RISC 1 #endif // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only // one may be #defined to 1. Only needed if something actually depends on byte order. #if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) #ifdef __GLIBC__ // GCC handles this for us #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define BLARGG_LITTLE_ENDIAN 1 #elif __BYTE_ORDER == __BIG_ENDIAN #define BLARGG_BIG_ENDIAN 1 #endif #else #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) #define BLARGG_LITTLE_ENDIAN 1 #endif #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ defined (__sparc__) || BLARGG_CPU_POWERPC || \ (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) #define BLARGG_BIG_ENDIAN 1 #elif !defined (__mips__) // No endian specified; assume little-endian, since it's most common #define BLARGG_LITTLE_ENDIAN 1 #endif #endif #endif #if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN #undef BLARGG_LITTLE_ENDIAN #undef BLARGG_BIG_ENDIAN #endif inline void blargg_verify_byte_order() { #ifndef NDEBUG #if BLARGG_BIG_ENDIAN volatile int i = 1; assert( *(volatile char*) &i == 0 ); #elif BLARGG_LITTLE_ENDIAN volatile int i = 1; assert( *(volatile char*) &i != 0 ); #endif #endif } inline unsigned get_le16( void const* p ) { return (unsigned) ((unsigned char const*) p) [1] << 8 | (unsigned) ((unsigned char const*) p) [0]; } inline unsigned get_be16( void const* p ) { return (unsigned) ((unsigned char const*) p) [0] << 8 | (unsigned) ((unsigned char const*) p) [1]; } inline blargg_ulong get_le32( void const* p ) { return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | (blargg_ulong) ((unsigned char const*) p) [2] << 16 | (blargg_ulong) ((unsigned char const*) p) [1] << 8 | (blargg_ulong) ((unsigned char const*) p) [0]; } inline blargg_ulong get_be32( void const* p ) { return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | (blargg_ulong) ((unsigned char const*) p) [1] << 16 | (blargg_ulong) ((unsigned char const*) p) [2] << 8 | (blargg_ulong) ((unsigned char const*) p) [3]; } inline void set_le16( void* p, unsigned n ) { ((unsigned char*) p) [1] = (unsigned char) (n >> 8); ((unsigned char*) p) [0] = (unsigned char) n; } inline void set_be16( void* p, unsigned n ) { ((unsigned char*) p) [0] = (unsigned char) (n >> 8); ((unsigned char*) p) [1] = (unsigned char) n; } inline void set_le32( void* p, blargg_ulong n ) { ((unsigned char*) p) [0] = (unsigned char) n; ((unsigned char*) p) [1] = (unsigned char) (n >> 8); ((unsigned char*) p) [2] = (unsigned char) (n >> 16); ((unsigned char*) p) [3] = (unsigned char) (n >> 24); } inline void set_be32( void* p, blargg_ulong n ) { ((unsigned char*) p) [3] = (unsigned char) n; ((unsigned char*) p) [2] = (unsigned char) (n >> 8); ((unsigned char*) p) [1] = (unsigned char) (n >> 16); ((unsigned char*) p) [0] = (unsigned char) (n >> 24); } #if BLARGG_NONPORTABLE // Optimized implementation if byte order is known #if BLARGG_LITTLE_ENDIAN #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) #elif BLARGG_BIG_ENDIAN #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) #if BLARGG_CPU_POWERPC // PowerPC has special byte-reversed instructions #if defined (__MWERKS__) #define GET_LE16( addr ) (__lhbrx( addr, 0 )) #define GET_LE32( addr ) (__lwbrx( addr, 0 )) #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) #elif defined (__GNUC__) #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) #endif #endif #endif #endif #ifndef GET_LE16 #define GET_LE16( addr ) get_le16( addr ) #define SET_LE16( addr, data ) set_le16( addr, data ) #endif #ifndef GET_LE32 #define GET_LE32( addr ) get_le32( addr ) #define SET_LE32( addr, data ) set_le32( addr, data ) #endif #ifndef GET_BE16 #define GET_BE16( addr ) get_be16( addr ) #define SET_BE16( addr, data ) set_be16( addr, data ) #endif #ifndef GET_BE32 #define GET_BE32( addr ) get_be32( addr ) #define SET_BE32( addr, data ) set_be32( addr, data ) #endif // auto-selecting versions inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } #endif memmap.cpp000664 001750 001750 00000325315 12720446475 013706 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include #include #ifdef UNZIP_SUPPORT #include "unzip/unzip.h" #endif #ifdef JMA_SUPPORT #include "jma/s9x-jma.h" #endif #include #include "snes9x.h" #include "memmap.h" #include "apu/apu.h" #include "fxemu.h" #include "sdd1.h" #include "srtc.h" #include "controls.h" #include "cheats.h" #include "movie.h" #include "display.h" #ifdef __LIBRETRO__ #include "libretro/libretro.h" void S9xAppendMapping(struct retro_memory_descriptor *desc); #endif #ifndef SET_UI_COLOR #define SET_UI_COLOR(r, g, b) ; #endif #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif static bool8 stopMovie = TRUE; static char LastRomFilename[PATH_MAX + 1] = ""; // from NSRT static const char *nintendo_licensees[] = { "Unlicensed", "Nintendo", "Rocket Games/Ajinomoto", "Imagineer-Zoom", "Gray Matter", "Zamuse", "Falcom", NULL, "Capcom", "Hot B Co.", "Jaleco", "Coconuts Japan", "Coconuts Japan/G.X.Media", "Micronet", "Technos", "Mebio Software", "Shouei System", "Starfish", NULL, "Mitsui Fudosan/Dentsu", NULL, "Warashi Inc.", NULL, "Nowpro", NULL, "Game Village", "IE Institute", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Banarex", "Starfish", "Infocom", "Electronic Arts Japan", NULL, "Cobra Team", "Human/Field", "KOEI", "Hudson Soft", "S.C.P./Game Village", "Yanoman", NULL, "Tecmo Products", "Japan Glary Business", "Forum/OpenSystem", "Virgin Games (Japan)", "SMDE", "Yojigen", NULL, "Daikokudenki", NULL, NULL, NULL, NULL, NULL, "Creatures Inc.", "TDK Deep Impresion", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Destination Software/KSS", "Sunsoft/Tokai Engineering", "POW (Planning Office Wada)/VR 1 Japan", "Micro World", NULL, "San-X", "Enix", "Loriciel/Electro Brain", "Kemco Japan", "Seta Co.,Ltd.", "Culture Brain", "Irem Corp.", "Palsoft", "Visit Co., Ltd.", "Intec", "System Sacom", "Poppo", "Ubisoft Japan", NULL, "Media Works", "NEC InterChannel", "Tam", "Gajin/Jordan", "Smilesoft", NULL, NULL, "Mediakite", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Viacom", "Carrozzeria", "Dynamic", NULL, "Magifact", "Hect", "Codemasters", "Taito/GAGA Communications", "Laguna", "Telstar Fun & Games/Event/Taito", NULL, "Arcade Zone Ltd.", "Entertainment International/Empire Software", "Loriciel", "Gremlin Graphics", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Seika Corp.", "UBI SOFT Entertainment Software", "Sunsoft US", NULL, "Life Fitness", NULL, "System 3", "Spectrum Holobyte", NULL, "Irem", NULL, "Raya Systems", "Renovation Products", "Malibu Games", NULL, "Eidos/U.S. Gold", "Playmates Interactive", NULL, NULL, "Fox Interactive", "Time Warner Interactive", NULL, NULL, NULL, NULL, NULL, "Disney Interactive", NULL, "Black Pearl", NULL, "Advanced Productions", NULL, NULL, "GT Interactive", "RARE", "Crave Entertainment", "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "Take 2/GameTek", "Hi Tech", "LJN Ltd.", NULL, "Mattel", NULL, "Mindscape/Red Orb Entertainment", "Romstar", "Taxan", "Midway/Tradewest", NULL, "American Softworks Corp.", "Majesco Sales Inc.", "3DO", NULL, NULL, "Hasbro", "NewKidCo", "Telegames", "Metro3D", NULL, "Vatical Entertainment", "LEGO Media", NULL, "Xicat Interactive", "Cryo Interactive", NULL, NULL, "Red Storm Entertainment", "Microids", NULL, "Conspiracy/Swing", "Titus", "Virgin Interactive", "Maxis", NULL, "LucasArts Entertainment", NULL, NULL, "Ocean", NULL, "Electronic Arts", NULL, "Laser Beam", NULL, NULL, "Elite Systems", "Electro Brain", "The Learning Company", "BBC", NULL, "Software 2000", NULL, "BAM! Entertainment", "Studio 3", NULL, NULL, NULL, "Classified Games", NULL, "TDK Mediactive", NULL, "DreamCatcher", "JoWood Produtions", "SEGA", "Wannado Edition", "LSP (Light & Shadow Prod.)", "ITE Media", "Infogrames", "Interplay", "JVC (US)", "Parker Brothers", NULL, "SCI (Sales Curve Interactive)/Storm", NULL, NULL, "THQ Software", "Accolade Inc.", "Triffix Entertainment", NULL, "Microprose Software", "Universal Interactive/Sierra/Simon & Schuster", NULL, "Kemco", "Rage Software", "Encore", NULL, "Zoo", "Kiddinx", "Simon & Schuster Interactive", "Asmik Ace Entertainment Inc./AIA", "Empire Interactive", NULL, NULL, "Jester Interactive", NULL, "Rockstar Games", "Scholastic", "Ignition Entertainment", "Summitsoft", "Stadlbauer", NULL, NULL, NULL, "Misawa", "Teichiku", "Namco Ltd.", "LOZC", "KOEI", NULL, "Tokuma Shoten Intermedia", "Tsukuda Original", "DATAM-Polystar", NULL, NULL, "Bullet-Proof Software", "Vic Tokai Inc.", NULL, "Character Soft", "I'Max", "Saurus", NULL, NULL, "General Entertainment", NULL, NULL, "I'Max", "Success", NULL, "SEGA Japan", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Takara", "Chun Soft", "Video System Co., Ltd./McO'River", "BEC", NULL, "Varie", "Yonezawa/S'pal", "Kaneko", NULL, "Victor Interactive Software/Pack-in-Video", "Nichibutsu/Nihon Bussan", "Tecmo", "Imagineer", NULL, NULL, "Nova", "Den'Z", "Bottom Up", NULL, "TGL (Technical Group Laboratory)", NULL, "Hasbro Japan", NULL, "Marvelous Entertainment", NULL, "Keynet Inc.", "Hands-On Entertainment", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Telenet", "Hori", NULL, NULL, "Konami", "K.Amusement Leasing Co.", "Kawada", "Takara", NULL, "Technos Japan Corp.", "JVC (Europe/Japan)/Victor Musical Industries", NULL, "Toei Animation", "Toho", NULL, "Namco", "Media Rings Corp.", "J-Wing", NULL, "Pioneer LDC", "KID", "Mediafactory", NULL, NULL, NULL, "Infogrames Hudson", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Acclaim Japan", "ASCII Co./Nexoft", "Bandai", NULL, "Enix", NULL, "HAL Laboratory/Halken", "SNK", NULL, "Pony Canyon Hanbai", "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", NULL, "Sammy", "Magical", "Visco", NULL, "Compile", NULL, "MTO Inc.", NULL, "Sunrise Interactive", NULL, "Global A Entertainment", "Fuuki", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Taito", NULL, "Kemco", "Square", "Tokuma Shoten", "Data East", "Tonkin House", NULL, "KOEI", NULL, "Konami/Ultra/Palcom", "NTVIC/VAP", "Use Co., Ltd.", "Meldac", "Pony Canyon (Japan)/FCI (US)", "Angel/Sotsu Agency/Sunrise", "Yumedia/Aroma Co., Ltd.", NULL, NULL, "Boss", "Axela/Crea-Tech", "Sekaibunka-Sha/Sumire kobo/Marigul Management Inc.", "Konami Computer Entertainment Osaka", NULL, NULL, "Enterbrain", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Taito/Disco", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha", NULL, "Naxat", "Copya System", "Capcom Co., Ltd.", "Banpresto", "TOMY", "Acclaim/LJN Japan", NULL, "NCS", "Human Entertainment", "Altron", "Jaleco", "Gaps Inc.", NULL, NULL, NULL, NULL, NULL, "Elf", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Jaleco", NULL, "Yutaka", "Varie", "T&ESoft", "Epoch Co., Ltd.", NULL, "Athena", "Asmik", "Natsume", "King Records", "Atlus", "Epic/Sony Records (Japan)", NULL, "IGS (Information Global Service)", NULL, "Chatnoir", "Right Stuff", NULL, "NTT COMWARE", NULL, "Spike", "Konami Computer Entertainment Tokyo", "Alphadream Corp.", NULL, "Sting", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "A Wave", "Motown Software", "Left Field Entertainment", "Extreme Entertainment Group", "TecMagik", NULL, NULL, NULL, NULL, "Cybersoft", NULL, "Psygnosis", NULL, NULL, "Davidson/Western Tech.", "Unlicensed", NULL, NULL, NULL, NULL, "The Game Factory Europe", "Hip Games", "Aspyr", NULL, NULL, "Mastiff", "iQue", "Digital Tainment Pool", "XS Games", "Daiwon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "PCCW Japan", NULL, NULL, "KiKi Co. Ltd.", "Open Sesame Inc.", "Sims", "Broccoli", "Avex", "D3 Publisher", NULL, "Konami Computer Entertainment Japan", NULL, "Square-Enix", "KSG", "Micott & Basara Inc.", NULL, "Orbital Media", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "The Game Factory USA", NULL, NULL, "Treasure", "Aruze", "Ertain", "SNK Playmore", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Yojigen" }; static const uint32 crc32Table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; static void S9xDeinterleaveType1 (int, uint8 *); static void S9xDeinterleaveType2 (int, uint8 *); static void S9xDeinterleaveGD24 (int, uint8 *); static bool8 allASCII (uint8 *, int); static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32); static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32); static bool8 is_SameGame_BIOS (const uint8 *, uint32); static bool8 is_SameGame_Add_On (const uint8 *, uint32); static bool8 is_GNEXT_BIOS (const uint8 *, uint32); static bool8 is_GNEXT_Add_On (const uint8 *, uint32); static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff); static uint32 ReadUPSPointer (const uint8 *, unsigned &, unsigned); static bool8 ReadUPSPatch (Stream *, long, int32 &); static long ReadInt (Stream *, unsigned); static bool8 ReadIPSPatch (Stream *, long, int32 &); #ifdef UNZIP_SUPPORT static int unzFindExtension (unzFile &, const char *, bool restart = TRUE, bool print = TRUE); #endif // deinterleave static void S9xDeinterleaveType1 (int size, uint8 *base) { Settings.DisplayColor = BUILD_PIXEL(0, 31, 0); SET_UI_COLOR(0, 255, 0); uint8 blocks[256]; int nblocks = size >> 16; for (int i = 0; i < nblocks; i++) { blocks[i * 2] = i + nblocks; blocks[i * 2 + 1] = i; } uint8 *tmp = (uint8 *) malloc(0x8000); if (tmp) { for (int i = 0; i < nblocks * 2; i++) { for (int j = i; j < nblocks * 2; j++) { if (blocks[j] == i) { memmove(tmp, &base[blocks[j] * 0x8000], 0x8000); memmove(&base[blocks[j] * 0x8000], &base[blocks[i] * 0x8000], 0x8000); memmove(&base[blocks[i] * 0x8000], tmp, 0x8000); uint8 b = blocks[j]; blocks[j] = blocks[i]; blocks[i] = b; break; } } } free(tmp); } } static void S9xDeinterleaveType2 (int size, uint8 *base) { // for odd Super FX images Settings.DisplayColor = BUILD_PIXEL(31, 14, 6); SET_UI_COLOR(255, 119, 25); uint8 blocks[256]; int nblocks = size >> 16; int step = 64; while (nblocks <= step) step >>= 1; nblocks = step; for (int i = 0; i < nblocks * 2; i++) blocks[i] = (i & ~0xf) | ((i & 3) << 2) | ((i & 12) >> 2); uint8 *tmp = (uint8 *) malloc(0x10000); if (tmp) { for (int i = 0; i < nblocks * 2; i++) { for (int j = i; j < nblocks * 2; j++) { if (blocks[j] == i) { memmove(tmp, &base[blocks[j] * 0x10000], 0x10000); memmove(&base[blocks[j] * 0x10000], &base[blocks[i] * 0x10000], 0x10000); memmove(&base[blocks[i] * 0x10000], tmp, 0x10000); uint8 b = blocks[j]; blocks[j] = blocks[i]; blocks[i] = b; break; } } } free(tmp); } } static void S9xDeinterleaveGD24 (int size, uint8 *base) { // for 24Mb images dumped with Game Doctor if (size != 0x300000) return; Settings.DisplayColor = BUILD_PIXEL(0, 31, 31); SET_UI_COLOR(0, 255, 255); uint8 *tmp = (uint8 *) malloc(0x80000); if (tmp) { memmove(tmp, &base[0x180000], 0x80000); memmove(&base[0x180000], &base[0x200000], 0x80000); memmove(&base[0x200000], &base[0x280000], 0x80000); memmove(&base[0x280000], tmp, 0x80000); free(tmp); S9xDeinterleaveType1(size, base); } } // allocation and deallocation bool8 CMemory::Init (void) { RAM = (uint8 *) malloc(0x20000); SRAM = (uint8 *) malloc(0x20000); VRAM = (uint8 *) malloc(0x10000); ROM = (uint8 *) malloc(MAX_ROM_SIZE + 0x200 + 0x8000); IPPU.TileCache[TILE_2BIT] = (uint8 *) malloc(MAX_2BIT_TILES * 64); IPPU.TileCache[TILE_4BIT] = (uint8 *) malloc(MAX_4BIT_TILES * 64); IPPU.TileCache[TILE_8BIT] = (uint8 *) malloc(MAX_8BIT_TILES * 64); IPPU.TileCache[TILE_2BIT_EVEN] = (uint8 *) malloc(MAX_2BIT_TILES * 64); IPPU.TileCache[TILE_2BIT_ODD] = (uint8 *) malloc(MAX_2BIT_TILES * 64); IPPU.TileCache[TILE_4BIT_EVEN] = (uint8 *) malloc(MAX_4BIT_TILES * 64); IPPU.TileCache[TILE_4BIT_ODD] = (uint8 *) malloc(MAX_4BIT_TILES * 64); IPPU.TileCached[TILE_2BIT] = (uint8 *) malloc(MAX_2BIT_TILES); IPPU.TileCached[TILE_4BIT] = (uint8 *) malloc(MAX_4BIT_TILES); IPPU.TileCached[TILE_8BIT] = (uint8 *) malloc(MAX_8BIT_TILES); IPPU.TileCached[TILE_2BIT_EVEN] = (uint8 *) malloc(MAX_2BIT_TILES); IPPU.TileCached[TILE_2BIT_ODD] = (uint8 *) malloc(MAX_2BIT_TILES); IPPU.TileCached[TILE_4BIT_EVEN] = (uint8 *) malloc(MAX_4BIT_TILES); IPPU.TileCached[TILE_4BIT_ODD] = (uint8 *) malloc(MAX_4BIT_TILES); if (!RAM || !SRAM || !VRAM || !ROM || !IPPU.TileCache[TILE_2BIT] || !IPPU.TileCache[TILE_4BIT] || !IPPU.TileCache[TILE_8BIT] || !IPPU.TileCache[TILE_2BIT_EVEN] || !IPPU.TileCache[TILE_2BIT_ODD] || !IPPU.TileCache[TILE_4BIT_EVEN] || !IPPU.TileCache[TILE_4BIT_ODD] || !IPPU.TileCached[TILE_2BIT] || !IPPU.TileCached[TILE_4BIT] || !IPPU.TileCached[TILE_8BIT] || !IPPU.TileCached[TILE_2BIT_EVEN] || !IPPU.TileCached[TILE_2BIT_ODD] || !IPPU.TileCached[TILE_4BIT_EVEN] || !IPPU.TileCached[TILE_4BIT_ODD]) { Deinit(); return (FALSE); } memset(RAM, 0, 0x20000); memset(SRAM, 0, 0x20000); memset(VRAM, 0, 0x10000); memset(ROM, 0, MAX_ROM_SIZE + 0x200 + 0x8000); memset(IPPU.TileCache[TILE_2BIT], 0, MAX_2BIT_TILES * 64); memset(IPPU.TileCache[TILE_4BIT], 0, MAX_4BIT_TILES * 64); memset(IPPU.TileCache[TILE_8BIT], 0, MAX_8BIT_TILES * 64); memset(IPPU.TileCache[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES * 64); memset(IPPU.TileCache[TILE_2BIT_ODD], 0, MAX_2BIT_TILES * 64); memset(IPPU.TileCache[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES * 64); memset(IPPU.TileCache[TILE_4BIT_ODD], 0, MAX_4BIT_TILES * 64); memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES); memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES); // FillRAM uses first 32K of ROM image area, otherwise space just // wasted. Might be read by the SuperFX code. FillRAM = ROM; // Add 0x8000 to ROM image pointer to stop SuperFX code accessing // unallocated memory (can cause crash on some ports). ROM += 0x8000; C4RAM = ROM + 0x400000 + 8192 * 8; // C4 OBC1RAM = ROM + 0x400000; // OBC1 BIOSROM = ROM + 0x300000; // BS BSRAM = ROM + 0x400000; // BS SuperFX.pvRegisters = FillRAM + 0x3000; SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB=512Mb, 2=128KB=1024Mb SuperFX.pvRam = SRAM; SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024); SuperFX.pvRom = (uint8 *) ROM; PostRomInitFunc = NULL; return (TRUE); } void CMemory::Deinit (void) { if (RAM) { free(RAM); RAM = NULL; } if (SRAM) { free(SRAM); SRAM = NULL; } if (VRAM) { free(VRAM); VRAM = NULL; } if (ROM) { ROM -= 0x8000; free(ROM); ROM = NULL; } for (int t = 0; t < 7; t++) { if (IPPU.TileCache[t]) { free(IPPU.TileCache[t]); IPPU.TileCache[t] = NULL; } if (IPPU.TileCached[t]) { free(IPPU.TileCached[t]); IPPU.TileCached[t] = NULL; } } Safe(NULL); SafeANK(NULL); } // file management and ROM detection static bool8 allASCII (uint8 *b, int size) { for (int i = 0; i < size; i++) { if (b[i] < 32 || b[i] > 126) return (FALSE); } return (TRUE); } static bool8 is_SufamiTurbo_BIOS (const uint8 *data, uint32 size) { if (size == 0x40000 && strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) == 0) return (TRUE); else return (FALSE); } static bool8 is_SufamiTurbo_Cart (const uint8 *data, uint32 size) { if (size >= 0x80000 && size <= 0x100000 && strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) != 0) return (TRUE); else return (FALSE); } static bool8 is_SameGame_BIOS (const uint8 *data, uint32 size) { if (size == 0x100000 && strncmp((char *) (data + 0xffc0), "Same Game Tsume Game", 20) == 0) return (TRUE); else return (FALSE); } static bool8 is_SameGame_Add_On (const uint8 *data, uint32 size) { if (size == 0x80000) return (TRUE); else return (FALSE); } static bool8 is_GNEXT_BIOS (const uint8 *data, uint32 size) { if (size == 0x180000 && strncmp((char *) (data + 0x7fc0), "SFC SDGUNDAMGNEXT", 17) == 0) return (TRUE); else return (FALSE); } static bool8 is_GNEXT_Add_On (const uint8 *data, uint32 size) { if (size == 0x80000) return (TRUE); else return (FALSE); } int CMemory::ScoreHiROM (bool8 skip_header, int32 romoff) { uint8 *buf = ROM + 0xff00 + romoff + (skip_header ? 0x200 : 0); int score = 0; if (buf[0xd5] & 0x1) score += 2; // Mode23 is SA-1 if (buf[0xd5] == 0x23) score -= 2; if (buf[0xd4] == 0x20) score += 2; if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff) { score += 2; if (0 != (buf[0xde] + (buf[0xdf] << 8))) score++; } if (buf[0xda] == 0x33) score += 2; if ((buf[0xd5] & 0xf) < 4) score += 2; if (!(buf[0xfd] & 0x80)) score -= 6; if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0) score -= 2; // reduced after looking at a scan by Cowering if (CalculatedSize > 1024 * 1024 * 3) score += 4; if ((1 << (buf[0xd7] - 7)) > 48) score -= 1; if (!allASCII(&buf[0xb0], 6)) score -= 1; if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1)) score -= 1; return (score); } int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff) { uint8 *buf = ROM + 0x7f00 + romoff + (skip_header ? 0x200 : 0); int score = 0; if (!(buf[0xd5] & 0x1)) score += 3; // Mode23 is SA-1 if (buf[0xd5] == 0x23) score += 2; if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff) { score += 2; if (0 != (buf[0xde] + (buf[0xdf] << 8))) score++; } if (buf[0xda] == 0x33) score += 2; if ((buf[0xd5] & 0xf) < 4) score += 2; if (!(buf[0xfd] & 0x80)) score -= 6; if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0) score -= 2; // reduced per Cowering suggestion if (CalculatedSize <= 1024 * 1024 * 16) score += 2; if ((1 << (buf[0xd7] - 7)) > 48) score -= 1; if (!allASCII(&buf[0xb0], 6)) score -= 1; if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1)) score -= 1; return (score); } uint32 CMemory::HeaderRemove (uint32 size, uint8 *buf) { uint32 calc_size = (size / 0x2000) * 0x2000; if ((size - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader) { uint8 *NSRTHead = buf + 0x1D0; // NSRT Header Location // detect NSRT header if (!strncmp("NSRT", (char *) &NSRTHead[24], 4)) { if (NSRTHead[28] == 22) { if (((std::accumulate(NSRTHead, NSRTHead + sizeof(NSRTHeader), 0) & 0xFF) == NSRTHead[30]) && (NSRTHead[30] + NSRTHead[31] == 255) && ((NSRTHead[0] & 0x0F) <= 13) && (((NSRTHead[0] & 0xF0) >> 4) <= 3) && ((NSRTHead[0] & 0xF0) >> 4)) memcpy(NSRTHeader, NSRTHead, sizeof(NSRTHeader)); } } memmove(buf, buf + 512, calc_size); HeaderCount++; size -= 512; } return (size); } uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, uint32 maxsize) { // <- ROM size without header // ** Memory.HeaderCount // ** Memory.ROMFilename uint32 totalSize = 0; char fname[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], name[_MAX_FNAME + 1], exts[_MAX_EXT + 1]; char *ext; #if defined(__WIN32__) || defined(__MACOSX__) ext = &exts[1]; #else ext = &exts[0]; #endif memset(NSRTHeader, 0, sizeof(NSRTHeader)); HeaderCount = 0; _splitpath(filename, drive, dir, name, exts); _makepath(fname, drive, dir, name, exts); int nFormat = FILE_DEFAULT; if (strcasecmp(ext, "zip") == 0) nFormat = FILE_ZIP; else if (strcasecmp(ext, "jma") == 0) nFormat = FILE_JMA; switch (nFormat) { case FILE_ZIP: { #ifdef UNZIP_SUPPORT if (!LoadZip(fname, &totalSize, buffer)) { S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid Zip archive."); return (0); } strcpy(ROMFilename, fname); #else S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with Zip support."); return (0); #endif break; } case FILE_JMA: { #ifdef JMA_SUPPORT size_t size = load_jma_file(fname, buffer); if (!size) { S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid JMA archive."); return (0); } totalSize = HeaderRemove(size, buffer); strcpy(ROMFilename, fname); #else S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with JMA support."); return (0); #endif break; } case FILE_DEFAULT: default: { STREAM fp = OPEN_STREAM(fname, "rb"); if (!fp) return (0); strcpy(ROMFilename, fname); int len = 0; uint32 size = 0; bool8 more = FALSE; uint8 *ptr = buffer; do { size = READ_STREAM(ptr, maxsize + 0x200 - (ptr - buffer), fp); CLOSE_STREAM(fp); size = HeaderRemove(size, ptr); totalSize += size; ptr += size; // check for multi file roms if (ptr - buffer < maxsize + 0x200 && (isdigit(ext[0]) && ext[1] == 0 && ext[0] < '9')) { more = TRUE; ext[0]++; _makepath(fname, drive, dir, name, exts); } else if (ptr - buffer < maxsize + 0x200 && (((len = strlen(name)) == 7 || len == 8) && strncasecmp(name, "sf", 2) == 0 && isdigit(name[2]) && isdigit(name[3]) && isdigit(name[4]) && isdigit(name[5]) && isalpha(name[len - 1]))) { more = TRUE; name[len - 1]++; _makepath(fname, drive, dir, name, exts); } else more = FALSE; } while (more && (fp = OPEN_STREAM(fname, "rb")) != NULL); break; } } if (HeaderCount == 0) S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found."); else if (HeaderCount == 1) S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found ROM file header (and ignored it)."); else S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found multiple ROM file headers (and ignored them)."); return ((uint32) totalSize); } bool8 CMemory::LoadROMMem (const uint8 *source, uint32 sourceSize) { if(!source || sourceSize > MAX_ROM_SIZE) return FALSE; strcpy(ROMFilename,"MemoryROM"); do { memset(ROM,0, MAX_ROM_SIZE); memset(&Multi, 0,sizeof(Multi)); memcpy(ROM,source,sourceSize); } while(!LoadROMInt(sourceSize)); return TRUE; } bool8 CMemory::LoadROM (const char *filename) { if(!filename || !*filename) return FALSE; int32 totalFileSize; do { memset(ROM,0, MAX_ROM_SIZE); memset(&Multi, 0,sizeof(Multi)); totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE); if (!totalFileSize) return (FALSE); if (!Settings.NoPatch) CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize); } while(!LoadROMInt(totalFileSize)); return TRUE; } bool8 CMemory::LoadROMInt (int32 ROMfillSize) { Settings.DisplayColor = BUILD_PIXEL(31, 31, 31); SET_UI_COLOR(255, 255, 255); CalculatedSize = 0; ExtendedFormat = NOPE; int hi_score, lo_score; hi_score = ScoreHiROM(FALSE); lo_score = ScoreLoROM(FALSE); if (HeaderCount == 0 && !Settings.ForceNoHeader && ((hi_score > lo_score && ScoreHiROM(TRUE) > hi_score) || (hi_score <= lo_score && ScoreLoROM(TRUE) > lo_score))) { memmove(ROM, ROM + 512, ROMfillSize - 512); ROMfillSize -= 512; S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try 'force no-header' option if the game doesn't work"); // modifying ROM, so we need to rescore hi_score = ScoreHiROM(FALSE); lo_score = ScoreLoROM(FALSE); } CalculatedSize = (ROMfillSize / 0x2000) * 0x2000; if (CalculatedSize > 0x400000 && (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3423 && // exclude SA-1 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3523 && (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4332 && // exclude S-DD1 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4532 && (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF93a && // exclude SPC7110 (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF53a) ExtendedFormat = YEAH; // if both vectors are invalid, it's type 1 interleaved LoROM if (ExtendedFormat == NOPE && ((ROM[0x7ffc] + (ROM[0x7ffd] << 8)) < 0x8000) && ((ROM[0xfffc] + (ROM[0xfffd] << 8)) < 0x8000)) { if (!Settings.ForceInterleaved && !Settings.ForceNotInterleaved) S9xDeinterleaveType1(ROMfillSize, ROM); } // CalculatedSize is now set, so rescore hi_score = ScoreHiROM(FALSE); lo_score = ScoreLoROM(FALSE); uint8 *RomHeader = ROM; if (ExtendedFormat != NOPE) { int swappedhirom, swappedlorom; swappedhirom = ScoreHiROM(FALSE, 0x400000); swappedlorom = ScoreLoROM(FALSE, 0x400000); // set swapped here if (max(swappedlorom, swappedhirom) >= max(lo_score, hi_score)) { ExtendedFormat = BIGFIRST; hi_score = swappedhirom; lo_score = swappedlorom; RomHeader += 0x400000; } else ExtendedFormat = SMALLFIRST; } bool8 interleaved, tales = FALSE; interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2 || Settings.ForceInterleaveGD24; if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score)) { LoROM = TRUE; HiROM = FALSE; // ignore map type byte if not 0x2x or 0x3x if ((RomHeader[0x7fd5] & 0xf0) == 0x20 || (RomHeader[0x7fd5] & 0xf0) == 0x30) { switch (RomHeader[0x7fd5] & 0xf) { case 1: interleaved = TRUE; break; case 5: interleaved = TRUE; tales = TRUE; break; } } } else { LoROM = FALSE; HiROM = TRUE; if ((RomHeader[0xffd5] & 0xf0) == 0x20 || (RomHeader[0xffd5] & 0xf0) == 0x30) { switch (RomHeader[0xffd5] & 0xf) { case 0: case 3: interleaved = TRUE; break; } } } // this two games fail to be detected if (!Settings.ForceHiROM && !Settings.ForceLoROM) { if (strncmp((char *) &ROM[0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0 || (strncmp((char *) &ROM[0xffc0], "BATMAN--REVENGE JOKER", 21) == 0)) { LoROM = TRUE; HiROM = FALSE; interleaved = FALSE; tales = FALSE; } } if (!Settings.ForceNotInterleaved && interleaved) { S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting..."); if (tales) { if (ExtendedFormat == BIGFIRST) { S9xDeinterleaveType1(0x400000, ROM); S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM + 0x400000); } else { S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM); S9xDeinterleaveType1(0x400000, ROM + CalculatedSize - 0x400000); } LoROM = FALSE; HiROM = TRUE; } else if (Settings.ForceInterleaveGD24 && CalculatedSize == 0x300000) { bool8 t = LoROM; LoROM = HiROM; HiROM = t; S9xDeinterleaveGD24(CalculatedSize, ROM); } else if (Settings.ForceInterleaved2) S9xDeinterleaveType2(CalculatedSize, ROM); else { bool8 t = LoROM; LoROM = HiROM; HiROM = t; S9xDeinterleaveType1(CalculatedSize, ROM); } hi_score = ScoreHiROM(FALSE); lo_score = ScoreLoROM(FALSE); if ((HiROM && (lo_score >= hi_score || hi_score < 0)) || (LoROM && (hi_score > lo_score || lo_score < 0))) { S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again."); Settings.ForceNotInterleaved = TRUE; Settings.ForceInterleaved = FALSE; return (FALSE); } } if (ExtendedFormat == SMALLFIRST) tales = TRUE; if (tales) { uint8 *tmp = (uint8 *) malloc(CalculatedSize - 0x400000); if (tmp) { S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "Fixing swapped ExHiROM..."); memmove(tmp, ROM, CalculatedSize - 0x400000); memmove(ROM, ROM + CalculatedSize - 0x400000, 0x400000); memmove(ROM + 0x400000, tmp, CalculatedSize - 0x400000); free(tmp); } } if (strncmp(LastRomFilename, ROMFilename, PATH_MAX + 1)) { strncpy(LastRomFilename, ROMFilename, PATH_MAX + 1); LastRomFilename[PATH_MAX] = 0; } memset(&SNESGameFixes, 0, sizeof(SNESGameFixes)); SNESGameFixes.SRAMInitialValue = 0x60; S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); InitROM(); S9xInitCheatData(); S9xApplyCheats(); S9xReset(); return (TRUE); } bool8 CMemory::LoadMultiCartMem (const uint8 *sourceA, uint32 sourceASize, const uint8 *sourceB, uint32 sourceBSize, const uint8 *bios, uint32 biosSize) { uint32 offset = 0; memset(ROM, 0, MAX_ROM_SIZE); memset(&Multi, 0, sizeof(Multi)); if(bios) { if(!is_SufamiTurbo_BIOS(bios,biosSize)) return FALSE; memcpy(ROM,bios,biosSize); offset+=biosSize; } if(sourceA) { memcpy(ROM + offset,sourceA,sourceASize); Multi.cartOffsetA = offset; Multi.cartSizeA = sourceASize; offset += sourceASize; strcpy(Multi.fileNameA,"MemCartA"); } if(sourceB) { memcpy(ROM + offset,sourceB,sourceBSize); Multi.cartOffsetB = offset; Multi.cartSizeB = sourceBSize; offset += sourceBSize; strcpy(Multi.fileNameB,"MemCartB"); } return LoadMultiCartInt(); } bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB) { memset(ROM, 0, MAX_ROM_SIZE); memset(&Multi, 0, sizeof(Multi)); Settings.DisplayColor = BUILD_PIXEL(31, 31, 31); SET_UI_COLOR(255, 255, 255); if (cartB && cartB[0]) Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE); if (Multi.cartSizeB) { strcpy(Multi.fileNameB, cartB); if(!Settings.NoPatch) CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB); Multi.cartOffsetB = 0x400000; memcpy(ROM + Multi.cartOffsetB,ROM,Multi.cartSizeB); } if (cartA && cartA[0]) Multi.cartSizeA = FileLoader(ROM, cartA, MAX_ROM_SIZE); if (Multi.cartSizeA) { strcpy(Multi.fileNameA, cartA); if(!Settings.NoPatch) CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA); } return LoadMultiCartInt(); } bool8 CMemory::LoadMultiCartInt () { bool8 r = TRUE; CalculatedSize = 0; ExtendedFormat = NOPE; if (Multi.cartSizeA) { if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetA, Multi.cartSizeA)) Multi.cartType = 4; else if (is_SameGame_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) Multi.cartType = 3; else if (is_GNEXT_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) Multi.cartType = 5; } else if (Multi.cartSizeB) { if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartType = 4; } else Multi.cartType = 4; // assuming BIOS only if(Multi.cartType == 4 && Multi.cartOffsetA == 0) { // try to load bios from file Multi.cartOffsetA = 0x40000; if(Multi.cartSizeA) memmove(ROM + Multi.cartOffsetA,ROM,Multi.cartOffsetB - Multi.cartOffsetA); else // clear cart A so the bios can detect that it's not present memset(ROM,0,Multi.cartOffsetB); FILE *fp; size_t size; char path[PATH_MAX + 1]; strcpy(path, S9xGetDirectory(BIOS_DIR)); strcat(path, SLASH_STR); strcat(path, "STBIOS.bin"); fp = fopen(path, "rb"); if (fp) { size = fread((void *) ROM, 1, 0x40000, fp); fclose(fp); if (!is_SufamiTurbo_BIOS(ROM, size)) return (FALSE); } else return (FALSE); strcpy(ROMFilename, path); } switch (Multi.cartType) { case 4: r = LoadSufamiTurbo(); break; case 3: r = LoadSameGame(); break; case 5: r = LoadGNEXT(); break; default: r = FALSE; } if (!r) { memset(&Multi, 0, sizeof(Multi)); return (FALSE); } if (Multi.cartSizeA) strcpy(ROMFilename, Multi.fileNameA); else if (Multi.cartSizeB) strcpy(ROMFilename, Multi.fileNameB); memset(&SNESGameFixes, 0, sizeof(SNESGameFixes)); SNESGameFixes.SRAMInitialValue = 0x60; S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); InitROM(); S9xInitCheatData(); S9xApplyCheats(); S9xReset(); return (TRUE); } bool8 CMemory::LoadSufamiTurbo () { Multi.sramA = SRAM; Multi.sramB = SRAM + 0x10000; if (Multi.cartSizeA) { Multi.sramSizeA = 4; // ROM[0x37]? Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; } if (Multi.cartSizeB) { if (!is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartSizeB = 0; } if (Multi.cartSizeB) { Multi.sramSizeB = 4; // ROM[0x37]? Multi.sramMaskB = Multi.sramSizeB ? ((1 << (Multi.sramSizeB + 3)) * 128 - 1) : 0; } LoROM = TRUE; HiROM = FALSE; CalculatedSize = 0x40000; return (TRUE); } bool8 CMemory::LoadSameGame () { Multi.sramA = SRAM; Multi.sramB = NULL; Multi.sramSizeA = ROM[0xffd8]; Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; Multi.sramSizeB = 0; Multi.sramMaskB = 0; if (Multi.cartSizeB) { if (!is_SameGame_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartSizeB = 0; } LoROM = FALSE; HiROM = TRUE; CalculatedSize = Multi.cartSizeA; return (TRUE); } bool8 CMemory::LoadGNEXT () { Multi.sramA = SRAM; Multi.sramB = NULL; Multi.sramSizeA = ROM[0x7fd8]; Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; Multi.sramSizeB = 0; Multi.sramMaskB = 0; if (Multi.cartSizeB) { if (!is_GNEXT_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartSizeB = 0; } LoROM = TRUE; HiROM = FALSE; CalculatedSize = Multi.cartSizeA; return (TRUE); } bool8 CMemory::LoadSRTC (void) { FILE *fp; size_t ignore; fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "rb"); if (!fp) return (FALSE); ignore = fread(RTCData.reg, 1, 20, fp); fclose(fp); return (TRUE); } bool8 CMemory::SaveSRTC (void) { FILE *fp; size_t ignore; fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "wb"); if (!fp) return (FALSE); ignore = fwrite(RTCData.reg, 1, 20, fp); fclose(fp); return (TRUE); } void CMemory::ClearSRAM (bool8 onlyNonSavedSRAM) { if (onlyNonSavedSRAM) if (!(Settings.SuperFX && ROMType < 0x15) && !(Settings.SA1 && ROMType == 0x34)) // can have SRAM return; memset(SRAM, SNESGameFixes.SRAMInitialValue, 0x20000); } bool8 CMemory::LoadSRAM (const char *filename) { FILE *file; int size, len; char sramName[PATH_MAX + 1]; strcpy(sramName, filename); ClearSRAM(); if (Multi.cartType && Multi.sramSizeB) { char temp[PATH_MAX + 1]; strcpy(temp, ROMFilename); strcpy(ROMFilename, Multi.fileNameB); size = (1 << (Multi.sramSizeB + 3)) * 128; file = fopen(S9xGetFilename(".srm", SRAM_DIR), "rb"); if (file) { len = fread((char *) Multi.sramB, 1, 0x10000, file); fclose(file); if (len - size == 512) memmove(Multi.sramB, Multi.sramB + 512, size); } strcpy(ROMFilename, temp); } size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0; if (size > 0x20000) size = 0x20000; if (size) { file = fopen(sramName, "rb"); if (file) { len = fread((char *) SRAM, 1, 0x20000, file); fclose(file); if (len - size == 512) memmove(SRAM, SRAM + 512, size); if (Settings.SRTC || Settings.SPC7110RTC) LoadSRTC(); return (TRUE); } else if (Settings.BS && !Settings.BSXItself) { // The BS game's SRAM was not found // Try to read BS-X.srm instead char path[PATH_MAX + 1]; strcpy(path, S9xGetDirectory(SRAM_DIR)); strcat(path, SLASH_STR); strcat(path, "BS-X.srm"); file = fopen(path, "rb"); if (file) { len = fread((char *) SRAM, 1, 0x20000, file); fclose(file); if (len - size == 512) memmove(SRAM, SRAM + 512, size); S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found: BS-X.srm was read instead."); return (TRUE); } else { S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found, BS-X.srm wasn't found either."); return (FALSE); } } return (FALSE); } return (TRUE); } bool8 CMemory::SaveSRAM (const char *filename) { if (Settings.SuperFX && ROMType < 0x15) // doesn't have SRAM return (TRUE); if (Settings.SA1 && ROMType == 0x34) // doesn't have SRAM return (TRUE); FILE *file; int size; char sramName[PATH_MAX + 1]; strcpy(sramName, filename); if (Multi.cartType && Multi.sramSizeB) { char name[PATH_MAX + 1], temp[PATH_MAX + 1]; strcpy(temp, ROMFilename); strcpy(ROMFilename, Multi.fileNameB); strcpy(name, S9xGetFilename(".srm", SRAM_DIR)); size = (1 << (Multi.sramSizeB + 3)) * 128; file = fopen(name, "wb"); if (file) { size_t ignore; ignore = fwrite((char *) Multi.sramB, size, 1, file); fclose(file); } strcpy(ROMFilename, temp); } size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0; if (size > 0x20000) size = 0x20000; if (size) { file = fopen(sramName, "wb"); if (file) { size_t ignore; ignore = fwrite((char *) SRAM, size, 1, file); fclose(file); if (Settings.SRTC || Settings.SPC7110RTC) SaveSRTC(); return (TRUE); } } return (FALSE); } // initialization static uint32 caCRC32 (uint8 *array, uint32 size, uint32 crc32) { for (uint32 i = 0; i < size; i++) crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF]; return (~crc32); } char * CMemory::Safe (const char *s) { static char *safe = NULL; static int safe_len = 0; if (s == NULL) { if (safe) { free(safe); safe = NULL; } return (NULL); } int len = strlen(s); if (!safe || len + 1 > safe_len) { if (safe) free(safe); safe_len = len + 1; safe = (char *) malloc(safe_len); } for (int i = 0; i < len; i++) { if (s[i] >= 32 && s[i] < 127) safe[i] = s[i]; else safe[i] = '_'; } safe[len] = 0; return (safe); } char * CMemory::SafeANK (const char *s) { static char *safe = NULL; static int safe_len = 0; if (s == NULL) { if (safe) { free(safe); safe = NULL; } return (NULL); } int len = strlen(s); if (!safe || len + 1 > safe_len) { if (safe) free(safe); safe_len = len + 1; safe = (char *) malloc(safe_len); } for (int i = 0; i < len; i++) { if (s[i] >= 32 && s[i] < 127) // ASCII safe [i] = s[i]; else if (ROMRegion == 0 && ((uint8) s[i] >= 0xa0 && (uint8) s[i] < 0xe0)) // JIS X 201 - Katakana safe [i] = s[i]; else safe [i] = '_'; } safe [len] = 0; return (safe); } void CMemory::ParseSNESHeader (uint8 *RomHeader) { bool8 bs = Settings.BS & !Settings.BSXItself; strncpy(ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1); if (bs) memset(ROMName + 16, 0x20, ROM_NAME_LEN - 17); if (bs) { if (!(((RomHeader[0x29] & 0x20) && CalculatedSize < 0x100000) || (!(RomHeader[0x29] & 0x20) && CalculatedSize == 0x100000))) printf("BS: Size mismatch\n"); // FIXME int p = 0; while ((1 << p) < (int) CalculatedSize) p++; ROMSize = p - 10; } else ROMSize = RomHeader[0x27]; SRAMSize = bs ? 5 /* BS-X */ : RomHeader[0x28]; ROMSpeed = bs ? RomHeader[0x28] : RomHeader[0x25]; ROMType = bs ? 0xE5 /* BS-X */ : RomHeader[0x26]; ROMRegion = bs ? 0 : RomHeader[0x29]; ROMChecksum = RomHeader[0x2E] + (RomHeader[0x2F] << 8); ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8); memmove(ROMId, &RomHeader[0x02], 4); if (RomHeader[0x2A] != 0x33) CompanyId = ((RomHeader[0x2A] >> 4) & 0x0F) * 36 + (RomHeader[0x2A] & 0x0F); else if (isalnum(RomHeader[0x00]) && isalnum(RomHeader[0x01])) { int l, r, l2, r2; l = toupper(RomHeader[0x00]); r = toupper(RomHeader[0x01]); l2 = (l > '9') ? l - '7' : l - '0'; r2 = (r > '9') ? r - '7' : r - '0'; CompanyId = l2 * 36 + r2; } } void CMemory::InitROM (void) { Settings.SuperFX = FALSE; Settings.DSP = 0; Settings.SA1 = FALSE; Settings.C4 = FALSE; Settings.SDD1 = FALSE; Settings.SPC7110 = FALSE; Settings.SPC7110RTC = FALSE; Settings.OBC1 = FALSE; Settings.SETA = 0; Settings.SRTC = FALSE; Settings.BS = FALSE; SuperFX.nRomBanks = CalculatedSize >> 15; //// Parse ROM header and read ROM informatoin CompanyId = -1; memset(ROMId, 0, 5); uint8 *RomHeader = ROM + 0x7FB0; if (ExtendedFormat == BIGFIRST) RomHeader += 0x400000; if (HiROM) RomHeader += 0x8000; S9xInitBSX(); // Set BS header before parsing ParseSNESHeader(RomHeader); //// Detect and initialize chips //// detection codes are compatible with NSRT // DSP1/2/3/4 if (ROMType == 0x03) { if (ROMSpeed == 0x30) Settings.DSP = 4; // DSP4 else Settings.DSP = 1; // DSP1 } else if (ROMType == 0x05) { if (ROMSpeed == 0x20) Settings.DSP = 2; // DSP2 else if (ROMSpeed == 0x30 && RomHeader[0x2a] == 0xb2) Settings.DSP = 3; // DSP3 else Settings.DSP = 1; // DSP1 } switch (Settings.DSP) { case 1: // DSP1 if (HiROM) { DSP0.boundary = 0x7000; DSP0.maptype = M_DSP1_HIROM; } else if (CalculatedSize > 0x100000) { DSP0.boundary = 0x4000; DSP0.maptype = M_DSP1_LOROM_L; } else { DSP0.boundary = 0xc000; DSP0.maptype = M_DSP1_LOROM_S; } SetDSP = &DSP1SetByte; GetDSP = &DSP1GetByte; break; case 2: // DSP2 DSP0.boundary = 0x10000; DSP0.maptype = M_DSP2_LOROM; SetDSP = &DSP2SetByte; GetDSP = &DSP2GetByte; break; case 3: // DSP3 DSP0.boundary = 0xc000; DSP0.maptype = M_DSP3_LOROM; SetDSP = &DSP3SetByte; GetDSP = &DSP3GetByte; break; case 4: // DSP4 DSP0.boundary = 0xc000; DSP0.maptype = M_DSP4_LOROM; SetDSP = &DSP4SetByte; GetDSP = &DSP4GetByte; break; default: SetDSP = NULL; GetDSP = NULL; break; } uint32 identifier = ((ROMType & 0xff) << 8) + (ROMSpeed & 0xff); switch (identifier) { // SRTC case 0x5535: Settings.SRTC = TRUE; S9xInitSRTC(); break; // SPC7110 case 0xF93A: Settings.SPC7110RTC = TRUE; case 0xF53A: Settings.SPC7110 = TRUE; S9xInitSPC7110(); break; // OBC1 case 0x2530: Settings.OBC1 = TRUE; break; // SA1 case 0x3423: case 0x3523: Settings.SA1 = TRUE; break; // SuperFX case 0x1320: case 0x1420: case 0x1520: case 0x1A20: Settings.SuperFX = TRUE; S9xInitSuperFX(); if (ROM[0x7FDA] == 0x33) SRAMSize = ROM[0x7FBD]; else SRAMSize = 5; break; // SDD1 case 0x4332: case 0x4532: Settings.SDD1 = TRUE; break; // ST018 case 0xF530: Settings.SETA = ST_018; SetSETA = NULL; GetSETA = NULL; SRAMSize = 2; SNESGameFixes.SRAMInitialValue = 0x00; break; // ST010/011 case 0xF630: if (ROM[0x7FD7] == 0x09) { Settings.SETA = ST_011; SetSETA = &S9xSetST011; GetSETA = &S9xGetST011; } else { Settings.SETA = ST_010; SetSETA = &S9xSetST010; GetSETA = &S9xGetST010; } SRAMSize = 2; SNESGameFixes.SRAMInitialValue = 0x00; break; // C4 case 0xF320: Settings.C4 = TRUE; break; } //// Map memory and calculate checksum Map_Initialize(); CalculatedChecksum = 0; // SRAM size SRAMMask = SRAMSize ? ((1 << (SRAMSize + 3)) * 128) - 1 : 0; if (HiROM) { if (Settings.BS) /* Do nothing */; else if (Settings.SPC7110) Map_SPC7110HiROMMap(); else if (ExtendedFormat != NOPE) Map_ExtendedHiROMMap(); else if (Multi.cartType == 3) Map_SameGameHiROMMap(); else Map_HiROMMap(); } else { if (Settings.BS) /* Do nothing */; else if (Settings.SETA && Settings.SETA != ST_018) Map_SetaDSPLoROMMap(); else if (Settings.SuperFX) Map_SuperFXLoROMMap(); else if (Settings.SA1) { if (Multi.cartType == 5) Map_GNEXTSA1LoROMMap(); else Map_SA1LoROMMap(); } else if (Settings.SDD1) Map_SDD1LoROMMap(); else if (ExtendedFormat != NOPE) Map_JumboLoROMMap(); else if (strncmp(ROMName, "WANDERERS FROM YS", 17) == 0) Map_NoMAD1LoROMMap(); else if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 || strncmp(ROMName, "DERBY STALLION 96", 17) == 0) Map_ROM24MBSLoROMMap(); else if (strncmp(ROMName, "THOROUGHBRED BREEDER3", 21) == 0 || strncmp(ROMName, "RPG-TCOOL 2", 11) == 0) Map_SRAM512KLoROMMap(); else if (strncmp(ROMName, "ADD-ON BASE CASSETE", 19) == 0) { if (Multi.cartType == 4) { SRAMSize = Multi.sramSizeA; Map_SufamiTurboLoROMMap(); } else { SRAMSize = 5; Map_SufamiTurboPseudoLoROMMap(); } } else Map_LoROMMap(); } Checksum_Calculate(); bool8 isChecksumOK = (ROMChecksum + ROMComplementChecksum == 0xffff) & (ROMChecksum == CalculatedChecksum); //// Build more ROM information // CRC32 if (!Settings.BS || Settings.BSXItself) // Not BS Dump ROMCRC32 = caCRC32(ROM, CalculatedSize); else // Convert to correct format before scan { int offset = HiROM ? 0xffc0 : 0x7fc0; // Backup uint8 BSMagic0 = ROM[offset + 22], BSMagic1 = ROM[offset + 23]; // uCONSRT standard ROM[offset + 22] = 0x42; ROM[offset + 23] = 0x00; // Calc ROMCRC32 = caCRC32(ROM, CalculatedSize); // Convert back ROM[offset + 22] = BSMagic0; ROM[offset + 23] = BSMagic1; } // NTSC/PAL if (Settings.ForceNTSC) Settings.PAL = FALSE; else if (Settings.ForcePAL) Settings.PAL = TRUE; else if (!Settings.BS && (ROMRegion >= 2) && (ROMRegion <= 12)) Settings.PAL = TRUE; else Settings.PAL = FALSE; if (Settings.PAL) { Settings.FrameTime = Settings.FrameTimePAL; ROMFramesPerSecond = 50; } else { Settings.FrameTime = Settings.FrameTimeNTSC; ROMFramesPerSecond = 60; } // truncate cart name ROMName[ROM_NAME_LEN - 1] = 0; if (strlen(ROMName)) { char *p = ROMName + strlen(ROMName); if (p > ROMName + 21 && ROMName[20] == ' ') p = ROMName + 21; while (p > ROMName && *(p - 1) == ' ') p--; *p = 0; } // checksum if (!isChecksumOK || ((uint32) CalculatedSize > (uint32) (((1 << (ROMSize - 7)) * 128) * 1024))) { Settings.DisplayColor = BUILD_PIXEL(31, 31, 0); SET_UI_COLOR(255, 255, 0); } if (Multi.cartType == 4) { Settings.DisplayColor = BUILD_PIXEL(0, 16, 31); SET_UI_COLOR(0, 128, 255); } //// Initialize emulation Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE; Timings.H_Max = Timings.H_Max_Master; Timings.HBlankStart = SNES_HBLANK_START_HC; Timings.HBlankEnd = SNES_HBLANK_END_HC; Timings.HDMAInit = SNES_HDMA_INIT_HC; Timings.HDMAStart = SNES_HDMA_START_HC; Timings.RenderPos = SNES_RENDER_START_HC; Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER; Timings.V_Max = Timings.V_Max_Master; /* From byuu: The total delay time for both the initial (H)DMA sync (to the DMA clock), and the end (H)DMA sync (back to the last CPU cycle's mcycle rate (6, 8, or 12)) always takes between 12-24 mcycles. Possible delays: { 12, 14, 16, 18, 20, 22, 24 } XXX: Snes9x can't emulate this timing :( so let's use the average value... */ Timings.DMACPUSync = 18; /* If the CPU is halted (i.e. for DMA) while /NMI goes low, the NMI will trigger after the DMA completes (even if /NMI goes high again before the DMA completes). In this case, there is a 24-30 cycle delay between the end of DMA and the NMI handler, time enough for an instruction or two. */ // Wild Guns, Mighty Morphin Power Rangers - The Fighting Edition Timings.NMIDMADelay = 24; Timings.IRQPendCount = 0; IPPU.TotalEmulatedFrames = 0; //// Hack games ApplyROMFixes(); //// Show ROM information char displayName[ROM_NAME_LEN]; strcpy(RawROMName, ROMName); sprintf(displayName, "%s", SafeANK(ROMName)); sprintf(ROMName, "%s", Safe(ROMName)); sprintf(ROMId, "%s", Safe(ROMId)); sprintf(String, "\"%s\" [%s] %s, %s, %s, %s, SRAM:%s, ID:%s, CRC32:%08X", displayName, isChecksumOK ? "checksum ok" : ((Multi.cartType == 4) ? "no checksum" : "bad checksum"), MapType(), Size(), KartContents(), Settings.PAL ? "PAL" : "NTSC", StaticRAMSize(), ROMId, ROMCRC32); S9xMessage(S9X_INFO, S9X_ROM_INFO, String); Settings.ForceLoROM = FALSE; Settings.ForceHiROM = FALSE; Settings.ForceHeader = FALSE; Settings.ForceNoHeader = FALSE; Settings.ForceInterleaved = FALSE; Settings.ForceInterleaved2 = FALSE; Settings.ForceInterleaveGD24 = FALSE; Settings.ForceNotInterleaved = FALSE; Settings.ForcePAL = FALSE; Settings.ForceNTSC = FALSE; Settings.TakeScreenshot = FALSE; if (stopMovie) S9xMovieStop(TRUE); if (PostRomInitFunc) PostRomInitFunc(); S9xVerifyControllers(); } // memory map uint32 CMemory::map_mirror (uint32 size, uint32 pos) { // from bsnes if (size == 0) return (0); if (pos < size) return (pos); uint32 mask = 1 << 31; while (!(pos & mask)) mask >>= 1; if (size <= (pos & mask)) return (map_mirror(size, pos - mask)); else return (mask + map_mirror(size - mask, pos - mask)); } void CMemory::map_lorom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, bool auto_export_map) { uint32 c, i, p, addr; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); addr = (c & 0x7f) * 0x8000; Map[p] = ROM + map_mirror(size, addr) - (i & 0x8000); BlockIsROM[p] = TRUE; BlockIsRAM[p] = FALSE; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.flags=RETRO_MEMDESC_CONST; desc.ptr=ROM; desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; desc.disconnect=0x8000; desc.len=size; S9xAppendMapping(&desc); } #endif } void CMemory::map_hirom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, bool auto_export_map) { uint32 c, i, p, addr; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); addr = c << 16; Map[p] = ROM + map_mirror(size, addr); BlockIsROM[p] = TRUE; BlockIsRAM[p] = FALSE; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.flags=RETRO_MEMDESC_CONST; desc.ptr=ROM; desc.offset=map_mirror(size, addr_s); desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; desc.len=size - desc.offset; S9xAppendMapping(&desc); } #endif } void CMemory::map_lorom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset, bool auto_export_map) { uint32 c, i, p, addr; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); addr = ((c - bank_s) & 0x7f) * 0x8000; Map[p] = ROM + offset + map_mirror(size, addr) - (i & 0x8000); BlockIsROM[p] = TRUE; BlockIsRAM[p] = FALSE; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.flags=RETRO_MEMDESC_CONST; desc.ptr=ROM; desc.offset=offset; desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; desc.disconnect=0x8000; desc.len=size; S9xAppendMapping(&desc); } #endif } void CMemory::map_hirom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset, bool auto_export_map) { uint32 c, i, p, addr; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); addr = (c - bank_s) << 16; Map[p] = ROM + offset + map_mirror(size, addr); BlockIsROM[p] = TRUE; BlockIsRAM[p] = FALSE; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.flags=RETRO_MEMDESC_CONST; desc.ptr=ROM; desc.offset=map_mirror(size, offset + addr_s); desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; desc.len=size; S9xAppendMapping(&desc); } #endif } void CMemory::map_space (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint8 *data, bool auto_export_map) { uint32 c, i, p; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); Map[p] = data; BlockIsROM[p] = FALSE; BlockIsRAM[p] = TRUE; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.ptr=data; desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; desc.disconnect=0xFF0000; S9xAppendMapping(&desc); } #endif } void CMemory::map_index (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, int index, int type, bool auto_export_map) { uint32 c, i, p; bool8 isROM, isRAM; isROM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_RAM)) ? FALSE : TRUE; isRAM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_ROM)) ? FALSE : TRUE; for (c = bank_s; c <= bank_e; c++) { for (i = addr_s; i <= addr_e; i += 0x1000) { p = (c << 4) | (i >> 12); Map[p] = (uint8 *) index; BlockIsROM[p] = isROM; BlockIsRAM[p] = isRAM; } } #ifdef __LIBRETRO__ if (auto_export_map) { struct retro_memory_descriptor desc = {0}; desc.start=bank_s<<16 | addr_s; desc.select=(bank_s<<16 | addr_s) ^ (bank_e<<16 | addr_e) ^ 0xFFFFFF; if (type==MAP_LOROM_SRAM || type==MAP_SA1RAM) { desc.ptr=Memory.SRAM; desc.disconnect=0x8000; desc.len=Memory.SRAMMask+1; S9xAppendMapping(&desc); } if (type==MAP_LOROM_SRAM_B) { desc.ptr=Multi.sramB; desc.disconnect=0x8000; desc.len=Multi.sramMaskB+1; S9xAppendMapping(&desc); } if (type==MAP_HIROM_SRAM || type==MAP_RONLY_SRAM) { desc.ptr=Memory.SRAM; desc.disconnect=0x00E000; desc.len=Memory.SRAMMask+1; S9xAppendMapping(&desc); } if (type==MAP_BWRAM) { desc.ptr=Memory.SRAM;//this one varies, but we can't use variable maps in this system. desc.disconnect=0xFFE000;//It's the same as SRAM, anyways. Let's point it to there and let the front ignore it. S9xAppendMapping(&desc); } } #endif } void CMemory::map_System (void) { // will be overwritten map_space(0x00, 0x3f, 0x0000, 0x1fff, RAM); map_index(0x00, 0x3f, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O); map_index(0x00, 0x3f, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O); map_space(0x80, 0xbf, 0x0000, 0x1fff, RAM); map_index(0x80, 0xbf, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O); } void CMemory::map_WRAM (void) { // will overwrite others map_space(0x7e, 0x7e, 0x0000, 0xffff, RAM); map_space(0x7f, 0x7f, 0x0000, 0xffff, RAM + 0x10000); } void CMemory::map_LoROMSRAM (void) { map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM); map_index(0xf0, 0xff, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM); } void CMemory::map_HiROMSRAM (void) { map_index(0x20, 0x3f, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); } void CMemory::map_DSP (void) { switch (DSP0.maptype) { case M_DSP1_LOROM_S: map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); break; case M_DSP1_LOROM_L: map_index(0x60, 0x6f, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O); map_index(0xe0, 0xef, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O); break; case M_DSP1_HIROM: map_index(0x00, 0x1f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O); map_index(0x80, 0x9f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O); break; case M_DSP2_LOROM: map_index(0x20, 0x3f, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O); map_index(0x20, 0x3f, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O); map_index(0xa0, 0xbf, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O); map_index(0xa0, 0xbf, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O); break; case M_DSP3_LOROM: map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); break; case M_DSP4_LOROM: map_index(0x30, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); map_index(0xb0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O); break; } } void CMemory::map_C4 (void) { map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O); } void CMemory::map_OBC1 (void) { map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O); } void CMemory::map_SetaRISC (void) { map_index(0x00, 0x3f, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O); } void CMemory::map_SetaDSP (void) { // where does the SETA chip access, anyway? // please confirm this? map_index(0x68, 0x6f, 0x0000, 0x7fff, MAP_SETA_DSP, MAP_TYPE_RAM); // and this! map_index(0x60, 0x67, 0x0000, 0x3fff, MAP_SETA_DSP, MAP_TYPE_I_O); // ST-0010: // map_index(0x68, 0x6f, 0x0000, 0x0fff, MAP_SETA_DSP, ?); } void CMemory::map_WriteProtectROM (void) { memmove((void *) WriteMap, (void *) Map, sizeof(Map)); for (int c = 0; c < 0x1000; c++) { if (BlockIsROM[c]) WriteMap[c] = (uint8 *) MAP_NONE; } } void CMemory::Map_Initialize (void) { for (int c = 0; c < 0x1000; c++) { Map[c] = (uint8 *) MAP_NONE; WriteMap[c] = (uint8 *) MAP_NONE; BlockIsROM[c] = FALSE; BlockIsRAM[c] = FALSE; } } void CMemory::Map_LoROMMap (void) { printf("Map_LoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize); if (Settings.DSP) map_DSP(); else if (Settings.C4) map_C4(); else if (Settings.OBC1) map_OBC1(); else if (Settings.SETA == ST_018) map_SetaRISC(); map_LoROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_NoMAD1LoROMMap (void) { printf("Map_NoMAD1LoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize); map_index(0x70, 0x7f, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM); map_index(0xf0, 0xff, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_JumboLoROMMap (void) { // XXX: Which game uses this? printf("Map_JumboLoROMMap\n"); map_System(); map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000); map_lorom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x600000, 0x600000); map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0); map_lorom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0x200000); map_LoROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_ROM24MBSLoROMMap (void) { // PCB: BSC-1A5M-01, BSC-1A7M-10 printf("Map_ROM24MBSLoROMMap\n"); map_System(); map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x100000, 0); map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000); map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x100000, 0x200000); map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000); map_LoROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SRAM512KLoROMMap (void) { printf("Map_SRAM512KLoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize); map_space(0x70, 0x70, 0x0000, 0xffff, SRAM); map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x8000); map_space(0x72, 0x72, 0x0000, 0xffff, SRAM + 0x10000); map_space(0x73, 0x73, 0x0000, 0xffff, SRAM + 0x18000); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SufamiTurboLoROMMap (void) { printf("Map_SufamiTurboLoROMMap\n"); map_System(); map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0); map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0); map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); if (Multi.sramSizeA) { map_index(0x60, 0x63, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM); map_index(0xe0, 0xe3, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM); } if (Multi.sramSizeB) { map_index(0x70, 0x73, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM); map_index(0xf0, 0xf3, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM); } map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SufamiTurboPseudoLoROMMap (void) { // for combined images printf("Map_SufamiTurboPseudoLoROMMap\n"); map_System(); map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0); map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000); map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, 0x100000, 0x200000); map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0); map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000); map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, 0x100000, 0x200000); // I don't care :P map_space(0x60, 0x63, 0x8000, 0xffff, SRAM - 0x8000); map_space(0xe0, 0xe3, 0x8000, 0xffff, SRAM - 0x8000); map_space(0x70, 0x73, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000, false);//these two seem to duplicate the above ones in map_space(0xf0, 0xf3, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000, false);//way that makes the duplicates hard to find. map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SuperFXLoROMMap (void) { printf("Map_SuperFXLoROMMap\n"); map_System(); // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K // block is repeated twice in each 64K block. for (int c = 0; c < 64; c++) { memmove(&ROM[0x200000 + c * 0x10000], &ROM[c * 0x8000], 0x8000); memmove(&ROM[0x208000 + c * 0x10000], &ROM[c * 0x8000], 0x8000); } map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize, 0); map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0); map_space(0x00, 0x3f, 0x6000, 0x7fff, SRAM - 0x6000); map_space(0x80, 0xbf, 0x6000, 0x7fff, SRAM - 0x6000); map_space(0x70, 0x70, 0x0000, 0xffff, SRAM); map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x10000); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SetaDSPLoROMMap (void) { printf("Map_SetaDSPLoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x40, 0x7f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_lorom(0xc0, 0xff, 0x8000, 0xffff, CalculatedSize); map_SetaDSP(); map_LoROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SDD1LoROMMap (void) { printf("Map_SDD1LoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize, 0); map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0); // will be overwritten dynamically map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SA1LoROMMap (void) { printf("Map_SA1LoROMMap\n"); map_System(); map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0); map_space(0x00, 0x3f, 0x3000, 0x3fff, FillRAM); map_space(0x80, 0xbf, 0x3000, 0x3fff, FillRAM); map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); for (int c = 0x40; c < 0x80; c++) map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000); map_WRAM(); map_WriteProtectROM(); // Now copy the map and correct it for the SA1 CPU. memmove((void *) SA1.Map, (void *) Map, sizeof(Map)); memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap)); // SA-1 Banks 00->3f and 80->bf for (int c = 0x000; c < 0x400; c += 0x10) { SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000; SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8 *) MAP_NONE; SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000; SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8 *) MAP_NONE; } // SA-1 Banks 60->6f for (int c = 0x600; c < 0x700; c++) SA1.Map[c] = SA1.WriteMap[c] = (uint8 *) MAP_BWRAM_BITMAP; BWRAM = SRAM; } void CMemory::Map_GNEXTSA1LoROMMap (void) { printf("Map_GNEXTSA1LoROMMap\n"); map_System(); map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_space(0x00, 0x3f, 0x3000, 0x3fff, FillRAM); map_space(0x80, 0xbf, 0x3000, 0x3fff, FillRAM); map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); for (int c = 0x40; c < 0x80; c++) map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000); // FIXME: untested! map_hirom_offset(0x70, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_WRAM(); map_WriteProtectROM(); // Now copy the map and correct it for the SA1 CPU. memmove((void *) SA1.Map, (void *) Map, sizeof(Map)); memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap)); // SA-1 Banks 00->3f and 80->bf for (int c = 0x000; c < 0x400; c += 0x10) { SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000; SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8 *) MAP_NONE; SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000; SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8 *) MAP_NONE; } // SA-1 Banks 60->6f for (int c = 0x600; c < 0x700; c++) SA1.Map[c] = SA1.WriteMap[c] = (uint8 *) MAP_BWRAM_BITMAP; BWRAM = SRAM; } void CMemory::Map_HiROMMap (void) { printf("Map_HiROMMap\n"); map_System(); map_hirom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); map_hirom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize); map_hirom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); map_hirom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize); if (Settings.DSP) map_DSP(); map_HiROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_ExtendedHiROMMap (void) { printf("Map_ExtendedHiROMMap\n"); map_System(); map_hirom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000); map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x400000, 0x400000); map_hirom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0); map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0); map_HiROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SameGameHiROMMap (void) { printf("Map_SameGameHiROMMap\n"); map_System(); map_hirom_offset(0x00, 0x1f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_hirom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_hirom_offset(0x40, 0x5f, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_hirom_offset(0x80, 0x9f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_hirom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_hirom_offset(0xc0, 0xdf, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); map_HiROMSRAM(); map_WRAM(); map_WriteProtectROM(); } void CMemory::Map_SPC7110HiROMMap (void) { printf("Map_SPC7110HiROMMap\n"); map_System(); map_index(0x00, 0x00, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); map_hirom(0x00, 0x0f, 0x8000, 0xffff, CalculatedSize); map_index(0x30, 0x30, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); map_index(0x50, 0x50, 0x0000, 0xffff, MAP_SPC7110_DRAM, MAP_TYPE_ROM); map_hirom(0x80, 0x8f, 0x8000, 0xffff, CalculatedSize); map_hirom_offset(0xc0, 0xcf, 0x0000, 0xffff, CalculatedSize, 0); map_index(0xd0, 0xff, 0x0000, 0xffff, MAP_SPC7110_ROM, MAP_TYPE_ROM); map_WRAM(); map_WriteProtectROM(); } // checksum uint16 CMemory::checksum_calc_sum (uint8 *data, uint32 length) { uint16 sum = 0; for (uint32 i = 0; i < length; i++) sum += data[i]; return (sum); } uint16 CMemory::checksum_mirror_sum (uint8 *start, uint32 &length, uint32 mask) { // from NSRT while (!(length & mask) && mask) mask >>= 1; uint16 part1 = checksum_calc_sum(start, mask); uint16 part2 = 0; uint32 next_length = length - mask; if (next_length) { part2 = checksum_mirror_sum(start + mask, next_length, mask >> 1); while (next_length < mask) { next_length += next_length; part2 += part2; } length = mask + mask; } return (part1 + part2); } void CMemory::Checksum_Calculate (void) { // from NSRT uint16 sum = 0; if (Settings.BS && !Settings.BSXItself) sum = checksum_calc_sum(ROM, CalculatedSize) - checksum_calc_sum(ROM + (HiROM ? 0xffb0 : 0x7fb0), 48); else if (Settings.SPC7110) { sum = checksum_calc_sum(ROM, CalculatedSize); if (CalculatedSize == 0x300000) sum += sum; } else { if (CalculatedSize & 0x7fff) sum = checksum_calc_sum(ROM, CalculatedSize); else { uint32 length = CalculatedSize; sum = checksum_mirror_sum(ROM, length); } } CalculatedChecksum = sum; } // information const char * CMemory::MapType (void) { return (HiROM ? ((ExtendedFormat != NOPE) ? "ExHiROM": "HiROM") : "LoROM"); } const char * CMemory::StaticRAMSize (void) { static char str[20]; if (SRAMSize > 16) strcpy(str, "Corrupt"); else sprintf(str, "%dKbits", 8 * (SRAMMask + 1) / 1024); return (str); } const char * CMemory::Size (void) { static char str[20]; if (Multi.cartType == 4) strcpy(str, "N/A"); else if (ROMSize < 7 || ROMSize - 7 > 23) strcpy(str, "Corrupt"); else sprintf(str, "%dMbits", 1 << (ROMSize - 7)); return (str); } const char * CMemory::Revision (void) { static char str[20]; sprintf(str, "1.%d", HiROM ? ((ExtendedFormat != NOPE) ? ROM[0x40ffdb] : ROM[0xffdb]) : ROM[0x7fdb]); return (str); } const char * CMemory::KartContents (void) { static char str[64]; static const char *contents[3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" }; char chip[16]; if (ROMType == 0 && !Settings.BS) return ("ROM"); if (Settings.BS) strcpy(chip, "+BS"); else if (Settings.SuperFX) strcpy(chip, "+Super FX"); else if (Settings.SDD1) strcpy(chip, "+S-DD1"); else if (Settings.OBC1) strcpy(chip, "+OBC1"); else if (Settings.SA1) strcpy(chip, "+SA-1"); else if (Settings.SPC7110RTC) strcpy(chip, "+SPC7110+RTC"); else if (Settings.SPC7110) strcpy(chip, "+SPC7110"); else if (Settings.SRTC) strcpy(chip, "+S-RTC"); else if (Settings.C4) strcpy(chip, "+C4"); else if (Settings.SETA == ST_010) strcpy(chip, "+ST-010"); else if (Settings.SETA == ST_011) strcpy(chip, "+ST-011"); else if (Settings.SETA == ST_018) strcpy(chip, "+ST-018"); else if (Settings.DSP) sprintf(chip, "+DSP-%d", Settings.DSP); else strcpy(chip, ""); sprintf(str, "%s%s", contents[(ROMType & 0xf) % 3], chip); return (str); } const char * CMemory::Country (void) { switch (ROMRegion) { case 0: return("Japan"); case 1: return("USA and Canada"); case 2: return("Oceania, Europe and Asia"); case 3: return("Sweden"); case 4: return("Finland"); case 5: return("Denmark"); case 6: return("France"); case 7: return("Holland"); case 8: return("Spain"); case 9: return("Germany, Austria and Switzerland"); case 10: return("Italy"); case 11: return("Hong Kong and China"); case 12: return("Indonesia"); case 13: return("South Korea"); default: return("Unknown"); } } const char * CMemory::PublishingCompany (void) { if (CompanyId >= (int) (sizeof(nintendo_licensees) / sizeof(nintendo_licensees[0])) || CompanyId < 0) return ("Unknown"); if (nintendo_licensees[CompanyId] == NULL) return ("Unknown"); return (nintendo_licensees[CompanyId]); } void CMemory::MakeRomInfoText (char *romtext) { char temp[256]; romtext[0] = 0; sprintf(temp, " Cart Name: %s", ROMName); strcat(romtext, temp); sprintf(temp, "\n Game Code: %s", ROMId); strcat(romtext, temp); sprintf(temp, "\n Contents: %s", KartContents()); strcat(romtext, temp); sprintf(temp, "\n Map: %s", MapType()); strcat(romtext, temp); sprintf(temp, "\n Speed: 0x%02X (%s)", ROMSpeed, (ROMSpeed & 0x10) ? "FastROM" : "SlowROM"); strcat(romtext, temp); sprintf(temp, "\n Type: 0x%02X", ROMType); strcat(romtext, temp); sprintf(temp, "\n Size (calculated): %dMbits", CalculatedSize / 0x20000); strcat(romtext, temp); sprintf(temp, "\n Size (header): %s", Size()); strcat(romtext, temp); sprintf(temp, "\n SRAM size: %s", StaticRAMSize()); strcat(romtext, temp); sprintf(temp, "\nChecksum (calculated): 0x%04X", CalculatedChecksum); strcat(romtext, temp); sprintf(temp, "\n Checksum (header): 0x%04X", ROMChecksum); strcat(romtext, temp); sprintf(temp, "\n Complement (header): 0x%04X", ROMComplementChecksum); strcat(romtext, temp); sprintf(temp, "\n Video Output: %s", (ROMRegion > 12 || ROMRegion < 2) ? "NTSC 60Hz" : "PAL 50Hz"); strcat(romtext, temp); sprintf(temp, "\n Revision: %s", Revision()); strcat(romtext, temp); sprintf(temp, "\n Licensee: %s", PublishingCompany()); strcat(romtext, temp); sprintf(temp, "\n Region: %s", Country()); strcat(romtext, temp); sprintf(temp, "\n CRC32: 0x%08X", ROMCRC32); strcat(romtext, temp); } // hack bool8 CMemory::match_na (const char *str) { return (strcmp(ROMName, str) == 0); } bool8 CMemory::match_nn (const char *str) { return (strncmp(ROMName, str, strlen(str)) == 0); } bool8 CMemory::match_nc (const char *str) { return (strncasecmp(ROMName, str, strlen(str)) == 0); } bool8 CMemory::match_id (const char *str) { return (strncmp(ROMId, str, strlen(str)) == 0); } void CMemory::ApplyROMFixes (void) { Settings.BlockInvalidVRAMAccess = Settings.BlockInvalidVRAMAccessMaster; //// Warnings // Reject strange hacked games if ((ROMCRC32 == 0x6810aa95) || (ROMCRC32 == 0x340f23e5) || (ROMCRC32 == 0x77fd806a) || (match_nn("HIGHWAY BATTLE 2")) || (match_na("FX SKIING NINTENDO 96") && (ROM[0x7fda] == 0)) || (match_nn("HONKAKUHA IGO GOSEI") && (ROM[0xffd5] != 0x31))) { Settings.DisplayColor = BUILD_PIXEL(31, 0, 0); SET_UI_COLOR(255, 0, 0); } //// APU timing hacks :( Timings.APUSpeedup = 0; if (!Settings.DisableGameSpecificHacks) { if (match_id("AVCJ")) // Rendering Ranger R2 Timings.APUSpeedup = 2; /* if (match_na("GAIA GENSOUKI 1 JPN") || // Gaia Gensouki match_id("JG ") || // Illusion of Gaia match_id("CQ ") || // Stunt Race FX match_na("SOULBLADER - 1") || // Soul Blader match_na("SOULBLAZER - 1 USA") || // Soul Blazer match_na("SLAP STICK 1 JPN") || // Slap Stick match_id("E9 ") || // Robotrek match_nn("ACTRAISER") || // Actraiser match_nn("ActRaiser-2") || // Actraiser 2 match_id("AQT") || // Tenchi Souzou, Terranigma match_id("ATV") || // Tales of Phantasia match_id("ARF") || // Star Ocean match_id("APR") || // Zen-Nippon Pro Wrestling 2 - 3-4 Budoukan match_id("A4B") || // Super Bomberman 4 match_id("Y7 ") || // U.F.O. Kamen Yakisoban - Present Ban match_id("Y9 ") || // U.F.O. Kamen Yakisoban - Shihan Ban match_id("APB") || // Super Bomberman - Panic Bomber W match_na("DARK KINGDOM") || // Dark Kingdom match_na("ZAN3 SFC") || // Zan III Spirits match_na("HIOUDEN") || // Hiouden - Mamono-tachi Tono Chikai match_na("\xC3\xDD\xBC\xC9\xB3\xC0") || // Tenshi no Uta match_na("FORTUNE QUEST") || // Fortune Quest - Dice wo Korogase match_na("FISHING TO BASSING") || // Shimono Masaki no Fishing To Bassing match_na("OHMONO BLACKBASS") || // Oomono Black Bass Fishing - Jinzouko Hen match_na("MASTERS") || // Harukanaru Augusta 2 - Masters match_na("SFC \xB6\xD2\xDD\xD7\xB2\xC0\xDE\xB0") || // Kamen Rider match_na("ZENKI TENCHIMEIDOU") || // Kishin Douji Zenki - Tenchi Meidou match_nn("TokyoDome '95Battle 7") || // Shin Nippon Pro Wrestling Kounin '95 - Tokyo Dome Battle 7 match_nn("SWORD WORLD SFC") || // Sword World SFC/2 match_nn("LETs PACHINKO(") || // BS Lets Pachinko Nante Gindama 1/2/3/4 match_nn("THE FISHING MASTER") || // Mark Davis The Fishing Master match_nn("Parlor") || // Parlor mini/2/3/4/5/6/7, Parlor Parlor!/2/3/4/5 match_na("HEIWA Parlor!Mini8") || // Parlor mini 8 match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever! Timings.APUSpeedup = 1; */ } S9xAPUTimingSetSpeedup(Timings.APUSpeedup); //// Other timing hacks :( Timings.HDMAStart = SNES_HDMA_START_HC + Settings.HDMATimingHack - 100; Timings.HBlankStart = SNES_HBLANK_START_HC + Timings.HDMAStart - SNES_HDMA_START_HC; Timings.IRQTriggerCycles = 10; if (!Settings.DisableGameSpecificHacks) { // The delay to sync CPU and DMA which Snes9x cannot emulate. // Some games need really severe delay timing... if (match_na("BATTLE GRANDPRIX")) // Battle Grandprix { Timings.DMACPUSync = 20; printf("DMA sync: %d\n", Timings.DMACPUSync); } } if (!Settings.DisableGameSpecificHacks) { // An infinite loop reads $4212 and waits V-blank end, whereas VIRQ is set V=0. // If Snes9x succeeds to escape from the loop before jumping into the IRQ handler, the game goes further. // If Snes9x jumps into the IRQ handler before escaping from the loop, // Snes9x cannot escape from the loop permanently because the RTI is in the next V-blank. if (match_na("Aero the AcroBat 2")) { Timings.IRQPendCount = 2; printf("IRQ count hack: %d\n", Timings.IRQPendCount); } } if (!Settings.DisableGameSpecificHacks) { // XXX: What's happening? if (match_na("X-MEN")) // Spider-Man and the X-Men { Settings.BlockInvalidVRAMAccess = FALSE; printf("Invalid VRAM access hack\n"); } } //// SRAM initial value if (!Settings.DisableGameSpecificHacks) { if (match_na("HITOMI3")) { SRAMSize = 1; SRAMMask = ((1 << (SRAMSize + 3)) * 128) - 1; } // SRAM value fixes if (match_na("SUPER DRIFT OUT") || // Super Drift Out match_na("SATAN IS OUR FATHER!") || match_na("goemon 4")) // Ganbare Goemon Kirakira Douchuu SNESGameFixes.SRAMInitialValue = 0x00; // Additional game fixes by sanmaiwashi ... // XXX: unnecessary? if (match_na("SFX \xC5\xB2\xC4\xB6\xDE\xDD\xC0\xDE\xD1\xD3\xC9\xB6\xDE\xC0\xD8 1")) // SD Gundam Gaiden - Knight Gundam Monogatari SNESGameFixes.SRAMInitialValue = 0x6b; // others: BS and ST-01x games are 0x00. } //// OAM hacks :( if (!Settings.DisableGameSpecificHacks) { // OAM hacks because we don't fully understand the behavior of the SNES. // Totally wacky display in 2P mode... // seems to need a disproven behavior, so we're definitely overlooking some other bug? if (match_nn("UNIRACERS")) // Uniracers { SNESGameFixes.Uniracers = TRUE; printf("Applied Uniracers hack.\n"); } } } // BPS % UPS % IPS // number decoding used for both BPS and UPS static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size) { uint32 offset = 0, shift = 1; while(addr < size) { uint8 x = data[addr++]; offset += (x & 0x7f) * shift; if(x & 0x80) break; shift <<= 7; offset += shift; } return offset; } //NOTE: UPS patches are *never* created against a headered ROM! //this is per the UPS file specification. however, do note that it is //technically possible for a non-compliant patcher to ignore this requirement. //therefore, it is *imperative* that no emulator support such patches. //thusly, we ignore the "long offset" parameter below. failure to do so would //completely invalidate the purpose of UPS; which is to avoid header vs //no-header patching errors that result in IPS patches having a 50/50 chance of //being applied correctly. static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size) { //Reader lacks size() and rewind(), so we need to read in the file to get its size uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ... uint32 size = 0; while(true) { int value = r->get_char(); if(value == EOF) break; data[size++] = value; if(size >= 8 * 1024 * 1024) { //prevent buffer overflow: SNES-made UPS patches should never be this big anyway ... delete[] data; return false; } } //4-byte header + 1-byte input size + 1-byte output size + 4-byte patch CRC32 + 4-byte unpatched CRC32 + 4-byte patched CRC32 if(size < 18) { delete[] data; return false; } //patch is too small uint32 addr = 0; if(data[addr++] != 'U') { delete[] data; return false; } //patch has an invalid header if(data[addr++] != 'P') { delete[] data; return false; } //... if(data[addr++] != 'S') { delete[] data; return false; } //... if(data[addr++] != '1') { delete[] data; return false; } //... uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size); uint32 px_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24); uint32 py_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24); uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24); if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted if((rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) { delete[] data; return false; } //patch is for a different ROM uint32 px_size = XPSdecode(data, addr, size); uint32 py_size = XPSdecode(data, addr, size); uint32 out_size = ((uint32) rom_size == px_size) ? py_size : px_size; if(out_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer //fill expanded area with 0x00s; so that XORing works as expected below. //note that this is needed (and works) whether output ROM is larger or smaller than pre-patched ROM for(unsigned i = min((uint32) rom_size, out_size); i < max((uint32) rom_size, out_size); i++) { Memory.ROM[i] = 0x00; } uint32 relative = 0; while(addr < size - 12) { relative += XPSdecode(data, addr, size); while(addr < size - 12) { uint8 x = data[addr++]; Memory.ROM[relative++] ^= x; if(!x) break; } } rom_size = out_size; delete[] data; uint32 out_crc32 = caCRC32(Memory.ROM, rom_size); if(((rom_crc32 == px_crc32) && (out_crc32 == py_crc32)) || ((rom_crc32 == py_crc32) && (out_crc32 == px_crc32)) ) { return true; } else { //technically, reaching here means that patching has failed. //we should return false, but unfortunately Memory.ROM has already //been modified above and cannot be undone. to do this properly, we //would need to make a copy of Memory.ROM, apply the patch, and then //copy that back to Memory.ROM. // //however, the only way for this case to happen is if the UPS patch file //itself is corrupted, which should be detected by the patch CRC32 check //above anyway. errors due to the wrong ROM or patch file being used are //already caught above. fprintf(stderr, "WARNING: UPS patching appears to have failed.\nGame may not be playable.\n"); return true; } } // header notes for UPS patches also apply to BPS // // logic taken from http://byuu.org/programming/bps and the accompanying source // static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size) { uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ... uint32 size = 0; while(true) { int value = r->get_char(); if(value == EOF) break; data[size++] = value; if(size >= 8 * 1024 * 1024) { //prevent buffer overflow: SNES-made BPS patches should never be this big anyway ... delete[] data; return false; } } /* 4-byte header + 1-byte input size + 1-byte output size + 1-byte metadata size + 4-byte unpatched CRC32 + 4-byte patched CRC32 + 4-byte patch CRC32 */ if(size < 19) { delete[] data; return false; } //patch is too small uint32 addr = 0; if(data[addr++] != 'B') { delete[] data; return false; } //patch has an invalid header if(data[addr++] != 'P') { delete[] data; return false; } //... if(data[addr++] != 'S') { delete[] data; return false; } //... if(data[addr++] != '1') { delete[] data; return false; } //... uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size); uint32 source_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24); uint32 target_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24); uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24); if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted if(rom_crc32 != source_crc32) { delete[] data; return false; } //patch is for a different ROM uint32 source_size = XPSdecode(data, addr, size); uint32 target_size = XPSdecode(data, addr, size); uint32 metadata_size = XPSdecode(data, addr, size); addr += metadata_size; if(target_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer enum { SourceRead, TargetRead, SourceCopy, TargetCopy }; uint32 outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0; uint8 *patched_rom = new uint8[target_size]; memset(patched_rom,0,target_size); while(addr < size - 12) { uint32 length = XPSdecode(data, addr, size); uint32 mode = length & 3; length = (length >> 2) + 1; switch((int)mode) { case SourceRead: while(length--) patched_rom[outputOffset++] = Memory.ROM[outputOffset]; break; case TargetRead: while(length--) patched_rom[outputOffset++] = data[addr++]; break; case SourceCopy: case TargetCopy: int32 offset = XPSdecode(data, addr, size); bool negative = offset & 1; offset >>= 1; if(negative) offset = -offset; if(mode == SourceCopy) { sourceRelativeOffset += offset; while(length--) patched_rom[outputOffset++] = Memory.ROM[sourceRelativeOffset++]; } else { targetRelativeOffset += offset; while(length--) patched_rom[outputOffset++] = patched_rom[targetRelativeOffset++]; } break; } } delete[] data; uint32 out_crc32 = caCRC32(patched_rom, target_size); if(out_crc32 == target_crc32) { memcpy(Memory.ROM, patched_rom, target_size); rom_size = target_size; delete[] patched_rom; return true; } else { delete[] patched_rom; fprintf(stderr, "WARNING: BPS patching failed.\nROM has not been altered.\n"); return false; } } static long ReadInt (Stream *r, unsigned nbytes) { long v = 0; while (nbytes--) { int c = r->get_char(); if (c == EOF) return (-1); v = (v << 8) | (c & 0xFF); } return (v); } static bool8 ReadIPSPatch (Stream *r, long offset, int32 &rom_size) { const int32 IPS_EOF = 0x00454F46l; int32 ofs; char fname[6]; fname[5] = 0; for (int i = 0; i < 5; i++) { int c = r->get_char(); if (c == EOF) return (0); fname[i] = (char) c; } if (strncmp(fname, "PATCH", 5)) return (0); for (;;) { long len, rlen; int rchar; ofs = ReadInt(r, 3); if (ofs == -1) return (0); if (ofs == IPS_EOF) break; ofs -= offset; len = ReadInt(r, 2); if (len == -1) return (0); if (len) { if (ofs + len > CMemory::MAX_ROM_SIZE) return (0); while (len--) { rchar = r->get_char(); if (rchar == EOF) return (0); Memory.ROM[ofs++] = (uint8) rchar; } if (ofs > rom_size) rom_size = ofs; } else { rlen = ReadInt(r, 2); if (rlen == -1) return (0); rchar = r->get_char(); if (rchar == EOF) return (0); if (ofs + rlen > CMemory::MAX_ROM_SIZE) return (0); while (rlen--) Memory.ROM[ofs++] = (uint8) rchar; if (ofs > rom_size) rom_size = ofs; } } ofs = ReadInt(r, 3); if (ofs != -1 && ofs - offset < rom_size) rom_size = ofs - offset; return (1); } #ifdef UNZIP_SUPPORT static int unzFindExtension (unzFile &file, const char *ext, bool restart, bool print) { unz_file_info info; int port, l = strlen(ext); if (restart) port = unzGoToFirstFile(file); else port = unzGoToNextFile(file); while (port == UNZ_OK) { int len; char name[132]; unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0); len = strlen(name); if (len >= l + 1 && name[len - l - 1] == '.' && strcasecmp(name + len - l, ext) == 0 && unzOpenCurrentFile(file) == UNZ_OK) { if (print) printf("Using patch %s", name); return (port); } port = unzGoToNextFile(file); } return (port); } #endif void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &rom_size) { if (Settings.NoPatch) return; FSTREAM patch_file = NULL; uint32 i; long offset = header ? 512 : 0; int ret; bool flag; char dir[_MAX_DIR + 1], drive[_MAX_DRIVE + 1], name[_MAX_FNAME + 1], ext[_MAX_EXT + 1], ips[_MAX_EXT + 3], fname[PATH_MAX + 1]; const char *n; _splitpath(rom_filename, drive, dir, name, ext); // BPS _makepath(fname, drive, dir, name, "bps"); if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) { printf("Using BPS patch %s", fname); ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } #ifdef UNZIP_SUPPORT if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip")) { unzFile file = unzOpen(rom_filename); if (file) { int port = unzFindExtension(file, "bps"); if (port == UNZ_OK) { printf(" in %s", rom_filename); ret = ReadBPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) printf("!\n"); else printf(" failed!\n"); } } } #endif n = S9xGetFilename(".bps", IPS_DIR); if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) { printf("Using BPS patch %s", n); ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } // UPS _makepath(fname, drive, dir, name, "ups"); if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) { printf("Using UPS patch %s", fname); ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } #ifdef UNZIP_SUPPORT if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip")) { unzFile file = unzOpen(rom_filename); if (file) { int port = unzFindExtension(file, "ups"); if (port == UNZ_OK) { printf(" in %s", rom_filename); ret = ReadUPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) printf("!\n"); else printf(" failed!\n"); } } } #endif n = S9xGetFilename(".ups", IPS_DIR); if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) { printf("Using UPS patch %s", n); ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } // IPS _makepath(fname, drive, dir, name, "ips"); if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) { printf("Using IPS patch %s", fname); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } if (_MAX_EXT > 6) { i = 0; flag = false; do { snprintf(ips, 8, "%03d.ips", i); _makepath(fname, drive, dir, name, ips); if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i < 1000); if (flag) return; } if (_MAX_EXT > 3) { i = 0; flag = false; do { snprintf(ips, _MAX_EXT + 2, "ips%d", i); if (strlen(ips) > _MAX_EXT) break; _makepath(fname, drive, dir, name, ips); if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i != 0); if (flag) return; } if (_MAX_EXT > 2) { i = 0; flag = false; do { snprintf(ips, 4, "ip%d", i); _makepath(fname, drive, dir, name, ips); if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i < 10); if (flag) return; } #ifdef UNZIP_SUPPORT if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip")) { unzFile file = unzOpen(rom_filename); if (file) { int port = unzFindExtension(file, "ips"); while (port == UNZ_OK) { printf(" in %s", rom_filename); ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) { printf("!\n"); flag = true; } else printf(" failed!\n"); port = unzFindExtension(file, "ips", false); } if (!flag) { i = 0; do { snprintf(ips, 8, "%03d.ips", i); if (unzFindExtension(file, ips) != UNZ_OK) break; printf(" in %s", rom_filename); ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } if (unzFindExtension(file, ips, false, false) == UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips); } while (++i < 1000); } if (!flag) { i = 0; do { snprintf(ips, _MAX_EXT + 2, "ips%d", i); if (strlen(ips) > _MAX_EXT) break; if (unzFindExtension(file, ips) != UNZ_OK) break; printf(" in %s", rom_filename); ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } if (unzFindExtension(file, ips, false, false) == UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips); } while (++i != 0); } if (!flag) { i = 0; do { snprintf(ips, 4, "ip%d", i); if (unzFindExtension(file, ips) != UNZ_OK) break; printf(" in %s", rom_filename); ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } if (unzFindExtension(file, ips, false, false) == UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips); } while (++i < 10); } assert(unzClose(file) == UNZ_OK); if (flag) return; } } #endif n = S9xGetFilename(".ips", IPS_DIR); if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) { printf("Using IPS patch %s", n); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); return; } else printf(" failed!\n"); } if (_MAX_EXT > 6) { i = 0; flag = false; do { snprintf(ips, 9, ".%03d.ips", i); n = S9xGetFilename(ips, IPS_DIR); if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i < 1000); if (flag) return; } if (_MAX_EXT > 3) { i = 0; flag = false; do { snprintf(ips, _MAX_EXT + 3, ".ips%d", i); if (strlen(ips) > _MAX_EXT + 1) break; n = S9xGetFilename(ips, IPS_DIR); if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i != 0); if (flag) return; } if (_MAX_EXT > 2) { i = 0; flag = false; do { snprintf(ips, 5, ".ip%d", i); n = S9xGetFilename(ips, IPS_DIR); if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); CLOSE_FSTREAM(patch_file); if (ret) { printf("!\n"); flag = true; } else { printf(" failed!\n"); break; } } while (++i < 10); if (flag) return; } } globals.cpp000664 001750 001750 00000037565 12720446475 014064 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "dma.h" #include "apu/apu.h" #include "fxinst.h" #include "fxemu.h" #include "srtc.h" #include "cheats.h" #ifdef NETPLAY_SUPPORT #include "netplay.h" #endif #ifdef DEBUGGER #include "debug.h" #include "missing.h" #endif struct SCPUState CPU; struct SICPU ICPU; struct SRegisters Registers; struct SPPU PPU; struct InternalPPU IPPU; struct SDMA DMA[8]; struct STimings Timings; struct SGFX GFX; struct SBG BG; struct SLineData LineData[240]; struct SLineMatrixData LineMatrixData[240]; struct SDSP0 DSP0; struct SDSP1 DSP1; struct SDSP2 DSP2; struct SDSP3 DSP3; struct SDSP4 DSP4; struct SSA1 SA1; struct SSA1Registers SA1Registers; struct FxRegs_s GSU; struct FxInfo_s SuperFX; struct SST010 ST010; struct SST011 ST011; struct SST018 ST018; struct SOBC1 OBC1; struct SSPC7110Snapshot s7snap; struct SSRTCSnapshot srtcsnap; struct SRTCData RTCData; struct SBSX BSX; struct SMulti Multi; struct SSettings Settings; struct SSNESGameFixes SNESGameFixes; #ifdef NETPLAY_SUPPORT struct SNetPlay NetPlay; #endif #ifdef DEBUGGER struct Missing missing; #endif struct SCheatData Cheat; struct Watch watches[16]; CMemory Memory; char String[513]; uint8 OpenBus = 0; uint8 *HDMAMemPointers[8]; uint16 BlackColourMap[256]; uint16 DirectColourMaps[8][256]; SnesModel M1SNES = { 1, 3, 2 }; SnesModel M2SNES = { 2, 4, 3 }; SnesModel *Model = &M1SNES; #ifdef GFX_MULTI_FORMAT uint32 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_RGB565; uint32 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_RGB565; uint32 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_RGB565; uint32 RED_HI_BIT_MASK = RED_HI_BIT_MASK_RGB565; uint32 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_RGB565; uint32 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_RGB565; uint32 MAX_RED = MAX_RED_RGB565; uint32 MAX_GREEN = MAX_GREEN_RGB565; uint32 MAX_BLUE = MAX_BLUE_RGB565; uint32 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_RGB565; uint32 GREEN_HI_BIT = (MAX_GREEN_RGB565 + 1) >> 1; uint32 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_RGB565 | GREEN_LOW_BIT_MASK_RGB565 | BLUE_LOW_BIT_MASK_RGB565); uint32 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_RGB565 | GREEN_HI_BIT_MASK_RGB565 | BLUE_HI_BIT_MASK_RGB565); uint32 RGB_HI_BITS_MASKx2 = (RED_HI_BIT_MASK_RGB565 | GREEN_HI_BIT_MASK_RGB565 | BLUE_HI_BIT_MASK_RGB565) << 1; uint32 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; uint32 FIRST_COLOR_MASK = FIRST_COLOR_MASK_RGB565; uint32 SECOND_COLOR_MASK = SECOND_COLOR_MASK_RGB565; uint32 THIRD_COLOR_MASK = THIRD_COLOR_MASK_RGB565; uint32 ALPHA_BITS_MASK = ALPHA_BITS_MASK_RGB565; uint32 FIRST_THIRD_COLOR_MASK = 0; uint32 TWO_LOW_BITS_MASK = 0; uint32 HIGH_BITS_SHIFTED_TWO_MASK = 0; #endif uint16 SignExtend[2] = { 0x0000, 0xff00 }; int HDMA_ModeByteCounts[8] = { 1, 2, 2, 4, 4, 4, 2, 4 }; uint8 mul_brightness[16][32] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04 }, { 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 }, { 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08 }, { 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a }, { 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c }, { 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e }, { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x11 }, { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x13 }, { 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15 }, { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17 }, { 0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19 }, { 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1b }, { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d }, { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f } }; uint8 S9xOpLengthsM0X0[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 3, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F }; uint8 S9xOpLengthsM0X1[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F }; uint8 S9xOpLengthsM1X0[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 3, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F }; uint8 S9xOpLengthsM1X1[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F }; libretro/libretro-win32.vcproj000664 001750 001750 00000032230 12720446475 017546 0ustar00sergiosergio000000 000000 debug.cpp000664 001750 001750 00000173521 12720446475 013520 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifdef DEBUGGER #include #include "snes9x.h" #include "memmap.h" #include "cpuops.h" #include "dma.h" #include "apu/apu.h" #include "display.h" #include "debug.h" #include "missing.h" extern SDMA DMA[8]; extern FILE *apu_trace; FILE *trace = NULL, *trace2 = NULL; struct SBreakPoint S9xBreakpoint[6]; struct SDebug { struct { uint8 Bank; uint16 Address; } Dump; struct { uint8 Bank; uint16 Address; } Unassemble; }; static struct SDebug Debug = { { 0, 0 }, { 0, 0 } }; static const char *HelpMessage[] = { "Command Help:", "?, help - Shows this command help", "r - Shows the registers", "i - Shows the interrupt vectors", "t - Trace current instruction [step-into]", "p - Proceed to next instruction [step-over]", "s - Skip to next instruction [skip]", "T - Toggle CPU instruction tracing to trace.log", "TS - Toggle SA-1 instruction tracing to trace_sa1.log", "E - Toggle HC-based event tracing to trace.log", "V - Toggle non-DMA V-RAM read/write tracing to stdout", "D - Toggle on-screen DMA tracing", "H - Toggle on-screen HDMA tracing", "U - Toggle on-screen unknown register read/write tracing", "P - Toggle on-screen DSP tracing", "S - Dump sprite (OBJ) status", "g [Address] - Go or go to [Address]", "u [Address] - Disassemble from PC or [Address]", "d [Address] - Dump from PC or [Address]", "bv [Number] - View breakpoints or view breakpoint [Number]", "bs [Number] [Address] - Enable/disable breakpoint", " [enable example: bs #2 $02:8002]", " [disable example: bs #2]", "c - Dump SNES colour palette", "W - Show what SNES hardware features the ROM is using", " which might not be implemented yet", "w - Show some SNES hardware features used so far in this frame", "R - Reset SNES", "q - Quit emulation", // "ai - Shou APU vectors", // "a - Show APU status", // "x - Show Sound DSP status", // "A - Toggle APU instruction tracing to aputrace.log", // "B - Toggle sound DSP register tracing to aputrace.log", // "C - Dump sound sample addresses", // "ad [Address] - Dump APU RAM from PC or [Address]", "", "[Address] - $Bank:Address or $Address", " [for example: $01:8123]", "[Number] - #Number", " [for example: #1]", "z - ", "f - ", "dump - ", "", NULL }; static const char *S9xMnemonics[256] = { "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", "JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", "BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", "RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", "BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", "RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", "BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", "BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", "BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", "LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", "BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" }; static int AddrModes[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 3, 10, 3, 19, 6, 6, 6, 12, 0, 1, 24, 0, 14, 14, 14, 17, // 0 4, 11, 9, 20, 6, 7, 7, 13, 0, 16, 24, 0, 14, 15, 15, 18, // 1 14, 10, 17, 19, 6, 6, 6, 12, 0, 1, 24, 0, 14, 14, 14, 17, // 2 4, 11, 9, 20, 7, 7, 7, 13, 0, 16, 24, 0, 15, 15, 15, 18, // 3 0, 10, 3, 19, 25, 6, 6, 12, 0, 1, 24, 0, 14, 14, 14, 17, // 4 4, 11, 9, 20, 25, 7, 7, 13, 0, 16, 0, 0, 17, 15, 15, 18, // 5 0, 10, 5, 19, 6, 6, 6, 12, 0, 1, 24, 0, 21, 14, 14, 17, // 6 4, 11, 9, 20, 7, 7, 7, 13, 0, 16, 0, 0, 23, 15, 15, 18, // 7 4, 10, 5, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, // 8 4, 11, 9, 20, 7, 7, 8, 13, 0, 16, 0, 0, 14, 15, 15, 18, // 9 2, 10, 2, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, // A 4, 11, 9, 20, 7, 7, 8, 13, 0, 16, 0, 0, 15, 15, 16, 18, // B 2, 10, 3, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, // C 4, 11, 9, 9, 27, 7, 7, 13, 0, 16, 0, 0, 22, 15, 15, 18, // D 2, 10, 3, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, // E 4, 11, 9, 20, 26, 7, 7, 13, 0, 16, 0, 0, 23, 15, 15, 18 // F }; static uint8 S9xDebugGetByte (uint32); static uint16 S9xDebugGetWord (uint32); static uint8 S9xDebugSA1GetByte (uint32); static uint16 S9xDebugSA1GetWord (uint32); static uint8 debug_cpu_op_print (char *, uint8, uint16); static uint8 debug_sa1_op_print (char *, uint8, uint16); static void debug_line_print (const char *); static int debug_get_number (char *, uint16 *); static short debug_get_start_address (char *, uint8 *, uint32 *); static void debug_process_command (char *); static void debug_print_window (uint8 *); static const char * debug_clip_fn (int); static void debug_whats_used (void); static void debug_whats_missing (void); static uint8 S9xDebugGetByte (uint32 Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *GetAddress = Memory.Map[block]; uint8 byte = 0; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { byte = *(GetAddress + (Address & 0xffff)); return (byte); } switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: byte = *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)); return (byte); case CMemory::MAP_LOROM_SRAM_B: byte = *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)); return (byte); case CMemory::MAP_HIROM_SRAM: case CMemory::MAP_RONLY_SRAM: byte = *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); return (byte); case CMemory::MAP_BWRAM: byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); return (byte); default: return (byte); } } static uint16 S9xDebugGetWord (uint32 Address) { uint16 word; word = S9xDebugGetByte(Address); word |= S9xDebugGetByte(Address + 1) << 8; return (word); } static uint8 S9xDebugSA1GetByte (uint32 Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8 *GetAddress = SA1.Map[block]; uint8 byte = 0; if (GetAddress >= (uint8 *) CMemory::MAP_LAST) { byte = *(GetAddress + (Address & 0xffff)); return (byte); } switch ((pint) GetAddress) { case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: byte = *(Memory.SRAM + (Address & 0xffff)); return (byte); case CMemory::MAP_BWRAM: byte = *(SA1.BWRAM + ((Address & 0x7fff) - 0x6000)); return (byte); case CMemory::MAP_BWRAM_BITMAP: Address -= 0x600000; if (SA1.VirtualBitmapFormat == 2) byte = (Memory.SRAM[(Address >> 2) & 0xffff] >> ((Address & 3) << 1)) & 3; else byte = (Memory.SRAM[(Address >> 1) & 0xffff] >> ((Address & 1) << 2)) & 15; return (byte); case CMemory::MAP_BWRAM_BITMAP2: Address = (Address & 0xffff) - 0x6000; if (SA1.VirtualBitmapFormat == 2) byte = (SA1.BWRAM[(Address >> 2) & 0xffff] >> ((Address & 3) << 1)) & 3; else byte = (SA1.BWRAM[(Address >> 1) & 0xffff] >> ((Address & 1) << 2)) & 15; return (byte); default: return (byte); } } static uint16 S9xDebugSA1GetWord (uint32 Address) { uint16 word; word = S9xDebugSA1GetByte(Address); word |= S9xDebugSA1GetByte(Address + 1) << 8; return (word); } static uint8 debug_cpu_op_print (char *Line, uint8 Bank, uint16 Address) { uint8 S9xOpcode; uint8 Operant[3]; uint16 Word; uint8 Byte; int16 SWord; int8 SByte; uint8 Size = 0; S9xOpcode = S9xDebugGetByte((Bank << 16) + Address); sprintf(Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); Operant[0] = S9xDebugGetByte((Bank << 16) + Address + 1); Operant[1] = S9xDebugGetByte((Bank << 16) + Address + 2); Operant[2] = S9xDebugGetByte((Bank << 16) + Address + 3); switch (AddrModes[S9xOpcode]) { case 0: // Implied sprintf(Line, "%s %s", Line, S9xMnemonics[S9xOpcode]); Size = 1; break; case 1: // Immediate[MemoryFlag] if (!CheckFlag(MemoryFlag)) { // Accumulator 16 - Bit sprintf(Line, "%s%02X %02X %s #$%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; } else { // Accumulator 8 - Bit sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; } break; case 2: // Immediate[IndexFlag] if (!CheckFlag(IndexFlag)) { // X / Y 16 - Bit sprintf(Line, "%s%02X %02X %s #$%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; } else { // X / Y 8 - Bit sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; } break; case 3: // Immediate[Always 8 - Bit] sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; break; case 4: // Relative sprintf(Line, "%s%02X %s $%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); SByte = Operant[0]; Word = Address; Word += SByte; Word += 2; sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 2; break; case 5: // Relative Long sprintf(Line, "%s%02X %02X %s $%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); SWord = (Operant[1] << 8) | Operant[0]; Word = Address; Word += SWord; Word += 3; sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 3; break; case 6: // Direct sprintf(Line, "%s%02X %s $%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 7: // Direct Indexed (with X) sprintf(Line, "%s%02X %s $%02X,x", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word += Registers.X.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 8: // Direct Indexed (with Y) sprintf(Line, "%s%02X %s $%02X,y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word += Registers.Y.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 9: // Direct Indirect sprintf(Line, "%s%02X %s ($%02X)", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; case 10: // Direct Indexed Indirect sprintf(Line, "%s%02X %s ($%02X,x)", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word += Registers.X.W; Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; case 11: // Direct Indirect Indexed sprintf(Line, "%s%02X %s ($%02X),y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; case 12: // Direct Indirect Long sprintf(Line, "%s%02X %s [$%02X]", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Byte = S9xDebugGetByte(Word + 2); Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; case 13: // Direct Indirect Indexed Long sprintf(Line, "%s%02X %s [$%02X],y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Byte = S9xDebugGetByte(Word + 2); Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; case 14: // Absolute sprintf(Line, "%s%02X %02X %s $%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 3; break; case 15: // Absolute Indexed (with X) sprintf(Line, "%s%02X %02X %s $%02X%02X,x", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += Registers.X.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 3; break; case 16: // Absolute Indexed (with Y) sprintf(Line, "%s%02X %02X %s $%02X%02X,y", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 3; break; case 17: // Absolute Long sprintf(Line, "%s%02X %02X %02X %s $%02X%02X%02X", Line, Operant[0], Operant[1], Operant[2], S9xMnemonics[S9xOpcode], Operant[2], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; sprintf(Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); Size = 4; break; case 18: // Absolute Indexed Long sprintf(Line, "%s%02X %02X %02X %s $%02X%02X%02X,x", Line, Operant[0], Operant[1], Operant[2], S9xMnemonics[S9xOpcode], Operant[2], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += Registers.X.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); Size = 4; break; case 19: // Stack Relative sprintf(Line, "%s%02X %s $%02X,s", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Registers.S.W; Word += Operant[0]; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 20: // Stack Relative Indirect Indexed sprintf(Line, "%s%02X %s ($%02X,s),y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Registers.S.W; Word += Operant[0]; Word = S9xDebugGetWord(Word); Word += Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); Size = 2; break; case 21: // Absolute Indirect sprintf(Line, "%s%02X %02X %s ($%02X%02X)", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); Size = 3; break; case 22: // Absolute Indirect Long sprintf(Line, "%s%02X %02X %s [$%02X%02X]", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Byte = S9xDebugGetByte(Word + 2); Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 3; break; case 23: // Absolute Indexed Indirect sprintf(Line, "%s%02X %02X %s ($%02X%02X,x)", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += Registers.X.W; Word = S9xDebugGetWord(ICPU.ShiftedPB + Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); Size = 3; break; case 24: // Implied Accumulator sprintf(Line, "%s %s A", Line, S9xMnemonics[S9xOpcode]); Size = 1; break; case 25: // MVN/MVP SRC DST sprintf(Line, "%s%02X %02X %s %02X %02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; break; case 26: // PEA sprintf(Line, "%s%02X %02X %s $%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; break; case 27: // PEI Direct Indirect sprintf(Line, "%s%02X %s ($%02X)", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += Registers.D.W; Word = S9xDebugGetWord(Word); sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 2; break; } sprintf(Line, "%-44s A:%04X X:%04X Y:%04X D:%04X DB:%02X S:%04X P:%c%c%c%c%c%c%c%c%c HC:%04ld VC:%03ld FC:%02d %03x", Line, Registers.A.W, Registers.X.W, Registers.Y.W, Registers.D.W, Registers.DB, Registers.S.W, CheckEmulation() ? 'E' : 'e', CheckNegative() ? 'N' : 'n', CheckOverflow() ? 'V' : 'v', CheckMemory() ? 'M' : 'm', CheckIndex() ? 'X' : 'x', CheckDecimal() ? 'D' : 'd', CheckIRQ() ? 'I' : 'i', CheckZero() ? 'Z' : 'z', CheckCarry() ? 'C' : 'c', (long) CPU.Cycles, (long) CPU.V_Counter, IPPU.FrameCount, (CPU.IRQExternal ? 0x100 : 0) | (PPU.HTimerEnabled ? 0x10 : 0) | (PPU.VTimerEnabled ? 0x01 : 0)); return (Size); } static uint8 debug_sa1_op_print (char *Line, uint8 Bank, uint16 Address) { uint8 S9xOpcode; uint8 Operant[3]; uint16 Word; uint8 Byte; int16 SWord; int8 SByte; uint8 Size = 0; S9xOpcode = S9xDebugSA1GetByte((Bank << 16) + Address); sprintf(Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); Operant[0] = S9xDebugSA1GetByte((Bank << 16) + Address + 1); Operant[1] = S9xDebugSA1GetByte((Bank << 16) + Address + 2); Operant[2] = S9xDebugSA1GetByte((Bank << 16) + Address + 3); switch (AddrModes[S9xOpcode]) { case 0: // Implied sprintf(Line, "%s %s", Line, S9xMnemonics[S9xOpcode]); Size = 1; break; case 1: // Immediate[MemoryFlag] if (!SA1CheckFlag(MemoryFlag)) { // Accumulator 16 - Bit sprintf(Line, "%s%02X %02X %s #$%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; } else { // Accumulator 8 - Bit sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; } break; case 2: // Immediate[IndexFlag] if (!SA1CheckFlag(IndexFlag)) { // X / Y 16 - Bit sprintf(Line, "%s%02X %02X %s #$%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Size = 3; } else { // X / Y 8 - Bit sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; } break; case 3: // Immediate[Always 8 - Bit] sprintf(Line, "%s%02X %s #$%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Size = 2; break; case 4: // Relative sprintf(Line, "%s%02X %s $%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); SByte = Operant[0]; Word = Address; Word += SByte; Word += 2; sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 2; break; case 5: // Relative Long sprintf(Line, "%s%02X %02X %s $%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); SWord = (Operant[1] << 8) | Operant[0]; Word = Address; Word += SWord; Word += 3; sprintf(Line, "%-32s[$%04X]", Line, Word); Size = 3; break; case 6: // Direct sprintf(Line, "%s%02X %s $%02X", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 7: // Direct Indexed (with X) sprintf(Line, "%s%02X %s $%02X,x", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Word += SA1Registers.X.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 8: // Direct Indexed (with Y) sprintf(Line, "%s%02X %s $%02X,y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 9: // Direct Indirect sprintf(Line, "%s%02X %s ($%02X)", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; case 10: // Direct Indexed Indirect sprintf(Line, "%s%02X %s ($%02X,x)", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Word += SA1Registers.X.W; Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; case 11: // Direct Indirect Indexed sprintf(Line, "%s%02X %s ($%02X),y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; case 12: // Direct Indirect Long sprintf(Line, "%s%02X %s [$%02X]", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Byte = S9xDebugSA1GetByte(Word + 2); Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; case 13: // Direct Indirect Indexed Long sprintf(Line, "%s%02X %s [$%02X],y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = Operant[0]; Word += SA1Registers.D.W; Byte = S9xDebugSA1GetByte(Word + 2); Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 2; break; case 14: // Absolute sprintf(Line, "%s%02X %02X %s $%02X%02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 3; break; case 15: // Absolute Indexed (with X) sprintf(Line, "%s%02X %02X %s $%02X%02X,x", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += SA1Registers.X.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 3; break; case 16: // Absolute Indexed (with Y) sprintf(Line, "%s%02X %02X %s $%02X%02X,y", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 3; break; case 17: // Absolute Long sprintf(Line, "%s%02X %02X %02X %s $%02X%02X%02X", Line, Operant[0], Operant[1], Operant[2], S9xMnemonics[S9xOpcode], Operant[2], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; sprintf(Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); Size = 4; break; case 18: // Absolute Indexed Long sprintf(Line, "%s%02X %02X %02X %s $%02X%02X%02X,x", Line, Operant[0], Operant[1], Operant[2], S9xMnemonics[S9xOpcode], Operant[2], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += SA1Registers.X.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); Size = 4; break; case 19: // Stack Relative sprintf(Line, "%s%02X %s $%02X,s", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = SA1Registers.S.W; Word += Operant[0]; sprintf(Line, "%-32s[$00:%04X]", Line, Word); Size = 2; break; case 20: // Stack Relative Indirect Indexed sprintf(Line, "%s%02X %s ($%02X,s),y", Line, Operant[0], S9xMnemonics[S9xOpcode], Operant[0]); Word = SA1Registers.S.W; Word += Operant[0]; Word = S9xDebugSA1GetWord(Word); Word += SA1Registers.Y.W; sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); Size = 2; break; case 21: // Absolute Indirect sprintf(Line, "%s%02X %02X %s ($%02X%02X)", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); Size = 3; break; case 22: // Absolute Indirect Long sprintf(Line, "%s%02X %02X %s [$%02X%02X]", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Byte = S9xDebugSA1GetByte(Word + 2); Word = S9xDebugSA1GetWord(Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, Byte, Word); Size = 3; break; case 23: // Absolute Indexed Indirect sprintf(Line, "%s%02X %02X %s ($%02X%02X,x)", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], Operant[1], Operant[0]); Word = (Operant[1] << 8) | Operant[0]; Word += SA1Registers.X.W; Word = S9xDebugSA1GetWord(SA1.ShiftedPB + Word); sprintf(Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); Size = 3; break; case 24: // Implied Accumulator sprintf(Line, "%s %s A", Line, S9xMnemonics[S9xOpcode]); Size = 1; break; case 25: // MVN/MVP SRC DST sprintf(Line, "%s %s %02X %02X", Line, S9xMnemonics[S9xOpcode], Operant[0], Operant[1]); Size = 3; break; } sprintf(Line, "%-44s A:%04X X:%04X Y:%04X D:%04X DB:%02X S:%04X P:%c%c%c%c%c%c%c%c%c HC:%04ld VC:%03ld FC:%02d", Line, SA1Registers.A.W, SA1Registers.X.W, SA1Registers.Y.W, SA1Registers.D.W, SA1Registers.DB, SA1Registers.S.W, SA1CheckEmulation() ? 'E' : 'e', SA1CheckNegative() ? 'N' : 'n', SA1CheckOverflow() ? 'V' : 'v', SA1CheckMemory() ? 'M' : 'm', SA1CheckIndex() ? 'X' : 'x', SA1CheckDecimal() ? 'D' : 'd', SA1CheckIRQ() ? 'I' : 'i', SA1CheckZero() ? 'Z' : 'z', SA1CheckCarry() ? 'C' : 'c', (long) CPU.Cycles, (long) CPU.V_Counter, IPPU.FrameCount); return (Size); } static void debug_line_print (const char *Line) { printf("%s\n", Line); } static int debug_get_number (char *Line, uint16 *Number) { int i; if (sscanf(Line, " #%d", &i) == 1) { *Number = i; return (1); } return (-1); } static short debug_get_start_address (char *Line, uint8 *Bank, uint32 *Address) { uint32 a, b; if (sscanf(Line + 1, " $%x:%x", &b, &a) != 2) return (-1); *Bank = b; *Address = a; return (1); } static void debug_process_command (char *Line) { uint8 Bank = Registers.PB; uint32 Address = Registers.PCw; uint16 Hold = 0; uint16 Number; short ErrorCode; char string[512]; if (strncasecmp(Line, "dump", 4) == 0) { int Count; if (sscanf(&Line[4], "%x %d", &Address, &Count) == 2) { FILE *fs; sprintf(string, "%06x%05d.sd2", Address, Count); fs = fopen(string, "wb"); if (fs) { for (int i = 0; i < Count; i++) putc(S9xDebugGetByte(Address + i), fs); fclose(fs); } else printf("Can't open %s for writing\n", string); } else printf("Usage: dump start_address_in_hex count_in_decimal\n"); return; } if (*Line == 'i') { printf("Vectors:\n"); sprintf(string, " 8 Bit 16 Bit "); debug_line_print(string); sprintf(string, "ABT $00:%04X|$00:%04X", S9xDebugGetWord(0xFFF8), S9xDebugGetWord(0xFFE8)); debug_line_print(string); sprintf(string, "BRK $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFE), S9xDebugGetWord(0xFFE6)); debug_line_print(string); sprintf(string, "COP $00:%04X|$00:%04X", S9xDebugGetWord(0xFFF4), S9xDebugGetWord(0xFFE4)); debug_line_print(string); sprintf(string, "IRQ $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFE), S9xDebugGetWord(0xFFEE)); debug_line_print(string); sprintf(string, "NMI $00:%04X|$00:%04X", S9xDebugGetWord(0xFFFA), S9xDebugGetWord(0xFFEA)); debug_line_print(string); sprintf(string, "RES $00:%04X", S9xDebugGetWord(0xFFFC)); debug_line_print(string); } /* if (strncmp(Line, "ai", 2) == 0) { printf("APU vectors:"); for (int i = 0; i < 0x40; i += 2) { if (i % 16 == 0) printf("\n%04x ", 0xffc0 + i); printf("%04x ", APU.ExtraRAM[i]); } printf("\n"); } */ if (*Line == 's') { Registers.PCw += debug_cpu_op_print(string, Bank, Address); Bank = Registers.PB; Address = Registers.PCw; *Line = 'r'; } if (*Line == 'z') { uint16 *p = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1]; for (int l = 0; l < 32; l++) { for (int c = 0; c < 32; c++, p++) printf("%04x,", *p++); printf("\n"); } } if (*Line == 'c') { printf("Colours:\n"); for (int i = 0; i < 256; i++) printf("%02x%02x%02x ", PPU.CGDATA[i] & 0x1f, (PPU.CGDATA[i] >> 5) & 0x1f, (PPU.CGDATA[i] >> 10) & 0x1f); printf("\n"); } if (*Line == 'S') { int SmallWidth, LargeWidth, SmallHeight, LargeHeight; switch ((Memory.FillRAM[0x2101] >> 5) & 7) { case 0: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 16; break; case 1: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 32; break; case 2: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 64; break; case 3: SmallWidth = SmallHeight = 16; LargeWidth = LargeHeight = 32; break; case 4: SmallWidth = SmallHeight = 16; LargeWidth = LargeHeight = 64; break; default: case 5: SmallWidth = SmallHeight = 32; LargeWidth = LargeHeight = 64; break; case 6: SmallWidth = 16; SmallHeight = 32; LargeWidth = 32; LargeHeight = 64; break; case 7: SmallWidth = 16; SmallHeight = 32; LargeWidth = LargeHeight = 32; break; } printf("Sprites: Small: %dx%d, Large: %dx%d, OAMAddr: 0x%04x, OBJNameBase: 0x%04x, OBJNameSelect: 0x%04x, First: %d\n", SmallWidth, SmallHeight, LargeWidth, LargeHeight, PPU.OAMAddr, PPU.OBJNameBase, PPU.OBJNameSelect, PPU.FirstSprite); for (int i = 0; i < 128; i++) { printf("X:%3d Y:%3d %c%c%d%c ", PPU.OBJ[i].HPos, PPU.OBJ[i].VPos, PPU.OBJ[i].VFlip ? 'V' : 'v', PPU.OBJ[i].HFlip ? 'H' : 'h', PPU.OBJ[i].Priority, PPU.OBJ[i].Size ? 'S' : 's'); if (i % 4 == 3) printf("\n"); } } if (*Line == 'T') { if (Line[1] == 'S') { SA1.Flags ^= TRACE_FLAG; if (SA1.Flags & TRACE_FLAG) { printf("SA1 CPU instruction tracing enabled.\n"); ENSURE_TRACE_OPEN(trace2, "trace_sa1.log", "wb") } else { printf("SA1 CPU instruction tracing disabled.\n"); fclose(trace2); trace2 = NULL; } } else { CPU.Flags ^= TRACE_FLAG; if (CPU.Flags & TRACE_FLAG) { printf("CPU instruction tracing enabled.\n"); ENSURE_TRACE_OPEN(trace, "trace.log", "wb") } else { printf("CPU instruction tracing disabled.\n"); fclose(trace); trace = NULL; } } } if (*Line == 'E') { Settings.TraceHCEvent = !Settings.TraceHCEvent; printf("HC event tracing %s.\n", Settings.TraceHCEvent ? "enabled" : "disabled"); } if (*Line == 'A') spc_core->debug_toggle_trace(); /* if (*Line == 'B') { Settings.TraceSoundDSP = !Settings.TraceSoundDSP; printf("Sound DSP register tracing %s.\n", Settings.TraceSoundDSP ? "enabled" : "disabled"); } if (*Line == 'x') S9xPrintSoundDSPState(); if (*Line == 'C') { printf("SPC700 sample addresses at 0x%04x:\n", APU.DSP[APU_DIR] << 8); for (int i = 0; i < 256; i++) { uint8 *dir = IAPU.RAM + (((APU.DSP[APU_DIR] << 8) + i * 4) & 0xffff); int addr = *dir + (*(dir + 1) << 8); int addr2 = *(dir + 2) + (*(dir + 3) << 8); printf("%04X %04X;", addr, addr2); if (i % 8 == 7) printf("\n"); } } */ if (*Line == 'R') { S9xReset(); printf("SNES reset.\n"); CPU.Flags |= DEBUG_MODE_FLAG; } /* if (strncmp(Line, "ad", 2) == 0) { uint32 Count = 16; Address = 0; if (sscanf(Line + 2, "%x,%x", &Address, &Count) != 2) { if (sscanf(Line + 2, "%x", &Address) == 1) Count = 16; } printf("APU RAM dump:\n"); for (uint32 l = 0; l < Count; l += 16) { printf("%04X ", Address); for (int i = 0; i < 16; i++) printf("%02X ", IAPU.RAM[Address++]); printf("\n"); } *Line = 0; } if (*Line == 'a') { printf("APU in-ports : %02X %02X %02X %02X\n", IAPU.RAM[0xF4], IAPU.RAM[0xF5], IAPU.RAM[0xF6], IAPU.RAM[0xF7]); printf("APU out-ports: %02X %02X %02X %02X\n", APU.OutPorts[0], APU.OutPorts[1], APU.OutPorts[2], APU.OutPorts[3]); printf("ROM/RAM switch: %s\n", (IAPU.RAM[0xf1] & 0x80) ? "ROM" : "RAM"); for (int i = 0; i < 3; i++) if (APU.TimerEnabled[i]) printf("Timer%d enabled, Value: 0x%03X, 4-bit: 0x%02X, Target: 0x%03X\n", i, APU.Timer[i], IAPU.RAM[0xfd + i], APU.TimerTarget[i]); } if (*Line == 'P') { Settings.TraceDSP = !Settings.TraceDSP; printf("DSP tracing %s.\n", Settings.TraceDSP ? "enabled" : "disabled"); } */ if (*Line == 'p') { S9xBreakpoint[5].Enabled = FALSE; Address += debug_cpu_op_print(string, Bank, Address); if (strncmp(&string[18], "JMP", 3) != 0 && strncmp(&string[18], "JML", 3) != 0 && strncmp(&string[18], "RT" , 2) != 0 && strncmp(&string[18], "BRA", 3)) { S9xBreakpoint[5].Enabled = TRUE; S9xBreakpoint[5].Bank = Bank; S9xBreakpoint[5].Address = Address; } else { CPU.Flags |= SINGLE_STEP_FLAG; CPU.Flags &= ~DEBUG_MODE_FLAG; } } if (*Line == 'b') { if (Line[1] == 's') { debug_get_number(Line + 2, &Hold); if (Hold > 4) Hold = 0; if (Hold < 5) { if (debug_get_start_address(Line + 5, &Bank, &Address) == -1) S9xBreakpoint[Hold].Enabled = FALSE; else { S9xBreakpoint[Hold].Enabled = TRUE; S9xBreakpoint[Hold].Bank = Bank; S9xBreakpoint[Hold].Address = Address; CPU.Flags |= BREAK_FLAG; } } Line[1] = 'v'; } if (Line[1] == 'v') { Number = 0; if (debug_get_number(Line + 2, &Number) == -1 && Number < 5) { debug_line_print("Breakpoints:"); for (Number = 0; Number != 5; Number++) { if (S9xBreakpoint[Number].Enabled) sprintf(string, "%i @ $%02X:%04X", Number, S9xBreakpoint[Number].Bank, S9xBreakpoint[Number].Address); else sprintf(string, "%i @ Disabled", Number); debug_line_print(string); } } else { debug_line_print("Breakpoint:"); if (S9xBreakpoint[Number].Enabled) sprintf(string, "%i @ $%02X:%04X", Number, S9xBreakpoint[Number].Bank, S9xBreakpoint[Number].Address); else sprintf(string, "%i @ Disabled", Number); debug_line_print(string); } } } if (*Line == '?' || strcasecmp(Line, "help") == 0) { for (int i = 0; HelpMessage[i] != NULL; i++) debug_line_print(HelpMessage[i]); } if (*Line == 't') { CPU.Flags |= SINGLE_STEP_FLAG; CPU.Flags &= ~DEBUG_MODE_FLAG; } if (*Line == 'f') { CPU.Flags |= FRAME_ADVANCE_FLAG; CPU.Flags &= ~DEBUG_MODE_FLAG; IPPU.RenderThisFrame = TRUE; IPPU.FrameSkip = 0; if (sscanf(&Line[1], "%u", &ICPU.FrameAdvanceCount) != 1) ICPU.Frame = 0; } if (*Line == 'g') { S9xBreakpoint[5].Enabled = FALSE; bool8 found = FALSE; for (int i = 0; i < 5; i++) { if (S9xBreakpoint[i].Enabled) { found = TRUE; if (S9xBreakpoint[i].Bank == Registers.PB && S9xBreakpoint[i].Address == Registers.PCw) { S9xBreakpoint[i].Enabled = 2; break; } } } if (!found) CPU.Flags &= ~BREAK_FLAG; ErrorCode = debug_get_start_address(Line, &Bank, &Address); if (ErrorCode == 1) { S9xBreakpoint[5].Enabled = TRUE; S9xBreakpoint[5].Bank = Bank; S9xBreakpoint[5].Address = Address; CPU.Flags |= BREAK_FLAG; } CPU.Flags &= ~DEBUG_MODE_FLAG; } if (*Line == 'D') { Settings.TraceDMA = !Settings.TraceDMA; printf("DMA tracing %s.\n", Settings.TraceDMA ? "enabled" : "disabled"); } if (*Line == 'V') { Settings.TraceVRAM = !Settings.TraceVRAM; printf("Non-DMA VRAM write tracing %s.\n", Settings.TraceVRAM ? "enabled" : "disabled"); } if (*Line == 'H') { Settings.TraceHDMA = !Settings.TraceHDMA; printf("HDMA tracing %s.\n", Settings.TraceHDMA ? "enabled" : "disabled"); } if (*Line == 'U') { Settings.TraceUnknownRegisters = !Settings.TraceUnknownRegisters; printf("Unknown registers read/write tracing %s.\n", Settings.TraceUnknownRegisters ? "enabled" : "disabled"); } if (*Line == 'd') { int CLine; int CByte; uint8 MemoryByte; if (Debug.Dump.Bank != 0 || Debug.Dump.Address != 0) { Bank = Debug.Dump.Bank; Address = Debug.Dump.Address; } ErrorCode = debug_get_start_address(Line, &Bank, &Address); for (CLine = 0; CLine != 10; CLine++) { sprintf(string, "$%02X:%04X", Bank, Address); for (CByte = 0; CByte != 16; CByte++) { if (Address + CByte == 0x2140 || Address + CByte == 0x2141 || Address + CByte == 0x2142 || Address + CByte == 0x2143 || Address + CByte == 0x4210) MemoryByte = 0; else MemoryByte = S9xDebugGetByte((Bank << 16) + Address + CByte); sprintf(string, "%s %02X", string, MemoryByte); } sprintf(string, "%s-", string); for (CByte = 0; CByte != 16; CByte++) { if (Address + CByte == 0x2140 || Address + CByte == 0x2141 || Address + CByte == 0x2142 || Address + CByte == 0x2143 || Address + CByte == 0x4210) MemoryByte = 0; else MemoryByte = S9xDebugGetByte((Bank << 16) + Address + CByte); if (MemoryByte < 32 || MemoryByte >= 127) MemoryByte = '?'; sprintf(string, "%s%c", string, MemoryByte); } Address += 16; debug_line_print(string); } Debug.Dump.Bank = Bank; Debug.Dump.Address = Address; } if (*Line == 'q') S9xExit(); if (*Line == 'W') debug_whats_missing(); if (*Line == 'w') debug_whats_used(); if (*Line == 'r') { debug_cpu_op_print(string, Bank, Address); debug_line_print(string); } if (*Line == 'u') { if (Debug.Unassemble.Bank != 0 || Debug.Unassemble.Address != 0) { Bank = Debug.Unassemble.Bank; Address = Debug.Unassemble.Address; } ErrorCode = debug_get_start_address(Line, &Bank, &Address); for (int i = 0; i != 10; i++) { Address += debug_cpu_op_print(string, Bank, Address); debug_line_print(string); } Debug.Unassemble.Bank = Bank; Debug.Unassemble.Address = Address; } debug_line_print(""); return; } static void debug_print_window (uint8 *window) { for (int i = 0; i < 6; i++) { if (window[i]) { switch (i) { case 0: printf("Background 0, "); break; case 1: printf("Background 1, "); break; case 2: printf("Background 2, "); break; case 3: printf("Background 3, "); break; case 4: printf("Objects, "); break; case 5: printf("Color window, "); break; } } } } static const char * debug_clip_fn (int logic) { switch (logic) { case CLIP_OR: return ("OR"); case CLIP_AND: return ("AND"); case CLIP_XOR: return ("XOR"); case CLIP_XNOR: return ("XNOR"); default: return ("???"); } } static void debug_whats_used (void) { printf("V-line: %ld, H-Pos: %ld, \n", (long) CPU.V_Counter, (long) CPU.Cycles); printf("Screen mode: %d, ", PPU.BGMode); if (PPU.BGMode <= 1 && (Memory.FillRAM[0x2105] & 8)) printf("(BG#2 Priority), "); printf("Brightness: %d, ", PPU.Brightness); if (Memory.FillRAM[0x2100] & 0x80) printf("(screen blanked), "); printf("\n"); if (Memory.FillRAM[0x2133] & 1) printf("Interlace, "); if (Memory.FillRAM[0x2133] & 4) printf("240 line visible, "); if (Memory.FillRAM[0x2133] & 8) printf("Pseudo 512 pixels horizontal resolution, "); if (Memory.FillRAM[0x2133] & 0x40) printf("Mode 7 priority per pixel, "); printf("\n"); if (PPU.BGMode == 7 && (Memory.FillRAM[0x211a] & 3)) printf("Mode 7 flipping, "); if (PPU.BGMode == 7) printf("Mode 7 screen repeat: %d, ", (Memory.FillRAM[0x211a] & 0xc0) >> 6); if (Memory.FillRAM[0x2130] & 1) printf("32K colour mode, "); printf("\n"); if (PPU.BGMode == 7) { // Sign extend 13 bit values to 16 bit values... if (PPU.CentreX & (1 << 12)) PPU.CentreX |= 0xe000; if (PPU.CentreY & (1 << 12)) PPU.CentreY |= 0xe000; printf("Matrix A: %.3f, B: %.3f, C: %.3f, D: %.3f, Centre X: %d Y:%d, \n", (double) PPU.MatrixA / 256, (double) PPU.MatrixB / 256, (double) PPU.MatrixC / 256, (double) PPU.MatrixD / 256, PPU.CentreX, PPU.CentreY); } if ((Memory.FillRAM[0x2106] & 0xf0) && (Memory.FillRAM[0x2106] & 0x0f)) { printf("Mosaic effect(%d) on, ", PPU.Mosaic); for (int i = 0; i < 4; i++) if (Memory.FillRAM[0x2106] & (1 << i)) printf("BG%d, ", i); } printf("\n"); if (PPU.HVBeamCounterLatched) printf("V and H beam pos latched, \n"); if (Memory.FillRAM[0x4200] & 0x20) printf("V-IRQ enabled at %d, \n", PPU.IRQVBeamPos); if (Memory.FillRAM[0x4200] & 0x10) printf("H-IRQ enabled at %d, \n", PPU.IRQHBeamPos); if (Memory.FillRAM[0x4200] & 0x80) printf("V-blank NMI enabled, \n"); for (int i = 0; i < 8; i++) { if (missing.hdma_this_frame & (1 << i)) { printf("H-DMA %d [%d] 0x%02X%04X->0x21%02X %s %s 0x%02X%04X %s addressing, \n", i, DMA[i].TransferMode, DMA[i].ABank, DMA[i].AAddress, DMA[i].BAddress, DMA[i].AAddressDecrement ? "dec" : "inc", DMA[i].Repeat ? "repeat" : "continue", DMA[i].IndirectBank, DMA[i].IndirectAddress, DMA[i].HDMAIndirectAddressing ? "indirect" : "absolute"); } } for (int i = 0; i < 8; i++) { if (missing.dma_this_frame & (1 << i)) { printf("DMA %d [%d] 0x%02X%04X->0x21%02X Num: %d %s, \n", i, DMA[i].TransferMode, DMA[i].ABank, DMA[i].AAddress, DMA[i].BAddress, DMA[i].TransferBytes, DMA[i].AAddressFixed ? "fixed" : (DMA[i].AAddressDecrement ? "dec" : "inc")); } } printf("VRAM write address: 0x%04x(%s), Full Graphic: %d, Address inc: %d, \n", PPU.VMA.Address, PPU.VMA.High ? "Byte" : "Word", PPU.VMA.FullGraphicCount, PPU.VMA.Increment); for (int i = 0; i < 4; i++) { printf("BG%d: VOffset:%d, HOffset:%d, W:%d, H:%d, TS:%d, BA:0x%04x, TA:0x%04X, \n", i, PPU.BG[i].VOffset, PPU.BG[i].HOffset, (PPU.BG[i].SCSize & 1) * 32 + 32, (PPU.BG[i].SCSize & 2) * 16 + 32, PPU.BG[i].BGSize * 8 + 8, PPU.BG[i].SCBase, PPU.BG[i].NameBase); } const char *s = ""; switch ((Memory.FillRAM[0x2130] & 0xc0) >> 6) { case 0: s = "always on"; break; case 1: s = "inside"; break; case 2: s = "outside"; break; case 3: s = "always off"; break; } printf("Main screen (%s): ", s); for (int i = 0; i < 5; i++) { if (Memory.FillRAM[0x212c] & (1 << i)) { switch (i) { case 0: printf("BG0, "); break; case 1: printf("BG1, "); break; case 2: printf("BG2, "); break; case 3: printf("BG3, "); break; case 4: printf("OBJ, "); break; } } } printf("\n"); switch ((Memory.FillRAM[0x2130] & 0x30) >> 4) { case 0: s = "always on"; break; case 1: s = "inside"; break; case 2: s = "outside"; break; case 3: s = "always off"; break; } printf("Subscreen (%s): ", s); for (int i = 0; i < 5; i++) { if (Memory.FillRAM[0x212d] & (1 << i)) { switch (i) { case 0: printf("BG0, "); break; case 1: printf("BG1, "); break; case 2: printf("BG2, "); break; case 3: printf("BG3, "); break; case 4: printf("OBJ, "); break; } } } printf("\n"); if ((Memory.FillRAM[0x2131] & 0x3f)) { if (Memory.FillRAM[0x2131] & 0x80) { if (Memory.FillRAM[0x2130] & 0x02) printf("Subscreen subtract"); else printf("Fixed colour subtract"); } else { if (Memory.FillRAM[0x2130] & 0x02) printf("Subscreen addition"); else printf("Fixed colour addition"); } if (Memory.FillRAM[0x2131] & 0x40) printf("(half): "); else printf(": "); for (int i = 0; i < 6; i++) { if (Memory.FillRAM[0x2131] & (1 << i)) { switch (i) { case 0: printf("BG0, "); break; case 1: printf("BG1, "); break; case 2: printf("BG2, "); break; case 3: printf("BG3, "); break; case 4: printf("OBJ, "); break; case 5: printf("BACK, "); break; } } } printf("\n"); } printf("Window 1 (%d, %d, %02x, %02x): ", PPU.Window1Left, PPU.Window1Right, Memory.FillRAM[0x212e], Memory.FillRAM[0x212f]); for (int i = 0; i < 6; i++) { if (PPU.ClipWindow1Enable[i]) { switch (i) { case 0: printf("BG0(%s-%s), ", PPU.ClipWindow1Inside[0] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[0])); break; case 1: printf("BG1(%s-%s), ", PPU.ClipWindow1Inside[1] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[1])); break; case 2: printf("BG2(%s-%s), ", PPU.ClipWindow1Inside[2] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[2])); break; case 3: printf("BG3(%s-%s), ", PPU.ClipWindow1Inside[3] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[3])); break; case 4: printf("OBJ(%s-%s), ", PPU.ClipWindow1Inside[4] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[4])); break; case 5: printf("COL(%s-%s), ", PPU.ClipWindow1Inside[5] ? "I" : "O", debug_clip_fn(PPU.ClipWindowOverlapLogic[5])); break; } } } printf("\n"); printf("Window 2 (%d, %d): ", PPU.Window2Left, PPU.Window2Right); for (int i = 0; i < 6; i++) { if (PPU.ClipWindow2Enable[i]) { switch (i) { case 0: printf("BG0(%s), ", PPU.ClipWindow2Inside[0] ? "I" : "O"); break; case 1: printf("BG1(%s), ", PPU.ClipWindow2Inside[1] ? "I" : "O"); break; case 2: printf("BG2(%s), ", PPU.ClipWindow2Inside[2] ? "I" : "O"); break; case 3: printf("BG3(%s), ", PPU.ClipWindow2Inside[3] ? "I" : "O"); break; case 4: printf("OBJ(%s), ", PPU.ClipWindow2Inside[4] ? "I" : "O"); break; case 5: printf("COL(%s), " , PPU.ClipWindow2Inside[5] ? "I" : "O"); break; } } } printf("\n"); printf("Fixed colour: %02x%02x%02x, \n", PPU.FixedColourRed, PPU.FixedColourGreen, PPU.FixedColourBlue); } static void debug_whats_missing (void) { printf("Processor: "); if (missing.emulate6502) printf("emulation mode, "); if (missing.decimal_mode) printf("decimal mode, "); if (missing.mv_8bit_index) printf("MVP/MVN with 8bit index registers and XH or YH > 0, "); if (missing.mv_8bit_acc) printf("MVP/MVN with 8bit accumulator > 255, "); printf("\n"); printf("Screen modes used: "); for (int i = 0; i < 8; i++) if (missing.modes[i]) printf("%d, ", i); printf("\n"); if (missing.interlace) printf("Interlace, "); if (missing.pseudo_512) printf("Pseudo 512 pixels horizontal resolution, "); if (missing.lines_239) printf("240 lines visible, "); if (missing.sprite_double_height) printf("double-hight sprites, "); printf("\n"); if (missing.mode7_fx) printf("Mode 7 rotation/scaling, "); if (missing.matrix_read) printf("Mode 7 read matrix registers, "); if (missing.mode7_flip) printf("Mode 7 flipping, "); if (missing.mode7_bgmode) printf("Mode 7 priority per pixel, "); if (missing.direct) printf("Direct 32000 colour mode, "); printf("\n"); if (missing.mosaic) printf("Mosaic effect, "); if (missing.subscreen) printf("Subscreen enabled, "); if (missing.subscreen_add) printf("Subscreen colour add, "); if (missing.subscreen_sub) printf("Subscreen colour subtract, "); if (missing.fixed_colour_add) printf("Fixed colour add, "); if (missing.fixed_colour_sub) printf("Fixed colour subtract, "); printf("\n"); printf("Window 1 enabled on: "); debug_print_window(missing.window1); printf("\n"); printf("Window 2 enabled on: "); debug_print_window(missing.window2); printf("\n"); if (missing.bg_offset_read) printf("BG offset read, "); if (missing.oam_address_read) printf("OAM address read, "); if (missing.sprite_priority_rotation) printf("Sprite priority rotation, "); if (missing.fast_rom) printf("Fast 3.58MHz ROM access enabled, "); if (missing.matrix_multiply) printf("Matrix multiply 16bit by 8bit used, "); printf("\n"); if (missing.virq) printf("V-IRQ used at line %d, ", missing.virq_pos); if (missing.hirq) printf("H-IRQ used at position %d, ", missing.hirq_pos); printf("\n"); if (missing.h_v_latch) printf("H and V-Pos latched, "); if (missing.h_counter_read) printf("H-Pos read, "); if (missing.v_counter_read) printf("V-Pos read, "); printf("\n"); if (missing.oam_read) printf("OAM read, "); if (missing.vram_read) printf("VRAM read, "); if (missing.cgram_read) printf("CG-RAM read, "); if (missing.wram_read) printf("WRAM read, "); if (missing.dma_read) printf("DMA read, "); if (missing.vram_inc) printf("VRAM inc: %d, ", missing.vram_inc); if (missing.vram_full_graphic_inc) printf("VRAM full graphic inc: %d, ", missing.vram_full_graphic_inc); printf("\n"); for (int i = 0; i < 8; i++) { if (missing.hdma[i].used) { printf("HDMA %d 0x%02X%04X->0x21%02X %s, ", i, missing.hdma[i].abus_bank, missing.hdma[i].abus_address, missing.hdma[i].bbus_address, missing.hdma[i].indirect_address ? "indirect" : "absolute"); if (missing.hdma[i].force_table_address_write) printf("Forced address write, "); if (missing.hdma[i].force_table_address_read) printf("Current address read, "); if (missing.hdma[i].line_count_write) printf("Line count write, "); if (missing.hdma[i].line_count_read) printf("Line count read, "); printf("\n"); } } for (int i = 0; i < 8; i++) { if (missing.dma_channels & (1 << i)) { printf("DMA %d [%d] 0x%02X%04X->0x21%02X Num: %d %s, \n", i, DMA[i].TransferMode, DMA[i].ABank, DMA[i].AAddress, DMA[i].BAddress, DMA[i].TransferBytes, DMA[i].AAddressFixed ? "fixed" : (DMA[i].AAddressDecrement ? "dec" : "inc")); } } if (missing.unknownppu_read) printf("Read from unknown PPU register: $%04X, \n", missing.unknownppu_read); if (missing.unknownppu_write) printf("Write to unknown PPU register: $%04X, \n", missing.unknownppu_write); if (missing.unknowncpu_read) printf("Read from unknown CPU register: $%04X, \n", missing.unknowncpu_read); if (missing.unknowncpu_write) printf("Write to unknown CPU register: $%04X, \n", missing.unknowncpu_write); if (missing.unknowndsp_read) printf("Read from unknown DSP register: $%04X, \n", missing.unknowndsp_read); if (missing.unknowndsp_write) printf("Write to unknown DSP register: $%04X, \n", missing.unknowndsp_write); } void S9xDoDebug (void) { char Line[513]; Debug.Dump.Bank = 0; Debug.Dump.Address = 0; Debug.Unassemble.Bank = 0; Debug.Unassemble.Address = 0; S9xTextMode(); strcpy(Line, "r"); debug_process_command(Line); while (CPU.Flags & DEBUG_MODE_FLAG) { int32 Cycles; char *p; printf("> "); fflush(stdout); p = fgets(Line, sizeof(Line) - 1, stdin); Line[strlen(Line) - 1] = 0; Cycles = CPU.Cycles; debug_process_command(Line); CPU.Cycles = Cycles; } if (!(CPU.Flags & SINGLE_STEP_FLAG)) S9xGraphicsMode(); } void S9xTrace (void) { char msg[512]; ENSURE_TRACE_OPEN(trace, "trace.log", "a") debug_cpu_op_print(msg, Registers.PB, Registers.PCw); fprintf(trace, "%s\n", msg); } void S9xSA1Trace (void) { char msg[512]; ENSURE_TRACE_OPEN(trace2, "trace_sa1.log", "a") debug_sa1_op_print(msg, SA1Registers.PB, SA1Registers.PCw); fprintf(trace2, "%s\n", msg); } void S9xTraceMessage (const char *s) { if (s) { if (trace) fprintf(trace, "%s\n", s); else if (trace2) fprintf(trace2, "%s\n", s); } } void S9xTraceFormattedMessage (const char *s, ...) { char msg[512]; if (s) { va_list argptr; va_start(argptr, s); vsprintf(msg, s, argptr); va_end(argptr); S9xTraceMessage(msg); } } void S9xPrintHVPosition (char *s) { sprintf(s, "HC:%04ld VC:%03ld FC:%02d", (long) CPU.Cycles, (long) CPU.V_Counter, IPPU.FrameCount); } #endif libretro/msvc/000700 001750 001750 00000000000 12724164663 014473 5ustar00sergiosergio000000 000000 cheats2.cpp000664 001750 001750 00000025012 12720446475 013752 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "cheats.h" static uint8 S9xGetByteFree (uint32); static void S9xSetByteFree (uint8, uint32); static uint8 S9xGetByteFree (uint32 address) { int32 Cycles = CPU.Cycles; int32 NextEvent = CPU.NextEvent; uint8 byte; CPU.NextEvent = 0x7FFFFFFF; byte = S9xGetByte(address); CPU.NextEvent = NextEvent; CPU.Cycles = Cycles; return (byte); } static void S9xSetByteFree (uint8 byte, uint32 address) { int32 Cycles = CPU.Cycles; int32 NextEvent = CPU.NextEvent; CPU.NextEvent = 0x7FFFFFFF; S9xSetByte(byte, address); CPU.NextEvent = NextEvent; CPU.Cycles = Cycles; } void S9xInitWatchedAddress (void) { for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++) watches[i].on = false; } void S9xInitCheatData (void) { Cheat.RAM = Memory.RAM; Cheat.SRAM = Memory.SRAM; Cheat.FillRAM = Memory.FillRAM; } void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, uint8 byte) { if (Cheat.num_cheats < sizeof(Cheat.c) / sizeof(Cheat.c[0])) { Cheat.c[Cheat.num_cheats].address = address; Cheat.c[Cheat.num_cheats].byte = byte; Cheat.c[Cheat.num_cheats].enabled = enable; if (save_current_value) { Cheat.c[Cheat.num_cheats].saved_byte = S9xGetByteFree(address); Cheat.c[Cheat.num_cheats].saved = TRUE; } Cheat.num_cheats++; } } void S9xDeleteCheat (uint32 which1) { if (which1 < Cheat.num_cheats) { if (Cheat.c[which1].enabled) S9xRemoveCheat(which1); memmove(&Cheat.c[which1], &Cheat.c[which1 + 1], sizeof(Cheat.c[0]) * (Cheat.num_cheats - which1 - 1)); Cheat.num_cheats--; } } void S9xDeleteCheats (void) { S9xRemoveCheats(); Cheat.num_cheats = 0; } void S9xRemoveCheat (uint32 which1) { if (Cheat.c[which1].saved) { uint32 address = Cheat.c[which1].address; int block = (address & 0xffffff) >> MEMMAP_SHIFT; uint8 *ptr = Memory.Map[block]; if (ptr >= (uint8 *) CMemory::MAP_LAST) *(ptr + (address & 0xffff)) = Cheat.c[which1].saved_byte; else S9xSetByteFree(Cheat.c[which1].saved_byte, address); } } void S9xRemoveCheats (void) { for (uint32 i = 0; i < Cheat.num_cheats; i++) if (Cheat.c[i].enabled) S9xRemoveCheat(i); } void S9xEnableCheat (uint32 which1) { if (which1 < Cheat.num_cheats && !Cheat.c[which1].enabled) { Cheat.c[which1].enabled = TRUE; S9xApplyCheat(which1); } } void S9xDisableCheat (uint32 which1) { if (which1 < Cheat.num_cheats && Cheat.c[which1].enabled) { S9xRemoveCheat(which1); Cheat.c[which1].enabled = FALSE; } } void S9xApplyCheat (uint32 which1) { uint32 address = Cheat.c[which1].address; if (!Cheat.c[which1].saved) { Cheat.c[which1].saved_byte = S9xGetByteFree(address); Cheat.c[which1].saved = TRUE; } int block = (address & 0xffffff) >> MEMMAP_SHIFT; uint8 *ptr = Memory.Map[block]; if (ptr >= (uint8 *) CMemory::MAP_LAST) *(ptr + (address & 0xffff)) = Cheat.c[which1].byte; else S9xSetByteFree(Cheat.c[which1].byte, address); } void S9xApplyCheats (void) { if (Settings.ApplyCheats) { for (uint32 i = 0; i < Cheat.num_cheats; i++) if (Cheat.c[i].enabled) S9xApplyCheat(i); } } bool8 S9xLoadCheatFile (const char *filename) { FILE *fs; uint8 data[28]; Cheat.num_cheats = 0; fs = fopen(filename, "rb"); if (!fs) return (FALSE); while (fread((void *) data, 1, 28, fs) == 28) { Cheat.c[Cheat.num_cheats].enabled = (data[0] & 4) == 0; Cheat.c[Cheat.num_cheats].byte = data[1]; Cheat.c[Cheat.num_cheats].address = data[2] | (data[3] << 8) | (data[4] << 16); Cheat.c[Cheat.num_cheats].saved_byte = data[5]; Cheat.c[Cheat.num_cheats].saved = (data[0] & 8) != 0; memmove(Cheat.c[Cheat.num_cheats].name, &data[8], 20); Cheat.c[Cheat.num_cheats++].name[20] = 0; } fclose(fs); return (TRUE); } bool8 S9xSaveCheatFile (const char *filename) { if (Cheat.num_cheats == 0) { remove(filename); return (TRUE); } FILE *fs; uint8 data[28]; fs = fopen(filename, "wb"); if (!fs) return (FALSE); for (uint32 i = 0; i < Cheat.num_cheats; i++) { memset(data, 0, 28); if (i == 0) { data[6] = 254; data[7] = 252; } if (!Cheat.c[i].enabled) data[0] |= 4; if (Cheat.c[i].saved) data[0] |= 8; data[1] = Cheat.c[i].byte; data[2] = (uint8) (Cheat.c[i].address >> 0); data[3] = (uint8) (Cheat.c[i].address >> 8); data[4] = (uint8) (Cheat.c[i].address >> 16); data[5] = Cheat.c[i].saved_byte; memmove(&data[8], Cheat.c[i].name, 19); if (fwrite(data, 28, 1, fs) != 1) { fclose(fs); return (FALSE); } } return (fclose(fs) == 0); } apu/bapu/smp/core/op_read.cpp000664 001750 001750 00000027117 12720446475 017305 0ustar00sergiosergio000000 000000 case 0x88: { rd = op_readpc(); regs.a = op_adc(regs.a, rd); break; } case 0x28: { rd = op_readpc(); regs.a = op_and(regs.a, rd); break; } case 0x68: { rd = op_readpc(); regs.a = op_cmp(regs.a, rd); break; } case 0xc8: { rd = op_readpc(); regs.x = op_cmp(regs.x, rd); break; } case 0xad: { rd = op_readpc(); regs.y = op_cmp(regs.y, rd); break; } case 0x48: { rd = op_readpc(); regs.a = op_eor(regs.a, rd); break; } case 0x08: { rd = op_readpc(); regs.a = op_or(regs.a, rd); break; } case 0xa8: { rd = op_readpc(); regs.a = op_sbc(regs.a, rd); break; } case 0x86: { op_io(); rd = op_readdp(regs.x); regs.a = op_adc(regs.a, rd); break; } case 0x26: { op_io(); rd = op_readdp(regs.x); regs.a = op_and(regs.a, rd); break; } case 0x66: { op_io(); rd = op_readdp(regs.x); regs.a = op_cmp(regs.a, rd); break; } case 0x46: { op_io(); rd = op_readdp(regs.x); regs.a = op_eor(regs.a, rd); break; } case 0x06: { op_io(); rd = op_readdp(regs.x); regs.a = op_or(regs.a, rd); break; } case 0xa6: { op_io(); rd = op_readdp(regs.x); regs.a = op_sbc(regs.a, rd); break; } case 0x84: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_adc(regs.a, rd); break; } case 0x24: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_and(regs.a, rd); break; } case 0x64: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_cmp(regs.a, rd); break; } case 0x3e: { dp = op_readpc(); rd = op_readdp(dp); regs.x = op_cmp(regs.x, rd); break; } case 0x7e: { dp = op_readpc(); rd = op_readdp(dp); regs.y = op_cmp(regs.y, rd); break; } case 0x44: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_eor(regs.a, rd); break; } case 0x04: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_or(regs.a, rd); break; } case 0xa4: { dp = op_readpc(); rd = op_readdp(dp); regs.a = op_sbc(regs.a, rd); break; } case 0x94: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_adc(regs.a, rd); break; } case 0x34: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_and(regs.a, rd); break; } case 0x74: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_cmp(regs.a, rd); break; } case 0x54: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_eor(regs.a, rd); break; } case 0x14: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_or(regs.a, rd); break; } case 0xb4: { dp = op_readpc(); op_io(); rd = op_readdp(dp + regs.x); regs.a = op_sbc(regs.a, rd); break; } case 0x85: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_adc(regs.a, rd); break; } case 0x25: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_and(regs.a, rd); break; } case 0x65: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_cmp(regs.a, rd); break; } case 0x1e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.x = op_cmp(regs.x, rd); break; } case 0x5e: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.y = op_cmp(regs.y, rd); break; } case 0x45: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_eor(regs.a, rd); break; } case 0x05: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_or(regs.a, rd); break; } case 0xa5: { dp = op_readpc(); dp |= op_readpc() << 8; rd = op_readaddr(dp); regs.a = op_sbc(regs.a, rd); break; } case 0x95: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_adc(regs.a, rd); break; } case 0x96: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_adc(regs.a, rd); break; } case 0x35: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_and(regs.a, rd); break; } case 0x36: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_and(regs.a, rd); break; } case 0x75: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_cmp(regs.a, rd); break; } case 0x76: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_cmp(regs.a, rd); break; } case 0x55: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_eor(regs.a, rd); break; } case 0x56: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_eor(regs.a, rd); break; } case 0x15: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_or(regs.a, rd); break; } case 0x16: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_or(regs.a, rd); break; } case 0xb5: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.x); regs.a = op_sbc(regs.a, rd); break; } case 0xb6: { dp = op_readpc(); dp |= op_readpc() << 8; op_io(); rd = op_readaddr(dp + regs.y); regs.a = op_sbc(regs.a, rd); break; } case 0x87: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_adc(regs.a, rd); break; } case 0x27: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_and(regs.a, rd); break; } case 0x67: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_cmp(regs.a, rd); break; } case 0x47: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_eor(regs.a, rd); break; } case 0x07: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_or(regs.a, rd); break; } case 0xa7: { dp = op_readpc() + regs.x; op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp); regs.a = op_sbc(regs.a, rd); break; } case 0x97: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_adc(regs.a, rd); break; } case 0x37: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_and(regs.a, rd); break; } case 0x77: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_cmp(regs.a, rd); break; } case 0x57: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_eor(regs.a, rd); break; } case 0x17: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_or(regs.a, rd); break; } case 0xb7: { dp = op_readpc(); op_io(); sp = op_readdp(dp); sp |= op_readdp(dp + 1) << 8; rd = op_readaddr(sp + regs.y); regs.a = op_sbc(regs.a, rd); break; } case 0x99: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_adc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x39: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_and(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x79: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_cmp(wr, rd); (0) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x59: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_eor(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x19: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_or(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0xb9: { op_io(); rd = op_readdp(regs.y); wr = op_readdp(regs.x); wr = op_sbc(wr, rd); (1) ? op_writedp(regs.x, wr) : op_io(); break; } case 0x89: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x29: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x69: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); break; } case 0x49: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x09: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0xa9: { sp = op_readpc(); rd = op_readdp(sp); dp = op_readpc(); wr = op_readdp(dp); wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x98: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_adc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x38: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_and(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x78: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_cmp(wr, rd); (0) ? op_writedp(dp, wr) : op_io(); break; } case 0x58: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_eor(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x18: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_or(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0xb8: { rd = op_readpc(); dp = op_readpc(); wr = op_readdp(dp); wr = op_sbc(wr, rd); (1) ? op_writedp(dp, wr) : op_io(); break; } case 0x7a: { dp = op_readpc(); rd = op_readdp(dp); op_io(); rd |= op_readdp(dp + 1) << 8; regs.ya = op_addw(regs.ya, rd); break; } case 0x9a: { dp = op_readpc(); rd = op_readdp(dp); op_io(); rd |= op_readdp(dp + 1) << 8; regs.ya = op_subw(regs.ya, rd); break; } case 0x5a: { dp = op_readpc(); rd = op_readdp(dp); rd |= op_readdp(dp + 1) << 8; op_cmpw(regs.ya, rd); break; } case 0x4a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !!(rd & (1 << bit)); break; } case 0x6a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); regs.p.c = regs.p.c & !(rd & (1 << bit)); break; } case 0x8a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); break; } case 0xea: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); rd ^= (1 << bit); op_writeaddr(dp, rd); break; } case 0x0a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c | !!(rd & (1 << bit)); break; } case 0x2a: { dp = op_readpc(); dp |= op_readpc() << 8; bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); op_io(); regs.p.c = regs.p.c | !(rd & (1 << bit)); break; } apu/bapu/smp/debugger/debugger.cpp000664 001750 001750 00000003456 12720446475 020314 0ustar00sergiosergio000000 000000 #ifdef SMP_CPP void SMPDebugger::op_step() { bool break_event = false; usage[regs.pc] |= UsageExec; opcode_pc = regs.pc; opcode_edge = true; debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); if(step_event && step_event() == true) { debugger.break_event = Debugger::BreakEvent::SMPStep; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); } opcode_edge = false; SMP::op_step(); synchronize_cpu(); } uint8 SMPDebugger::op_read(uint16 addr) { uint8 data = SMP::op_read(addr); usage[addr] |= UsageRead; debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); return data; } void SMPDebugger::op_write(uint16 addr, uint8 data) { SMP::op_write(addr, data); usage[addr] |= UsageWrite; usage[addr] &= ~UsageExec; debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); } SMPDebugger::SMPDebugger() { usage = new uint8[1 << 16](); opcode_pc = 0xffc0; opcode_edge = false; } SMPDebugger::~SMPDebugger() { delete[] usage; } bool SMPDebugger::property(unsigned id, string &name, string &value) { unsigned n = 0; #define item(name_, value_) \ if(id == n++) { \ name = name_; \ value = value_; \ return true; \ } //$00f0 item("$00f0", ""); item("Clock Speed", (unsigned)status.clock_speed); item("Timers Enable", status.timers_enable); item("RAM Disable", status.ram_disable); item("RAM Writable", status.ram_writable); item("Timers Disable", status.timers_disable); //$00f1 item("$00f1", ""); item("IPLROM Enable", status.iplrom_enable); //$00f2 item("$00f2", ""); item("DSP Address", string("0x", hex<2>(status.dsp_addr))); #undef item return false; } #endif srtcemu.h000664 001750 001750 00000001005 12720446475 013544 0ustar00sergiosergio000000 000000 /***** * S-RTC emulation code * Copyright (c) byuu *****/ #ifndef _SRTCEMU_H_ #define _SRTCEMU_H_ class SRTC { public: void update_time(); unsigned weekday(unsigned year, unsigned month, unsigned day); void init(); void enable(); void power(); void reset(); uint8 mmio_read (unsigned addr); void mmio_write(unsigned addr, uint8 data); SRTC(); static const unsigned months[12]; enum RTC_Mode { RTCM_Ready, RTCM_Command, RTCM_Read, RTCM_Write } rtc_mode; signed rtc_index; }; #endif apu/bapu/dsp/sdsp.hpp000664 001750 001750 00000001010 12720446475 015671 0ustar00sergiosergio000000 000000 #include "SPC_DSP.h" #include class DSP : public Processor { public: inline uint8 read(uint8 addr) { synchronize (); return spc_dsp.read(addr); } inline void synchronize (void) { if (clock) { spc_dsp.run (clock); clock = 0; } } inline void write(uint8 addr, uint8 data) { synchronize (); spc_dsp.write(addr, data); } void save_state(uint8 **); void load_state(uint8 **); void power(); void reset(); DSP(); SPC_DSP spc_dsp; }; extern DSP dsp; libretro/msvc/msvc-2010.sln000664 001750 001750 00000001552 12720446475 016560 0ustar00sergiosergio000000 000000  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2010", "msvc-2010\msvc-2010.vcxproj", "{5BDB0E63-AD88-4547-BF48-169312DDD188}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5BDB0E63-AD88-4547-BF48-169312DDD188}.Debug|Win32.ActiveCfg = Debug|Win32 {5BDB0E63-AD88-4547-BF48-169312DDD188}.Debug|Win32.Build.0 = Debug|Win32 {5BDB0E63-AD88-4547-BF48-169312DDD188}.Release|Win32.ActiveCfg = Release|Win32 {5BDB0E63-AD88-4547-BF48-169312DDD188}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal apu/bapu/000700 001750 001750 00000000000 12724164663 013415 5ustar00sergiosergio000000 000000 spc7110.cpp000664 001750 001750 00000033330 12720446475 013521 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ /***** * SPC7110 emulator - version 0.03 (2008-08-10) * Copyright (c) 2008, byuu and neviksti * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * The software is provided "as is" and the author disclaims all warranties * with regard to this software including all implied warranties of * merchantibility and fitness, in no event shall the author be liable for * any special, direct, indirect, or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an * action of contract, negligence or other tortious action, arising out of * or in connection with the use or performance of this software. *****/ #include #include "snes9x.h" #include "memmap.h" #include "srtc.h" #include "display.h" #define memory_cartrom_size() Memory.CalculatedSize #define memory_cartrom_read(a) Memory.ROM[(a)] #define memory_cartrtc_read(a) RTCData.reg[(a)] #define memory_cartrtc_write(a, b) { RTCData.reg[(a)] = (b); } #define cartridge_info_spc7110rtc Settings.SPC7110RTC #define cpu_regs_mdr OpenBus #include "spc7110emu.h" #include "spc7110emu.cpp" SPC7110 s7emu; static void SetSPC7110SRAMMap (uint8); void S9xInitSPC7110 (void) { s7emu.power(); memset(RTCData.reg, 0, 20); } void S9xResetSPC7110 (void) { s7emu.reset(); } static void SetSPC7110SRAMMap (uint8 newstate) { if (newstate & 0x80) { Memory.Map[0x006] = (uint8 *) Memory.MAP_HIROM_SRAM; Memory.Map[0x007] = (uint8 *) Memory.MAP_HIROM_SRAM; Memory.Map[0x306] = (uint8 *) Memory.MAP_HIROM_SRAM; Memory.Map[0x307] = (uint8 *) Memory.MAP_HIROM_SRAM; } else { Memory.Map[0x006] = (uint8 *) Memory.MAP_RONLY_SRAM; Memory.Map[0x007] = (uint8 *) Memory.MAP_RONLY_SRAM; Memory.Map[0x306] = (uint8 *) Memory.MAP_RONLY_SRAM; Memory.Map[0x307] = (uint8 *) Memory.MAP_RONLY_SRAM; } } uint8 * S9xGetBasePointerSPC7110 (uint32 address) { uint32 i; switch (address & 0xf00000) { case 0xd00000: i = s7emu.dx_offset; break; case 0xe00000: i = s7emu.ex_offset; break; case 0xf00000: i = s7emu.fx_offset; break; default: i = 0; break; } i += address & 0x0f0000; return (&Memory.ROM[i]); } uint8 S9xGetSPC7110Byte (uint32 address) { uint32 i; switch (address & 0xf00000) { case 0xd00000: i = s7emu.dx_offset; break; case 0xe00000: i = s7emu.ex_offset; break; case 0xf00000: i = s7emu.fx_offset; break; default: i = 0; break; } i += address & 0x0fffff; return (Memory.ROM[i]); } uint8 S9xGetSPC7110 (uint16 address) { if (!Settings.SPC7110RTC && address > 0x483f) return (OpenBus); return (s7emu.mmio_read(address)); } void S9xSetSPC7110 (uint8 byte, uint16 address) { if (!Settings.SPC7110RTC && address > 0x483f) return; if (address == 0x4830) SetSPC7110SRAMMap(byte); s7emu.mmio_write(address, byte); } void S9xSPC7110PreSaveState (void) { s7snap.r4801 = s7emu.r4801; s7snap.r4802 = s7emu.r4802; s7snap.r4803 = s7emu.r4803; s7snap.r4804 = s7emu.r4804; s7snap.r4805 = s7emu.r4805; s7snap.r4806 = s7emu.r4806; s7snap.r4807 = s7emu.r4807; s7snap.r4808 = s7emu.r4808; s7snap.r4809 = s7emu.r4809; s7snap.r480a = s7emu.r480a; s7snap.r480b = s7emu.r480b; s7snap.r480c = s7emu.r480c; s7snap.r4811 = s7emu.r4811; s7snap.r4812 = s7emu.r4812; s7snap.r4813 = s7emu.r4813; s7snap.r4814 = s7emu.r4814; s7snap.r4815 = s7emu.r4815; s7snap.r4816 = s7emu.r4816; s7snap.r4817 = s7emu.r4817; s7snap.r4818 = s7emu.r4818; s7snap.r481x = s7emu.r481x; s7snap.r4814_latch = s7emu.r4814_latch ? TRUE : FALSE; s7snap.r4815_latch = s7emu.r4815_latch ? TRUE : FALSE; s7snap.r4820 = s7emu.r4820; s7snap.r4821 = s7emu.r4821; s7snap.r4822 = s7emu.r4822; s7snap.r4823 = s7emu.r4823; s7snap.r4824 = s7emu.r4824; s7snap.r4825 = s7emu.r4825; s7snap.r4826 = s7emu.r4826; s7snap.r4827 = s7emu.r4827; s7snap.r4828 = s7emu.r4828; s7snap.r4829 = s7emu.r4829; s7snap.r482a = s7emu.r482a; s7snap.r482b = s7emu.r482b; s7snap.r482c = s7emu.r482c; s7snap.r482d = s7emu.r482d; s7snap.r482e = s7emu.r482e; s7snap.r482f = s7emu.r482f; s7snap.r4830 = s7emu.r4830; s7snap.r4831 = s7emu.r4831; s7snap.r4832 = s7emu.r4832; s7snap.r4833 = s7emu.r4833; s7snap.r4834 = s7emu.r4834; s7snap.dx_offset = (uint32) s7emu.dx_offset; s7snap.ex_offset = (uint32) s7emu.ex_offset; s7snap.fx_offset = (uint32) s7emu.fx_offset; s7snap.r4840 = s7emu.r4840; s7snap.r4841 = s7emu.r4841; s7snap.r4842 = s7emu.r4842; s7snap.rtc_state = (int32) s7emu.rtc_state; s7snap.rtc_mode = (int32) s7emu.rtc_mode; s7snap.rtc_index = (uint32) s7emu.rtc_index; s7snap.decomp_mode = (uint32) s7emu.decomp.decomp_mode; s7snap.decomp_offset = (uint32) s7emu.decomp.decomp_offset; for (int i = 0; i < SPC7110_DECOMP_BUFFER_SIZE; i++) s7snap.decomp_buffer[i] = s7emu.decomp.decomp_buffer[i]; s7snap.decomp_buffer_rdoffset = (uint32) s7emu.decomp.decomp_buffer_rdoffset; s7snap.decomp_buffer_wroffset = (uint32) s7emu.decomp.decomp_buffer_wroffset; s7snap.decomp_buffer_length = (uint32) s7emu.decomp.decomp_buffer_length; for (int i = 0; i < 32; i++) { s7snap.context[i].index = s7emu.decomp.context[i].index; s7snap.context[i].invert = s7emu.decomp.context[i].invert; } } void S9xSPC7110PostLoadState (int version) { s7emu.r4801 = s7snap.r4801; s7emu.r4802 = s7snap.r4802; s7emu.r4803 = s7snap.r4803; s7emu.r4804 = s7snap.r4804; s7emu.r4805 = s7snap.r4805; s7emu.r4806 = s7snap.r4806; s7emu.r4807 = s7snap.r4807; s7emu.r4808 = s7snap.r4808; s7emu.r4809 = s7snap.r4809; s7emu.r480a = s7snap.r480a; s7emu.r480b = s7snap.r480b; s7emu.r480c = s7snap.r480c; s7emu.r4811 = s7snap.r4811; s7emu.r4812 = s7snap.r4812; s7emu.r4813 = s7snap.r4813; s7emu.r4814 = s7snap.r4814; s7emu.r4815 = s7snap.r4815; s7emu.r4816 = s7snap.r4816; s7emu.r4817 = s7snap.r4817; s7emu.r4818 = s7snap.r4818; s7emu.r481x = s7snap.r481x; s7emu.r4814_latch = s7snap.r4814_latch ? true : false; s7emu.r4815_latch = s7snap.r4815_latch ? true : false; s7emu.r4820 = s7snap.r4820; s7emu.r4821 = s7snap.r4821; s7emu.r4822 = s7snap.r4822; s7emu.r4823 = s7snap.r4823; s7emu.r4824 = s7snap.r4824; s7emu.r4825 = s7snap.r4825; s7emu.r4826 = s7snap.r4826; s7emu.r4827 = s7snap.r4827; s7emu.r4828 = s7snap.r4828; s7emu.r4829 = s7snap.r4829; s7emu.r482a = s7snap.r482a; s7emu.r482b = s7snap.r482b; s7emu.r482c = s7snap.r482c; s7emu.r482d = s7snap.r482d; s7emu.r482e = s7snap.r482e; s7emu.r482f = s7snap.r482f; s7emu.r4830 = s7snap.r4830; s7emu.r4831 = s7snap.r4831; s7emu.r4832 = s7snap.r4832; s7emu.r4833 = s7snap.r4833; s7emu.r4834 = s7snap.r4834; s7emu.dx_offset = (unsigned) s7snap.dx_offset; s7emu.ex_offset = (unsigned) s7snap.ex_offset; s7emu.fx_offset = (unsigned) s7snap.fx_offset; s7emu.r4840 = s7snap.r4840; s7emu.r4841 = s7snap.r4841; s7emu.r4842 = s7snap.r4842; s7emu.rtc_state = (SPC7110::RTC_State) s7snap.rtc_state; s7emu.rtc_mode = (SPC7110::RTC_Mode) s7snap.rtc_mode; s7emu.rtc_index = (unsigned) s7snap.rtc_index; s7emu.decomp.decomp_mode = (unsigned) s7snap.decomp_mode; s7emu.decomp.decomp_offset = (unsigned) s7snap.decomp_offset; for (int i = 0; i < SPC7110_DECOMP_BUFFER_SIZE; i++) s7emu.decomp.decomp_buffer[i] = s7snap.decomp_buffer[i]; s7emu.decomp.decomp_buffer_rdoffset = (unsigned) s7snap.decomp_buffer_rdoffset; s7emu.decomp.decomp_buffer_wroffset = (unsigned) s7snap.decomp_buffer_wroffset; s7emu.decomp.decomp_buffer_length = (unsigned) s7snap.decomp_buffer_length; for (int i = 0; i < 32; i++) { s7emu.decomp.context[i].index = s7snap.context[i].index; s7emu.decomp.context[i].invert = s7snap.context[i].invert; } s7emu.update_time(0); } fxemu.h000664 001750 001750 00000015562 12720446475 013223 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _FXEMU_H_ #define _FXEMU_H_ #define FX_BREAKPOINT (-1) #define FX_ERROR_ILLEGAL_ADDRESS (-2) // The FxInfo_s structure, the link between the FxEmulator and the Snes Emulator struct FxInfo_s { uint32 vFlags; uint8 *pvRegisters; // 768 bytes located in the memory at address 0x3000 uint32 nRamBanks; // Number of 64kb-banks in GSU-RAM/BackupRAM (banks 0x70-0x73) uint8 *pvRam; // Pointer to GSU-RAM uint32 nRomBanks; // Number of 32kb-banks in Cart-ROM uint8 *pvRom; // Pointer to Cart-ROM uint32 speedPerLine; bool8 oneLineDone; }; extern struct FxInfo_s SuperFX; void S9xInitSuperFX (void); void S9xResetSuperFX (void); void S9xSuperFXExec (void); void S9xSetSuperFX (uint8, uint16); uint8 S9xGetSuperFX (uint16); void fx_flushCache (void); void fx_computeScreenPointers (void); uint32 fx_run (uint32); #endif apu/bapu/smp/core/oppseudo_misc.cpp000664 001750 001750 00000010346 12720446475 020541 0ustar00sergiosergio000000 000000 case 0x00: { op_io(); break; } case 0xef: { op_io(2); regs.pc--; break; } case 0xff: { op_io(2); regs.pc--; break; } case 0x9f: { op_io(4); regs.B.a = (regs.B.a >> 4) | (regs.B.a << 4); regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0xdf: { op_io(2); if(regs.p.c || (regs.B.a) > 0x99) { regs.B.a += 0x60; regs.p.c = 1; } if(regs.p.h || (regs.B.a & 15) > 0x09) { regs.B.a += 0x06; } regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0xbe: { op_io(2); if(!regs.p.c || (regs.B.a) > 0x99) { regs.B.a -= 0x60; regs.p.c = 0; } if(!regs.p.h || (regs.B.a & 15) > 0x09) { regs.B.a -= 0x06; } regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } case 0x60: { op_io(); regs.p.c = 0; break; } case 0x20: { op_io(); regs.p.p = 0; break; } case 0x80: { op_io(); regs.p.c = 1; break; } case 0x40: { op_io(); regs.p.p = 1; break; } case 0xe0: { op_io(); regs.p.v = 0; regs.p.h = 0; break; } case 0xed: { op_io(2); regs.p.c = !regs.p.c; break; } case 0xa0: { op_io(2); regs.p.i = 1; break; } case 0xc0: { op_io(2); regs.p.i = 0; break; } case 0x02: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x01; op_writedp(dp, rd); break; } case 0x12: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x01; op_writedp(dp, rd); break; } case 0x22: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x02; op_writedp(dp, rd); break; } case 0x32: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x02; op_writedp(dp, rd); break; } case 0x42: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x04; op_writedp(dp, rd); break; } case 0x52: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x04; op_writedp(dp, rd); break; } case 0x62: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x08; op_writedp(dp, rd); break; } case 0x72: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x08; op_writedp(dp, rd); break; } case 0x82: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x10; op_writedp(dp, rd); break; } case 0x92: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x10; op_writedp(dp, rd); break; } case 0xa2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x20; op_writedp(dp, rd); break; } case 0xb2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x20; op_writedp(dp, rd); break; } case 0xc2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x40; op_writedp(dp, rd); break; } case 0xd2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x40; op_writedp(dp, rd); break; } case 0xe2: { dp = op_readpc(); rd = op_readdp(dp); rd |= 0x80; op_writedp(dp, rd); break; } case 0xf2: { dp = op_readpc(); rd = op_readdp(dp); rd &= ~0x80; op_writedp(dp, rd); break; } case 0x2d: { op_io(2); op_writestack(regs.B.a); break; } case 0x4d: { op_io(2); op_writestack(regs.x); break; } case 0x6d: { op_io(2); op_writestack(regs.B.y); break; } case 0x0d: { op_io(2); op_writestack(regs.p); break; } case 0xae: { op_io(2); regs.B.a = op_readstack(); break; } case 0xce: { op_io(2); regs.x = op_readstack(); break; } case 0xee: { op_io(2); regs.B.y = op_readstack(); break; } case 0x8e: { op_io(2); regs.p = op_readstack(); break; } case 0xcf: { op_io(8); ya = regs.B.y * regs.B.a; regs.B.a = ya; regs.B.y = ya >> 8; //result is set based on y (high-byte) only regs.p.n = !!(regs.B.y & 0x80); regs.p.z = (regs.B.y == 0); break; } case 0x9e: { op_io(11); ya = regs.ya; //overflow set if quotient >= 256 regs.p.v = !!(regs.B.y >= regs.x); regs.p.h = !!((regs.B.y & 15) >= (regs.x & 15)); if(regs.B.y < (regs.x << 1)) { //if quotient is <= 511 (will fit into 9-bit result) regs.B.a = ya / regs.x; regs.B.y = ya % regs.x; } else { //otherwise, the quotient won't fit into regs.p.v + regs.B.a //this emulates the odd behavior of the S-SMP in this case regs.B.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); regs.B.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); } //result is set based on a (quotient) only regs.p.n = !!(regs.B.a & 0x80); regs.p.z = (regs.B.a == 0); break; } gfx.cpp000664 001750 001750 00000172714 12720446475 013221 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "ppu.h" #include "tile.h" #include "controls.h" #include "crosshairs.h" #include "cheats.h" #include "movie.h" #include "screenshot.h" #include "font.h" #include "display.h" extern struct SCheatData Cheat; extern struct SLineData LineData[240]; extern struct SLineMatrixData LineMatrixData[240]; void S9xComputeClipWindows (void); static int font_width = 8, font_height = 9; static void SetupOBJ (void); static void DrawOBJS (int); static void DisplayFrameRate (void); static void DisplayPressedKeys (void); static void DisplayWatchedAddresses (void); static void DisplayStringFromBottom (const char *, int, int, bool); static void DrawBackground (int, uint8, uint8); static void DrawBackgroundMosaic (int, uint8, uint8); static void DrawBackgroundOffset (int, uint8, uint8, int); static void DrawBackgroundOffsetMosaic (int, uint8, uint8, int); static inline void DrawBackgroundMode7 (int, void (*DrawMath) (uint32, uint32, int), void (*DrawNomath) (uint32, uint32, int), int); static inline void DrawBackdrop (void); static inline void RenderScreen (bool8); static uint16 get_crosshair_color (uint8); #define TILE_PLUS(t, x) (((t) & 0xfc00) | ((t + x) & 0x3ff)) bool8 S9xGraphicsInit (void) { S9xInitTileRenderer(); memset(BlackColourMap, 0, 256 * sizeof(uint16)); #ifdef GFX_MULTI_FORMAT if (GFX.BuildPixel == NULL) S9xSetRenderPixelFormat(RGB565); #endif GFX.DoInterlace = 0; GFX.InterlaceFrame = 0; GFX.RealPPL = GFX.Pitch >> 1; IPPU.OBJChanged = TRUE; IPPU.DirectColourMapsNeedRebuild = TRUE; Settings.BG_Forced = 0; S9xFixColourBrightness(); GFX.X2 = (uint16 *) malloc(sizeof(uint16) * 0x10000); GFX.ZERO = (uint16 *) malloc(sizeof(uint16) * 0x10000); GFX.ScreenSize = GFX.Pitch / 2 * SNES_HEIGHT_EXTENDED * (Settings.SupportHiRes ? 2 : 1); GFX.SubScreen = (uint16 *) malloc(GFX.ScreenSize * sizeof(uint16)); GFX.ZBuffer = (uint8 *) malloc(GFX.ScreenSize); GFX.SubZBuffer = (uint8 *) malloc(GFX.ScreenSize); if (!GFX.X2 || !GFX.ZERO || !GFX.SubScreen || !GFX.ZBuffer || !GFX.SubZBuffer) { S9xGraphicsDeinit(); return (FALSE); } // Lookup table for color addition memset(GFX.X2, 0, 0x10000 * sizeof(uint16)); for (uint32 r = 0; r <= MAX_RED; r++) { uint32 r2 = r << 1; if (r2 > MAX_RED) r2 = MAX_RED; for (uint32 g = 0; g <= MAX_GREEN; g++) { uint32 g2 = g << 1; if (g2 > MAX_GREEN) g2 = MAX_GREEN; for (uint32 b = 0; b <= MAX_BLUE; b++) { uint32 b2 = b << 1; if (b2 > MAX_BLUE) b2 = MAX_BLUE; GFX.X2[BUILD_PIXEL2(r, g, b)] = BUILD_PIXEL2(r2, g2, b2); GFX.X2[BUILD_PIXEL2(r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2(r2, g2, b2); } } } // Lookup table for 1/2 color subtraction memset(GFX.ZERO, 0, 0x10000 * sizeof(uint16)); for (uint32 r = 0; r <= MAX_RED; r++) { uint32 r2 = r; if (r2 & 0x10) r2 &= ~0x10; else r2 = 0; for (uint32 g = 0; g <= MAX_GREEN; g++) { uint32 g2 = g; if (g2 & GREEN_HI_BIT) g2 &= ~GREEN_HI_BIT; else g2 = 0; for (uint32 b = 0; b <= MAX_BLUE; b++) { uint32 b2 = b; if (b2 & 0x10) b2 &= ~0x10; else b2 = 0; GFX.ZERO[BUILD_PIXEL2(r, g, b)] = BUILD_PIXEL2(r2, g2, b2); GFX.ZERO[BUILD_PIXEL2(r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2(r2, g2, b2); } } } return (TRUE); } void S9xGraphicsDeinit (void) { if (GFX.X2) { free(GFX.X2); GFX.X2 = NULL; } if (GFX.ZERO) { free(GFX.ZERO); GFX.ZERO = NULL; } if (GFX.SubScreen) { free(GFX.SubScreen); GFX.SubScreen = NULL; } if (GFX.ZBuffer) { free(GFX.ZBuffer); GFX.ZBuffer = NULL; } if (GFX.SubZBuffer) { free(GFX.SubZBuffer); GFX.SubZBuffer = NULL; } } void S9xBuildDirectColourMaps (void) { IPPU.XB = mul_brightness[PPU.Brightness]; for (uint32 p = 0; p < 8; p++) for (uint32 c = 0; c < 256; c++) DirectColourMaps[p][c] = BUILD_PIXEL(IPPU.XB[((c & 7) << 2) | ((p & 1) << 1)], IPPU.XB[((c & 0x38) >> 1) | (p & 2)], IPPU.XB[((c & 0xc0) >> 3) | (p & 4)]); IPPU.DirectColourMapsNeedRebuild = FALSE; } void S9xStartScreenRefresh (void) { if (IPPU.RenderThisFrame) { GFX.InterlaceFrame = !GFX.InterlaceFrame; if (!GFX.DoInterlace || !GFX.InterlaceFrame) { if (!S9xInitUpdate()) { IPPU.RenderThisFrame = FALSE; return; } if (GFX.DoInterlace) GFX.DoInterlace--; IPPU.MaxBrightness = PPU.Brightness; IPPU.Interlace = Memory.FillRAM[0x2133] & 1; IPPU.InterlaceOBJ = Memory.FillRAM[0x2133] & 2; IPPU.PseudoHires = Memory.FillRAM[0x2133] & 8; if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires)) { GFX.RealPPL = GFX.Pitch >> 1; IPPU.DoubleWidthPixels = TRUE; IPPU.RenderedScreenWidth = SNES_WIDTH << 1; } else { #ifdef USE_OPENGL if (Settings.OpenGLEnable) GFX.RealPPL = SNES_WIDTH; else #endif GFX.RealPPL = GFX.Pitch >> 1; IPPU.DoubleWidthPixels = FALSE; IPPU.RenderedScreenWidth = SNES_WIDTH; } if (Settings.SupportHiRes && IPPU.Interlace) { GFX.PPL = GFX.RealPPL << 1; IPPU.DoubleHeightPixels = TRUE; IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; GFX.DoInterlace++; } else { GFX.PPL = GFX.RealPPL; IPPU.DoubleHeightPixels = FALSE; IPPU.RenderedScreenHeight = PPU.ScreenHeight; } IPPU.RenderedFramesCount++; } PPU.MosaicStart = 0; PPU.RecomputeClipWindows = TRUE; IPPU.PreviousLine = IPPU.CurrentLine = 0; memset(GFX.ZBuffer, 0, GFX.ScreenSize); memset(GFX.SubZBuffer, 0, GFX.ScreenSize); } if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0) { IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount; IPPU.RenderedFramesCount = 0; IPPU.FrameCount = 0; } if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0) GFX.InfoString = NULL; IPPU.TotalEmulatedFrames++; } void S9xEndScreenRefresh (void) { if (IPPU.RenderThisFrame) { FLUSH_REDRAW(); if (GFX.DoInterlace && GFX.InterlaceFrame == 0) { S9xControlEOF(); S9xContinueUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); } else { if (IPPU.ColorsChanged) { uint32 saved = PPU.CGDATA[0]; IPPU.ColorsChanged = FALSE; S9xSetPalette(); PPU.CGDATA[0] = saved; } S9xControlEOF(); if (Settings.TakeScreenshot) S9xDoScreenshot(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); if (Settings.AutoDisplayMessages) S9xDisplayMessages(GFX.Screen, GFX.RealPPL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, 1); S9xDeinitUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); } } else S9xControlEOF(); S9xApplyCheats(); #ifdef DEBUGGER if (CPU.Flags & FRAME_ADVANCE_FLAG) { if (ICPU.FrameAdvanceCount) { ICPU.FrameAdvanceCount--; IPPU.RenderThisFrame = TRUE; IPPU.FrameSkip = 0; } else { CPU.Flags &= ~FRAME_ADVANCE_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } } #endif if (CPU.SRAMModified) { if (!CPU.AutoSaveTimer) { if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond)) CPU.SRAMModified = FALSE; } else { if (!--CPU.AutoSaveTimer) { S9xAutoSaveSRAM(); CPU.SRAMModified = FALSE; } } } } void RenderLine (uint8 C) { if (IPPU.RenderThisFrame) { LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1; LineData[C].BG[0].HOffset = PPU.BG[0].HOffset; LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1; LineData[C].BG[1].HOffset = PPU.BG[1].HOffset; if (PPU.BGMode == 7) { struct SLineMatrixData *p = &LineMatrixData[C]; p->MatrixA = PPU.MatrixA; p->MatrixB = PPU.MatrixB; p->MatrixC = PPU.MatrixC; p->MatrixD = PPU.MatrixD; p->CentreX = PPU.CentreX; p->CentreY = PPU.CentreY; p->M7HOFS = PPU.M7HOFS; p->M7VOFS = PPU.M7VOFS; } else { LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1; LineData[C].BG[2].HOffset = PPU.BG[2].HOffset; LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1; LineData[C].BG[3].HOffset = PPU.BG[3].HOffset; } IPPU.CurrentLine = C + 1; } else { // if we're not rendering this frame, we still need to update this // XXX: Check ForceBlank? Or anything else? if (IPPU.OBJChanged) SetupOBJ(); PPU.RangeTimeOver |= GFX.OBJLines[C].RTOFlags; } } static inline void RenderScreen (bool8 sub) { uint8 BGActive; int D; if (!sub) { GFX.S = GFX.Screen; if (GFX.DoInterlace && GFX.InterlaceFrame) GFX.S += GFX.RealPPL; GFX.DB = GFX.ZBuffer; GFX.Clip = IPPU.Clip[0]; BGActive = Memory.FillRAM[0x212c] & ~Settings.BG_Forced; D = 32; } else { GFX.S = GFX.SubScreen; GFX.DB = GFX.SubZBuffer; GFX.Clip = IPPU.Clip[1]; BGActive = Memory.FillRAM[0x212d] & ~Settings.BG_Forced; D = (Memory.FillRAM[0x2130] & 2) << 4; // 'do math' depth flag } if (BGActive & 0x10) { BG.TileAddress = PPU.OBJNameBase; BG.NameSelect = PPU.OBJNameSelect; BG.EnableMath = !sub && (Memory.FillRAM[0x2131] & 0x10); BG.StartPalette = 128; S9xSelectTileConverter(4, FALSE, sub, FALSE); S9xSelectTileRenderers(PPU.BGMode, sub, TRUE); DrawOBJS(D + 4); } BG.NameSelect = 0; S9xSelectTileRenderers(PPU.BGMode, sub, FALSE); #define DO_BG(n, pal, depth, hires, offset, Zh, Zl, voffoff) \ if (BGActive & (1 << n)) \ { \ BG.StartPalette = pal; \ BG.EnableMath = !sub && (Memory.FillRAM[0x2131] & (1 << n)); \ BG.TileSizeH = (!hires && PPU.BG[n].BGSize) ? 16 : 8; \ BG.TileSizeV = (PPU.BG[n].BGSize) ? 16 : 8; \ S9xSelectTileConverter(depth, hires, sub, PPU.BGMosaic[n]); \ \ if (offset) \ { \ BG.OffsetSizeH = (!hires && PPU.BG[2].BGSize) ? 16 : 8; \ BG.OffsetSizeV = (PPU.BG[2].BGSize) ? 16 : 8; \ \ if (PPU.BGMosaic[n] && (hires || PPU.Mosaic > 1)) \ DrawBackgroundOffsetMosaic(n, D + Zh, D + Zl, voffoff); \ else \ DrawBackgroundOffset(n, D + Zh, D + Zl, voffoff); \ } \ else \ { \ if (PPU.BGMosaic[n] && (hires || PPU.Mosaic > 1)) \ DrawBackgroundMosaic(n, D + Zh, D + Zl); \ else \ DrawBackground(n, D + Zh, D + Zl); \ } \ } switch (PPU.BGMode) { case 0: DO_BG(0, 0, 2, FALSE, FALSE, 15, 11, 0); DO_BG(1, 32, 2, FALSE, FALSE, 14, 10, 0); DO_BG(2, 64, 2, FALSE, FALSE, 7, 3, 0); DO_BG(3, 96, 2, FALSE, FALSE, 6, 2, 0); break; case 1: DO_BG(0, 0, 4, FALSE, FALSE, 15, 11, 0); DO_BG(1, 0, 4, FALSE, FALSE, 14, 10, 0); DO_BG(2, 0, 2, FALSE, FALSE, (PPU.BG3Priority ? 17 : 7), 3, 0); break; case 2: DO_BG(0, 0, 4, FALSE, TRUE, 15, 7, 8); DO_BG(1, 0, 4, FALSE, TRUE, 11, 3, 8); break; case 3: DO_BG(0, 0, 8, FALSE, FALSE, 15, 7, 0); DO_BG(1, 0, 4, FALSE, FALSE, 11, 3, 0); break; case 4: DO_BG(0, 0, 8, FALSE, TRUE, 15, 7, 0); DO_BG(1, 0, 2, FALSE, TRUE, 11, 3, 0); break; case 5: DO_BG(0, 0, 4, TRUE, FALSE, 15, 7, 0); DO_BG(1, 0, 2, TRUE, FALSE, 11, 3, 0); break; case 6: DO_BG(0, 0, 4, TRUE, TRUE, 15, 7, 8); break; case 7: if (BGActive & 0x01) { BG.EnableMath = !sub && (Memory.FillRAM[0x2131] & 1); DrawBackgroundMode7(0, GFX.DrawMode7BG1Math, GFX.DrawMode7BG1Nomath, D); } if ((Memory.FillRAM[0x2133] & 0x40) && (BGActive & 0x02)) { BG.EnableMath = !sub && (Memory.FillRAM[0x2131] & 2); DrawBackgroundMode7(1, GFX.DrawMode7BG2Math, GFX.DrawMode7BG2Nomath, D); } break; } #undef DO_BG BG.EnableMath = !sub && (Memory.FillRAM[0x2131] & 0x20); DrawBackdrop(); } void S9xUpdateScreen (void) { if (IPPU.OBJChanged || IPPU.InterlaceOBJ) SetupOBJ(); // XXX: Check ForceBlank? Or anything else? PPU.RangeTimeOver |= GFX.OBJLines[GFX.EndY].RTOFlags; GFX.StartY = IPPU.PreviousLine; if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight) GFX.EndY = PPU.ScreenHeight - 1; if (!PPU.ForcedBlanking) { // If force blank, may as well completely skip all this. We only did // the OBJ because (AFAWK) the RTO flags are updated even during force-blank. if (PPU.RecomputeClipWindows) { S9xComputeClipWindows(); PPU.RecomputeClipWindows = FALSE; } if (Settings.SupportHiRes) { if (!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires)) { #ifdef USE_OPENGL if (Settings.OpenGLEnable && GFX.RealPPL == 256) { // Have to back out of the speed up hack where the low res. // SNES image was rendered into a 256x239 sized buffer, // ignoring the true, larger size of the buffer. GFX.RealPPL = GFX.Pitch >> 1; for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--) { register uint16 *p = GFX.Screen + y * GFX.PPL + 255; register uint16 *q = GFX.Screen + y * GFX.RealPPL + 510; for (register int x = 255; x >= 0; x--, p--, q -= 2) *q = *(q + 1) = *p; } GFX.PPL = GFX.RealPPL; // = GFX.Pitch >> 1 above } else #endif { // Have to back out of the regular speed hack for (register uint32 y = 0; y < GFX.StartY; y++) { register uint16 *p = GFX.Screen + y * GFX.PPL + 255; register uint16 *q = GFX.Screen + y * GFX.PPL + 510; for (register int x = 255; x >= 0; x--, p--, q -= 2) *q = *(q + 1) = *p; } } IPPU.DoubleWidthPixels = TRUE; IPPU.RenderedScreenWidth = 512; } if (!IPPU.DoubleHeightPixels && IPPU.Interlace && (PPU.BGMode == 5 || PPU.BGMode == 6)) { IPPU.DoubleHeightPixels = TRUE; IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; GFX.PPL = GFX.RealPPL << 1; GFX.DoInterlace = 2; for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--) memmove(GFX.Screen + y * GFX.PPL, GFX.Screen + y * GFX.RealPPL, IPPU.RenderedScreenWidth * sizeof(uint16)); } } if ((Memory.FillRAM[0x2130] & 0x30) != 0x30 && (Memory.FillRAM[0x2131] & 0x3f)) GFX.FixedColour = BUILD_PIXEL(IPPU.XB[PPU.FixedColourRed], IPPU.XB[PPU.FixedColourGreen], IPPU.XB[PPU.FixedColourBlue]); if (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires || ((Memory.FillRAM[0x2130] & 0x30) != 0x30 && (Memory.FillRAM[0x2130] & 2) && (Memory.FillRAM[0x2131] & 0x3f) && (Memory.FillRAM[0x212d] & 0x1f))) // If hires (Mode 5/6 or pseudo-hires) or math is to be done // involving the subscreen, then we need to render the subscreen... RenderScreen(TRUE); RenderScreen(FALSE); } else { const uint16 black = BUILD_PIXEL(0, 0, 0); GFX.S = GFX.Screen + GFX.StartY * GFX.PPL; if (GFX.DoInterlace && GFX.InterlaceFrame) GFX.S += GFX.RealPPL; for (uint32 l = GFX.StartY; l <= GFX.EndY; l++, GFX.S += GFX.PPL) for (int x = 0; x < IPPU.RenderedScreenWidth; x++) GFX.S[x] = black; } IPPU.PreviousLine = IPPU.CurrentLine; } static void SetupOBJ (void) { int SmallWidth, SmallHeight, LargeWidth, LargeHeight; switch (PPU.OBJSizeSelect) { case 0: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 16; break; case 1: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 32; break; case 2: SmallWidth = SmallHeight = 8; LargeWidth = LargeHeight = 64; break; case 3: SmallWidth = SmallHeight = 16; LargeWidth = LargeHeight = 32; break; case 4: SmallWidth = SmallHeight = 16; LargeWidth = LargeHeight = 64; break; case 5: default: SmallWidth = SmallHeight = 32; LargeWidth = LargeHeight = 64; break; case 6: SmallWidth = 16; SmallHeight = 32; LargeWidth = 32; LargeHeight = 64; break; case 7: SmallWidth = 16; SmallHeight = 32; LargeWidth = LargeHeight = 32; break; } int inc = IPPU.InterlaceOBJ ? 2 : 1; int startline = (IPPU.InterlaceOBJ && GFX.InterlaceFrame) ? 1 : 0; // OK, we have three cases here. Either there's no priority, priority is // normal FirstSprite, or priority is FirstSprite+Y. The first two are // easy, the last is somewhat more ... interesting. So we split them up. int Height; uint8 S; if (!PPU.OAMPriorityRotation || !(PPU.OAMFlip & PPU.OAMAddr & 1)) // normal case { uint8 LineOBJ[SNES_HEIGHT_EXTENDED]; memset(LineOBJ, 0, sizeof(LineOBJ)); for (int i = 0; i < SNES_HEIGHT_EXTENDED; i++) { GFX.OBJLines[i].RTOFlags = 0; GFX.OBJLines[i].Tiles = 34; for (int j = 0; j < 32; j++) GFX.OBJLines[i].OBJ[j].Sprite = -1; } uint8 FirstSprite = PPU.FirstSprite; S = FirstSprite; do { if (PPU.OBJ[S].Size) { GFX.OBJWidths[S] = LargeWidth; Height = LargeHeight; } else { GFX.OBJWidths[S] = SmallWidth; Height = SmallHeight; } int HPos = PPU.OBJ[S].HPos; if (HPos == -256) HPos = 0; if (HPos > -GFX.OBJWidths[S] && HPos <= 256) { if (HPos < 0) GFX.OBJVisibleTiles[S] = (GFX.OBJWidths[S] + HPos + 7) >> 3; else if (HPos + GFX.OBJWidths[S] > 255) GFX.OBJVisibleTiles[S] = (256 - HPos + 7) >> 3; else GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3; for (uint8 line = startline, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc) { if (Y >= SNES_HEIGHT_EXTENDED) continue; if (LineOBJ[Y] >= 32) { GFX.OBJLines[Y].RTOFlags |= 0x40; continue; } GFX.OBJLines[Y].Tiles -= GFX.OBJVisibleTiles[S]; if (GFX.OBJLines[Y].Tiles < 0) GFX.OBJLines[Y].RTOFlags |= 0x80; GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite = S; if (PPU.OBJ[S].VFlip) // Yes, Width not Height. It so happens that the // sprites with H=2*W flip as two WxW sprites. GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line = line ^ (GFX.OBJWidths[S] - 1); else GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line = line; LineOBJ[Y]++; } } S = (S + 1) & 0x7f; } while (S != FirstSprite); for (int Y = 1; Y < SNES_HEIGHT_EXTENDED; Y++) GFX.OBJLines[Y].RTOFlags |= GFX.OBJLines[Y - 1].RTOFlags; } else // evil FirstSprite+Y case { // First, find out which sprites are on which lines uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128]; // memset(OBJOnLine, 0, sizeof(OBJOnLine)); /* Hold on here, that's a lot of bytes to initialise at once! * So we only initialise them per line, as needed. [Neb] * Bonus: We can quickly avoid looping if a line has no OBJs. */ bool8 AnyOBJOnLine[SNES_HEIGHT_EXTENDED]; memset(AnyOBJOnLine, FALSE, sizeof(AnyOBJOnLine)); // better for (S = 0; S < 128; S++) { if (PPU.OBJ[S].Size) { GFX.OBJWidths[S] = LargeWidth; Height = LargeHeight; } else { GFX.OBJWidths[S] = SmallWidth; Height = SmallHeight; } int HPos = PPU.OBJ[S].HPos; if (HPos == -256) HPos = 256; if (HPos > -GFX.OBJWidths[S] && HPos <= 256) { if (HPos < 0) GFX.OBJVisibleTiles[S] = (GFX.OBJWidths[S] + HPos + 7) >> 3; else if (HPos + GFX.OBJWidths[S] >= 257) GFX.OBJVisibleTiles[S] = (257 - HPos + 7) >> 3; else GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3; for (uint8 line = startline, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc) { if (Y >= SNES_HEIGHT_EXTENDED) continue; if (!AnyOBJOnLine[Y]) { memset(OBJOnLine[Y], 0, sizeof(OBJOnLine[Y])); AnyOBJOnLine[Y] = TRUE; } if (PPU.OBJ[S].VFlip) // Yes, Width not Height. It so happens that the // sprites with H=2*W flip as two WxW sprites. OBJOnLine[Y][S] = (line ^ (GFX.OBJWidths[S] - 1)) | 0x80; else OBJOnLine[Y][S] = line | 0x80; } } } // Now go through and pull out those OBJ that are actually visible. int j; for (int Y = 0; Y < SNES_HEIGHT_EXTENDED; Y++) { GFX.OBJLines[Y].RTOFlags = Y ? GFX.OBJLines[Y - 1].RTOFlags : 0; GFX.OBJLines[Y].Tiles = 34; uint8 FirstSprite = (PPU.FirstSprite + Y) & 0x7f; S = FirstSprite; j = 0; if (AnyOBJOnLine[Y]) { do { if (OBJOnLine[Y][S]) { if (j >= 32) { GFX.OBJLines[Y].RTOFlags |= 0x40; break; } GFX.OBJLines[Y].Tiles -= GFX.OBJVisibleTiles[S]; if (GFX.OBJLines[Y].Tiles < 0) GFX.OBJLines[Y].RTOFlags |= 0x80; GFX.OBJLines[Y].OBJ[j].Sprite = S; GFX.OBJLines[Y].OBJ[j++].Line = OBJOnLine[Y][S] & ~0x80; } S = (S + 1) & 0x7f; } while (S != FirstSprite); } if (j < 32) GFX.OBJLines[Y].OBJ[j].Sprite = -1; } } IPPU.OBJChanged = FALSE; } static void DrawOBJS (int D) { void (*DrawTile) (uint32, uint32, uint32, uint32) = NULL; void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32) = NULL; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; BG.InterlaceLine = GFX.InterlaceFrame ? 8 : 0; GFX.Z1 = 2; for (uint32 Y = GFX.StartY, Offset = Y * GFX.PPL; Y <= GFX.EndY; Y++, Offset += GFX.PPL) { int I = 0; int tiles = GFX.OBJLines[Y].Tiles; for (int S = GFX.OBJLines[Y].OBJ[I].Sprite; S >= 0 && I < 32; S = GFX.OBJLines[Y].OBJ[++I].Sprite) { tiles += GFX.OBJVisibleTiles[S]; if (tiles <= 0) continue; int BaseTile = (((GFX.OBJLines[Y].OBJ[I].Line << 1) + (PPU.OBJ[S].Name & 0xf0)) & 0xf0) | (PPU.OBJ[S].Name & 0x100) | (PPU.OBJ[S].Palette << 10); int TileX = PPU.OBJ[S].Name & 0x0f; int TileLine = (GFX.OBJLines[Y].OBJ[I].Line & 7) * 8; int TileInc = 1; if (PPU.OBJ[S].HFlip) { TileX = (TileX + (GFX.OBJWidths[S] >> 3) - 1) & 0x0f; BaseTile |= H_FLIP; TileInc = -1; } GFX.Z2 = D + PPU.OBJ[S].Priority * 4; int DrawMode = 3; int clip = 0, next_clip = -1000; int X = PPU.OBJ[S].HPos; if (X == -256) X = 256; for (int t = tiles, O = Offset + X * PixWidth; X <= 256 && X < PPU.OBJ[S].HPos + GFX.OBJWidths[S]; TileX = (TileX + TileInc) & 0x0f, X += 8, O += 8 * PixWidth) { if (X < -7 || --t < 0 || X == 256) continue; for (int x = X; x < X + 8;) { if (x >= next_clip) { for (; clip < GFX.Clip[4].Count && GFX.Clip[4].Left[clip] <= x; clip++) ; if (clip == 0 || x >= GFX.Clip[4].Right[clip - 1]) { DrawMode = 0; next_clip = ((clip < GFX.Clip[4].Count) ? GFX.Clip[4].Left[clip] : 1000); } else { DrawMode = GFX.Clip[4].DrawMode[clip - 1]; next_clip = GFX.Clip[4].Right[clip - 1]; GFX.ClipColors = !(DrawMode & 1); if (BG.EnableMath && (PPU.OBJ[S].Palette & 4) && (DrawMode & 2)) { DrawTile = GFX.DrawTileMath; DrawClippedTile = GFX.DrawClippedTileMath; } else { DrawTile = GFX.DrawTileNomath; DrawClippedTile = GFX.DrawClippedTileNomath; } } } if (x == X && x + 8 < next_clip) { if (DrawMode) DrawTile(BaseTile | TileX, O, TileLine, 1); x += 8; } else { int w = (next_clip <= X + 8) ? next_clip - x : X + 8 - x; if (DrawMode) DrawClippedTile(BaseTile | TileX, O, x - X, w, TileLine, 1); x += w; } } } } } } static void DrawBackground (int bg, uint8 Zh, uint8 Zl) { BG.TileAddress = PPU.BG[bg].NameBase << 1; uint32 Tile; uint16 *SC0, *SC1, *SC2, *SC3; SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1]; SC1 = (PPU.BG[bg].SCSize & 1) ? SC0 + 1024 : SC0; if (SC1 >= (uint16 *) (Memory.VRAM + 0x10000)) SC1 -= 0x8000; SC2 = (PPU.BG[bg].SCSize & 2) ? SC1 + 1024 : SC0; if (SC2 >= (uint16 *) (Memory.VRAM + 0x10000)) SC2 -= 0x8000; SC3 = (PPU.BG[bg].SCSize & 1) ? SC2 + 1024 : SC2; if (SC3 >= (uint16 *) (Memory.VRAM + 0x10000)) SC3 -= 0x8000; uint32 Lines; int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff; int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels; void (*DrawTile) (uint32, uint32, uint32, uint32); void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32); for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) { GFX.ClipColors = !(GFX.Clip[bg].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) { DrawTile = GFX.DrawTileMath; DrawClippedTile = GFX.DrawClippedTileMath; } else { DrawTile = GFX.DrawTileNomath; DrawClippedTile = GFX.DrawClippedTileNomath; } for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines) { uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y; uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0); uint32 HOffset = LineData[Y].BG[bg].HOffset; int VirtAlign = ((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0); for (Lines = 1; Lines < GFX.LinesPerTile - VirtAlign; Lines++) { if ((VOffset != LineData[Y + Lines].BG[bg].VOffset) || (HOffset != LineData[Y + Lines].BG[bg].HOffset)) break; } if (Y + Lines > GFX.EndY) Lines = GFX.EndY - Y + 1; VirtAlign <<= 3; uint32 t1, t2; uint32 TilemapRow = (VOffset + Y2) >> OffsetShift; BG.InterlaceLine = ((VOffset + Y2) & 1) << 3; if ((VOffset + Y2) & 8) { t1 = 16; t2 = 0; } else { t1 = 0; t2 = 16; } uint16 *b1, *b2; if (TilemapRow & 0x20) { b1 = SC2; b2 = SC3; } else { b1 = SC0; b2 = SC1; } b1 += (TilemapRow & 0x1f) << 5; b2 += (TilemapRow & 0x1f) << 5; uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Offset = Left * PixWidth + Y * GFX.PPL; uint32 HPos = (HOffset + Left) & OffsetMask; uint32 HTile = HPos >> 3; uint16 *t; if (BG.TileSizeH == 8) { if (HTile > 31) t = b2 + (HTile & 0x1f); else t = b1 + HTile; } else { if (HTile > 63) t = b2 + ((HTile >> 1) & 0x1f); else t = b1 + (HTile >> 1); } uint32 Width = Right - Left; if (HPos & 7) { uint32 l = HPos & 7; uint32 w = 8 - l; if (w > Width) w = Width; Offset -= l * PixWidth; Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) { DrawClippedTile(Tile, Offset, l, w, VirtAlign, Lines); t++; if (HTile == 31) t = b2; else if (HTile == 63) t = b1; } else { if (!(Tile & H_FLIP)) DrawClippedTile(TILE_PLUS(Tile, (HTile & 1)), Offset, l, w, VirtAlign, Lines); else DrawClippedTile(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, l, w, VirtAlign, Lines); t += HTile & 1; if (HTile == 63) t = b2; else if (HTile == 127) t = b1; } HTile++; Offset += 8 * PixWidth; Width -= w; } while (Width >= 8) { Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) { DrawTile(Tile, Offset, VirtAlign, Lines); t++; if (HTile == 31) t = b2; else if (HTile == 63) t = b1; } else { if (!(Tile & H_FLIP)) DrawTile(TILE_PLUS(Tile, (HTile & 1)), Offset, VirtAlign, Lines); else DrawTile(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, VirtAlign, Lines); t += HTile & 1; if (HTile == 63) t = b2; else if (HTile == 127) t = b1; } HTile++; Offset += 8 * PixWidth; Width -= 8; } if (Width) { Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) DrawClippedTile(Tile, Offset, 0, Width, VirtAlign, Lines); else { if (!(Tile & H_FLIP)) DrawClippedTile(TILE_PLUS(Tile, (HTile & 1)), Offset, 0, Width, VirtAlign, Lines); else DrawClippedTile(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, 0, Width, VirtAlign, Lines); } } } } } static void DrawBackgroundMosaic (int bg, uint8 Zh, uint8 Zl) { BG.TileAddress = PPU.BG[bg].NameBase << 1; uint32 Tile; uint16 *SC0, *SC1, *SC2, *SC3; SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1]; SC1 = (PPU.BG[bg].SCSize & 1) ? SC0 + 1024 : SC0; if (SC1 >= (uint16 *) (Memory.VRAM + 0x10000)) SC1 -= 0x8000; SC2 = (PPU.BG[bg].SCSize & 2) ? SC1 + 1024 : SC0; if (SC2 >= (uint16 *) (Memory.VRAM + 0x10000)) SC2 -= 0x8000; SC3 = (PPU.BG[bg].SCSize & 1) ? SC2 + 1024 : SC2; if (SC3 >= (uint16 *) (Memory.VRAM + 0x10000)) SC3 -= 0x8000; int Lines; int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff; int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels; void (*DrawPix) (uint32, uint32, uint32, uint32, uint32, uint32); int MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % PPU.Mosaic; for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) { GFX.ClipColors = !(GFX.Clip[bg].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) DrawPix = GFX.DrawMosaicPixelMath; else DrawPix = GFX.DrawMosaicPixelNomath; for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic) { uint32 Y2 = HiresInterlace ? Y * 2 : Y; uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0); uint32 HOffset = LineData[Y].BG[bg].HOffset; Lines = PPU.Mosaic - MosaicStart; if (Y + MosaicStart + Lines > GFX.EndY) Lines = GFX.EndY - Y - MosaicStart + 1; int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3; uint32 t1, t2; uint32 TilemapRow = (VOffset + Y2) >> OffsetShift; BG.InterlaceLine = ((VOffset + Y2) & 1) << 3; if ((VOffset + Y2) & 8) { t1 = 16; t2 = 0; } else { t1 = 0; t2 = 16; } uint16 *b1, *b2; if (TilemapRow & 0x20) { b1 = SC2; b2 = SC3; } else { b1 = SC0; b2 = SC1; } b1 += (TilemapRow & 0x1f) << 5; b2 += (TilemapRow & 0x1f) << 5; uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Offset = Left * PixWidth + (Y + MosaicStart) * GFX.PPL; uint32 HPos = (HOffset + Left - (Left % PPU.Mosaic)) & OffsetMask; uint32 HTile = HPos >> 3; uint16 *t; if (BG.TileSizeH == 8) { if (HTile > 31) t = b2 + (HTile & 0x1f); else t = b1 + HTile; } else { if (HTile > 63) t = b2 + ((HTile >> 1) & 0x1f); else t = b1 + (HTile >> 1); } uint32 Width = Right - Left; HPos &= 7; while (Left < Right) { uint32 w = PPU.Mosaic - (Left % PPU.Mosaic); if (w > Width) w = Width; Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) DrawPix(Tile, Offset, VirtAlign, HPos & 7, w, Lines); else { if (!(Tile & H_FLIP)) DrawPix(TILE_PLUS(Tile, (HTile & 1)), Offset, VirtAlign, HPos & 7, w, Lines); else DrawPix(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, VirtAlign, HPos & 7, w, Lines); } HPos += PPU.Mosaic; while (HPos >= 8) { HPos -= 8; if (BG.TileSizeH == 8) { t++; if (HTile == 31) t = b2; else if (HTile == 63) t = b1; } else { t += HTile & 1; if (HTile == 63) t = b2; else if (HTile == 127) t = b1; } HTile++; } Offset += w * PixWidth; Width -= w; Left += w; } MosaicStart = 0; } } } static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff) { BG.TileAddress = PPU.BG[bg].NameBase << 1; uint32 Tile; uint16 *SC0, *SC1, *SC2, *SC3; uint16 *BPS0, *BPS1, *BPS2, *BPS3; BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1]; BPS1 = (PPU.BG[2].SCSize & 1) ? BPS0 + 1024 : BPS0; if (BPS1 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS1 -= 0x8000; BPS2 = (PPU.BG[2].SCSize & 2) ? BPS1 + 1024 : BPS0; if (BPS2 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS2 -= 0x8000; BPS3 = (PPU.BG[2].SCSize & 1) ? BPS2 + 1024 : BPS2; if (BPS3 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS3 -= 0x8000; SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1]; SC1 = (PPU.BG[bg].SCSize & 1) ? SC0 + 1024 : SC0; if (SC1 >= (uint16 *) (Memory.VRAM + 0x10000)) SC1 -= 0x8000; SC2 = (PPU.BG[bg].SCSize & 2) ? SC1 + 1024 : SC0; if (SC2 >= (uint16 *) (Memory.VRAM + 0x10000)) SC2 -= 0x8000; SC3 = (PPU.BG[bg].SCSize & 1) ? SC2 + 1024 : SC2; if (SC3 >= (uint16 *) (Memory.VRAM + 0x10000)) SC3 -= 0x8000; int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff; int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3; int Offset2Mask = (BG.OffsetSizeH == 16) ? 0x3ff : 0x1ff; int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3; int OffsetEnableMask = 0x2000 << bg; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels; void (*DrawTile) (uint32, uint32, uint32, uint32); void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32); for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) { GFX.ClipColors = !(GFX.Clip[bg].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) { DrawTile = GFX.DrawTileMath; DrawClippedTile = GFX.DrawClippedTileMath; } else { DrawTile = GFX.DrawTileNomath; DrawClippedTile = GFX.DrawClippedTileNomath; } for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++) { uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y; uint32 VOff = LineData[Y].BG[2].VOffset - 1; uint32 HOff = LineData[Y].BG[2].HOffset; uint32 HOffsetRow = VOff >> Offset2Shift; uint32 VOffsetRow = (VOff + VOffOff) >> Offset2Shift; uint16 *s, *s1, *s2; if (HOffsetRow & 0x20) { s1 = BPS2; s2 = BPS3; } else { s1 = BPS0; s2 = BPS1; } s1 += (HOffsetRow & 0x1f) << 5; s2 += (HOffsetRow & 0x1f) << 5; s = ((VOffsetRow & 0x20) ? BPS2 : BPS0) + ((VOffsetRow & 0x1f) << 5); int32 VOffsetOffset = s - s1; uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Offset = Left * PixWidth + Y * GFX.PPL; uint32 LineHOffset = LineData[Y].BG[bg].HOffset; bool8 left_edge = (Left < (8 - (LineHOffset & 7))); uint32 Width = Right - Left; while (Left < Right) { uint32 VOffset, HOffset; if (left_edge) { // SNES cannot do OPT for leftmost tile column VOffset = LineData[Y].BG[bg].VOffset; HOffset = LineHOffset; left_edge = FALSE; } else { int HOffTile = ((HOff + Left - 1) & Offset2Mask) >> 3; if (BG.OffsetSizeH == 8) { if (HOffTile > 31) s = s2 + (HOffTile & 0x1f); else s = s1 + HOffTile; } else { if (HOffTile > 63) s = s2 + ((HOffTile >> 1) & 0x1f); else s = s1 + (HOffTile >> 1); } uint16 HCellOffset = READ_WORD(s); uint16 VCellOffset; if (VOffOff) VCellOffset = READ_WORD(s + VOffsetOffset); else { if (HCellOffset & 0x8000) { VCellOffset = HCellOffset; HCellOffset = 0; } else VCellOffset = 0; } if (VCellOffset & OffsetEnableMask) VOffset = VCellOffset + 1; else VOffset = LineData[Y].BG[bg].VOffset; if (HCellOffset & OffsetEnableMask) HOffset = (HCellOffset & ~7) | (LineHOffset & 7); else HOffset = LineHOffset; } if (HiresInterlace) VOffset++; uint32 t1, t2; int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3; int TilemapRow = (VOffset + Y2) >> OffsetShift; BG.InterlaceLine = ((VOffset + Y2) & 1) << 3; if ((VOffset + Y2) & 8) { t1 = 16; t2 = 0; } else { t1 = 0; t2 = 16; } uint16 *b1, *b2; if (TilemapRow & 0x20) { b1 = SC2; b2 = SC3; } else { b1 = SC0; b2 = SC1; } b1 += (TilemapRow & 0x1f) << 5; b2 += (TilemapRow & 0x1f) << 5; uint32 HPos = (HOffset + Left) & OffsetMask; uint32 HTile = HPos >> 3; uint16 *t; if (BG.TileSizeH == 8) { if (HTile > 31) t = b2 + (HTile & 0x1f); else t = b1 + HTile; } else { if (HTile > 63) t = b2 + ((HTile >> 1) & 0x1f); else t = b1 + (HTile >> 1); } uint32 l = HPos & 7; uint32 w = 8 - l; if (w > Width) w = Width; Offset -= l * PixWidth; Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) { DrawClippedTile(Tile, Offset, l, w, VirtAlign, 1); } else { if (!(Tile & H_FLIP)) DrawClippedTile(TILE_PLUS(Tile, (HTile & 1)), Offset, l, w, VirtAlign, 1); else DrawClippedTile(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, l, w, VirtAlign, 1); } Left += w; Offset += 8 * PixWidth; Width -= w; } } } } static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff) { BG.TileAddress = PPU.BG[bg].NameBase << 1; uint32 Tile; uint16 *SC0, *SC1, *SC2, *SC3; uint16 *BPS0, *BPS1, *BPS2, *BPS3; BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1]; BPS1 = (PPU.BG[2].SCSize & 1) ? BPS0 + 1024 : BPS0; if (BPS1 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS1 -= 0x8000; BPS2 = (PPU.BG[2].SCSize & 2) ? BPS1 + 1024 : BPS0; if (BPS2 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS2 -= 0x8000; BPS3 = (PPU.BG[2].SCSize & 1) ? BPS2 + 1024 : BPS2; if (BPS3 >= (uint16 *) (Memory.VRAM + 0x10000)) BPS3 -= 0x8000; SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1]; SC1 = (PPU.BG[bg].SCSize & 1) ? SC0 + 1024 : SC0; if (SC1 >= (uint16 *) (Memory.VRAM + 0x10000)) SC1 -= 0x8000; SC2 = (PPU.BG[bg].SCSize & 2) ? SC1 + 1024 : SC0; if (SC2 >= (uint16 *) (Memory.VRAM + 0x10000)) SC2 -= 0x8000; SC3 = (PPU.BG[bg].SCSize & 1) ? SC2 + 1024 : SC2; if (SC3 >= (uint16 *) (Memory.VRAM + 0x10000)) SC3 -= 0x8000; int Lines; int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff; int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3; int Offset2Mask = (BG.OffsetSizeH == 16) ? 0x3ff : 0x1ff; int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3; int OffsetEnableMask = 0x2000 << bg; int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1; bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels; void (*DrawPix) (uint32, uint32, uint32, uint32, uint32, uint32); int MosaicStart = ((uint32) GFX.StartY - PPU.MosaicStart) % PPU.Mosaic; for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) { GFX.ClipColors = !(GFX.Clip[bg].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) DrawPix = GFX.DrawMosaicPixelMath; else DrawPix = GFX.DrawMosaicPixelNomath; for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic) { uint32 Y2 = HiresInterlace ? Y * 2 : Y; uint32 VOff = LineData[Y].BG[2].VOffset - 1; uint32 HOff = LineData[Y].BG[2].HOffset; Lines = PPU.Mosaic - MosaicStart; if (Y + MosaicStart + Lines > GFX.EndY) Lines = GFX.EndY - Y - MosaicStart + 1; uint32 HOffsetRow = VOff >> Offset2Shift; uint32 VOffsetRow = (VOff + VOffOff) >> Offset2Shift; uint16 *s, *s1, *s2; if (HOffsetRow & 0x20) { s1 = BPS2; s2 = BPS3; } else { s1 = BPS0; s2 = BPS1; } s1 += (HOffsetRow & 0x1f) << 5; s2 += (HOffsetRow & 0x1f) << 5; s = ((VOffsetRow & 0x20) ? BPS2 : BPS0) + ((VOffsetRow & 0x1f) << 5); int32 VOffsetOffset = s - s1; uint32 Left = GFX.Clip[bg].Left[clip]; uint32 Right = GFX.Clip[bg].Right[clip]; uint32 Offset = Left * PixWidth + (Y + MosaicStart) * GFX.PPL; uint32 LineHOffset = LineData[Y].BG[bg].HOffset; bool8 left_edge = (Left < (8 - (LineHOffset & 7))); uint32 Width = Right - Left; while (Left < Right) { uint32 VOffset, HOffset; if (left_edge) { // SNES cannot do OPT for leftmost tile column VOffset = LineData[Y].BG[bg].VOffset; HOffset = LineHOffset; left_edge = FALSE; } else { int HOffTile = ((HOff + Left - 1) & Offset2Mask) >> 3; if (BG.OffsetSizeH == 8) { if (HOffTile > 31) s = s2 + (HOffTile & 0x1f); else s = s1 + HOffTile; } else { if (HOffTile > 63) s = s2 + ((HOffTile >> 1) & 0x1f); else s = s1 + (HOffTile >> 1); } uint16 HCellOffset = READ_WORD(s); uint16 VCellOffset; if (VOffOff) VCellOffset = READ_WORD(s + VOffsetOffset); else { if (HCellOffset & 0x8000) { VCellOffset = HCellOffset; HCellOffset = 0; } else VCellOffset = 0; } if (VCellOffset & OffsetEnableMask) VOffset = VCellOffset + 1; else VOffset = LineData[Y].BG[bg].VOffset; if (HCellOffset & OffsetEnableMask) HOffset = (HCellOffset & ~7) | (LineHOffset & 7); else HOffset = LineHOffset; } if (HiresInterlace) VOffset++; uint32 t1, t2; int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3; int TilemapRow = (VOffset + Y2) >> OffsetShift; BG.InterlaceLine = ((VOffset + Y2) & 1) << 3; if ((VOffset + Y2) & 8) { t1 = 16; t2 = 0; } else { t1 = 0; t2 = 16; } uint16 *b1, *b2; if (TilemapRow & 0x20) { b1 = SC2; b2 = SC3; } else { b1 = SC0; b2 = SC1; } b1 += (TilemapRow & 0x1f) << 5; b2 += (TilemapRow & 0x1f) << 5; uint32 HPos = (HOffset + Left - (Left % PPU.Mosaic)) & OffsetMask; uint32 HTile = HPos >> 3; uint16 *t; if (BG.TileSizeH == 8) { if (HTile > 31) t = b2 + (HTile & 0x1f); else t = b1 + HTile; } else { if (HTile > 63) t = b2 + ((HTile >> 1) & 0x1f); else t = b1 + (HTile >> 1); } uint32 w = PPU.Mosaic - (Left % PPU.Mosaic); if (w > Width) w = Width; Tile = READ_WORD(t); GFX.Z1 = GFX.Z2 = (Tile & 0x2000) ? Zh : Zl; if (BG.TileSizeV == 16) Tile = TILE_PLUS(Tile, ((Tile & V_FLIP) ? t2 : t1)); if (BG.TileSizeH == 8) DrawPix(Tile, Offset, VirtAlign, HPos & 7, w, Lines); else { if (!(Tile & H_FLIP)) DrawPix(TILE_PLUS(Tile, (HTile & 1)), Offset, VirtAlign, HPos & 7, w, Lines); else if (!(Tile & V_FLIP)) DrawPix(TILE_PLUS(Tile, 1 - (HTile & 1)), Offset, VirtAlign, HPos & 7, w, Lines); } Left += w; Offset += w * PixWidth; Width -= w; } MosaicStart = 0; } } } static inline void DrawBackgroundMode7 (int bg, void (*DrawMath) (uint32, uint32, int), void (*DrawNomath) (uint32, uint32, int), int D) { for (int clip = 0; clip < GFX.Clip[bg].Count; clip++) { GFX.ClipColors = !(GFX.Clip[bg].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[bg].DrawMode[clip] & 2)) DrawMath(GFX.Clip[bg].Left[clip], GFX.Clip[bg].Right[clip], D); else DrawNomath(GFX.Clip[bg].Left[clip], GFX.Clip[bg].Right[clip], D); } } static inline void DrawBackdrop (void) { uint32 Offset = GFX.StartY * GFX.PPL; for (int clip = 0; clip < GFX.Clip[5].Count; clip++) { GFX.ClipColors = !(GFX.Clip[5].DrawMode[clip] & 1); if (BG.EnableMath && (GFX.Clip[5].DrawMode[clip] & 2)) GFX.DrawBackdropMath(Offset, GFX.Clip[5].Left[clip], GFX.Clip[5].Right[clip]); else GFX.DrawBackdropNomath(Offset, GFX.Clip[5].Left[clip], GFX.Clip[5].Right[clip]); } } void S9xReRefresh (void) { // Be careful when calling this function from the thread other than the emulation one... // Here it's assumed no drawing occurs from the emulation thread when Settings.Paused is TRUE. if (Settings.Paused) S9xDeinitUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); } void S9xSetInfoString (const char *string) { if (Settings.InitialInfoStringTimeout > 0) { GFX.InfoString = string; GFX.InfoStringTimeout = Settings.InitialInfoStringTimeout; S9xReRefresh(); } } void S9xDisplayChar (uint16 *s, uint8 c) { const uint16 black = BUILD_PIXEL(0, 0, 0); int line = ((c - 32) >> 4) * font_height; int offset = ((c - 32) & 15) * font_width; for (int h = 0; h < font_height; h++, line++, s += GFX.RealPPL - font_width) { for (int w = 0; w < font_width; w++, s++) { char p = font[line][offset + w]; if (p == '#') *s = Settings.DisplayColor; else if (p == '.') *s = black; } } } static void DisplayStringFromBottom (const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap) { if (linesFromBottom <= 0) linesFromBottom = 1; uint16 *dst = GFX.Screen + (IPPU.RenderedScreenHeight - font_height * linesFromBottom) * GFX.RealPPL + pixelsFromLeft; int len = strlen(string); int max_chars = IPPU.RenderedScreenWidth / (font_width - 1); int char_count = 0; for (int i = 0 ; i < len ; i++, char_count++) { if (char_count >= max_chars || (uint8) string[i] < 32) { if (!allowWrap) break; dst += font_height * GFX.RealPPL - (font_width - 1) * max_chars; if (dst >= GFX.Screen + IPPU.RenderedScreenHeight * GFX.RealPPL) break; char_count -= max_chars; } if ((uint8) string[i] < 32) continue; S9xDisplayChar(dst, string[i]); dst += font_width - 1; } } static void DisplayFrameRate (void) { char string[10]; static uint32 lastFrameCount = 0, calcFps = 0; static time_t lastTime = time(NULL); time_t currTime = time(NULL); if (lastTime != currTime) { if (lastFrameCount < IPPU.TotalEmulatedFrames) { calcFps = (IPPU.TotalEmulatedFrames - lastFrameCount) / (uint32)(currTime - lastTime); } lastTime = currTime; lastFrameCount = IPPU.TotalEmulatedFrames; } sprintf(string, "%u fps", calcFps); S9xDisplayString(string, 2, IPPU.RenderedScreenWidth - (font_width - 1) * strlen(string) - 1, false); #ifdef DEBUGGER const int len = 8; sprintf(string, "%02d/%02d %02d", (int) IPPU.DisplayedRenderedFrameCount, (int) Memory.ROMFramesPerSecond, (int) IPPU.FrameCount); #else const int len = 5; sprintf(string, "%02d/%02d", (int) IPPU.DisplayedRenderedFrameCount, (int) Memory.ROMFramesPerSecond); #endif S9xDisplayString(string, 1, IPPU.RenderedScreenWidth - (font_width - 1) * len - 1, false); } static void DisplayPressedKeys (void) { static char KeyMap[] = { '0', '1', '2', 'R', 'L', 'X', 'A', '>', '<', 'v', '^', 'S', 's', 'Y', 'B' }; static int KeyOrder[] = { 8, 10, 7, 9, 0, 6, 14, 13, 5, 1, 4, 3, 2, 11, 12 }; // < ^ > v A B Y X L R S s enum controllers controller; int line = Settings.DisplayMovieFrame && S9xMovieActive() ? 2 : 1; int8 ids[4]; char string[255]; for (int port = 0; port < 2; port++) { S9xGetController(port, &controller, &ids[0], &ids[1], &ids[2], &ids[3]); switch (controller) { case CTL_MOUSE: { uint8 buf[5], *p = buf; MovieGetMouse(port, buf); int16 x = READ_WORD(p); int16 y = READ_WORD(p + 2); uint8 buttons = buf[4]; sprintf(string, "#%d %d: (%03d,%03d) %c%c", port, ids[0], x, y, (buttons & 0x40) ? 'L' : ' ', (buttons & 0x80) ? 'R' : ' '); S9xDisplayString(string, line++, 1, false); break; } case CTL_SUPERSCOPE: { uint8 buf[6], *p = buf; MovieGetScope(port, buf); int16 x = READ_WORD(p); int16 y = READ_WORD(p + 2); uint8 buttons = buf[4]; sprintf(string, "#%d %d: (%03d,%03d) %c%c%c%c", port, ids[0], x, y, (buttons & 0x80) ? 'F' : ' ', (buttons & 0x40) ? 'C' : ' ', (buttons & 0x20) ? 'T' : ' ', (buttons & 0x10) ? 'P' : ' '); S9xDisplayString(string, line++, 1, false); break; } case CTL_JUSTIFIER: { uint8 buf[11], *p = buf; MovieGetJustifier(port, buf); int16 x1 = READ_WORD(p); int16 x2 = READ_WORD(p + 2); int16 y1 = READ_WORD(p + 4); int16 y2 = READ_WORD(p + 6); uint8 buttons = buf[8]; bool8 offscreen1 = buf[9]; bool8 offscreen2 = buf[10]; sprintf(string, "#%d %d: (%03d,%03d) %c%c%c / (%03d,%03d) %c%c%c", port, ids[0], x1, y1, (buttons & 0x80) ? 'T' : ' ', (buttons & 0x20) ? 'S' : ' ', offscreen1 ? 'O' : ' ', x2, y2, (buttons & 0x40) ? 'T' : ' ', (buttons & 0x10) ? 'S' : ' ', offscreen2 ? 'O' : ' '); S9xDisplayString(string, line++, 1, false); break; } case CTL_JOYPAD: { sprintf(string, "#%d %d: ", port, ids[0]); uint16 pad = MovieGetJoypad(ids[0]); for (int i = 0; i < 15; i++) { int j = KeyOrder[i]; int mask = (1 << (j + 1)); string[6 + i]= (pad & mask) ? KeyMap[j] : ' '; } S9xDisplayString(string, line++, 1, false); break; } case CTL_MP5: { for (int n = 0; n < 4; n++) { if (ids[n] != -1) { sprintf(string, "#%d %d: ", port, ids[n]); uint16 pad = MovieGetJoypad(ids[n]); for (int i = 0; i < 15; i++) { int j = KeyOrder[i]; int mask = (1 << (j + 1)); string[6 + i]= (pad & mask) ? KeyMap[j] : ' '; } S9xDisplayString(string, line++, 1, false); } } break; } case CTL_NONE: { sprintf(string, "#%d -", port); S9xDisplayString(string, line++, 1, false); break; } } } } static void DisplayWatchedAddresses (void) { for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++) { if (!watches[i].on) break; int32 displayNumber = 0; char buf[32]; for (int r = 0; r < watches[i].size; r++) displayNumber += (Cheat.CWatchRAM[(watches[i].address - 0x7E0000) + r]) << (8 * r); if (watches[i].format == 1) sprintf(buf, "%s,%du = %u", watches[i].desc, watches[i].size, (unsigned int) displayNumber); else if (watches[i].format == 3) sprintf(buf, "%s,%dx = %X", watches[i].desc, watches[i].size, (unsigned int) displayNumber); else // signed { if (watches[i].size == 1) displayNumber = (int32) ((int8) displayNumber); else if (watches[i].size == 2) displayNumber = (int32) ((int16) displayNumber); else if (watches[i].size == 3) if (displayNumber >= 8388608) displayNumber -= 16777216; sprintf(buf, "%s,%ds = %d", watches[i].desc, watches[i].size, (int) displayNumber); } S9xDisplayString(buf, 6 + i, 1, false); } } void S9xDisplayMessages (uint16 *screen, int ppl, int width, int height, int scale) { if (Settings.DisplayFrameRate) DisplayFrameRate(); if (Settings.DisplayWatchedAddresses) DisplayWatchedAddresses(); if (Settings.DisplayPressedKeys) DisplayPressedKeys(); if (Settings.DisplayMovieFrame && S9xMovieActive()) S9xDisplayString(GFX.FrameDisplayString, 1, 1, false); if (GFX.InfoString && *GFX.InfoString) S9xDisplayString(GFX.InfoString, 5, 1, true); } static uint16 get_crosshair_color (uint8 color) { switch (color & 15) { case 0: return (BUILD_PIXEL( 0, 0, 0)); // transparent, shouldn't be used case 1: return (BUILD_PIXEL( 0, 0, 0)); // Black case 2: return (BUILD_PIXEL( 8, 8, 8)); // 25Grey case 3: return (BUILD_PIXEL(16, 16, 16)); // 50Grey case 4: return (BUILD_PIXEL(23, 23, 23)); // 75Grey case 5: return (BUILD_PIXEL(31, 31, 31)); // White case 6: return (BUILD_PIXEL(31, 0, 0)); // Red case 7: return (BUILD_PIXEL(31, 16, 0)); // Orange case 8: return (BUILD_PIXEL(31, 31, 0)); // Yellow case 9: return (BUILD_PIXEL( 0, 31, 0)); // Green case 10: return (BUILD_PIXEL( 0, 31, 31)); // Cyan case 11: return (BUILD_PIXEL( 0, 23, 31)); // Sky case 12: return (BUILD_PIXEL( 0, 0, 31)); // Blue case 13: return (BUILD_PIXEL(23, 0, 31)); // Violet case 14: return (BUILD_PIXEL(31, 0, 31)); // Magenta case 15: return (BUILD_PIXEL(31, 0, 16)); // Purple } return (0); } void S9xDrawCrosshair (const char *crosshair, uint8 fgcolor, uint8 bgcolor, int16 x, int16 y) { if (!crosshair) return; int16 r, rx = 1, c, cx = 1, W = SNES_WIDTH, H = PPU.ScreenHeight; uint16 fg, bg; x -= 7; y -= 7; if (IPPU.DoubleWidthPixels) { cx = 2; x *= 2; W *= 2; } if (IPPU.DoubleHeightPixels) { rx = 2; y *= 2; H *= 2; } fg = get_crosshair_color(fgcolor); bg = get_crosshair_color(bgcolor); uint16 *s = GFX.Screen + y * (int32)GFX.RealPPL + x; for (r = 0; r < 15 * rx; r++, s += GFX.RealPPL - 15 * cx) { if (y + r < 0) { s += 15 * cx; continue; } if (y + r >= H) break; for (c = 0; c < 15 * cx; c++, s++) { if (x + c < 0 || s < GFX.Screen) continue; if (x + c >= W) { s += 15 * cx - c; break; } uint8 p = crosshair[(r / rx) * 15 + (c / cx)]; if (p == '#' && fgcolor) *s = (fgcolor & 0x10) ? COLOR_ADD1_2(fg, *s) : fg; else if (p == '.' && bgcolor) *s = (bgcolor & 0x10) ? COLOR_ADD1_2(*s, bg) : bg; } } } #ifdef GFX_MULTI_FORMAT static uint32 BuildPixelRGB565 (uint32, uint32, uint32); static uint32 BuildPixelRGB555 (uint32, uint32, uint32); static uint32 BuildPixelBGR565 (uint32, uint32, uint32); static uint32 BuildPixelBGR555 (uint32, uint32, uint32); static uint32 BuildPixelGBR565 (uint32, uint32, uint32); static uint32 BuildPixelGBR555 (uint32, uint32, uint32); static uint32 BuildPixelRGB5551 (uint32, uint32, uint32); static uint32 BuildPixel2RGB565 (uint32, uint32, uint32); static uint32 BuildPixel2RGB555 (uint32, uint32, uint32); static uint32 BuildPixel2BGR565 (uint32, uint32, uint32); static uint32 BuildPixel2BGR555 (uint32, uint32, uint32); static uint32 BuildPixel2GBR565 (uint32, uint32, uint32); static uint32 BuildPixel2GBR555 (uint32, uint32, uint32); static uint32 BuildPixel2RGB5551 (uint32, uint32, uint32); static void DecomposePixelRGB565 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelRGB555 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelBGR565 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelBGR555 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelGBR565 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelGBR555 (uint32, uint32 &, uint32 &, uint32 &); static void DecomposePixelRGB5551 (uint32, uint32 &, uint32 &, uint32 &); #define _BUILD_PIXEL(F) \ static uint32 BuildPixel##F (uint32 R, uint32 G, uint32 B) \ { \ return (BUILD_PIXEL_##F(R, G, B)); \ } \ \ static uint32 BuildPixel2##F (uint32 R, uint32 G, uint32 B) \ { \ return (BUILD_PIXEL2_##F(R, G, B)); \ } \ \ static void DecomposePixel##F (uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \ { \ DECOMPOSE_PIXEL_##F(pixel, R, G, B); \ } _BUILD_PIXEL(RGB565) _BUILD_PIXEL(RGB555) _BUILD_PIXEL(BGR565) _BUILD_PIXEL(BGR555) _BUILD_PIXEL(GBR565) _BUILD_PIXEL(GBR555) _BUILD_PIXEL(RGB5551) #define _BUILD_SETUP(F) \ GFX.BuildPixel = BuildPixel##F; \ GFX.BuildPixel2 = BuildPixel2##F; \ GFX.DecomposePixel = DecomposePixel##F; \ RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \ GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \ BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \ RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \ GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \ BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \ MAX_RED = MAX_RED_##F; \ MAX_GREEN = MAX_GREEN_##F; \ MAX_BLUE = MAX_BLUE_##F; \ SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \ GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \ RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | GREEN_LOW_BIT_MASK_##F | BLUE_LOW_BIT_MASK_##F); \ RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | GREEN_HI_BIT_MASK_##F | BLUE_HI_BIT_MASK_##F); \ RGB_HI_BITS_MASKx2 = (RED_HI_BIT_MASK_##F | GREEN_HI_BIT_MASK_##F | BLUE_HI_BIT_MASK_##F) << 1; \ RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \ FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \ SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \ THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \ ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \ FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \ TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \ HIGH_BITS_SHIFTED_TWO_MASK = ((FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & ~TWO_LOW_BITS_MASK) >> 2; bool8 S9xSetRenderPixelFormat (int format) { GFX.PixelFormat = format; switch (format) { case RGB565: _BUILD_SETUP(RGB565) return (TRUE); case RGB555: _BUILD_SETUP(RGB555) return (TRUE); case BGR565: _BUILD_SETUP(BGR565) return (TRUE); case BGR555: _BUILD_SETUP(BGR555) return (TRUE); case GBR565: _BUILD_SETUP(GBR565) return (TRUE); case GBR555: _BUILD_SETUP(GBR555) return (TRUE); case RGB5551: _BUILD_SETUP(RGB5551) return (TRUE); default: break; } return (FALSE); } #endif libretro/control000664 001750 001750 00000000322 12720446475 015137 0ustar00sergiosergio000000 000000 Package: com.libretro.snes9x Name: snes9x Depends: Version: 0.0.1 Architecture: iphoneos-arm Description: Libretro iOS core of SNES9x Maintainer: libretro Author: libretro Section: System Tag: role::developer apu/bapu/smp/core/opcycle_rmw.cpp000664 001750 001750 00000017137 12720446475 020220 0ustar00sergiosergio000000 000000 case 0xbc: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_inc(regs.a); opcode_cycle = 0; break; } break; } case 0x3d: { switch(opcode_cycle++) { case 1: op_io(); regs.x = op_inc(regs.x); opcode_cycle = 0; break; } break; } case 0xfc: { switch(opcode_cycle++) { case 1: op_io(); regs.y = op_inc(regs.y); opcode_cycle = 0; break; } break; } case 0x9c: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_dec(regs.a); opcode_cycle = 0; break; } break; } case 0x1d: { switch(opcode_cycle++) { case 1: op_io(); regs.x = op_dec(regs.x); opcode_cycle = 0; break; } break; } case 0xdc: { switch(opcode_cycle++) { case 1: op_io(); regs.y = op_dec(regs.y); opcode_cycle = 0; break; } break; } case 0x1c: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_asl(regs.a); opcode_cycle = 0; break; } break; } case 0x5c: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_lsr(regs.a); opcode_cycle = 0; break; } break; } case 0x3c: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_rol(regs.a); opcode_cycle = 0; break; } break; } case 0x7c: { switch(opcode_cycle++) { case 1: op_io(); regs.a = op_ror(regs.a); opcode_cycle = 0; break; } break; } case 0xab: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_inc(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x8b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_dec(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x0b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_asl(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x4b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_lsr(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x2b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_rol(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x6b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); break; case 3: rd = op_ror(rd); op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xbb: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_inc(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0x9b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_dec(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0x1b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_asl(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0x5b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_lsr(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0x3b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_rol(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0x7b: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: rd = op_readdp(dp + regs.x); break; case 4: rd = op_ror(rd); op_writedp(dp + regs.x, rd); opcode_cycle = 0; break; } break; } case 0xac: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_inc(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x8c: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_dec(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x0c: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_asl(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x4c: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_lsr(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x2c: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_rol(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x6c: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); break; case 4: rd = op_ror(rd); op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } case 0x0e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.p.n = !!((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, rd | regs.a); opcode_cycle = 0; break; } break; } case 0x4e: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: rd = op_readaddr(dp); regs.p.n = !!((regs.a - rd) & 0x80); regs.p.z = ((regs.a - rd) == 0); break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, rd &~ regs.a); opcode_cycle = 0; break; } break; } case 0x3a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); rd++; break; case 3: op_writedp(dp++, rd); break; case 4: rd += op_readdp(dp) << 8; break; case 5: op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); opcode_cycle = 0; break; } break; } case 0x1a: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: rd = op_readdp(dp); rd--; break; case 3: op_writedp(dp++, rd); break; case 4: rd += op_readdp(dp) << 8; break; case 5: op_writedp(dp, rd >> 8); regs.p.n = !!(rd & 0x8000); regs.p.z = (rd == 0); opcode_cycle = 0; break; } break; } seta011.cpp000664 001750 001750 00000021076 12720446475 013605 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" #include "seta.h" static uint8 board[9][9]; // shougi playboard static int line = 0; // line counter uint8 S9xGetST011 (uint32 Address) { uint8 t; uint16 address = (uint16) Address & 0xFFFF; line++; // status check if (address == 0x01) t = 0xFF; else t = Memory.SRAM[address]; // read directly from s-ram #ifdef DEBUGGER if (address < 0x150) printf("ST011 R: %06X %02X\n", Address, t); #endif return (t); } void S9xSetST011 (uint32 Address, uint8 Byte) { static bool reset = false; uint16 address = (uint16) Address & 0xFFFF; line++; if (!reset) { // bootup values ST011.waiting4command = true; reset = true; } #ifdef DEBUGGER if (address < 0x150) printf("ST011 W: %06X %02X\n", Address, Byte); #endif Memory.SRAM[address] = Byte; // op commands/data goes through this address if (address == 0x00) { // check for new commands if (ST011.waiting4command) { ST011.waiting4command = false; ST011.command = Byte; ST011.in_index = 0; ST011.out_index = 0; switch (ST011.command) { case 0x01: ST011.in_count = 12 * 10 + 8; break; case 0x02: ST011.in_count = 4; break; case 0x04: ST011.in_count = 0; break; case 0x05: ST011.in_count = 0; break; case 0x06: ST011.in_count = 0; break; case 0x07: ST011.in_count = 0; break; case 0x0E: ST011.in_count = 0; break; default: ST011.waiting4command = true; break; } } else { ST011.parameters[ST011.in_index] = Byte; ST011.in_index++; } } if (ST011.in_count == ST011.in_index) { // actually execute the command ST011.waiting4command = true; ST011.out_index = 0; switch (ST011.command) { // unknown: download playboard case 0x01: // 9x9 board data: top to bottom, left to right // Values represent piece types and ownership for (int lcv = 0; lcv < 9; lcv++) memcpy(board[lcv], ST011.parameters + lcv * 10, 9 * 1); break; // unknown case 0x02: break; // unknown case 0x04: // outputs Memory.SRAM[0x12C] = 0x00; //Memory.SRAM[0x12D] = 0x00; Memory.SRAM[0x12E] = 0x00; break; // unknown case 0x05: // outputs Memory.SRAM[0x12C] = 0x00; //Memory.SRAM[0x12D] = 0x00; Memory.SRAM[0x12E] = 0x00; break; // unknown case 0x06: break; case 0x07: break; // unknown case 0x0E: // outputs Memory.SRAM[0x12C] = 0x00; Memory.SRAM[0x12D] = 0x00; break; } } } apu/ring_buffer.h000664 001750 001750 00000004075 12720446475 015151 0ustar00sergiosergio000000 000000 /* Simple byte-based ring buffer. Licensed under public domain (C) BearOso. */ #ifndef __RING_BUFFER_H #define __RING_BUFFER_H #include #undef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) class ring_buffer { protected: int size; int buffer_size; int start; unsigned char *buffer; public: ring_buffer (int buffer_size) { this->buffer_size = buffer_size; buffer = new unsigned char[this->buffer_size]; memset (buffer, 0, this->buffer_size); size = 0; start = 0; } ~ring_buffer (void) { delete[] buffer; } bool push (unsigned char *src, int bytes) { if (space_empty () < bytes) return false; int end = (start + size) % buffer_size; int first_write_size = MIN (bytes, buffer_size - end); memcpy (buffer + end, src, first_write_size); if (bytes > first_write_size) memcpy (buffer, src + first_write_size, bytes - first_write_size); size += bytes; return true; } bool pull (unsigned char *dst, int bytes) { if (space_filled () < bytes) return false; memcpy (dst, buffer + start, MIN (bytes, buffer_size - start)); if (bytes > (buffer_size - start)) memcpy (dst + (buffer_size - start), buffer, bytes - (buffer_size - start)); start = (start + bytes) % buffer_size; size -= bytes; return true; } inline int space_empty (void) { return buffer_size - size; } inline int space_filled (void) { return size; } void clear (void) { start = 0; size = 0; memset (buffer, 0, buffer_size); } void resize (int size) { delete[] buffer; buffer_size = size; buffer = new unsigned char[buffer_size]; memset (buffer, 0, this->buffer_size); size = 0; start = 0; } inline void cache_silence (void) { clear (); size = buffer_size; } }; #endif libretro/msvc/msvc-2010/msvc-2010.vcxproj000664 001750 001750 00000016013 12720446475 021005 0ustar00sergiosergio000000 000000  Debug Win32 Release Win32 {5BDB0E63-AD88-4547-BF48-169312DDD188} Win32Proj msvc2010 DynamicLibrary true Unicode DynamicLibrary false true Unicode true $(SolutionDir)msvc-2010\$(Configuration)\ false $(SolutionDir)msvc-2010\$(Configuration)\ Level3 Disabled WIN32;_DEBUG;_WINDOWS;_USRDLL;MSVC2010_EXPORTS;%(PreprocessorDefinitions);HAVE_STDINT_H;RIGHTSHIFT_IS_SAR;__LIBRETRO__;__WIN32__;__WIN32_LIBSNES__;_CRT_SECURE_NO_WARNINGS $(SolutionDir)\..\..\;$(SolutionDir)\..\..\..\;$(SolutionDir)\..\..\apu\bapu\;%(AdditionalIncludeDirectories) Windows true libretro.def Level3 MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;MSVC2010_EXPORTS;%(PreprocessorDefinitions);HAVE_STDINT_H;RIGHTSHIFT_IS_SAR;__LIBRETRO__;__WIN32__;__WIN32_LIBSNES__;_CRT_SECURE_NO_WARNINGS $(SolutionDir)\..\..\;$(SolutionDir)\..\..\..\;$(SolutionDir)\..\..\apu\bapu\;%(AdditionalIncludeDirectories) Windows true true true libretro.def dsp.h000664 001750 001750 00000033554 12720446475 012666 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _DSP1_H_ #define _DSP1_H_ enum { M_DSP1_LOROM_S, M_DSP1_LOROM_L, M_DSP1_HIROM, M_DSP2_LOROM, M_DSP3_LOROM, M_DSP4_LOROM }; struct SDSP0 { uint32 maptype; uint32 boundary; }; struct SDSP1 { bool8 waiting4command; bool8 first_parameter; uint8 command; uint32 in_count; uint32 in_index; uint32 out_count; uint32 out_index; uint8 parameters[512]; uint8 output[512]; int16 CentreX; int16 CentreY; int16 VOffset; int16 VPlane_C; int16 VPlane_E; // Azimuth and Zenith angles int16 SinAas; int16 CosAas; int16 SinAzs; int16 CosAzs; // Clipped Zenith angle int16 SinAZS; int16 CosAZS; int16 SecAZS_C1; int16 SecAZS_E1; int16 SecAZS_C2; int16 SecAZS_E2; int16 Nx; int16 Ny; int16 Nz; int16 Gx; int16 Gy; int16 Gz; int16 C_Les; int16 E_Les; int16 G_Les; int16 matrixA[3][3]; int16 matrixB[3][3]; int16 matrixC[3][3]; int16 Op00Multiplicand; int16 Op00Multiplier; int16 Op00Result; int16 Op20Multiplicand; int16 Op20Multiplier; int16 Op20Result; int16 Op10Coefficient; int16 Op10Exponent; int16 Op10CoefficientR; int16 Op10ExponentR; int16 Op04Angle; int16 Op04Radius; int16 Op04Sin; int16 Op04Cos; int16 Op0CA; int16 Op0CX1; int16 Op0CY1; int16 Op0CX2; int16 Op0CY2; int16 Op02FX; int16 Op02FY; int16 Op02FZ; int16 Op02LFE; int16 Op02LES; int16 Op02AAS; int16 Op02AZS; int16 Op02VOF; int16 Op02VVA; int16 Op02CX; int16 Op02CY; int16 Op0AVS; int16 Op0AA; int16 Op0AB; int16 Op0AC; int16 Op0AD; int16 Op06X; int16 Op06Y; int16 Op06Z; int16 Op06H; int16 Op06V; int16 Op06M; int16 Op01m; int16 Op01Zr; int16 Op01Xr; int16 Op01Yr; int16 Op11m; int16 Op11Zr; int16 Op11Xr; int16 Op11Yr; int16 Op21m; int16 Op21Zr; int16 Op21Xr; int16 Op21Yr; int16 Op0DX; int16 Op0DY; int16 Op0DZ; int16 Op0DF; int16 Op0DL; int16 Op0DU; int16 Op1DX; int16 Op1DY; int16 Op1DZ; int16 Op1DF; int16 Op1DL; int16 Op1DU; int16 Op2DX; int16 Op2DY; int16 Op2DZ; int16 Op2DF; int16 Op2DL; int16 Op2DU; int16 Op03F; int16 Op03L; int16 Op03U; int16 Op03X; int16 Op03Y; int16 Op03Z; int16 Op13F; int16 Op13L; int16 Op13U; int16 Op13X; int16 Op13Y; int16 Op13Z; int16 Op23F; int16 Op23L; int16 Op23U; int16 Op23X; int16 Op23Y; int16 Op23Z; int16 Op14Zr; int16 Op14Xr; int16 Op14Yr; int16 Op14U; int16 Op14F; int16 Op14L; int16 Op14Zrr; int16 Op14Xrr; int16 Op14Yrr; int16 Op0EH; int16 Op0EV; int16 Op0EX; int16 Op0EY; int16 Op0BX; int16 Op0BY; int16 Op0BZ; int16 Op0BS; int16 Op1BX; int16 Op1BY; int16 Op1BZ; int16 Op1BS; int16 Op2BX; int16 Op2BY; int16 Op2BZ; int16 Op2BS; int16 Op28X; int16 Op28Y; int16 Op28Z; int16 Op28R; int16 Op1CX; int16 Op1CY; int16 Op1CZ; int16 Op1CXBR; int16 Op1CYBR; int16 Op1CZBR; int16 Op1CXAR; int16 Op1CYAR; int16 Op1CZAR; int16 Op1CX1; int16 Op1CY1; int16 Op1CZ1; int16 Op1CX2; int16 Op1CY2; int16 Op1CZ2; uint16 Op0FRamsize; uint16 Op0FPass; int16 Op2FUnknown; int16 Op2FSize; int16 Op08X; int16 Op08Y; int16 Op08Z; int16 Op08Ll; int16 Op08Lh; int16 Op18X; int16 Op18Y; int16 Op18Z; int16 Op18R; int16 Op18D; int16 Op38X; int16 Op38Y; int16 Op38Z; int16 Op38R; int16 Op38D; }; struct SDSP2 { bool8 waiting4command; uint8 command; uint32 in_count; uint32 in_index; uint32 out_count; uint32 out_index; uint8 parameters[512]; uint8 output[512]; bool8 Op05HasLen; int32 Op05Len; uint8 Op05Transparent; bool8 Op06HasLen; int32 Op06Len; uint16 Op09Word1; uint16 Op09Word2; bool8 Op0DHasLen; int32 Op0DOutLen; int32 Op0DInLen; }; struct SDSP3 { uint16 DR; uint16 SR; uint16 MemoryIndex; int16 WinLo; int16 WinHi; int16 AddLo; int16 AddHi; uint16 Codewords; uint16 Outwords; uint16 Symbol; uint16 BitCount; uint16 Index; uint16 Codes[512]; uint16 BitsLeft; uint16 ReqBits; uint16 ReqData; uint16 BitCommand; uint8 BaseLength; uint16 BaseCodes; uint16 BaseCode; uint8 CodeLengths[8]; uint16 CodeOffsets[8]; uint16 LZCode; uint8 LZLength; uint16 X; uint16 Y; uint8 Bitmap[8]; uint8 Bitplane[8]; uint16 BMIndex; uint16 BPIndex; uint16 Count; int16 op3e_x; int16 op3e_y; int16 op1e_terrain[0x2000]; int16 op1e_cost[0x2000]; int16 op1e_weight[0x2000]; int16 op1e_cell; int16 op1e_turn; int16 op1e_search; int16 op1e_x; int16 op1e_y; int16 op1e_min_radius; int16 op1e_max_radius; int16 op1e_max_search_radius; int16 op1e_max_path_radius; int16 op1e_lcv_radius; int16 op1e_lcv_steps; int16 op1e_lcv_turns; }; struct SDSP4 { bool8 waiting4command; bool8 half_command; uint16 command; uint32 in_count; uint32 in_index; uint32 out_count; uint32 out_index; uint8 parameters[512]; uint8 output[512]; uint8 byte; uint16 address; // op control int8 Logic; // controls op flow // projection format int16 lcv; // loop-control variable int16 distance; // z-position into virtual world int16 raster; // current raster line int16 segments; // number of raster lines drawn // 1.15.16 or 1.15.0 [sign, integer, fraction] int32 world_x; // line of x-projection in world int32 world_y; // line of y-projection in world int32 world_dx; // projection line x-delta int32 world_dy; // projection line y-delta int16 world_ddx; // x-delta increment int16 world_ddy; // y-delta increment int32 world_xenv; // world x-shaping factor int16 world_yofs; // world y-vertical scroll int16 view_x1; // current viewer-x int16 view_y1; // current viewer-y int16 view_x2; // future viewer-x int16 view_y2; // future viewer-y int16 view_dx; // view x-delta factor int16 view_dy; // view y-delta factor int16 view_xofs1; // current viewer x-vertical scroll int16 view_yofs1; // current viewer y-vertical scroll int16 view_xofs2; // future viewer x-vertical scroll int16 view_yofs2; // future viewer y-vertical scroll int16 view_yofsenv; // y-scroll shaping factor int16 view_turnoff_x; // road turnoff data int16 view_turnoff_dx; // road turnoff delta factor // drawing area int16 viewport_cx; // x-center of viewport window int16 viewport_cy; // y-center of render window int16 viewport_left; // x-left of viewport int16 viewport_right; // x-right of viewport int16 viewport_top; // y-top of viewport int16 viewport_bottom; // y-bottom of viewport // sprite structure int16 sprite_x; // projected x-pos of sprite int16 sprite_y; // projected y-pos of sprite int16 sprite_attr; // obj attributes bool8 sprite_size; // sprite size: 8x8 or 16x16 int16 sprite_clipy; // visible line to clip pixels off int16 sprite_count; // generic projection variables designed for two solid polygons + two polygon sides int16 poly_clipLf[2][2]; // left clip boundary int16 poly_clipRt[2][2]; // right clip boundary int16 poly_ptr[2][2]; // HDMA structure pointers int16 poly_raster[2][2]; // current raster line below horizon int16 poly_top[2][2]; // top clip boundary int16 poly_bottom[2][2]; // bottom clip boundary int16 poly_cx[2][2]; // center for left/right points int16 poly_start[2]; // current projection points int16 poly_plane[2]; // previous z-plane distance // OAM int16 OAM_attr[16]; // OAM (size, MSB) data int16 OAM_index; // index into OAM table int16 OAM_bits; // offset into OAM table int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row) int16 OAM_Row[32]; // current number of tiles per row }; extern struct SDSP0 DSP0; extern struct SDSP1 DSP1; extern struct SDSP2 DSP2; extern struct SDSP3 DSP3; extern struct SDSP4 DSP4; uint8 S9xGetDSP (uint16); void S9xSetDSP (uint8, uint16); void S9xResetDSP (void); uint8 DSP1GetByte (uint16); void DSP1SetByte (uint8, uint16); uint8 DSP2GetByte (uint16); void DSP2SetByte (uint8, uint16); uint8 DSP3GetByte (uint16); void DSP3SetByte (uint8, uint16); uint8 DSP4GetByte (uint16); void DSP4SetByte (uint8, uint16); void DSP3_Reset (void); extern uint8 (*GetDSP) (uint16); extern void (*SetDSP) (uint8, uint16); #endif dsp2.cpp000664 001750 001750 00000034153 12720446475 013277 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include "snes9x.h" #include "memmap.h" static void DSP2_Op01 (void); static void DSP2_Op03 (void); static void DSP2_Op05 (void); static void DSP2_Op06 (void); static void DSP2_Op09 (void); static void DSP2_Op0D (void); // convert bitmap to bitplane tile static void DSP2_Op01 (void) { // Op01 size is always 32 bytes input and output // The hardware does strange things if you vary the size uint8 c0, c1, c2, c3; uint8 *p1 = DSP2.parameters; uint8 *p2a = DSP2.output; uint8 *p2b = DSP2.output + 16; // halfway // Process 8 blocks of 4 bytes each for (int j = 0; j < 8; j++) { c0 = *p1++; c1 = *p1++; c2 = *p1++; c3 = *p1++; *p2a++ = (c0 & 0x10) << 3 | (c0 & 0x01) << 6 | (c1 & 0x10) << 1 | (c1 & 0x01) << 4 | (c2 & 0x10) >> 1 | (c2 & 0x01) << 2 | (c3 & 0x10) >> 3 | (c3 & 0x01); *p2a++ = (c0 & 0x20) << 2 | (c0 & 0x02) << 5 | (c1 & 0x20) | (c1 & 0x02) << 3 | (c2 & 0x20) >> 2 | (c2 & 0x02) << 1 | (c3 & 0x20) >> 4 | (c3 & 0x02) >> 1; *p2b++ = (c0 & 0x40) << 1 | (c0 & 0x04) << 4 | (c1 & 0x40) >> 1 | (c1 & 0x04) << 2 | (c2 & 0x40) >> 3 | (c2 & 0x04) | (c3 & 0x40) >> 5 | (c3 & 0x04) >> 2; *p2b++ = (c0 & 0x80) | (c0 & 0x08) << 3 | (c1 & 0x80) >> 2 | (c1 & 0x08) << 1 | (c2 & 0x80) >> 4 | (c2 & 0x08) >> 1 | (c3 & 0x80) >> 6 | (c3 & 0x08) >> 3; } } // set transparent color static void DSP2_Op03 (void) { DSP2.Op05Transparent = DSP2.parameters[0]; } // replace bitmap using transparent color static void DSP2_Op05 (void) { // Overlay bitmap with transparency. // Input: // // Bitmap 1: i[0] <=> i[size-1] // Bitmap 2: i[size] <=> i[2*size-1] // // Output: // // Bitmap 3: o[0] <=> o[size-1] // // Processing: // // Process all 4-bit pixels (nibbles) in the bitmap // // if ( BM2_pixel == transparent_color ) // pixelout = BM1_pixel // else // pixelout = BM2_pixel // The max size bitmap is limited to 255 because the size parameter is a byte // I think size=0 is an error. The behavior of the chip on size=0 is to // return the last value written to DR if you read DR on Op05 with // size = 0. I don't think it's worth implementing this quirk unless it's // proven necessary. uint8 color; uint8 c1, c2; uint8 *p1 = DSP2.parameters; uint8 *p2 = DSP2.parameters + DSP2.Op05Len; uint8 *p3 = DSP2.output; color = DSP2.Op05Transparent & 0x0f; for (int32 n = 0; n < DSP2.Op05Len; n++) { c1 = *p1++; c2 = *p2++; *p3++ = (((c2 >> 4) == color) ? c1 & 0xf0: c2 & 0xf0) | (((c2 & 0x0f) == color) ? c1 & 0x0f: c2 & 0x0f); } } // reverse bitmap static void DSP2_Op06 (void) { // Input: // size // bitmap for (int32 i = 0, j = DSP2.Op06Len - 1; i < DSP2.Op06Len; i++, j--) DSP2.output[j] = (DSP2.parameters[i] << 4) | (DSP2.parameters[i] >> 4); } // multiply static void DSP2_Op09 (void) { DSP2.Op09Word1 = DSP2.parameters[0] | (DSP2.parameters[1] << 8); DSP2.Op09Word2 = DSP2.parameters[2] | (DSP2.parameters[3] << 8); uint32 temp = DSP2.Op09Word1 * DSP2.Op09Word2; DSP2.output[0] = temp & 0xFF; DSP2.output[1] = (temp >> 8) & 0xFF; DSP2.output[2] = (temp >> 16) & 0xFF; DSP2.output[3] = (temp >> 24) & 0xFF; } // scale bitmap static void DSP2_Op0D (void) { // Bit accurate hardware algorithm - uses fixed point math // This should match the DSP2 Op0D output exactly // I wouldn't recommend using this unless you're doing hardware debug. // In some situations it has small visual artifacts that // are not readily apparent on a TV screen but show up clearly // on a monitor. Use Overload's scaling instead. // This is for hardware verification testing. // // One note: the HW can do odd byte scaling but since we divide // by two to get the count of bytes this won't work well for // odd byte scaling (in any of the current algorithm implementations). // So far I haven't seen Dungeon Master use it. // If it does we can adjust the parameters and code to work with it uint32 multiplier; // Any size int >= 32-bits uint32 pixloc; // match size of multiplier uint8 pixelarray[512]; if (DSP2.Op0DInLen <= DSP2.Op0DOutLen) multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1 else multiplier = (DSP2.Op0DInLen << 17) / ((DSP2.Op0DOutLen << 1) + 1); pixloc = 0; for (int32 i = 0; i < DSP2.Op0DOutLen * 2; i++) { int32 j = pixloc >> 16; if (j & 1) pixelarray[i] = DSP2.parameters[j >> 1] & 0x0f; else pixelarray[i] = (DSP2.parameters[j >> 1] & 0xf0) >> 4; pixloc += multiplier; } for (int32 i = 0; i < DSP2.Op0DOutLen; i++) DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; } /* static void DSP2_Op0D (void) { // Overload's algorithm - use this unless doing hardware testing // One note: the HW can do odd byte scaling but since we divide // by two to get the count of bytes this won't work well for // odd byte scaling (in any of the current algorithm implementations). // So far I haven't seen Dungeon Master use it. // If it does we can adjust the parameters and code to work with it int32 pixel_offset; uint8 pixelarray[512]; for (int32 i = 0; i < DSP2.Op0DOutLen * 2; i++) { pixel_offset = (i * DSP2.Op0DInLen) / DSP2.Op0DOutLen; if ((pixel_offset & 1) == 0) pixelarray[i] = DSP2.parameters[pixel_offset >> 1] >> 4; else pixelarray[i] = DSP2.parameters[pixel_offset >> 1] & 0x0f; } for (int32 i = 0; i < DSP2.Op0DOutLen; i++) DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; } */ void DSP2SetByte (uint8 byte, uint16 address) { if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) { if (DSP2.waiting4command) { DSP2.command = byte; DSP2.in_index = 0; DSP2.waiting4command = FALSE; switch (byte) { case 0x01: DSP2.in_count = 32; break; case 0x03: DSP2.in_count = 1; break; case 0x05: DSP2.in_count = 1; break; case 0x06: DSP2.in_count = 1; break; case 0x09: DSP2.in_count = 4; break; case 0x0D: DSP2.in_count = 2; break; default: #ifdef DEBUGGER //printf("Op%02X\n", byte); #endif case 0x0f: DSP2.in_count = 0; break; } } else { DSP2.parameters[DSP2.in_index] = byte; DSP2.in_index++; } if (DSP2.in_count == DSP2.in_index) { DSP2.waiting4command = TRUE; DSP2.out_index = 0; switch (DSP2.command) { case 0x01: DSP2.out_count = 32; DSP2_Op01(); break; case 0x03: DSP2_Op03(); break; case 0x05: if (DSP2.Op05HasLen) { DSP2.Op05HasLen = FALSE; DSP2.out_count = DSP2.Op05Len; DSP2_Op05(); } else { DSP2.Op05Len = DSP2.parameters[0]; DSP2.in_index = 0; DSP2.in_count = 2 * DSP2.Op05Len; DSP2.Op05HasLen = TRUE; if (byte) DSP2.waiting4command = FALSE; } break; case 0x06: if (DSP2.Op06HasLen) { DSP2.Op06HasLen = FALSE; DSP2.out_count = DSP2.Op06Len; DSP2_Op06(); } else { DSP2.Op06Len = DSP2.parameters[0]; DSP2.in_index = 0; DSP2.in_count = DSP2.Op06Len; DSP2.Op06HasLen = TRUE; if (byte) DSP2.waiting4command = FALSE; } break; case 0x09: DSP2.out_count = 4; DSP2_Op09(); break; case 0x0D: if (DSP2.Op0DHasLen) { DSP2.Op0DHasLen = FALSE; DSP2.out_count = DSP2.Op0DOutLen; DSP2_Op0D(); } else { DSP2.Op0DInLen = DSP2.parameters[0]; DSP2.Op0DOutLen = DSP2.parameters[1]; DSP2.in_index = 0; DSP2.in_count = (DSP2.Op0DInLen + 1) >> 1; DSP2.Op0DHasLen = TRUE; if (byte) DSP2.waiting4command = FALSE; } break; case 0x0f: default: break; } } } } uint8 DSP2GetByte (uint16 address) { uint8 t; if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) { if (DSP2.out_count) { t = (uint8) DSP2.output[DSP2.out_index]; DSP2.out_index++; if (DSP2.out_count == DSP2.out_index) DSP2.out_count = 0; } else t = 0xff; } else t = 0x80; return (t); } apu/bapu/smp/smp.hpp000664 001750 001750 00000006321 12720446475 015542 0ustar00sergiosergio000000 000000 class SMP : public Processor { public: static const uint8 iplrom[64]; uint8 *apuram; enum { Threaded = false }; alwaysinline void synchronize_cpu(); alwaysinline void synchronize_dsp(); unsigned port_read(unsigned port); void port_write(unsigned port, unsigned data); unsigned mmio_read(unsigned addr); void mmio_write(unsigned addr, unsigned data); void enter(); void power(); void reset(); #ifndef SNES9X void serialize(serializer&); #else void load_state(uint8 **); void save_state(uint8 **); void save_spc (uint8 *); #endif SMP(); ~SMP(); //private: struct Flags { bool n, v, p, b, h, i, z, c; alwaysinline operator unsigned() const { return (n << 7) | (v << 6) | (p << 5) | (b << 4) | (h << 3) | (i << 2) | (z << 1) | (c << 0); }; alwaysinline unsigned operator=(unsigned data) { n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; return data; } alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } }; unsigned opcode_number; unsigned opcode_cycle; uint16 rd, wr, dp, sp, ya, bit; struct Regs { uint16 pc; uint8 sp; union { uint16 ya; #ifndef __BIG_ENDIAN__ struct { uint8 a, y; } B; #else struct { uint8 y, a; } B; #endif }; uint8 x; Flags p; } regs; struct Status { //$00f1 bool iplrom_enable; //$00f2 unsigned dsp_addr; //$00f8,$00f9 unsigned ram00f8; unsigned ram00f9; } status; template struct Timer { bool enable; uint8 target; uint8 stage1_ticks; uint8 stage2_ticks; uint8 stage3_ticks; inline void tick(); inline void tick(unsigned clocks); }; Timer<128> timer0; Timer<128> timer1; Timer< 16> timer2; inline void tick(); inline void tick(unsigned clocks); alwaysinline void op_io(); alwaysinline void op_io(unsigned clocks); debugvirtual alwaysinline uint8 op_read(uint16 addr); debugvirtual alwaysinline void op_write(uint16 addr, uint8 data); debugvirtual alwaysinline void op_step(); static const unsigned cycle_count_table[256]; uint64 cycle_table_cpu[256]; unsigned cycle_table_dsp[256]; uint64 cycle_step_cpu; inline uint8 op_adc (uint8 x, uint8 y); inline uint16 op_addw(uint16 x, uint16 y); inline uint8 op_and (uint8 x, uint8 y); inline uint8 op_cmp (uint8 x, uint8 y); inline uint16 op_cmpw(uint16 x, uint16 y); inline uint8 op_eor (uint8 x, uint8 y); inline uint8 op_inc (uint8 x); inline uint8 op_dec (uint8 x); inline uint8 op_or (uint8 x, uint8 y); inline uint8 op_sbc (uint8 x, uint8 y); inline uint16 op_subw(uint16 x, uint16 y); inline uint8 op_asl (uint8 x); inline uint8 op_lsr (uint8 x); inline uint8 op_rol (uint8 x); inline uint8 op_ror (uint8 x); }; #if defined(DEBUGGER) #include "debugger/debugger.hpp" extern SMPDebugger smp; #else extern SMP smp; #endif language.h000664 001750 001750 00000016032 12720446475 013653 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _LANGUAGE_H_ #define _LANGUAGE_H_ // Movie Messages #define MOVIE_ERR_SNAPSHOT_WRONG_MOVIE "Snapshot not from this movie" #define MOVIE_ERR_SNAPSHOT_NOT_MOVIE "Not a movie snapshot" #define MOVIE_INFO_REPLAY "Movie replay" #define MOVIE_INFO_RECORD "Movie record" #define MOVIE_INFO_RERECORD "Movie re-record" #define MOVIE_INFO_REWIND "Movie rewind" #define MOVIE_INFO_STOP "Movie stop" #define MOVIE_INFO_END "Movie end" #define MOVIE_INFO_SNAPSHOT "Movie snapshot" #define MOVIE_ERR_SNAPSHOT_INCONSISTENT "Snapshot inconsistent with movie" // Snapshot Messages #define SAVE_INFO_SNAPSHOT "Saved" #define SAVE_INFO_LOAD "Loaded" #define SAVE_INFO_OOPS "Auto-saving 'oops' snapshot" #define SAVE_ERR_WRONG_FORMAT "File not in Snes9x snapshot format" #define SAVE_ERR_WRONG_VERSION "Incompatable snapshot version" #define SAVE_ERR_ROM_NOT_FOUND "ROM image \"%s\" for snapshot not found" #define SAVE_ERR_SAVE_NOT_FOUND "Snapshot %s does not exist" #endif apu/bapu/smp/core/generate.cpp000664 001750 001750 00000010136 12720446475 017457 0ustar00sergiosergio000000 000000 #include #include #include using namespace nall; static bool cycle_accurate; struct opcode_t { string name; lstring args; unsigned opcode; }; void generate(const char *sourceFilename, const char *targetFilename) { file fp; fp.open(targetFilename, file::mode::write); string filedata; filedata.readfile(sourceFilename); filedata.replace("\r", ""); lstring block; block.split("\n\n", filedata); foreach(data, block) { lstring lines; lines.split("\n", data); linear_vector array; unsigned sourceStart = 0; foreach(line, lines, currentLine) { line.transform("()", "``"); lstring part; part.split("`", line); lstring arguments; arguments.split(", ", part[1]); opcode_t opcode; opcode.name = part[0]; opcode.args = arguments; opcode.opcode = hex(arguments[0]); array.append(opcode); line.rtrim<1>(","); if(line.endswith(" {")) { line.rtrim<1>("{ "); sourceStart = currentLine + 1; break; } } if(cycle_accurate == false) { foreach(opcode, array) { fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); for(unsigned n = sourceStart; n < lines.size(); n++) { if(lines[n] == "}") break; string output; if(lines[n].beginswith(" ")) { output = lines[n]; } else { lstring part; part.split<1>(":", lines[n]); output = { " ", part[1] }; } output.replace("$1", opcode.args[1]); output.replace("$2", opcode.args[2]); output.replace("$3", opcode.args[3]); output.replace("$4", opcode.args[4]); output.replace("$5", opcode.args[5]); output.replace("$6", opcode.args[6]); output.replace("$7", opcode.args[7]); output.replace("$8", opcode.args[8]); output.replace("end;", "break;"); fp.print(output, "\n"); } fp.print(" break;\n"); fp.print("}\n\n"); } } else { foreach(opcode, array) { fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); fp.print(" switch(opcode_cycle++) {\n"); for(unsigned n = sourceStart; n < lines.size(); n++) { if(lines[n] == "}") break; bool nextLineEndsCycle = false; if(lines[n + 1] == "}") nextLineEndsCycle = true; if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true; string output; if(lines[n].beginswith(" ")) { output = { " ", lines[n] }; } else { lstring part; part.split<1>(":", lines[n]); fp.print(" case ", (unsigned)decimal(part[0]), ":\n"); output = { " ", part[1] }; } output.replace("$1", opcode.args[1]); output.replace("$2", opcode.args[2]); output.replace("$3", opcode.args[3]); output.replace("$4", opcode.args[4]); output.replace("$5", opcode.args[5]); output.replace("$6", opcode.args[6]); output.replace("$7", opcode.args[7]); output.replace("$8", opcode.args[8]); output.replace("end;", "{ opcode_cycle = 0; break; }"); fp.print(output, "\n"); if(nextLineEndsCycle) { if(lines[n + 1].beginswith("}")) { fp.print(" opcode_cycle = 0;\n"); } fp.print(" break;\n"); } } fp.print(" }\n"); fp.print(" break;\n"); fp.print("}\n\n"); } } } fp.close(); } int main() { cycle_accurate = false; generate("op_misc.b", "op_misc.cpp"); generate("op_mov.b", "op_mov.cpp" ); generate("op_pc.b", "op_pc.cpp" ); generate("op_read.b", "op_read.cpp"); generate("op_rmw.b", "op_rmw.cpp" ); cycle_accurate = true; generate("op_misc.b", "opcycle_misc.cpp"); generate("op_mov.b", "opcycle_mov.cpp" ); generate("op_pc.b", "opcycle_pc.cpp" ); generate("op_read.b", "opcycle_read.cpp"); generate("op_rmw.b", "opcycle_rmw.cpp" ); return 0; } docs/lgpl-2.1.txt000664 001750 001750 00000063502 12720446475 014650 0ustar00sergiosergio000000 000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! apu/bapu/smp/core/opcycle_mov.cpp000664 001750 001750 00000026775 12720446475 020224 0ustar00sergiosergio000000 000000 case 0x7d: { switch(opcode_cycle++) { case 1: op_io(); regs.a = regs.x; regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xdd: { switch(opcode_cycle++) { case 1: op_io(); regs.a = regs.y; regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0x5d: { switch(opcode_cycle++) { case 1: op_io(); regs.x = regs.a; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xfd: { switch(opcode_cycle++) { case 1: op_io(); regs.y = regs.a; regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0x9d: { switch(opcode_cycle++) { case 1: op_io(); regs.x = regs.sp; regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xbd: { switch(opcode_cycle++) { case 1: op_io(); regs.sp = regs.x; opcode_cycle = 0; break; } break; } case 0xe8: { switch(opcode_cycle++) { case 1: regs.a = op_readpc(); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xcd: { switch(opcode_cycle++) { case 1: regs.x = op_readpc(); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0x8d: { switch(opcode_cycle++) { case 1: regs.y = op_readpc(); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0xe6: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: regs.a = op_readdp(regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xbf: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: regs.a = op_readdp(regs.x++); break; case 3: op_io(); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xe4: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: regs.a = op_readdp(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xf8: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: regs.x = op_readdp(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xeb: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: regs.y = op_readdp(sp); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0xf4: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: op_io(); break; case 3: regs.a = op_readdp(sp + regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xf9: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: op_io(); break; case 3: regs.x = op_readdp(sp + regs.y); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xfb: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: op_io(); break; case 3: regs.y = op_readdp(sp + regs.x); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0xe5: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: regs.a = op_readaddr(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xe9: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: regs.x = op_readaddr(sp); regs.p.n = !!(regs.x & 0x80); regs.p.z = (regs.x == 0); opcode_cycle = 0; break; } break; } case 0xec: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: regs.y = op_readaddr(sp); regs.p.n = !!(regs.y & 0x80); regs.p.z = (regs.y == 0); opcode_cycle = 0; break; } break; } case 0xf5: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: regs.a = op_readaddr(sp + regs.x); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xf6: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: op_io(); break; case 4: regs.a = op_readaddr(sp + regs.y); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xe7: { switch(opcode_cycle++) { case 1: dp = op_readpc() + regs.x; break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: regs.a = op_readaddr(sp); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xf7: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); break; case 3: sp = op_readdp(dp); break; case 4: sp |= op_readdp(dp + 1) << 8; break; case 5: regs.a = op_readaddr(sp + regs.y); regs.p.n = !!(regs.a & 0x80); regs.p.z = (regs.a == 0); opcode_cycle = 0; break; } break; } case 0xfa: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: rd = op_readdp(sp); break; case 3: dp = op_readpc(); break; case 4: op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0x8f: { switch(opcode_cycle++) { case 1: rd = op_readpc(); break; case 2: dp = op_readpc(); break; case 3: op_readdp(dp); break; case 4: op_writedp(dp, rd); opcode_cycle = 0; break; } break; } case 0xc6: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_readdp(regs.x); break; case 3: op_writedp(regs.x, regs.a); opcode_cycle = 0; break; } break; } case 0xaf: { switch(opcode_cycle++) { case 1: op_io(); break; case 2: op_io(); break; case 3: op_writedp(regs.x++, regs.a); opcode_cycle = 0; break; } break; } case 0xc4: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xd8: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xcb: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.y); opcode_cycle = 0; break; } break; } case 0xd4: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); dp += regs.x; break; case 3: op_readdp(dp); break; case 4: op_writedp(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xd9: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); dp += regs.y; break; case 3: op_readdp(dp); break; case 4: op_writedp(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xdb: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_io(); dp += regs.x; break; case 3: op_readdp(dp); break; case 4: op_writedp(dp, regs.y); opcode_cycle = 0; break; } break; } case 0xc5: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xc9: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.x); opcode_cycle = 0; break; } break; } case 0xcc: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_readaddr(dp); break; case 4: op_writeaddr(dp, regs.y); opcode_cycle = 0; break; } break; } case 0xd5: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); dp += regs.x; break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xd6: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: op_io(); dp += regs.y; break; case 4: op_readaddr(dp); break; case 5: op_writeaddr(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xc7: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: op_io(); sp += regs.x; break; case 3: dp = op_readdp(sp); break; case 4: dp |= op_readdp(sp + 1) << 8; break; case 5: op_readaddr(dp); break; case 6: op_writeaddr(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xd7: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: dp = op_readdp(sp); break; case 3: dp |= op_readdp(sp + 1) << 8; break; case 4: op_io(); dp += regs.y; break; case 5: op_readaddr(dp); break; case 6: op_writeaddr(dp, regs.a); opcode_cycle = 0; break; } break; } case 0xba: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: regs.a = op_readdp(sp); break; case 3: op_io(); break; case 4: regs.y = op_readdp(sp + 1); regs.p.n = !!(regs.ya & 0x8000); regs.p.z = (regs.ya == 0); opcode_cycle = 0; break; } break; } case 0xda: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: op_readdp(dp); break; case 3: op_writedp(dp, regs.a); break; case 4: op_writedp(dp + 1, regs.y); opcode_cycle = 0; break; } break; } case 0xaa: { switch(opcode_cycle++) { case 1: sp = op_readpc(); break; case 2: sp |= op_readpc() << 8; break; case 3: bit = sp >> 13; sp &= 0x1fff; rd = op_readaddr(sp); regs.p.c = !!(rd & (1 << bit)); opcode_cycle = 0; break; } break; } case 0xca: { switch(opcode_cycle++) { case 1: dp = op_readpc(); break; case 2: dp |= op_readpc() << 8; break; case 3: bit = dp >> 13; dp &= 0x1fff; rd = op_readaddr(dp); if(regs.p.c)rd |= (1 << bit); else rd &= ~(1 << bit); break; case 4: op_io(); break; case 5: op_writeaddr(dp, rd); opcode_cycle = 0; break; } break; } apu/bapu/smp/core/cc.sh000755 001750 001750 00000000074 12720446475 016103 0ustar00sergiosergio000000 000000 g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp docs/controls.txt000664 001750 001750 00000007406 12720446475 015260 0ustar00sergiosergio000000 000000 This lists the available commands, excluding the ones you get back from S9xGetAllSnes9xCommands(). The various meta-characters are: # - A number. The range is determined by the context ## - A two-digit number (i.e. with leading zeros) [...] - Something optional (...) - For grouping with | | - "or", choose one of the options. <...> - A named field {...} - A list of possible values. Multiple values may be used, but they must be in the order listed and joined with +-signs. "" - 'ditto', used to indicate the same list as the above line. Speeds are: Var, Slow, Med, and Fast. 'Var' starts slow and speeds up as the button is held. Axes are: Left/Right, Right/Left, Up/Down, Down/Up, Y/A, A/Y, X/B, B/X, L/R, and R/L. Negative is listed first (i.e. "Y/A" means negative deflection is towards Y, while "A/Y" means negative deflection is towards A). AxisToPointer, ButtonToPointer, and AxisToButtons allow for translating between different input types. There are 8 'pointers' with IDs PseudoPointerBase+0 to PseudoPointerBase+7, and 256 'buttons' with IDs PseudoButtonBase+0 to PseudoButtonBase+255. So for example, "AxisToButtons 0/255 T=50%" would take the axis data, and do S9xReportButton(PseudoButtonBase+0,1) when said axis goes past 50% in the negative direction and S9xReportButton(PseudoButtonBase+255,1) when it goes over 50% deflection in the positive direction. Similarly, it will do S9xReportButton(...,0) when the deflection drops under 50% in either direction. "ButtonToPointer 1u Slow" would move the pointer with ID PseudoPointerBase+0 up one pixel per frame as long as the button is pressed (reporting this change at the end of each frame). --------------- Button Commands --------------- Joypad# {Up, Down, Left, Right, A, B, X, Y, L, R, Start, Select} Joypad# Turbo "" Joypad# Sticky "" Joypad# StickyTurbo "" Joypad# ToggleTurbo "" Joypad# ToggleSticky "" Joypad# ToggleStickyTurbo "" Mouse# (L|R|LR) Superscope AimOffscreen Superscope {Fire, Cursor, ToggleTurbo, Pause} Superscope AimOffscreen "" Justifier# AimOffscreen Justifier# {Trigger, Start} Justifier# AimOffscreen "" ButtonToPointer #[u|d][l|r] ; NOTE: "# " is invalid ------------- Axis Commands ------------- Joypad# Axis T=#% ; T = 0.1 to 100 by tenths AxisToButtons #/# T=#% ; neg then pos, range 0-255, T as above AxisToPointer #(h|v) [-] ; NOTE: '-' inverts the axis ---------------- Pointer Commands ---------------- Pointer {Mouse1, Mouse2, Superscope, Justifier1, Justifier2} ------ Multis ------ Multis are a type of button command. The basic format of a multi is "{...}", where the '...' consists of 1 or more valid non-multi button command strings. The braces are literal, not metacharacters. Subcommands separated by commas are executed one after the next. Semicolons skip one frame before continuing subcommand execution. Semicolons may be repeated. When the multi button is pressed, each subcommand is 'pressed', and when the multi button is released each subcommand is 'released'. There are also press-only multis, defined as "+{...}". These act just like regular multis, with two differences: the multi is only run when you press the button (release is ignored), and each subcommand must be prefixed with '+' or '-' to indicate whether the the subcommand should be pressed or released. For example: {Joypad1 A,Joypad2 A;Joypad3 A;;;;;QuickSave000} This presses (or releases) A on pads 1 and 2, then waits one frame, then presses A on pad 3, then waits 5 frames, then saves to snapshot 0 (on press only). You may access the multi number in the returned s9xcommand_t structure as cmd.button.multi_idx. This may be used to assign the same multi to multiple buttons: MULTI# ; NOTE: that's a literal octothorpe cheats.h000664 001750 001750 00000017602 12720446475 013343 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #ifndef _CHEATS_H_ #define _CHEATS_H_ #define MAX_CHEATS 150 struct SCheat { uint32 address; uint8 byte; uint8 saved_byte; bool8 enabled; bool8 saved; char name[22]; }; struct SCheatData { struct SCheat c[MAX_CHEATS]; uint32 num_cheats; uint8 CWRAM[0x20000]; uint8 CSRAM[0x10000]; uint8 CIRAM[0x2000]; uint8 *RAM; uint8 *FillRAM; uint8 *SRAM; uint32 ALL_BITS[0x32000 >> 5]; uint8 CWatchRAM[0x32000]; }; struct Watch { bool on; int size; int format; uint32 address; char buf[12]; char desc[32]; }; typedef enum { S9X_LESS_THAN, S9X_GREATER_THAN, S9X_LESS_THAN_OR_EQUAL, S9X_GREATER_THAN_OR_EQUAL, S9X_EQUAL, S9X_NOT_EQUAL } S9xCheatComparisonType; typedef enum { S9X_8_BITS, S9X_16_BITS, S9X_24_BITS, S9X_32_BITS } S9xCheatDataSize; extern SCheatData Cheat; extern Watch watches[16]; void S9xApplyCheat (uint32); void S9xApplyCheats (void); void S9xRemoveCheat (uint32); void S9xRemoveCheats (void); void S9xDeleteCheat (uint32); void S9xDeleteCheats (void); void S9xEnableCheat (uint32); void S9xDisableCheat (uint32); void S9xAddCheat (bool8, bool8, uint32, uint8); void S9xInitCheatData (void); void S9xInitWatchedAddress (void); bool8 S9xLoadCheatFile (const char *); bool8 S9xSaveCheatFile (const char *); void S9xStartCheatSearch (SCheatData *); void S9xSearchForChange (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, bool8, bool8); void S9xSearchForValue (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8, bool8); void S9xSearchForAddress (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8); void S9xOutputCheatSearchResults (SCheatData *); const char * S9xGameGenieToRaw (const char *, uint32 &, uint8 &); const char * S9xProActionReplayToRaw (const char *, uint32 &, uint8 &); const char * S9xGoldFingerToRaw (const char *, uint32 &, bool8 &, uint8 &, uint8 bytes[3]); #endif libretro/link.T000664 001750 001750 00000000046 12720446475 014621 0ustar00sergiosergio000000 000000 { global: retro_*; local: *; }; snes9x.cpp000664 001750 001750 00000073176 12720446475 013670 0ustar00sergiosergio000000 000000 /*********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), Jerremy Koot (jkoot@snes9x.com) (c) Copyright 2002 - 2004 Matthew Kendora (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), Kris Bleakley (codeviolation@hotmail.com) (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja (c) Copyright 2009 - 2011 BearOso, OV2 BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, zones C4 x86 assembler and some C emulation code (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), Nach, zsKnight (zsknight@zsnes.com) C4 C++ code (c) Copyright 2003 - 2006 Brad Jorsch, Nach DSP-1 emulator code (c) Copyright 1998 - 2006 _Demo_, Andreas Naive (andreasnaive@gmail.com), Gary Henderson, Ivar (ivar@snes9x.com), John Weidman, Kris Bleakley, Matthew Kendora, Nach, neviksti (neviksti@hotmail.com) DSP-2 emulator code (c) Copyright 2003 John Weidman, Kris Bleakley, Lord Nightmare (lord_nightmare@users.sourceforge.net), Matthew Kendora, neviksti DSP-3 emulator code (c) Copyright 2003 - 2006 John Weidman, Kris Bleakley, Lancer, z80 gaiden DSP-4 emulator code (c) Copyright 2004 - 2006 Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden OBC1 emulator code (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com), Kris Bleakley Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code used in 1.39-1.51 (c) Copyright 2002 Matthew Kendora with research by zsKnight, John Weidman, Dark Force SPC7110 and RTC C++ emulator code used in 1.52+ (c) Copyright 2009 byuu, neviksti S-DD1 C emulator code (c) Copyright 2003 Brad Jorsch with research by Andreas Naive, John Weidman S-RTC C emulator code (c) Copyright 2001 - 2006 byuu, John Weidman ST010 C++ emulator code (c) Copyright 2003 Feather, John Weidman, Kris Bleakley, Matthew Kendora Super FX x86 assembler emulator code (c) Copyright 1998 - 2003 _Demo_, pagefault, zsKnight Super FX C emulator code (c) Copyright 1997 - 1999 Ivar, Gary Henderson, John Weidman Sound emulator code used in 1.5-1.51 (c) Copyright 1998 - 2003 Brad Martin (c) Copyright 1998 - 2006 Charles Bilyue' Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 2xSaI filter (c) Copyright 1999 - 2001 Derek Liauw Kie Fa HQ2x, HQ3x, HQ4x filters (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) NTSC filter (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code (c) Copyright 2004 - 2011 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, funkyass, Matthew Kendora, Nach, nitsuja (c) Copyright 2009 - 2011 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones Specific ports contains the works of other authors. See headers in individual files. Snes9x homepage: http://www.snes9x.com/ Permission to use, copy, modify and/or distribute Snes9x in both binary and source form, for non-commercial purposes, is hereby granted without fee, providing that this license information and copyright notice appear with all copies and any derived work. This software is provided 'as-is', without any express or implied warranty. In no event shall the authors be held liable for any damages arising from the use of this software or it's derivatives. Snes9x is freeware for PERSONAL USE only. Commercial users should seek permission of the copyright holders first. Commercial use includes, but is not limited to, charging money for Snes9x or software derived from Snes9x, including Snes9x or derivatives in commercial game bundles, and/or using Snes9x as a promotion for your commercial product. The copyright holders request that bug fixes and improvements to the code should be forwarded to them so everyone can benefit from the modifications in future versions. Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ #include #include #ifdef HAVE_STRINGS_H #include #endif #include "snes9x.h" #include "memmap.h" #include "controls.h" #include "crosshairs.h" #include "cheats.h" #include "display.h" #include "conffile.h" #ifdef NETPLAY_SUPPORT #include "netplay.h" #endif #ifdef DEBUGGER #include "debug.h" extern FILE *trace; #endif #define S9X_CONF_FILE_NAME "snes9x.conf" static char *rom_filename = NULL; static bool parse_controller_spec (int, const char *); static void parse_crosshair_spec (enum crosscontrols, const char *); static bool try_load_config_file (const char *, ConfigFile &); static bool parse_controller_spec (int port, const char *arg) { if (!strcasecmp(arg, "none")) S9xSetController(port, CTL_NONE, 0, 0, 0, 0); else if (!strncasecmp(arg, "pad", 3) && arg[3] >= '1' && arg[3] <= '8' && arg[4] == '\0') S9xSetController(port, CTL_JOYPAD, arg[3] - '1', 0, 0, 0); else if (!strncasecmp(arg, "mouse", 5) && arg[5] >= '1' && arg[5] <= '2' && arg[6] == '\0') S9xSetController(port, CTL_MOUSE, arg[5] - '1', 0, 0, 0); else if (!strcasecmp(arg, "superscope")) S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); else if (!strcasecmp(arg, "justifier")) S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); else if (!strcasecmp(arg, "two-justifiers")) S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0); else if (!strncasecmp(arg, "mp5:", 4) && ((arg[4] >= '1' && arg[4] <= '8') || arg[4] == 'n') && ((arg[5] >= '1' && arg[5] <= '8') || arg[5] == 'n') && ((arg[6] >= '1' && arg[6] <= '8') || arg[6] == 'n') && ((arg[7] >= '1' && arg[7] <= '8') || arg[7] == 'n') && arg[8] == '\0') S9xSetController(port, CTL_MP5, (arg[4] == 'n') ? -1 : arg[4] - '1', (arg[5] == 'n') ? -1 : arg[5] - '1', (arg[6] == 'n') ? -1 : arg[6] - '1', (arg[7] == 'n') ? -1 : arg[7] - '1'); else return (false); return (true); } static void parse_crosshair_spec (enum crosscontrols ctl, const char *spec) { int idx = -1, i; const char *fg = NULL, *bg = NULL, *s = spec; if (s[0] == '"') { s++; for (i = 0; s[i] != '\0'; i++) if (s[i] == '"' && s[i - 1] != '\\') break; idx = 31 - ctl; std::string fname(s, i); if (!S9xLoadCrosshairFile(idx, fname.c_str())) return; s += i + 1; } else { if (isdigit(*s)) { idx = *s - '0'; s++; } if (isdigit(*s)) { idx = idx * 10 + *s - '0'; s++; } if (idx > 31) { fprintf(stderr, "Invalid crosshair spec '%s'.\n", spec); return; } } while (*s != '\0' && isspace(*s)) s++; if (*s != '\0') { fg = s; while (isalnum(*s)) s++; if (*s != '/' || !isalnum(s[1])) { fprintf(stderr, "Invalid crosshair spec '%s.'\n", spec); return; } bg = ++s; while (isalnum(*s)) s++; if (*s != '\0') { fprintf(stderr, "Invalid crosshair spec '%s'.\n", spec); return; } } S9xSetControllerCrosshair(ctl, idx, fg, bg); } static bool try_load_config_file (const char *fname, ConfigFile &conf) { FSTREAM fp; fp = OPEN_FSTREAM(fname, "r"); if (fp) { fprintf(stdout, "Reading config file %s.\n", fname); conf.LoadFile(new fStream(fp)); CLOSE_FSTREAM(fp); return (true); } return (false); } void S9xLoadConfigFiles (char **argv, int argc) { static ConfigFile conf; // static because some of its functions return pointers conf.Clear(); bool skip = false; for (int i = 0; i < argc; i++) { if (!strcasecmp(argv[i], "-nostdconf")) { skip = true; break; } } if (!skip) { #ifdef SYS_CONFIG_FILE try_load_config_file(SYS_CONFIG_FILE, conf); S9xParsePortConfig(conf, 0); #endif std::string fname; fname = S9xGetDirectory(DEFAULT_DIR); fname += SLASH_STR S9X_CONF_FILE_NAME; try_load_config_file(fname.c_str(), conf); } else fprintf(stderr, "Skipping standard config files.\n"); for (int i = 0; i < argc - 1; i++) if (!strcasecmp(argv[i], "-conf")) try_load_config_file(argv[++i], conf); // Parse config file here // ROM Settings.ForceInterleaved2 = conf.GetBool("ROM::Interleaved2", false); Settings.ForceInterleaveGD24 = conf.GetBool("ROM::InterleaveGD24", false); Settings.ApplyCheats = conf.GetBool("ROM::Cheat", false); Settings.NoPatch = !conf.GetBool("ROM::Patch", true); Settings.ForceLoROM = conf.GetBool("ROM::LoROM", false); Settings.ForceHiROM = conf.GetBool("ROM::HiROM", false); if (Settings.ForceLoROM) Settings.ForceHiROM = false; Settings.SuperFXSpeedPerLine = 0.417 * 10.5e6; Settings.ForcePAL = conf.GetBool("ROM::PAL", false); Settings.ForceNTSC = conf.GetBool("ROM::NTSC", false); if (Settings.ForcePAL) Settings.ForceNTSC = false; if (conf.Exists("ROM::Header")) { Settings.ForceHeader = conf.GetBool("ROM::Header", false); Settings.ForceNoHeader = !Settings.ForceHeader; } if (conf.Exists("ROM::Interleaved")) { Settings.ForceInterleaved = conf.GetBool("ROM::Interleaved", false); Settings.ForceNotInterleaved = !Settings.ForceInterleaved; } rom_filename = conf.GetStringDup("ROM::Filename", NULL); // Sound Settings.SoundSync = conf.GetBool("Sound::Sync", true); Settings.SixteenBitSound = conf.GetBool("Sound::16BitSound", true); Settings.Stereo = conf.GetBool("Sound::Stereo", true); Settings.ReverseStereo = conf.GetBool("Sound::ReverseStereo", false); Settings.SoundPlaybackRate = conf.GetUInt("Sound::Rate", 32000); Settings.SoundInputRate = conf.GetUInt("Sound::InputRate", 32000); Settings.Mute = conf.GetBool("Sound::Mute", false); // Display Settings.SupportHiRes = conf.GetBool("Display::HiRes", true); Settings.Transparency = conf.GetBool("Display::Transparency", true); Settings.DisableGraphicWindows = !conf.GetBool("Display::GraphicWindows", true); Settings.DisplayFrameRate = conf.GetBool("Display::DisplayFrameRate", false); Settings.DisplayWatchedAddresses = conf.GetBool("Display::DisplayWatchedAddresses", false); Settings.DisplayPressedKeys = conf.GetBool("Display::DisplayInput", false); Settings.DisplayMovieFrame = conf.GetBool("Display::DisplayFrameCount", false); Settings.AutoDisplayMessages = conf.GetBool("Display::MessagesInImage", true); Settings.InitialInfoStringTimeout = conf.GetInt ("Display::MessageDisplayTime", 120); // Settings Settings.BSXBootup = conf.GetBool("Settings::BSXBootup", false); Settings.TurboMode = conf.GetBool("Settings::TurboMode", false); Settings.TurboSkipFrames = conf.GetUInt("Settings::TurboFrameSkip", 15); Settings.MovieTruncate = conf.GetBool("Settings::MovieTruncateAtEnd", false); Settings.MovieNotifyIgnored = conf.GetBool("Settings::MovieNotifyIgnored", false); Settings.WrongMovieStateProtection = conf.GetBool("Settings::WrongMovieStateProtection", true); Settings.StretchScreenshots = conf.GetInt ("Settings::StretchScreenshots", 1); Settings.SnapshotScreenshots = conf.GetBool("Settings::SnapshotScreenshots", true); Settings.DontSaveOopsSnapshot = conf.GetBool("Settings::DontSaveOopsSnapshot", false); Settings.AutoSaveDelay = conf.GetUInt("Settings::AutoSaveDelay", 0); if (conf.Exists("Settings::FrameTime")) Settings.FrameTimePAL = Settings.FrameTimeNTSC = conf.GetUInt("Settings::FrameTime", 16667); if (!strcasecmp(conf.GetString("Settings::FrameSkip", "Auto"), "Auto")) Settings.SkipFrames = AUTO_FRAMERATE; else Settings.SkipFrames = conf.GetUInt("Settings::FrameSkip", 0) + 1; // Controls Settings.MouseMaster = conf.GetBool("Controls::MouseMaster", true); Settings.SuperScopeMaster = conf.GetBool("Controls::SuperscopeMaster", true); Settings.JustifierMaster = conf.GetBool("Controls::JustifierMaster", true); Settings.MultiPlayer5Master = conf.GetBool("Controls::MP5Master", true); Settings.UpAndDown = conf.GetBool("Controls::AllowLeftRight", false); if (conf.Exists("Controls::Port1")) parse_controller_spec(0, conf.GetString("Controls::Port1")); if (conf.Exists("Controls::Port2")) parse_controller_spec(1, conf.GetString("Controls::Port2")); if (conf.Exists("Controls::Mouse1Crosshair")) parse_crosshair_spec(X_MOUSE1, conf.GetString("Controls::Mouse1Crosshair")); if (conf.Exists("Controls::Mouse2Crosshair")) parse_crosshair_spec(X_MOUSE2, conf.GetString("Controls::Mouse2Crosshair")); if (conf.Exists("Controls::SuperscopeCrosshair")) parse_crosshair_spec(X_SUPERSCOPE, conf.GetString("Controls::SuperscopeCrosshair")); if (conf.Exists("Controls::Justifier1Crosshair")) parse_crosshair_spec(X_JUSTIFIER1, conf.GetString("Controls::Justifier1Crosshair")); if (conf.Exists("Controls::Justifier2Crosshair")) parse_crosshair_spec(X_JUSTIFIER2, conf.GetString("Controls::Justifier2Crosshair")); // Hack Settings.DisableGameSpecificHacks = !conf.GetBool("Hack::EnableGameSpecificHacks", true); Settings.BlockInvalidVRAMAccessMaster = !conf.GetBool("Hack::AllowInvalidVRAMAccess", false); Settings.HDMATimingHack = conf.GetInt ("Hack::HDMATiming", 100); // Netplay #ifdef NETPLAY_SUPPORT Settings.NetPlay = conf.GetBool("Netplay::Enable"); Settings.Port = NP_DEFAULT_PORT; if (conf.Exists("Netplay::Port")) Settings.Port = -(int) conf.GetUInt("Netplay::Port"); Settings.ServerName[0] = '\0'; if (conf.Exists("Netplay::Server")) conf.GetString("Netplay::Server", Settings.ServerName, 128); #endif // Debug #ifdef DEBUGGER if (conf.GetBool("DEBUG::Debugger", false)) CPU.Flags |= DEBUG_MODE_FLAG; if (conf.GetBool("DEBUG::Trace", false)) { ENSURE_TRACE_OPEN(trace,"trace.log","wb") CPU.Flags |= TRACE_FLAG; } #endif S9xParsePortConfig(conf, 1); S9xVerifyControllers(); } void S9xUsage (void) { /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 */ S9xMessage(S9X_INFO, S9X_USAGE, ""); S9xMessage(S9X_INFO, S9X_USAGE, "Snes9x " VERSION); S9xMessage(S9X_INFO, S9X_USAGE, ""); S9xMessage(S9X_INFO, S9X_USAGE, "usage: snes9x [options] "); S9xMessage(S9X_INFO, S9X_USAGE, ""); // SOUND OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-soundsync Synchronize sound as far as possible"); S9xMessage(S9X_INFO, S9X_USAGE, "-playbackrate Set sound playback rate"); S9xMessage(S9X_INFO, S9X_USAGE, "-inputrate Set sound input rate"); S9xMessage(S9X_INFO, S9X_USAGE, "-reversestereo Reverse stereo sound output"); S9xMessage(S9X_INFO, S9X_USAGE, "-nostereo Disable stereo sound output"); S9xMessage(S9X_INFO, S9X_USAGE, "-eightbit Use 8bit sound instead of 16bit"); S9xMessage(S9X_INFO, S9X_USAGE, "-mute Mute sound"); S9xMessage(S9X_INFO, S9X_USAGE, ""); // DISPLAY OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-displayframerate Display the frame rate counter"); S9xMessage(S9X_INFO, S9X_USAGE, "-displaykeypress Display input of all controllers and peripherals"); S9xMessage(S9X_INFO, S9X_USAGE, "-nohires (Not recommended) Disable support for hi-res and"); S9xMessage(S9X_INFO, S9X_USAGE, " interlace modes"); S9xMessage(S9X_INFO, S9X_USAGE, "-notransparency (Not recommended) Disable transparency effects"); S9xMessage(S9X_INFO, S9X_USAGE, "-nowindows (Not recommended) Disable graphic window effects"); S9xMessage(S9X_INFO, S9X_USAGE, ""); // CONTROLLER OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-nomp5 Disable emulation of the Multiplayer 5 adapter"); S9xMessage(S9X_INFO, S9X_USAGE, "-nomouse Disable emulation of the SNES mouse"); S9xMessage(S9X_INFO, S9X_USAGE, "-nosuperscope Disable emulation of the Superscope"); S9xMessage(S9X_INFO, S9X_USAGE, "-nojustifier Disable emulation of the Konami Justifier"); S9xMessage(S9X_INFO, S9X_USAGE, "-port# Specify which controller to emulate in port 1/2"); S9xMessage(S9X_INFO, S9X_USAGE, " Controllers: none No controller"); S9xMessage(S9X_INFO, S9X_USAGE, " pad# Joypad number 1-8"); S9xMessage(S9X_INFO, S9X_USAGE, " mouse# Mouse number 1-2"); S9xMessage(S9X_INFO, S9X_USAGE, " superscope Superscope (not useful with -port1)"); S9xMessage(S9X_INFO, S9X_USAGE, " justifier Blue Justifier (not useful with -port1)"); S9xMessage(S9X_INFO, S9X_USAGE, " two-justifiers Blue & Pink Justifiers"); S9xMessage(S9X_INFO, S9X_USAGE, " mp5:#### MP5 with the 4 named pads (1-8 or n)"); S9xMessage(S9X_INFO, S9X_USAGE, ""); // ROM OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-hirom Force Hi-ROM memory map"); S9xMessage(S9X_INFO, S9X_USAGE, "-lorom Force Lo-ROM memory map"); S9xMessage(S9X_INFO, S9X_USAGE, "-ntsc Force NTSC timing (60 frames/sec)"); S9xMessage(S9X_INFO, S9X_USAGE, "-pal Force PAL timing (50 frames/sec)"); S9xMessage(S9X_INFO, S9X_USAGE, "-nointerleave Assume the ROM image is not in interleaved"); S9xMessage(S9X_INFO, S9X_USAGE, " format"); S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved Assume the ROM image is in interleaved format"); S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved2 Assume the ROM image is in interleaved 2 format"); S9xMessage(S9X_INFO, S9X_USAGE, "-interleavedgd24 Assume the ROM image is in interleaved gd24"); S9xMessage(S9X_INFO, S9X_USAGE, " format"); S9xMessage(S9X_INFO, S9X_USAGE, "-noheader Assume the ROM image doesn't have a header of a"); S9xMessage(S9X_INFO, S9X_USAGE, " copier"); S9xMessage(S9X_INFO, S9X_USAGE, "-header Assume the ROM image has a header of a copier"); S9xMessage(S9X_INFO, S9X_USAGE, "-bsxbootup Boot up BS games from BS-X"); S9xMessage(S9X_INFO, S9X_USAGE, ""); // PATCH/CHEAT OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-nopatch Do not apply any available IPS/UPS patches"); S9xMessage(S9X_INFO, S9X_USAGE, "-cheat Apply saved cheats"); S9xMessage(S9X_INFO, S9X_USAGE, "-gamegenie Supply a Game Genie code"); S9xMessage(S9X_INFO, S9X_USAGE, "-actionreplay Supply a Pro-Action Reply code"); S9xMessage(S9X_INFO, S9X_USAGE, "-goldfinger Supply a Gold Finger code"); S9xMessage(S9X_INFO, S9X_USAGE, ""); #ifdef NETPLAY_SUPPORT // NETPLAY OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-net Enable netplay"); S9xMessage(S9X_INFO, S9X_USAGE, "-port Use port for netplay (use with -net)"); S9xMessage(S9X_INFO, S9X_USAGE, "-server Use the specified server for netplay"); S9xMessage(S9X_INFO, S9X_USAGE, " (use with -net)"); S9xMessage(S9X_INFO, S9X_USAGE, ""); #endif // HACKING OR DEBUGGING OPTIONS #ifdef DEBUGGER S9xMessage(S9X_INFO, S9X_USAGE, "-debug Set the Debugger flag"); S9xMessage(S9X_INFO, S9X_USAGE, "-trace Begin CPU instruction tracing"); #endif S9xMessage(S9X_INFO, S9X_USAGE, "-hdmatiming <1-199> (Not recommended) Changes HDMA transfer timings"); S9xMessage(S9X_INFO, S9X_USAGE, " event comes"); S9xMessage(S9X_INFO, S9X_USAGE, "-invalidvramaccess (Not recommended) Allow invalid VRAM access"); S9xMessage(S9X_INFO, S9X_USAGE, ""); // OTHER OPTIONS S9xMessage(S9X_INFO, S9X_USAGE, "-frameskip Screen update frame skip rate"); S9xMessage(S9X_INFO, S9X_USAGE, "-frametime Milliseconds per frame for frameskip auto-adjust"); S9xMessage(S9X_INFO, S9X_USAGE, "-upanddown Override protection from pressing left+right or"); S9xMessage(S9X_INFO, S9X_USAGE, " up+down together"); S9xMessage(S9X_INFO, S9X_USAGE, "-conf Use specified conf file (after standard files)"); S9xMessage(S9X_INFO, S9X_USAGE, "-nostdconf Do not load the standard config files"); S9xMessage(S9X_INFO, S9X_USAGE, ""); S9xExtraUsage(); S9xMessage(S9X_INFO, S9X_USAGE, ""); S9xMessage(S9X_INFO, S9X_USAGE, "ROM image can be compressed with zip, gzip, JMA, or compress."); exit(1); } char * S9xParseArgs (char **argv, int argc) { for (int i = 1; i < argc; i++) { if (*argv[i] == '-') { if (!strcasecmp(argv[i], "-help")) S9xUsage(); else // SOUND OPTIONS if (!strcasecmp(argv[i], "-soundsync")) Settings.SoundSync = TRUE; else if (!strcasecmp(argv[i], "-playbackrate")) { if (i + 1 < argc) { Settings.SoundPlaybackRate = atoi(argv[++i]); if (Settings.SoundPlaybackRate < 8192) Settings.SoundPlaybackRate = 8192; } else S9xUsage(); } else if (!strcasecmp(argv[i], "-inputrate")) { if (i + 1 < argc) { Settings.SoundInputRate = atoi(argv[++i]); if (Settings.SoundInputRate < 8192) Settings.SoundInputRate = 8192; } else S9xUsage(); } else if (!strcasecmp(argv[i], "-reversestereo")) Settings.ReverseStereo = TRUE; else if (!strcasecmp(argv[i], "-nostereo")) Settings.Stereo = FALSE; else if (!strcasecmp(argv[i], "-eightbit")) Settings.SixteenBitSound = FALSE; else if (!strcasecmp(argv[i], "-mute")) Settings.Mute = TRUE; else // DISPLAY OPTIONS if (!strcasecmp(argv[i], "-displayframerate")) Settings.DisplayFrameRate = TRUE; else if (!strcasecmp(argv[i], "-displaykeypress")) Settings.DisplayPressedKeys = TRUE; else if (!strcasecmp(argv[i], "-nohires")) Settings.SupportHiRes = FALSE; else if (!strcasecmp(argv[i], "-notransparency")) Settings.Transparency = FALSE; else if (!strcasecmp(argv[i], "-nowindows")) Settings.DisableGraphicWindows = TRUE; else // CONTROLLER OPTIONS if (!strcasecmp(argv[i], "-nomp5")) Settings.MultiPlayer5Master = FALSE; else if (!strcasecmp(argv[i], "-nomouse")) Settings.MouseMaster = FALSE; else if (!strcasecmp(argv[i], "-nosuperscope")) Settings.SuperScopeMaster = FALSE; else if (!strcasecmp(argv[i], "-nojustifier")) Settings.JustifierMaster = FALSE; else if (!strcasecmp(argv[i], "-port1") || !strcasecmp(argv[i], "-port2")) { if (i + 1 < argc) { i++; if (!parse_controller_spec(argv[i - 1][5] - '1', argv[i])) S9xUsage(); } else S9xUsage(); } else // ROM OPTIONS if (!strcasecmp(argv[i], "-hirom")) Settings.ForceHiROM = TRUE; else if (!strcasecmp(argv[i], "-lorom")) Settings.ForceLoROM = TRUE; else if (!strcasecmp(argv[i], "-ntsc")) Settings.ForceNTSC = TRUE; else if (!strcasecmp(argv[i], "-pal")) Settings.ForcePAL = TRUE; else if (!strcasecmp(argv[i], "-nointerleave")) Settings.ForceNotInterleaved = TRUE; else if (!strcasecmp(argv[i], "-interleaved")) Settings.ForceInterleaved = TRUE; else if (!strcasecmp(argv[i], "-interleaved2")) Settings.ForceInterleaved2 = TRUE; else if (!strcasecmp(argv[i], "-interleavedgd24")) Settings.ForceInterleaveGD24 = TRUE; else if (!strcasecmp(argv[i], "-noheader")) Settings.ForceNoHeader = TRUE; else if (!strcasecmp(argv[i], "-header")) Settings.ForceHeader = TRUE; else if (!strcasecmp(argv[i], "-bsxbootup")) Settings.BSXBootup = TRUE; else // PATCH/CHEAT OPTIONS if (!strcasecmp(argv[i], "-nopatch")) Settings.NoPatch = TRUE; else if (!strcasecmp(argv[i], "-cheat")) Settings.ApplyCheats = TRUE; else if (!strcasecmp(argv[i], "-gamegenie")) { if (i + 1 < argc) { uint32 address; uint8 byte; const char *error; if ((error = S9xGameGenieToRaw(argv[++i], address, byte)) == NULL) S9xAddCheat(TRUE, FALSE, address, byte); else S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, error); } else S9xUsage(); } else if (!strcasecmp(argv[i], "-actionreplay")) { if (i + 1 < argc) { uint32 address; uint8 byte; const char *error; if ((error = S9xProActionReplayToRaw(argv[++i], address, byte)) == NULL) S9xAddCheat(TRUE, FALSE, address, byte); else S9xMessage(S9X_ERROR, S9X_ACTION_REPLY_CODE_ERROR, error); } else S9xUsage(); } else if (!strcasecmp(argv[i], "-goldfinger")) { if (i + 1 < argc) { uint32 address; uint8 bytes[3]; bool8 sram; uint8 num_bytes; const char *error; if ((error = S9xGoldFingerToRaw(argv[++i], address, sram, num_bytes, bytes)) == NULL) { for (int c = 0; c < num_bytes; c++) S9xAddCheat(TRUE, FALSE, address + c, bytes[c]); } else S9xMessage(S9X_ERROR, S9X_GOLD_FINGER_CODE_ERROR, error); } else S9xUsage(); } else // NETPLAY OPTIONS #ifdef NETPLAY_SUPPORT if (!strcasecmp(argv[i], "-net")) Settings.NetPlay = TRUE; else if (!strcasecmp(argv[i], "-port")) { if (i + 1 < argc) Settings.Port = -atoi(argv[++i]); else S9xUsage(); } else if (!strcasecmp(argv[i], "-server")) { if (i + 1 < argc) { strncpy(Settings.ServerName, argv[++i], 127); Settings.ServerName[127] = 0; } else S9xUsage(); } else #endif // HACKING OR DEBUGGING OPTIONS #ifdef DEBUGGER if (!strcasecmp(argv[i], "-debug")) CPU.Flags |= DEBUG_MODE_FLAG; else if (!strcasecmp(argv[i], "-trace")) { ENSURE_TRACE_OPEN(trace,"trace.log","wb") CPU.Flags |= TRACE_FLAG; } else #endif if (!strcasecmp(argv[i], "-hdmatiming")) { if (i + 1 < argc) { int p = atoi(argv[++i]); if (p > 0 && p < 200) Settings.HDMATimingHack = p; } else S9xUsage(); } else if (!strcasecmp(argv[i], "-invalidvramaccess")) Settings.BlockInvalidVRAMAccessMaster = FALSE; else // OTHER OPTIONS if (!strcasecmp(argv[i], "-frameskip")) { if (i + 1 < argc) Settings.SkipFrames = atoi(argv[++i]) + 1; else S9xUsage(); } else if (!strcasecmp(argv[i], "-frametime")) { if (i + 1 < argc) Settings.FrameTimePAL = Settings.FrameTimeNTSC = atoi(argv[++i]); else S9xUsage(); } else if (!strcasecmp(argv[i], "-upanddown")) Settings.UpAndDown = TRUE; else if (!strcasecmp(argv[i], "-conf")) { if (++i >= argc) S9xUsage(); // Else do nothing, S9xLoadConfigFiles() handled it. } else if (!strcasecmp(argv[i], "-nostdconf")) { // Do nothing, S9xLoadConfigFiles() handled it. } else S9xParseArg(argv, i, argc); } else rom_filename = argv[i]; } S9xVerifyControllers(); return (rom_filename); }