commit daa4f9a04f4c8ad03621cdf8913e5245d8813687 Author: xerox Date: Tue Jan 18 16:18:15 2022 -0800 init commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..59717e3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,198 @@ + 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 - 2019 BearOso, + OV2 + + (c) Copyright 2017 qwertymodo + + (c) Copyright 2011 - 2017 Hans-Kristian Arntzen, + Daniel De Matteis + (Under no circumstances will commercial rights be given) + + + 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) + + S-SMP emulator code used in 1.54+ + (c) Copyright 2016 byuu + + 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 - 2019 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2019 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + Libretro port + (c) Copyright 2011 - 2017 Hans-Kristian Arntzen, + Daniel De Matteis + (Under no circumstances will commercial rights be given) + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + Snes9x source code: https://github.com/snes9xgit/snes9x/ + + 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. + +------------------------------------------------------------------------------- + +Some parts included in Snes9x are usually available under a different license, +their authors have granted exception for their use in Snes9x (and/or they are +licensed as LGPL): + - JMA: GPL/LGPL, see jma/license.txt + - snes_ntsc: LGPL, see filter/snes_ntsc-license.txt + - xBRZ: GPLv3, see filter/xbrz-license.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..fffc839 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# FBSnes9x - Unix Frame Buffer Port + diff --git a/snes9x/.gitignore b/snes9x/.gitignore new file mode 100644 index 0000000..b9ed61c --- /dev/null +++ b/snes9x/.gitignore @@ -0,0 +1,505 @@ +# Files that can arise when using snes9x +win32/snes9x.conf +win32/Valid.Ext +win32/stdout.txt +win32/stderr.txt +win32/Roms +win32/Saves +win32/Cheats +win32/Screenshots +win32/Movies +win32/SPCs +win32/BIOS +*.smc +*.sfc +*.fig +*.srm +*.00[0123456789] +*.oops +*.ips +*.ups +*.bps +*.avi +*.shader +*.cg +*.cgp +*.smv +*.cht +*.rtc + + +# Included libraries in OS X that should not be ignored. +!macosx/libz_u.a +!macosx/libHIDUtilities_u.a + +# Included libraries in windows that should not be ignored. +!win32/ddraw/ddraw_x86.lib +!win32/ddraw/ddraw_x64.lib + +# Created by https://www.gitignore.io/api/c,c++,xcode,visualstudio +# Edit at https://www.gitignore.io/?templates=c,c++,xcode,visualstudio + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### C++ ### +# Prerequisites + +# Compiled Object files +*.slo + +# Precompiled Headers + +# Compiled Dynamic libraries + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai + +# Executables + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Xcode Patch +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### Xcode Patch ### +**/xcshareddata/WorkspaceSettings.xcsettings + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.meta +*.iobj +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# End of https://www.gitignore.io/api/c,c++,xcode,visualstudio + +# vim +*.swp + +# OS X temporary files +.DS_Store +*.lock +profile diff --git a/snes9x/65c816.h b/snes9x/65c816.h new file mode 100644 index 0000000..22876c4 --- /dev/null +++ b/snes9x/65c816.h @@ -0,0 +1,105 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/README.md b/snes9x/README.md new file mode 100644 index 0000000..54b38fb --- /dev/null +++ b/snes9x/README.md @@ -0,0 +1,61 @@ +# Snes9x +*Snes9x - Portable Super Nintendo Entertainment System (TM) emulator* + +This is the official source code repository for the Snes9x project. + +Please check the [Wiki](https://github.com/snes9xgit/snes9x/wiki) for additional information. + +## Nightly builds + +Download nightly builds from continuous integration: + +### snes9x + +| OS | status | +|---------------|--------------------------------------------------| +| Windows | [![Status][s9x-win-all]][appveyor] | +| Linux (GTK) | [![Status][snes9x_linux-gtk-amd64]][cirrus-ci] | +| Linux (X11) | [![Status][snes9x_linux-x11-amd64]][cirrus-ci] | +| FreeBSD (X11) | [![Status][snes9x_freebsd-x11-amd64]][cirrus-ci] | +| macOS | [![Status][snes9x_macOS-amd64]][cirrus-ci] | + +[appveyor]: https://ci.appveyor.com/project/snes9x/snes9x +[cirrus-ci]: http://cirrus-ci.com/github/snes9xgit/snes9x + +[s9x-win-all]: https://ci.appveyor.com/api/projects/status/github/snes9xgit/snes9x?branch=master&svg=true +[snes9x_linux-gtk-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=snes9x_linux-gtk-amd64 +[snes9x_linux-x11-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=snes9x_linux-x11-amd64 +[snes9x_freebsd-x11-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=snes9x_freebsd-x11-amd64 +[snes9x_macOS-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=snes9x_macOS-amd64 + +### libretro core + +| OS | status | +|---------------------|---------------------------------------------------------| +| Linux/amd64 | [![Status][libretro_linux-amd64]][cirrus-ci] | +| Linux/i386 | [![Status][libretro_linux-i386]][cirrus-ci] | +| Linux/armhf | [![Status][libretro_linux-armhf]][cirrus-ci] | +| Linux/armv7-neon-hf | [![Status][libretro_linux-armv7-neon-hf]][cirrus-ci] | +| Linux/arm64 | [![Status][libretro_linux-arm64]][cirrus-ci] | +| Android/arm | [![Status][libretro_android-arm]][cirrus-ci] | +| Android/arm64 | [![Status][libretro_android-arm64]][cirrus-ci] | +| Emscripten | [![Status][libretro_emscripten]][cirrus-ci] | +| macOS/amd64 | [![Status][libretro_macOS-amd64]][cirrus-ci] | +| Nintendo Wii | [![Status][libretro_nintendo-wii]][cirrus-ci] | +| Nintendo Switch | [![Status][libretro_nintendo-switch-libnx]][cirrus-ci] | +| Nintendo GameCube | [![Status][libretro_nintendo-ngc]][cirrus-ci] | +| PSP | [![Status][libretro_playstation-psp]][cirrus-ci] | + +[libretro_linux-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_linux-amd64 +[libretro_linux-i386]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_linux-i386 +[libretro_linux-armhf]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_linux-armhf +[libretro_linux-armv7-neon-hf]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_linux-armv7-neon-hf +[libretro_linux-arm64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_linux-arm64 +[libretro_android-arm]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_android-arm +[libretro_android-arm64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_android-arm64 +[libretro_emscripten]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_emscripten +[libretro_macOS-amd64]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_macOS-amd64 +[libretro_nintendo-wii]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_nintendo-wii +[libretro_nintendo-switch-libnx]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_nintendo-switch-libnx +[libretro_nintendo-ngc]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_nintendo-ngc +[libretro_playstation-psp]: https://api.cirrus-ci.com/github/snes9xgit/snes9x.svg?task=libretro_playstation-psp diff --git a/snes9x/apu/apu.cpp b/snes9x/apu/apu.cpp new file mode 100644 index 0000000..4c54f2b --- /dev/null +++ b/snes9x/apu/apu.cpp @@ -0,0 +1,536 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include +#include "../snes9x.h" +#include "apu.h" +#include "../msu1.h" +#include "../snapshot.h" +#include "../display.h" +#include "resampler.h" + +#include "bapu/snes/snes.hpp" + +static const int APU_DEFAULT_INPUT_RATE = 31950; // ~59.94Hz +static const int APU_SAMPLE_BLOCK = 48; +static const int APU_NUMERATOR_NTSC = 15664; +static const int APU_DENOMINATOR_NTSC = 328125; +static const int APU_NUMERATOR_PAL = 34176; +static const int APU_DENOMINATOR_PAL = 709379; + +// Max number of samples we'll ever generate before call to port API and +// moving the samples to the resampler. +// This is 535 sample frames, which corresponds to 1 video frame + some leeway +// for use with SoundSync, multiplied by 2, for left and right samples. +static const int MINIMUM_BUFFER_SIZE = 550 * 2; + +namespace SNES { +#include "bapu/dsp/blargg_endian.h" +CPU cpu; +} // namespace SNES + +namespace spc { +static apu_callback callback = NULL; +static void *callback_data = NULL; + +static bool8 sound_in_sync = TRUE; +static bool8 sound_enabled = FALSE; + +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 double dynamic_rate_multiplier = 1.0; +} // namespace spc + +namespace msu { +// Always 16-bit, Stereo; 1.5x dsp buffer to never overflow +static Resampler *resampler = NULL; +static int16 *resample_buffer = NULL; +static int resample_buffer_size = 0; +} // namespace msu + +static void UpdatePlaybackRate(void); +static void SPCSnapshotCallback(void); +static inline int S9xAPUGetClock(int32); +static inline int S9xAPUGetClockRemainder(int32); + +bool8 S9xMixSamples(uint8 *dest, int sample_count) +{ + int16 *out = (int16 *)dest; + + if (Settings.Mute) + { + memset(out, 0, sample_count << 1); + S9xClearSamples(); + } + else + { + if (spc::resampler->avail() >= sample_count) + { + spc::resampler->read((short *)out, sample_count); + + if (Settings.MSU1) + { + if (msu::resampler->avail() >= sample_count) + { + if (msu::resample_buffer_size < sample_count) + { + if (msu::resample_buffer) + delete[] msu::resample_buffer; + msu::resample_buffer = new int16[sample_count]; + msu::resample_buffer_size = sample_count; + } + msu::resampler->read(msu::resample_buffer, + sample_count); + for (int i = 0; i < sample_count; ++i) + { + int32 mixed = (int32)out[i] + msu::resample_buffer[i]; + out[i] = ((int16)mixed != mixed) ? (mixed >> 31) ^ 0x7fff : mixed; + } + } + else // should never occur + assert(0); + } + } + else + { + memset(out, 0, sample_count << 1); + return false; + } + } + + if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync || + Settings.TurboMode || Settings.Mute) + spc::sound_in_sync = true; + else + spc::sound_in_sync = false; + + return true; +} + +int S9xGetSampleCount(void) +{ + return spc::resampler->avail(); +} + +void S9xLandSamples(void) +{ + if (spc::callback != NULL) + spc::callback(spc::callback_data); + + if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync || + Settings.TurboMode || Settings.Mute) + spc::sound_in_sync = true; + else + spc::sound_in_sync = false; +} + +void S9xClearSamples(void) +{ + spc::resampler->clear(); + if (Settings.MSU1) + msu::resampler->clear(); +} + +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::callback = callback; + spc::callback_data = data; +} + +void S9xUpdateDynamicRate(int avail, int buffer_size) +{ + spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / + (double)(1000 * buffer_size); + + UpdatePlaybackRate(); +} + +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); + + if (Settings.DynamicRateControl) + { + time_ratio *= spc::dynamic_rate_multiplier; + } + + spc::resampler->time_ratio(time_ratio); + + if (Settings.MSU1) + { + time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0); + msu::resampler->time_ratio(time_ratio); + } +} + +bool8 S9xInitSound(int buffer_ms) +{ + // The resampler and spc unit use samples (16-bit short) as arguments. + int buffer_size_samples = MINIMUM_BUFFER_SIZE; + int requested_buffer_size_samples = Settings.SoundPlaybackRate * buffer_ms * 2 / 1000; + + if (requested_buffer_size_samples > buffer_size_samples) + buffer_size_samples = requested_buffer_size_samples; + + if (!spc::resampler) + { + spc::resampler = new Resampler(buffer_size_samples); + if (!spc::resampler) + return (FALSE); + } + else + spc::resampler->resize(buffer_size_samples); + + + if (!msu::resampler) + { + msu::resampler = new Resampler(buffer_size_samples * 3 / 2); + if (!msu::resampler) + return (FALSE); + } + else + msu::resampler->resize(buffer_size_samples * 3 / 2); + + SNES::dsp.spc_dsp.set_output(spc::resampler); + S9xMSU1SetOutput(msu::resampler); + + 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::resampler = NULL; + msu::resampler = NULL; + + return (TRUE); +} + +void S9xDeinitAPU(void) +{ + if (spc::resampler) + { + delete spc::resampler; + spc::resampler = NULL; + } + + if (msu::resampler) + { + delete msu::resampler; + msu::resampler = NULL; + } + + S9xMSU1DeInit(); +} + +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 (spc::resampler->space_filled() >= APU_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::smp.power(); + SNES::dsp.power(); + SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback); + + S9xClearSamples(); +} + +void S9xSoftResetAPU(void) +{ + spc::reference_time = 0; + spc::remainder = 0; + SNES::cpu.reset(); + SNES::smp.reset(); + SNES::dsp.reset(); + + S9xClearSamples(); +} + +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)((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 regs_in[0x10]; + uint8 regs[0x10]; + uint16 pc, spc_time, dsp_time; + uint8 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)); + a = copier.copy_int(0, sizeof(uint8)); + x = copier.copy_int(0, sizeof(uint8)); + y = copier.copy_int(0, sizeof(uint8)); + psw = copier.copy_int(0, sizeof(uint8)); + sp = copier.copy_int(0, sizeof(uint8)); + copier.extra(); + + // times + spc_time = copier.copy_int(0, sizeof(uint16)); + dsp_time = copier.copy_int(0, sizeof(uint16)); + + 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 next_time[3]; + uint8 divider[3], counter[3]; + for (int i = 0; i < 3; i++) + { + next_time[i] = copier.copy_int(0, sizeof(uint16)); + divider[i] = copier.copy_int(0, sizeof(uint8)); + counter[i] = copier.copy_int(0, sizeof(uint8)); + 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); + + // 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); + + ignore = fwrite(buf, SPC_FILE_SIZE, 1, fs); + + if (ignore == 0) + { + fprintf(stderr, "Couldn't write file %s.\n", filename); + } + + fclose(fs); + + S9xSetSoundMute(FALSE); + + return (TRUE); +} diff --git a/snes9x/apu/apu.h b/snes9x/apu/apu.h new file mode 100644 index 0000000..b8247de --- /dev/null +++ b/snes9x/apu/apu.h @@ -0,0 +1,52 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 S9xAPULoadState (uint8 *); +void S9xAPULoadBlarggState(uint8 *oldblock); +void S9xAPUSaveState (uint8 *); +void S9xDumpSPCSnapshot (void); +bool8 S9xSPCDump (const char *); + +bool8 S9xInitSound (int); +bool8 S9xOpenSoundDevice (void); + +bool8 S9xSyncSound (void); +int S9xGetSampleCount (void); +void S9xSetSoundControl (uint8); +void S9xSetSoundMute (bool8); +void S9xLandSamples (void); +void S9xClearSamples (void); +bool8 S9xMixSamples (uint8 *, int); +void S9xSetSamplesAvailableCallback (apu_callback, void *); +void S9xUpdateDynamicRate (int, int); + +#define DSP_INTERPOLATION_NONE 0 +#define DSP_INTERPOLATION_LINEAR 1 +#define DSP_INTERPOLATION_GAUSSIAN 2 +#define DSP_INTERPOLATION_CUBIC 3 +#define DSP_INTERPOLATION_SINC 4 + +#endif diff --git a/snes9x/apu/bapu/dsp/SPC_DSP.cpp b/snes9x/apu/bapu/dsp/SPC_DSP.cpp new file mode 100644 index 0000000..6213b08 --- /dev/null +++ b/snes9x/apu/bapu/dsp/SPC_DSP.cpp @@ -0,0 +1,1431 @@ +// snes_spc 0.9.0. http://www.slack.net/~ant/ + +#include "../../../snes9x.h" + +#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;\ +} + +#define SPC_DSP_OUT_HOOK(l, r) \ + { \ + resampler->push_sample(l, r); \ + if (Settings.MSU1) \ + S9xMSU1Generate(2); \ + } + +void SPC_DSP::set_output( Resampler *resampler ) +{ + this->resampler = resampler; +} + +void SPC_DSP::set_output( sample_t* out, int size ) +{ + require( (size & 1) == 0 ); // must be even + 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, +}; + +// Interpolation by Mudlord +static short const cubic [514] = +{ + 0, -4, -8, -12, -16, -20, -23, -27, -30, -34, -37, -41, -44, -47, -50, -53, + -56, -59, -62, -65, -68, -71, -73, -76, -78, -81, -84, -87, -89, -91, -93, -95, + -98,-100,-102,-104,-106,-109,-110,-112,-113,-116,-117,-119,-121,-122,-123,-125, +-126,-128,-129,-131,-132,-134,-134,-136,-136,-138,-138,-140,-141,-141,-142,-143, +-144,-144,-145,-146,-147,-148,-147,-148,-148,-149,-149,-150,-150,-150,-150,-151, +-151,-151,-151,-151,-152,-152,-151,-152,-151,-152,-151,-151,-151,-151,-150,-150, +-150,-149,-149,-149,-149,-148,-147,-147,-146,-146,-145,-145,-144,-144,-143,-142, +-141,-141,-140,-139,-139,-138,-137,-136,-135,-135,-133,-133,-132,-131,-130,-129, +-128,-127,-126,-125,-124,-123,-121,-121,-119,-118,-117,-116,-115,-114,-112,-111, +-110,-109,-107,-106,-105,-104,-102,-102,-100, -99, -97, -97, -95, -94, -92, -91, + -90, -88, -87, -86, -85, -84, -82, -81, -79, -78, -76, -76, -74, -73, -71, -70, + -68, -67, -66, -65, -63, -62, -60, -60, -58, -57, -55, -55, -53, -52, -50, -49, + -48, -46, -45, -44, -43, -42, -40, -39, -38, -37, -36, -35, -34, -32, -31, -30, + -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -19, -17, -16, -15, -14, + -14, -13, -12, -11, -11, -10, -9, -9, -8, -8, -7, -7, -6, -5, -4, -4, + -3, -3, -3, -2, -2, -2, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0, + 0, +2048,2048,2048,2048,2047,2047,2046,2045,2043,2042,2041,2039,2037,2035,2033,2031, +2028,2026,2024,2021,2018,2015,2012,2009,2005,2002,1999,1995,1991,1987,1982,1978, +1974,1969,1965,1960,1955,1951,1946,1940,1934,1929,1924,1918,1912,1906,1900,1895, +1888,1882,1875,1869,1862,1856,1849,1842,1835,1828,1821,1814,1806,1799,1791,1783, +1776,1768,1760,1753,1744,1737,1728,1720,1711,1703,1695,1686,1677,1668,1659,1651, +1641,1633,1623,1614,1605,1596,1587,1577,1567,1559,1549,1539,1529,1520,1510,1499, +1490,1480,1470,1460,1450,1440,1430,1420,1408,1398,1389,1378,1367,1357,1346,1336, +1325,1315,1304,1293,1282,1272,1261,1250,1239,1229,1218,1207,1196,1185,1174,1163, +1152,1141,1130,1119,1108,1097,1086,1075,1063,1052,1042,1030,1019,1008, 997, 986, + 974, 964, 952, 941, 930, 919, 908, 897, 886, 875, 864, 853, 842, 831, 820, 809, + 798, 787, 776, 765, 754, 744, 733, 722, 711, 700, 690, 679, 668, 658, 647, 637, + 626, 616, 605, 595, 584, 574, 564, 554, 543, 534, 524, 514, 503, 494, 483, 473, + 464, 454, 444, 435, 425, 416, 407, 397, 387, 378, 370, 360, 351, 342, 333, 325, + 315, 307, 298, 290, 281, 273, 265, 256, 248, 241, 233, 225, 216, 209, 201, 193, + 186, 178, 171, 164, 157, 150, 143, 137, 129, 123, 117, 110, 103, 97, 91, 85, + 79, 74, 68, 62, 56, 51, 46, 41, 35, 31, 27, 22, 17, 13, 8, 4, + 0 +}; + +static short const sinc [2048] = +{ + 39, -315, 666, 15642, 666, -315, 39, -38, + 38, -302, 613, 15642, 718, -328, 41, -38, + 36, -288, 561, 15641, 772, -342, 42, -38, + 35, -275, 510, 15639, 826, -355, 44, -38, + 33, -263, 459, 15636, 880, -369, 46, -38, + 32, -250, 408, 15632, 935, -383, 47, -38, + 31, -237, 358, 15628, 990, -396, 49, -38, + 29, -224, 309, 15622, 1046, -410, 51, -38, + 28, -212, 259, 15616, 1103, -425, 53, -38, + 27, -200, 211, 15609, 1159, -439, 54, -38, + 25, -188, 163, 15601, 1216, -453, 56, -38, + 24, -175, 115, 15593, 1274, -467, 58, -38, + 23, -164, 68, 15583, 1332, -482, 60, -38, + 22, -152, 22, 15573, 1391, -496, 62, -37, + 21, -140, -24, 15562, 1450, -511, 64, -37, + 19, -128, -70, 15550, 1509, -526, 66, -37, + 18, -117, -115, 15538, 1569, -540, 68, -37, + 17, -106, -159, 15524, 1629, -555, 70, -37, + 16, -94, -203, 15510, 1690, -570, 72, -36, + 15, -83, -247, 15495, 1751, -585, 74, -36, + 14, -72, -289, 15479, 1813, -600, 76, -36, + 13, -62, -332, 15462, 1875, -616, 79, -36, + 12, -51, -374, 15445, 1937, -631, 81, -35, + 11, -40, -415, 15426, 2000, -646, 83, -35, + 11, -30, -456, 15407, 2063, -662, 85, -35, + 10, -20, -496, 15387, 2127, -677, 88, -34, + 9, -9, -536, 15366, 2191, -693, 90, -34, + 8, 1, -576, 15345, 2256, -708, 92, -34, + 7, 10, -614, 15323, 2321, -724, 95, -33, + 7, 20, -653, 15300, 2386, -740, 97, -33, + 6, 30, -690, 15276, 2451, -755, 99, -33, + 5, 39, -728, 15251, 2517, -771, 102, -32, + 5, 49, -764, 15226, 2584, -787, 104, -32, + 4, 58, -801, 15200, 2651, -803, 107, -32, + 3, 67, -836, 15173, 2718, -819, 109, -31, + 3, 76, -871, 15145, 2785, -835, 112, -31, + 2, 85, -906, 15117, 2853, -851, 115, -30, + 2, 93, -940, 15087, 2921, -867, 117, -30, + 1, 102, -974, 15057, 2990, -883, 120, -29, + 1, 110, -1007, 15027, 3059, -899, 122, -29, + 0, 118, -1039, 14995, 3128, -915, 125, -29, + 0, 127, -1071, 14963, 3198, -931, 128, -28, + -1, 135, -1103, 14930, 3268, -948, 131, -28, + -1, 142, -1134, 14896, 3338, -964, 133, -27, + -1, 150, -1164, 14862, 3409, -980, 136, -27, + -2, 158, -1194, 14827, 3480, -996, 139, -26, + -2, 165, -1224, 14791, 3551, -1013, 142, -26, + -3, 172, -1253, 14754, 3622, -1029, 144, -25, + -3, 179, -1281, 14717, 3694, -1045, 147, -25, + -3, 187, -1309, 14679, 3766, -1062, 150, -24, + -3, 193, -1337, 14640, 3839, -1078, 153, -24, + -4, 200, -1363, 14601, 3912, -1094, 156, -23, + -4, 207, -1390, 14561, 3985, -1110, 159, -23, + -4, 213, -1416, 14520, 4058, -1127, 162, -22, + -4, 220, -1441, 14479, 4131, -1143, 165, -22, + -4, 226, -1466, 14437, 4205, -1159, 168, -22, + -5, 232, -1490, 14394, 4279, -1175, 171, -21, + -5, 238, -1514, 14350, 4354, -1192, 174, -21, + -5, 244, -1537, 14306, 4428, -1208, 177, -20, + -5, 249, -1560, 14261, 4503, -1224, 180, -20, + -5, 255, -1583, 14216, 4578, -1240, 183, -19, + -5, 260, -1604, 14169, 4653, -1256, 186, -19, + -5, 265, -1626, 14123, 4729, -1272, 189, -18, + -5, 271, -1647, 14075, 4805, -1288, 192, -18, + -5, 276, -1667, 14027, 4881, -1304, 195, -17, + -6, 280, -1687, 13978, 4957, -1320, 198, -17, + -6, 285, -1706, 13929, 5033, -1336, 201, -16, + -6, 290, -1725, 13879, 5110, -1352, 204, -16, + -6, 294, -1744, 13829, 5186, -1368, 207, -15, + -6, 299, -1762, 13777, 5263, -1383, 210, -15, + -6, 303, -1779, 13726, 5340, -1399, 213, -14, + -6, 307, -1796, 13673, 5418, -1414, 216, -14, + -6, 311, -1813, 13620, 5495, -1430, 219, -13, + -5, 315, -1829, 13567, 5573, -1445, 222, -13, + -5, 319, -1844, 13512, 5651, -1461, 225, -13, + -5, 322, -1859, 13458, 5728, -1476, 229, -12, + -5, 326, -1874, 13402, 5806, -1491, 232, -12, + -5, 329, -1888, 13347, 5885, -1506, 235, -11, + -5, 332, -1902, 13290, 5963, -1521, 238, -11, + -5, 335, -1915, 13233, 6041, -1536, 241, -10, + -5, 338, -1928, 13176, 6120, -1551, 244, -10, + -5, 341, -1940, 13118, 6199, -1566, 247, -10, + -5, 344, -1952, 13059, 6277, -1580, 250, -9, + -5, 347, -1964, 13000, 6356, -1595, 253, -9, + -5, 349, -1975, 12940, 6435, -1609, 256, -8, + -4, 352, -1986, 12880, 6514, -1623, 259, -8, + -4, 354, -1996, 12819, 6594, -1637, 262, -8, + -4, 356, -2005, 12758, 6673, -1651, 265, -7, + -4, 358, -2015, 12696, 6752, -1665, 268, -7, + -4, 360, -2024, 12634, 6831, -1679, 271, -7, + -4, 362, -2032, 12572, 6911, -1693, 274, -6, + -4, 364, -2040, 12509, 6990, -1706, 277, -6, + -4, 366, -2048, 12445, 7070, -1719, 280, -6, + -3, 367, -2055, 12381, 7149, -1732, 283, -5, + -3, 369, -2062, 12316, 7229, -1745, 286, -5, + -3, 370, -2068, 12251, 7308, -1758, 289, -5, + -3, 371, -2074, 12186, 7388, -1771, 291, -4, + -3, 372, -2079, 12120, 7467, -1784, 294, -4, + -3, 373, -2084, 12054, 7547, -1796, 297, -4, + -3, 374, -2089, 11987, 7626, -1808, 300, -4, + -2, 375, -2094, 11920, 7706, -1820, 303, -3, + -2, 376, -2098, 11852, 7785, -1832, 305, -3, + -2, 376, -2101, 11785, 7865, -1844, 308, -3, + -2, 377, -2104, 11716, 7944, -1855, 311, -3, + -2, 377, -2107, 11647, 8024, -1866, 313, -2, + -2, 378, -2110, 11578, 8103, -1877, 316, -2, + -2, 378, -2112, 11509, 8182, -1888, 318, -2, + -1, 378, -2113, 11439, 8262, -1899, 321, -2, + -1, 378, -2115, 11369, 8341, -1909, 323, -2, + -1, 378, -2116, 11298, 8420, -1920, 326, -2, + -1, 378, -2116, 11227, 8499, -1930, 328, -1, + -1, 378, -2116, 11156, 8578, -1940, 331, -1, + -1, 378, -2116, 11084, 8656, -1949, 333, -1, + -1, 377, -2116, 11012, 8735, -1959, 335, -1, + -1, 377, -2115, 10940, 8814, -1968, 337, -1, + -1, 377, -2114, 10867, 8892, -1977, 340, -1, + -1, 376, -2112, 10795, 8971, -1985, 342, -1, + 0, 375, -2111, 10721, 9049, -1994, 344, -1, + 0, 375, -2108, 10648, 9127, -2002, 346, 0, + 0, 374, -2106, 10574, 9205, -2010, 348, 0, + 0, 373, -2103, 10500, 9283, -2018, 350, 0, + 0, 372, -2100, 10426, 9360, -2025, 352, 0, + 0, 371, -2097, 10351, 9438, -2032, 354, 0, + 0, 370, -2093, 10276, 9515, -2039, 355, 0, + 0, 369, -2089, 10201, 9592, -2046, 357, 0, + 0, 367, -2084, 10126, 9669, -2052, 359, 0, + 0, 366, -2080, 10050, 9745, -2058, 360, 0, + 0, 365, -2075, 9974, 9822, -2064, 362, 0, + 0, 363, -2070, 9898, 9898, -2070, 363, 0, + 0, 362, -2064, 9822, 9974, -2075, 365, 0, + 0, 360, -2058, 9745, 10050, -2080, 366, 0, + 0, 359, -2052, 9669, 10126, -2084, 367, 0, + 0, 357, -2046, 9592, 10201, -2089, 369, 0, + 0, 355, -2039, 9515, 10276, -2093, 370, 0, + 0, 354, -2032, 9438, 10351, -2097, 371, 0, + 0, 352, -2025, 9360, 10426, -2100, 372, 0, + 0, 350, -2018, 9283, 10500, -2103, 373, 0, + 0, 348, -2010, 9205, 10574, -2106, 374, 0, + 0, 346, -2002, 9127, 10648, -2108, 375, 0, + -1, 344, -1994, 9049, 10721, -2111, 375, 0, + -1, 342, -1985, 8971, 10795, -2112, 376, -1, + -1, 340, -1977, 8892, 10867, -2114, 377, -1, + -1, 337, -1968, 8814, 10940, -2115, 377, -1, + -1, 335, -1959, 8735, 11012, -2116, 377, -1, + -1, 333, -1949, 8656, 11084, -2116, 378, -1, + -1, 331, -1940, 8578, 11156, -2116, 378, -1, + -1, 328, -1930, 8499, 11227, -2116, 378, -1, + -2, 326, -1920, 8420, 11298, -2116, 378, -1, + -2, 323, -1909, 8341, 11369, -2115, 378, -1, + -2, 321, -1899, 8262, 11439, -2113, 378, -1, + -2, 318, -1888, 8182, 11509, -2112, 378, -2, + -2, 316, -1877, 8103, 11578, -2110, 378, -2, + -2, 313, -1866, 8024, 11647, -2107, 377, -2, + -3, 311, -1855, 7944, 11716, -2104, 377, -2, + -3, 308, -1844, 7865, 11785, -2101, 376, -2, + -3, 305, -1832, 7785, 11852, -2098, 376, -2, + -3, 303, -1820, 7706, 11920, -2094, 375, -2, + -4, 300, -1808, 7626, 11987, -2089, 374, -3, + -4, 297, -1796, 7547, 12054, -2084, 373, -3, + -4, 294, -1784, 7467, 12120, -2079, 372, -3, + -4, 291, -1771, 7388, 12186, -2074, 371, -3, + -5, 289, -1758, 7308, 12251, -2068, 370, -3, + -5, 286, -1745, 7229, 12316, -2062, 369, -3, + -5, 283, -1732, 7149, 12381, -2055, 367, -3, + -6, 280, -1719, 7070, 12445, -2048, 366, -4, + -6, 277, -1706, 6990, 12509, -2040, 364, -4, + -6, 274, -1693, 6911, 12572, -2032, 362, -4, + -7, 271, -1679, 6831, 12634, -2024, 360, -4, + -7, 268, -1665, 6752, 12696, -2015, 358, -4, + -7, 265, -1651, 6673, 12758, -2005, 356, -4, + -8, 262, -1637, 6594, 12819, -1996, 354, -4, + -8, 259, -1623, 6514, 12880, -1986, 352, -4, + -8, 256, -1609, 6435, 12940, -1975, 349, -5, + -9, 253, -1595, 6356, 13000, -1964, 347, -5, + -9, 250, -1580, 6277, 13059, -1952, 344, -5, + -10, 247, -1566, 6199, 13118, -1940, 341, -5, + -10, 244, -1551, 6120, 13176, -1928, 338, -5, + -10, 241, -1536, 6041, 13233, -1915, 335, -5, + -11, 238, -1521, 5963, 13290, -1902, 332, -5, + -11, 235, -1506, 5885, 13347, -1888, 329, -5, + -12, 232, -1491, 5806, 13402, -1874, 326, -5, + -12, 229, -1476, 5728, 13458, -1859, 322, -5, + -13, 225, -1461, 5651, 13512, -1844, 319, -5, + -13, 222, -1445, 5573, 13567, -1829, 315, -5, + -13, 219, -1430, 5495, 13620, -1813, 311, -6, + -14, 216, -1414, 5418, 13673, -1796, 307, -6, + -14, 213, -1399, 5340, 13726, -1779, 303, -6, + -15, 210, -1383, 5263, 13777, -1762, 299, -6, + -15, 207, -1368, 5186, 13829, -1744, 294, -6, + -16, 204, -1352, 5110, 13879, -1725, 290, -6, + -16, 201, -1336, 5033, 13929, -1706, 285, -6, + -17, 198, -1320, 4957, 13978, -1687, 280, -6, + -17, 195, -1304, 4881, 14027, -1667, 276, -5, + -18, 192, -1288, 4805, 14075, -1647, 271, -5, + -18, 189, -1272, 4729, 14123, -1626, 265, -5, + -19, 186, -1256, 4653, 14169, -1604, 260, -5, + -19, 183, -1240, 4578, 14216, -1583, 255, -5, + -20, 180, -1224, 4503, 14261, -1560, 249, -5, + -20, 177, -1208, 4428, 14306, -1537, 244, -5, + -21, 174, -1192, 4354, 14350, -1514, 238, -5, + -21, 171, -1175, 4279, 14394, -1490, 232, -5, + -22, 168, -1159, 4205, 14437, -1466, 226, -4, + -22, 165, -1143, 4131, 14479, -1441, 220, -4, + -22, 162, -1127, 4058, 14520, -1416, 213, -4, + -23, 159, -1110, 3985, 14561, -1390, 207, -4, + -23, 156, -1094, 3912, 14601, -1363, 200, -4, + -24, 153, -1078, 3839, 14640, -1337, 193, -3, + -24, 150, -1062, 3766, 14679, -1309, 187, -3, + -25, 147, -1045, 3694, 14717, -1281, 179, -3, + -25, 144, -1029, 3622, 14754, -1253, 172, -3, + -26, 142, -1013, 3551, 14791, -1224, 165, -2, + -26, 139, -996, 3480, 14827, -1194, 158, -2, + -27, 136, -980, 3409, 14862, -1164, 150, -1, + -27, 133, -964, 3338, 14896, -1134, 142, -1, + -28, 131, -948, 3268, 14930, -1103, 135, -1, + -28, 128, -931, 3198, 14963, -1071, 127, 0, + -29, 125, -915, 3128, 14995, -1039, 118, 0, + -29, 122, -899, 3059, 15027, -1007, 110, 1, + -29, 120, -883, 2990, 15057, -974, 102, 1, + -30, 117, -867, 2921, 15087, -940, 93, 2, + -30, 115, -851, 2853, 15117, -906, 85, 2, + -31, 112, -835, 2785, 15145, -871, 76, 3, + -31, 109, -819, 2718, 15173, -836, 67, 3, + -32, 107, -803, 2651, 15200, -801, 58, 4, + -32, 104, -787, 2584, 15226, -764, 49, 5, + -32, 102, -771, 2517, 15251, -728, 39, 5, + -33, 99, -755, 2451, 15276, -690, 30, 6, + -33, 97, -740, 2386, 15300, -653, 20, 7, + -33, 95, -724, 2321, 15323, -614, 10, 7, + -34, 92, -708, 2256, 15345, -576, 1, 8, + -34, 90, -693, 2191, 15366, -536, -9, 9, + -34, 88, -677, 2127, 15387, -496, -20, 10, + -35, 85, -662, 2063, 15407, -456, -30, 11, + -35, 83, -646, 2000, 15426, -415, -40, 11, + -35, 81, -631, 1937, 15445, -374, -51, 12, + -36, 79, -616, 1875, 15462, -332, -62, 13, + -36, 76, -600, 1813, 15479, -289, -72, 14, + -36, 74, -585, 1751, 15495, -247, -83, 15, + -36, 72, -570, 1690, 15510, -203, -94, 16, + -37, 70, -555, 1629, 15524, -159, -106, 17, + -37, 68, -540, 1569, 15538, -115, -117, 18, + -37, 66, -526, 1509, 15550, -70, -128, 19, + -37, 64, -511, 1450, 15562, -24, -140, 21, + -37, 62, -496, 1391, 15573, 22, -152, 22, + -38, 60, -482, 1332, 15583, 68, -164, 23, + -38, 58, -467, 1274, 15593, 115, -175, 24, + -38, 56, -453, 1216, 15601, 163, -188, 25, + -38, 54, -439, 1159, 15609, 211, -200, 27, + -38, 53, -425, 1103, 15616, 259, -212, 28, + -38, 51, -410, 1046, 15622, 309, -224, 29, + -38, 49, -396, 990, 15628, 358, -237, 31, + -38, 47, -383, 935, 15632, 408, -250, 32, + -38, 46, -369, 880, 15636, 459, -263, 33, + -38, 44, -355, 826, 15639, 510, -275, 35, + -38, 42, -342, 772, 15641, 561, -288, 36, + -38, 41, -328, 718, 15642, 613, -302, 38, +}; + +inline int SPC_DSP::interpolate( voice_t const* v ) +{ + int out; + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; + + switch (Settings.InterpolationMethod) + { + case 0: // raw + { + out = in [0] & ~1; + break; + } + + case 1: // linear interpolation + { + int fract = v->interp_pos & 0xFFF; + out = (0x1000 - fract) * in [0]; + out += fract * in [1]; + out >>= 12; + + CLAMP16( out ); + break; + } + + case 3: // cubic filter + { + // Make pointers into cubic based on fractional position between samples + int offset = v->interp_pos >> 4 & 0xFF; + short const* fwd = cubic + offset; + short const* rev = cubic + 256 - offset; // mirror left half of cubic + + out = fwd [ 0] * in [0]; + out += fwd [257] * in [1]; + out += rev [257] * in [2]; + out += rev [ 0] * in [3]; + out >>= 11; + + CLAMP16( out ); + break; + } + + case 4: // sinc filter + { + int offset = (v->interp_pos & 0xFF0) >> 1; + short const* filt = sinc + offset; + + out = filt [0] * in [0]; + out += filt [1] * in [1]; + out += filt [2] * in [2]; + out += filt [3] * in [3]; + out += filt [4] * in [4]; + out += filt [5] * in [5]; + out += filt [6] * in [6]; + out += filt [7] * in [7]; + out >>= 14; + + CLAMP16( out ); + break; + } + + default: + case 2: // Original gaussian filter + { + // 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 + + 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; + + break; + } + + } + + 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) & 0xffff; + 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 +} + +inline 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] ); + } +} + +inline 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 ) ((Settings.SeparateEchoBuffer) ? (&m.separate_echo_buffer [m.t_echo_ptr + ch * 2]) : (&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; /* Fall through */ 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; + + memset(m.separate_echo_buffer, 0, 0x10000); + + 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; +} diff --git a/snes9x/apu/bapu/dsp/SPC_DSP.h b/snes9x/apu/bapu/dsp/SPC_DSP.h new file mode 100644 index 0000000..bea8ec0 --- /dev/null +++ b/snes9x/apu/bapu/dsp/SPC_DSP.h @@ -0,0 +1,324 @@ +// 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 ); + + void set_output( Resampler* resampler ); + + // 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 }; + + Resampler *resampler; + + 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]; + + uint8_t separate_echo_buffer [0x10000]; + }; + 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 diff --git a/snes9x/apu/bapu/dsp/blargg_common.h b/snes9x/apu/bapu/dsp/blargg_common.h new file mode 100644 index 0000000..75edff3 --- /dev/null +++ b/snes9x/apu/bapu/dsp/blargg_common.h @@ -0,0 +1,186 @@ +// 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 diff --git a/snes9x/apu/bapu/dsp/blargg_config.h b/snes9x/apu/bapu/dsp/blargg_config.h new file mode 100644 index 0000000..ba51d8f --- /dev/null +++ b/snes9x/apu/bapu/dsp/blargg_config.h @@ -0,0 +1,28 @@ +// 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 +#if !defined(DEBUGGER) && !defined(_DEBUG) +#define NDEBUG 1 +#endif + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations +#if !defined(__CELLOS_LV2__) +#define BLARGG_NONPORTABLE 1 +#endif + +// 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 diff --git a/snes9x/apu/bapu/dsp/blargg_endian.h b/snes9x/apu/bapu/dsp/blargg_endian.h new file mode 100644 index 0000000..f2daca6 --- /dev/null +++ b/snes9x/apu/bapu/dsp/blargg_endian.h @@ -0,0 +1,185 @@ +// 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 diff --git a/snes9x/apu/bapu/dsp/blargg_source.h b/snes9x/apu/bapu/dsp/blargg_source.h new file mode 100644 index 0000000..5e45c4f --- /dev/null +++ b/snes9x/apu/bapu/dsp/blargg_source.h @@ -0,0 +1,100 @@ +/* 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 diff --git a/snes9x/apu/bapu/dsp/sdsp.cpp b/snes9x/apu/bapu/dsp/sdsp.cpp new file mode 100644 index 0000000..64efcba --- /dev/null +++ b/snes9x/apu/bapu/dsp/sdsp.cpp @@ -0,0 +1,50 @@ +#include "../snes/snes.hpp" + +#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; +} + +} diff --git a/snes9x/apu/bapu/dsp/sdsp.hpp b/snes9x/apu/bapu/dsp/sdsp.hpp new file mode 100644 index 0000000..baf1e88 --- /dev/null +++ b/snes9x/apu/bapu/dsp/sdsp.hpp @@ -0,0 +1,34 @@ +#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; diff --git a/snes9x/apu/bapu/smp/algorithms.cpp b/snes9x/apu/bapu/smp/algorithms.cpp new file mode 100644 index 0000000..a55369f --- /dev/null +++ b/snes9x/apu/bapu/smp/algorithms.cpp @@ -0,0 +1,122 @@ +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; +} diff --git a/snes9x/apu/bapu/smp/core.cpp b/snes9x/apu/bapu/smp/core.cpp new file mode 100644 index 0000000..f5c2e6e --- /dev/null +++ b/snes9x/apu/bapu/smp/core.cpp @@ -0,0 +1,78 @@ +void SMP::tick() { + timer0.tick(); + timer1.tick(); + timer2.tick(); + + clock++; + dsp.clock++; +} + +void SMP::tick(unsigned clocks) { + timer0.tick(clocks); + timer1.tick(clocks); + timer2.tick(clocks); + + clock += clocks; + dsp.clock += clocks; +} + +void SMP::op_io() { + tick(); +} + +void SMP::op_io(unsigned clocks) { + tick(clocks); +} + +uint8 SMP::op_read(uint16 addr) { + tick(); + 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) { + tick(); + if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); + apuram[addr] = data; //all writes go to RAM, even MMIO writes +} + +uint8 SMP::op_readstack() +{ + tick(); + return apuram[0x0100 | ++regs.sp]; +} + +void SMP::op_writestack(uint8 data) +{ + tick(); + apuram[0x0100 | regs.sp--] = data; +} + +void SMP::op_step() { + #define op_readpc() op_read(regs.pc++) + #define op_readdp(addr) op_read((regs.p.p << 8) + ((addr) & 0xff)) + #define op_writedp(addr, data) op_write((regs.p.p << 8) + ((addr) & 0xff), data) + #define op_readaddr(addr) op_read(addr) + #define op_writeaddr(addr, data) op_write(addr, data) + + if(opcode_cycle == 0) + { +#ifdef DEBUGGER + if (Settings.TraceSMP) + { + disassemble_opcode(tmp, regs.pc); + S9xTraceMessage (tmp); + } +#endif + 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" + } +} diff --git a/snes9x/apu/bapu/smp/core/oppseudo_misc.cpp b/snes9x/apu/bapu/smp/core/oppseudo_misc.cpp new file mode 100644 index 0000000..53ec1f3 --- /dev/null +++ b/snes9x/apu/bapu/smp/core/oppseudo_misc.cpp @@ -0,0 +1,311 @@ +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; +} + diff --git a/snes9x/apu/bapu/smp/core/oppseudo_mov.cpp b/snes9x/apu/bapu/smp/core/oppseudo_mov.cpp new file mode 100644 index 0000000..9f3f366 --- /dev/null +++ b/snes9x/apu/bapu/smp/core/oppseudo_mov.cpp @@ -0,0 +1,706 @@ +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); + break; + 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; +} + diff --git a/snes9x/apu/bapu/smp/core/oppseudo_pc.cpp b/snes9x/apu/bapu/smp/core/oppseudo_pc.cpp new file mode 100644 index 0000000..5c31d49 --- /dev/null +++ b/snes9x/apu/bapu/smp/core/oppseudo_pc.cpp @@ -0,0 +1,536 @@ +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; +} + diff --git a/snes9x/apu/bapu/smp/core/oppseudo_read.cpp b/snes9x/apu/bapu/smp/core/oppseudo_read.cpp new file mode 100644 index 0000000..330ac6b --- /dev/null +++ b/snes9x/apu/bapu/smp/core/oppseudo_read.cpp @@ -0,0 +1,751 @@ +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: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.B.y = op_cmp(regs.B.y, rd); + opcode_cycle = 0; + break; + } + 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; +} + diff --git a/snes9x/apu/bapu/smp/core/oppseudo_rmw.cpp b/snes9x/apu/bapu/smp/core/oppseudo_rmw.cpp new file mode 100644 index 0000000..0664c70 --- /dev/null +++ b/snes9x/apu/bapu/smp/core/oppseudo_rmw.cpp @@ -0,0 +1,262 @@ +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; +} + diff --git a/snes9x/apu/bapu/smp/debugger/debugger.cpp b/snes9x/apu/bapu/smp/debugger/debugger.cpp new file mode 100644 index 0000000..9546c11 --- /dev/null +++ b/snes9x/apu/bapu/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#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 diff --git a/snes9x/apu/bapu/smp/debugger/debugger.hpp b/snes9x/apu/bapu/smp/debugger/debugger.hpp new file mode 100644 index 0000000..811aa4c --- /dev/null +++ b/snes9x/apu/bapu/smp/debugger/debugger.hpp @@ -0,0 +1,27 @@ +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); +}; diff --git a/snes9x/apu/bapu/smp/debugger/disassembler.cpp b/snes9x/apu/bapu/smp/debugger/disassembler.cpp new file mode 100644 index 0000000..624c8ac --- /dev/null +++ b/snes9x/apu/bapu/smp/debugger/disassembler.cpp @@ -0,0 +1,309 @@ +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.B.a, regs.x, regs.B.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); + + sprintf(t, " %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", + apuram[0xf4], apuram[0xf5], apuram[0xf6], apuram[0xf7], + cpu.port_read(0), cpu.port_read(1), cpu.port_read(2), cpu.port_read(3)); + strcat(s, t); +} diff --git a/snes9x/apu/bapu/smp/iplrom.cpp b/snes9x/apu/bapu/smp/iplrom.cpp new file mode 100644 index 0000000..a2ade89 --- /dev/null +++ b/snes9x/apu/bapu/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#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 diff --git a/snes9x/apu/bapu/smp/memory.cpp b/snes9x/apu/bapu/smp/memory.cpp new file mode 100644 index 0000000..3df43b1 --- /dev/null +++ b/snes9x/apu/bapu/smp/memory.cpp @@ -0,0 +1,126 @@ +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: + 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) { + 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: + 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; + } +} diff --git a/snes9x/apu/bapu/smp/smp.cpp b/snes9x/apu/bapu/smp/smp.cpp new file mode 100644 index 0000000..2cf58af --- /dev/null +++ b/snes9x/apu/bapu/smp/smp.cpp @@ -0,0 +1,76 @@ +#ifdef DEBUGGER +#include "../../../snes9x.h" +#include "../../../debug.h" +char tmp[1024]; +#endif + +#include "../snes/snes.hpp" + +#define SMP_CPP +namespace SNES { + +#ifdef DEBUGGER +#include "debugger/disassembler.cpp" +#endif + +SMP smp; + +#include "algorithms.cpp" +#include "core.cpp" +#include "iplrom.cpp" +#include "memory.cpp" +#include "timing.cpp" + +void SMP::enter() { + while(clock < 0) op_step(); +} + +void SMP::power() { + Processor::clock = 0; + + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + 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; +} + +SMP::SMP() { + apuram = new uint8[64 * 1024]; +} + +SMP::~SMP() { + delete[] apuram; +} + +} diff --git a/snes9x/apu/bapu/smp/smp.hpp b/snes9x/apu/bapu/smp/smp.hpp new file mode 100644 index 0000000..e268755 --- /dev/null +++ b/snes9x/apu/bapu/smp/smp.hpp @@ -0,0 +1,126 @@ +class SMP : public Processor { +public: + static const uint8 iplrom[64]; + uint8 *apuram; + + 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(); + + void load_state(uint8 **); + void save_state(uint8 **); + void save_spc (uint8 *); + 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(); + alwaysinline void op_writestack(uint8 data); + alwaysinline uint8 op_readstack(); + 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); +#ifdef DEBUGGER + void disassemble_opcode(char *output, uint16 addr); + inline uint8 disassemble_read(uint16 addr); + inline uint16 relb(int8 offset, int op_len); +#endif +}; + +extern SMP smp; diff --git a/snes9x/apu/bapu/smp/smp_state.cpp b/snes9x/apu/bapu/smp/smp_state.cpp new file mode 100644 index 0000000..536850f --- /dev/null +++ b/snes9x/apu/bapu/smp/smp_state.cpp @@ -0,0 +1,197 @@ +#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 diff --git a/snes9x/apu/bapu/smp/timing.cpp b/snes9x/apu/bapu/smp/timing.cpp new file mode 100644 index 0000000..d278f6f --- /dev/null +++ b/snes9x/apu/bapu/smp/timing.cpp @@ -0,0 +1,26 @@ +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; +} diff --git a/snes9x/apu/bapu/snes/snes.hpp b/snes9x/apu/bapu/snes/snes.hpp new file mode 100644 index 0000000..eb6e819 --- /dev/null +++ b/snes9x/apu/bapu/snes/snes.hpp @@ -0,0 +1,47 @@ +#ifndef __SNES_HPP +#define __SNES_HPP + +#include "../../../snes9x.h" +#include "../../resampler.h" +#include "../../../msu1.h" + +#define debugvirtual + +namespace SNES +{ + +struct Processor +{ + unsigned frequency; + int32 clock; +}; + +#include "../smp/smp.hpp" +#include "../dsp/sdsp.hpp" + +class CPU +{ +public: + 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 diff --git a/snes9x/apu/resampler.h b/snes9x/apu/resampler.h new file mode 100644 index 0000000..a917345 --- /dev/null +++ b/snes9x/apu/resampler.h @@ -0,0 +1,229 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef __NEW_RESAMPLER_H +#define __NEW_RESAMPLER_H + +#include +#include +#if __cplusplus >= 201103L +#include +#else +#include +#endif +#include + +class Resampler +{ + public: + int size; + int buffer_size; + int start; + int16_t *buffer; + + float r_step; + float r_frac; + int r_left[4], r_right[4]; + + static inline int16_t short_clamp(int n) + { + return (int16_t)(((int16_t)n != n) ? (n >> 31) ^ 0x7fff : n); + } + + static inline int min(int a, int b) + { + return ((a) < (b) ? (a) : (b)); + } + + 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); + } + + Resampler() + { + this->buffer_size = 0; + buffer = NULL; + r_step = 1.0; + } + + Resampler(int num_samples) + { + this->buffer_size = num_samples; + buffer = new int16_t[this->buffer_size]; + r_step = 1.0; + clear(); + } + + ~Resampler() + { + delete[] buffer; + buffer = NULL; + } + + inline void time_ratio(double ratio) + { + r_step = ratio; + } + + inline void clear(void) + { + if (!buffer) + return; + + start = 0; + size = 0; + memset(buffer, 0, buffer_size * 2); + + r_frac = 0.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; + } + + inline bool pull(int16_t *dst, int num_samples) + { + if (space_filled() < num_samples) + return false; + + memcpy(dst, buffer + start, min(num_samples, buffer_size - start) * 2); + + if (num_samples > (buffer_size - start)) + memcpy(dst + (buffer_size - start), buffer, (num_samples - (buffer_size - start)) * 2); + + start = (start + num_samples) % buffer_size; + size -= num_samples; + + return true; + } + + inline void push_sample(int16_t l, int16_t r) + { + if (space_empty() >= 2) + { + int end = start + size; + if (end >= buffer_size) + end -= buffer_size; + buffer[end] = l; + buffer[end + 1] = r; + size += 2; + } + } + + inline bool push(int16_t *src, int num_samples) + { + if (space_empty() < num_samples) + return false; + + int end = start + size; + if (end > buffer_size) + end -= buffer_size; + int first_write_size = min(num_samples, buffer_size - end); + + memcpy(buffer + end, src, first_write_size * 2); + + if (num_samples > first_write_size) + memcpy(buffer, src + first_write_size, (num_samples - first_write_size) * 2); + + size += num_samples; + + return true; + } + + void read(int16_t *data, int num_samples) + { + //If we are outputting the exact same ratio as the input, pull directly from the input buffer + if (r_step == 1.0) + { + pull(data, num_samples); + return; + } + + assert((num_samples & 1) == 0); // resampler always processes both stereo samples + int o_position = 0; + + while (o_position < num_samples && size > 0) + { + int s_left = buffer[start]; + int s_right = buffer[start + 1]; + int hermite_val[2]; + + while (r_frac <= 1.0 && o_position < num_samples) + { + hermite_val[0] = (int)hermite(r_frac, (float)r_left[0], (float)r_left[1], (float)r_left[2], (float)r_left[3]); + hermite_val[1] = (int)hermite(r_frac, (float)r_right[0], (float)r_right[1], (float)r_right[2], (float)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; + + start += 2; + if (start >= buffer_size) + start -= buffer_size; + size -= 2; + } + } + } + + inline int space_empty(void) const + { + return buffer_size - size; + } + + inline int space_filled(void) const + { + return size; + } + + inline int avail(void) + { + //If we are outputting the exact same ratio as the input, find out directly from the input buffer + if (r_step == 1.0) + return size; + + return (int)trunc(((size >> 1) - r_frac) / r_step) * 2; + } + + void resize(int num_samples) + { + if (buffer) + delete[] buffer; + buffer_size = num_samples; + buffer = new int16_t[buffer_size]; + clear(); + } +}; + +#endif /* __NEW_RESAMPLER_H */ \ No newline at end of file diff --git a/snes9x/bml.cpp b/snes9x/bml.cpp new file mode 100644 index 0000000..b31cac3 --- /dev/null +++ b/snes9x/bml.cpp @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include + +#include "port.h" +#include "bml.h" + +bml_node::bml_node() +{ + type = CHILD; + depth = -1; +} + +static inline int islf(char c) +{ + return (c == '\r' || c == '\n'); +} + +static inline int isblank(char c) +{ + return (c == ' ' || c == '\t'); +} + +static inline int isblankorlf(char c) +{ + return (islf(c) || isblank(c)); +} + +static inline int isalnum(char c) +{ + return ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')); +} + +static inline int bml_valid(char c) +{ + return (isalnum(c) || c == '-'); +} + +static std::string trim(std::string str) +{ + int start; + int end; + for (start = 0; str[start] && start != (int)str.length() && isblank(str[start]); start++) {} + if (start >= (int)str.length()) + return std::string(""); + for (end = str.length() - 1; isblankorlf(str[end]); end--) {} + return str.substr(start, end - start + 1); +} + +static std::string trimcomments(std::string str) +{ + int end = str.length(); + size_t comment = str.find("//"); + if (comment != std::string::npos) + end = comment; + + for (int i = end - 1; i >= 0; i--) + { + if (!isblankorlf(str[i])) + { + end = i + 1; + break; + } + } + + return str.substr(0, end); +} + +static inline int bml_read_depth(std::string &data) +{ + size_t depth; + for (depth = 0; isblank(data[depth]) && depth < data.length(); depth++) {} + return depth == data.length() ? -1 : depth; +} + +static void bml_parse_depth(bml_node &node, std::string &line) +{ + unsigned int depth = bml_read_depth(line); + line.erase(0, depth); + node.depth = depth; +} + +static void bml_parse_name(bml_node &node, std::string &line) +{ + int len; + + for (len = 0; bml_valid(line[len]); len++) {}; + + node.name = trim(line.substr(0, len)); + line.erase(0, len); +} + +static void bml_parse_data(bml_node &node, std::string &line) +{ + int len; + + if (line[0] == '=' && line[1] == '\"') + { + len = 2; + while (line[len] && line[len] != '\"' && !islf(line[len])) + len++; + if (line[len] != '\"') + return; + + node.data = line.substr(2, len - 2); + line.erase(0, len + 1); + } + else if (line[0] == '=') + { + len = 1; + while (line[len] && !islf(line[len]) && line[len] != '"' && line[len] != ' ') + len++; + if (line[len] == '\"') + return; + node.data = line.substr(1, len - 1); + line.erase(0, len); + } + else if (line[0] == ':') + { + len = 1; + while (line[len] && !islf(line[len])) + len++; + node.data = trim(line.substr(1, len - 1)); + line.erase(0, len); + } + + return; +} + +static std::string bml_read_line(std::ifstream &fd) +{ + std::string line; + + while (fd) + { + std::getline(fd, line); + line = trimcomments(line); + if (!line.empty()) + { + return line; + } + } + + return std::string(""); +} + +static void bml_parse_attr(bml_node &node, std::string &line) +{ + int len; + + while (line.length() > 0) + { + if (!isblank(line[0])) + return; + + while (isblank(line[0])) + line.erase(0, 1); + + bml_node n; + len = 0; + while (bml_valid(line[len])) + len++; + if (len == 0) + return; + n.name = trim(line.substr(0, len)); + line.erase(0, len); + bml_parse_data(n, line); + n.depth = node.depth + 1; + n.type = bml_node::ATTRIBUTE; + node.child.push_back(n); + } +} + +static int contains_space(const char *str) +{ + for (int i = 0; str[i]; i++) + { + if (isblank(str[i])) + return 1; + } + + return 0; +} + +static void bml_print_node(bml_node &node, int depth) +{ + int i; + + for (i = 0; i < depth * 2; i++) + { + printf(" "); + } + + if (!node.name.empty()) + printf("%s", node.name.c_str()); + + if (!node.data.empty()) + { + if (contains_space(node.data.c_str())) + printf("=\"%s\"", node.data.c_str()); + else + printf(": %s", node.data.c_str()); + } + for (i = 0; i < (int)node.child.size() && node.child[i].type == bml_node::ATTRIBUTE; i++) + { + if (!node.child[i].name.empty()) + { + printf(" %s", node.child[i].name.c_str()); + if (!node.child[i].data.empty()) + { + if (contains_space(node.child[i].data.c_str())) + printf("=\"%s\"", node.child[i].data.c_str()); + else + printf("=%s", node.child[i].data.c_str()); + } + } + } + + if (depth >= 0) + printf("\n"); + + for (; i < (int)node.child.size(); i++) + { + bml_print_node(node.child[i], depth + 1); + } + + if (depth == 0) + printf("\n"); +} + +void bml_node::print() +{ + bml_print_node(*this, -1); +} + +void bml_node::parse(std::ifstream &fd) +{ + std::stack nodestack; + nodestack.push(this); + + while (fd) + { + bml_node newnode; + std::string line = bml_read_line(fd); + if (line.empty()) + return; + + int line_depth = bml_read_depth(line); + while (line_depth <= nodestack.top()->depth && nodestack.size() > 1) + nodestack.pop(); + + bml_parse_depth(newnode, line); + bml_parse_name(newnode, line); + bml_parse_data(newnode, line); + bml_parse_attr(newnode, line); + + nodestack.top()->child.push_back(newnode); + nodestack.push(&nodestack.top()->child.back()); + } + + return; +} + +bml_node *bml_node::find_subnode(std::string name) +{ + unsigned int i; + + for (i = 0; i < child.size(); i++) + { + if (name.compare(child[i].name) == 0) + return &child[i]; + } + + return NULL; +} + +bool bml_node::parse_file(std::string filename) +{ + std::ifstream file(filename.c_str(), std::ios_base::binary); + + if (!file) + return false; + + parse(file); + + return true; +} diff --git a/snes9x/bml.h b/snes9x/bml.h new file mode 100644 index 0000000..56b6006 --- /dev/null +++ b/snes9x/bml.h @@ -0,0 +1,27 @@ +#ifndef __BML_H +#define __BML_H +#include +#include +#include + +struct bml_node +{ + enum node_type { + CHILD, + ATTRIBUTE + }; + + bml_node(); + bool parse_file(std::string filename); + void parse(std::ifstream &fd); + bml_node *find_subnode(std::string name); + void print(); + + std::string name; + std::string data; + int depth; + std::vector child; + node_type type; +}; + +#endif diff --git a/snes9x/bsx.cpp b/snes9x/bsx.cpp new file mode 100644 index 0000000..2881dbe --- /dev/null +++ b/snes9x/bsx.cpp @@ -0,0 +1,1436 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +// 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" +#include + +//#define BSX_DEBUG + +#define BIOS_SIZE 0x100000 +#define FLASH_SIZE 0x100000 +#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 year; + int month; + int dayweek; + int day; + 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, // ? + 0x1A, 0x00, // 2MB Flash (1MB = 0x2A) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#if 0 +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 +}; +#endif + +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 (void); +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 i, c; + + if (BSX.prevMMC[0x0C]) + { + // 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] = (uint8 *)MAP_BSX; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = TRUE; + BlockIsROM[i] = BlockIsROM[i + 0x800] = FALSE; + } + } + + // 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] = (uint8 *)MAP_BSX; + BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = TRUE; + BlockIsROM[i + 0x400] = BlockIsROM[i + 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.prevMMC[0x02]) + { + //HiROM + for (c = 0; c < 0x80; c += 16) + { + if ((bank & 0x7F0) >= 0x400) + { + 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 (i = c + 8; i < c + 16; i++) + { + Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + } + } + else + { + //LoROM + for (c = 0; c < 0x100; c += 16) + { + if ((bank & 0x7F0) >= 0x400) + { + for (i = c; i < c + 8; i++) + { + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + + for (i = c + 8; i < c + 16; i++) + { + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + } +} + +static void BSX_Map_PSRAM(void) +{ + int c; + + if (!BSX.prevMMC[0x02]) + { + //LoROM Mode + if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 00-0F/80-8F + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x00); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0x80); + } + else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 20-2F/A0-AF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x20); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xA0); + } + else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06]) + { + //Map PSRAM to 40-4F/C0-CF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x40); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xC0); + } + else + { + //Map PSRAM to 60-6F/E0-EF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x60); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xE0); + } + + //Map PSRAM to 70-7D/F0-FF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x70); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xF0); + } + else + { + //HiROM Mode + if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 00-07/40-47 / 80-87/C0-C7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x00); + map_psram_mirror_sub(0x40); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0x80); + map_psram_mirror_sub(0xC0); + } + } + else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 10-17/50-57 / 90-97-D0-D7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x10); + map_psram_mirror_sub(0x50); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0x90); + map_psram_mirror_sub(0xD0); + } + } + else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06]) + { + //Map PSRAM to 20-27/60-67 / A0-A7/E0-E7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x20); + map_psram_mirror_sub(0x60); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0xA0); + map_psram_mirror_sub(0xE0); + } + } + else + { + //Map PSRAM to 30-37/70-77 / B0-B7/F0-F7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x30); + map_psram_mirror_sub(0x70); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0xB0); + map_psram_mirror_sub(0xF0); + } + } + + if (BSX.prevMMC[0x03]) + { + //Map PSRAM to 20->3F: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.prevMMC[0x04]) + { + //Map PSRAM to A0->BF:6000-7FFF + for (c = 0xA00; c < 0xC00; 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; + } + } + } +} + +static void BSX_Map_BIOS (void) +{ + int i,c; + + // Banks 00->1F:8000-FFFF + if (BSX.prevMMC[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.prevMMC[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 (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)); + + MapROM = FlashROM; + FlashSize = FLASH_SIZE; + + if (BSX.prevMMC[0x02]) + BSX_Map_HiROM(); + else + BSX_Map_LoROM(); + + BSX_Map_FlashIO(); + BSX_Map_PSRAM(); + + BSX_Map_SNES(); + BSX_Map_SRAM(); + BSX_Map_RAM(); + + BSX_Map_BIOS(); + BSX_Map_MMC(); + + // Monitor new register changes + BSX.dirty = FALSE; + BSX.dirty2 = FALSE; + + Memory.map_WriteProtectROM(); +} + +static uint8 BSX_Get_Bypass_FlashIO (uint32 offset) +{ + //For games other than BS-X + FlashROM = Memory.ROM + Multi.cartOffsetB; + + if (BSX.prevMMC[0x02]) + return (FlashROM[offset & 0x0FFFFF]); + else + return (FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)]); +} + +static void BSX_Set_Bypass_FlashIO (uint32 offset, uint8 byte) +{ + //For games other than BS-X + FlashROM = Memory.ROM + Multi.cartOffsetB; + + if (BSX.prevMMC[0x02]) + FlashROM[offset & 0x0FFFFF] = FlashROM[offset & 0x0FFFFF] & byte; + else + FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] = FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] & byte; +} + +uint8 S9xGetBSX (uint32 address) +{ + uint8 bank = (address >> 16) & 0xFF; + uint16 offset = address & 0xFFFF; + uint8 t = 0; + + // MMC + if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000)) + return (BSX.MMC[bank]); + + // Flash Mapping + + // default: read-through mode + t = BSX_Get_Bypass_FlashIO(address); + + // note: may be more registers, purposes unknown + switch (offset) + { + case 0x0002: + case 0x8002: + if (BSX.flash_bsr) + t = 0xC0; // Page Status Register + break; + + case 0x0004: + case 0x8004: + if (BSX.flash_gsr) + t = 0x82; // Global 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; + } + + if (BSX.flash_csr) + { + t = 0x80; // Compatible Status Register + BSX.flash_csr = false; + } + + return (t); +} + +void S9xSetBSX (uint8 byte, uint32 address) +{ + uint8 bank = (address >> 16) & 0xFF; + + // MMC + if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000)) + { + //Avoid updating the memory map when it is not needed + if (bank == 0x0E && BSX.dirty) + { + BSX_Map(); + BSX.dirty = FALSE; + } + else if (bank != 0x0E && BSX.MMC[bank] != byte) + { + BSX.dirty = TRUE; + } + + BSX.MMC[bank] = byte; + } + + // Flash IO + + // Write to Flash + if (BSX.write_enable) + { + BSX_Set_Bypass_FlashIO(address, byte); + BSX.write_enable = false; + return; + } + + // Flash Command Handling + + //Memory Pack Type 1 & 3 & 4 + BSX.flash_command <<= 8; + BSX.flash_command |= byte; + + switch (BSX.flash_command & 0xFF) + { + case 0x00: + case 0xFF: + //Reset to normal + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = false; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x10: + case 0x40: + //Write Byte + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = true; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = true; + BSX.flash_cmd_done = true; + break; + + case 0x50: + //Clear Status Register + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = false; + BSX.flash_gsr = false; + BSX.flash_cmd_done = true; + break; + + case 0x70: + //Read CSR + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = true; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x71: + //Read Extended Status Registers (Page and Global) + BSX.flash_enable = false; + BSX.flash_bsr = true; + BSX.flash_csr = false; + BSX.flash_gsr = true; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x75: + //Show Page Buffer / Vendor Info + BSX.flash_csr = false; + BSX.read_enable = true; + BSX.flash_cmd_done = true; + break; + + case 0xD0: + //DO COMMAND + switch (BSX.flash_command & 0xFFFF) + { + case 0x20D0: //Block Erase + uint32 x; + for (x = 0; x < 0x10000; x++) { + //BSX_Set_Bypass_FlashIO(((address & 0xFF0000) + x), 0xFF); + if (BSX.MMC[0x02]) + FlashROM[(address & 0x0F0000) + x] = 0xFF; + else + FlashROM[((address & 0x1E0000) >> 1) + x] = 0xFF; + } + break; + + case 0xA7D0: //Chip Erase (ONLY IN TYPE 1 AND 4) + if ((flashcard[6] & 0xF0) == 0x10 || (flashcard[6] & 0xF0) == 0x40) + { + uint32 x; + for (x = 0; x < FLASH_SIZE; x++) { + //BSX_Set_Bypass_FlashIO(x, 0xFF); + FlashROM[x] = 0xFF; + } + } + break; + + case 0x38D0: //Flashcart Reset + break; + } + break; + } +} + +void S9xBSXSetStream1 (uint8 count) +{ + if (BSX.sat_stream1.is_open()) + BSX.sat_stream1.close(); //If Stream already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream1.clear(); + BSX.sat_stream1.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream1.good()) + { + BSX.sat_stream1.seekg(0, BSX.sat_stream1.end); + long str1size = BSX.sat_stream1.tellg(); + BSX.sat_stream1.seekg(0, BSX.sat_stream1.beg); + float QueueSize = str1size / 22.; + BSX.sat_stream1_queue = (uint16)(ceil(QueueSize)); + BSX.PPU[0x218D - BSXPPUBASE] = 0; + BSX.sat_stream1_first = TRUE; + BSX.sat_stream1_loaded = TRUE; + } + else + { + BSX.sat_stream1_loaded = FALSE; + } +} + +void S9xBSXSetStream2 (uint8 count) +{ + if (BSX.sat_stream2.is_open()) + BSX.sat_stream2.close(); //If Stream already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream2.clear(); + BSX.sat_stream2.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream2.good()) + { + BSX.sat_stream2.seekg(0, BSX.sat_stream2.end); + long str2size = BSX.sat_stream2.tellg(); + BSX.sat_stream2.seekg(0, BSX.sat_stream2.beg); + float QueueSize = str2size / 22.; + BSX.sat_stream2_queue = (uint16)(ceil(QueueSize)); + BSX.PPU[0x2193 - BSXPPUBASE] = 0; + BSX.sat_stream2_first = TRUE; + BSX.sat_stream2_loaded = TRUE; + } + else + { + BSX.sat_stream2_loaded = FALSE; + } +} + +uint8 S9xBSXGetRTC (void) +{ + //Get Time + time_t t; + struct tm *tmr; + + time(&t); + tmr = localtime(&t); + + BSX.test2192[0] = 0x00; + BSX.test2192[1] = 0x00; + BSX.test2192[2] = 0x00; + BSX.test2192[3] = 0x00; + BSX.test2192[4] = 0x10; + BSX.test2192[5] = 0x01; + BSX.test2192[6] = 0x01; + BSX.test2192[7] = 0x00; + BSX.test2192[8] = 0x00; + BSX.test2192[9] = 0x00; + 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; + BSX.test2192[13] = BSX_RTC.dayweek = (tmr->tm_wday) + 1; + BSX.test2192[14] = BSX_RTC.day = tmr->tm_mday; + BSX.test2192[15] = BSX_RTC.month = (tmr->tm_mon) + 1; + BSX_RTC.year = tmr->tm_year + 1900; + BSX.test2192[16] = (BSX_RTC.year) & 0xFF; + BSX.test2192[17] = (BSX_RTC.year) >> 8; + + t = BSX.test2192[BSX.out_index++]; + + if (BSX.out_index > 22) + BSX.out_index = 0; + + return t; +} + +uint8 S9xGetBSXPPU (uint16 address) +{ + uint8 t; + + // known read registers + switch (address) + { + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) + case 0x2188: + t = BSX.PPU[0x2188 - BSXPPUBASE]; + break; + + // Logical Channel 2 (R/W) [6bit] + case 0x2189: + t = BSX.PPU[0x2189 - BSXPPUBASE]; + break; + + // Prefix Count (R) + case 0x218A: + if (!BSX.sat_pf_latch1_enable || !BSX.sat_dt_latch1_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.sat_stream1_queue <= 0) + { + BSX.sat_stream1_count++; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (!BSX.sat_stream1_loaded && (BSX.sat_stream1_count - 1) > 0) + { + BSX.sat_stream1_count = 1; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (BSX.sat_stream1_loaded) + { + //Lock at 0x7F for bigger packets + if (BSX.sat_stream1_queue >= 128) + BSX.PPU[0x218A - BSXPPUBASE] = 0x7F; + else + BSX.PPU[0x218A - BSXPPUBASE] = BSX.sat_stream1_queue; + t = BSX.PPU[0x218A - BSXPPUBASE]; + } + else + t = 0; + break; + + // Prefix Latch (R/W) + case 0x218B: + if (BSX.sat_pf_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218B - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream1_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream1_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream1_first = FALSE; + } + + BSX.sat_stream1_queue--; + + if (BSX.sat_stream1_queue == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x218B - BSXPPUBASE] = temp; + } + + BSX.PPU[0x218D - BSXPPUBASE] |= BSX.PPU[0x218B - BSXPPUBASE]; + t = BSX.PPU[0x218B - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) + case 0x218C: + if (BSX.sat_dt_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218C - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream1_loaded) + { + if (BSX.sat_stream1.eof()) + BSX.PPU[0x218C - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x218C - BSXPPUBASE] = BSX.sat_stream1.get(); + } + t = BSX.PPU[0x218C - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // OR gate (R) + case 0x218D: + t = BSX.PPU[0x218D - BSXPPUBASE]; + BSX.PPU[0x218D - BSXPPUBASE] = 0; + break; + + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) + case 0x218E: + t = BSX.PPU[0x218E - BSXPPUBASE]; + break; + + // Logical Channel 2 (R/W) [6bit] + case 0x218F: + t = BSX.PPU[0x218F - BSXPPUBASE]; + break; + + // Prefix Count (R) + case 0x2190: + if (!BSX.sat_pf_latch2_enable || !BSX.sat_dt_latch2_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.sat_stream2_queue <= 0) + { + BSX.sat_stream2_count++; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (!BSX.sat_stream2_loaded && (BSX.sat_stream2_count - 1) > 0) + { + BSX.sat_stream2_count = 1; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (BSX.sat_stream2_loaded) + { + if (BSX.sat_stream2_queue >= 128) + BSX.PPU[0x2190 - BSXPPUBASE] = 0x7F; + else + BSX.PPU[0x2190 - BSXPPUBASE] = BSX.sat_stream2_queue; + t = BSX.PPU[0x2190 - BSXPPUBASE]; + } + else + t = 0; + break; + + // Prefix Latch (R/W) + case 0x2191: + if (BSX.sat_pf_latch2_enable) + { + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2191 - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream2_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream2_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream2_first = FALSE; + } + + BSX.sat_stream2_queue--; + + if (BSX.sat_stream2_queue == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x2191 - BSXPPUBASE] = temp; + } + + BSX.PPU[0x2193 - BSXPPUBASE] |= BSX.PPU[0x2191 - BSXPPUBASE]; + t = BSX.PPU[0x2191 - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) + case 0x2192: + if (BSX.sat_dt_latch2_enable) + { + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2192 - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream2_loaded) + { + if (BSX.sat_stream2.eof()) + BSX.PPU[0x2192 - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x2192 - BSXPPUBASE] = BSX.sat_stream2.get(); + } + t = BSX.PPU[0x2192 - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // OR gate (R) + case 0x2193: + t = BSX.PPU[0x2193 - BSXPPUBASE]; + BSX.PPU[0x2193 - BSXPPUBASE] = 0; + break; + + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] + case 0x2194: + t = BSX.PPU[0x2194 - BSXPPUBASE]; + break; + + // Unknown + case 0x2195: + t = BSX.PPU[0x2195 - BSXPPUBASE]; + break; + + // Satellaview Status (R) + case 0x2196: + t = BSX.PPU[0x2196 - BSXPPUBASE]; + break; + + // Soundlink Settings (R/W) + case 0x2197: + t = BSX.PPU[0x2197 - BSXPPUBASE]; + break; + + // Serial I/O - Serial Number (R/W) + case 0x2198: + t = BSX.PPU[0x2198 - BSXPPUBASE]; + break; + + // Serial I/O - Unknown (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) + { + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) + case 0x2188: + if (BSX.PPU[0x2188 - BSXPPUBASE] == byte) + { + BSX.sat_stream1_count = 0; + } + BSX.PPU[0x2188 - BSXPPUBASE] = byte; + break; + + // Logical Channel 2 (R/W) [6bit] + case 0x2189: + if (BSX.PPU[0x2188 - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream1_count = 0; + } + BSX.PPU[0x2189 - BSXPPUBASE] = byte & 0x3F; + break; + + // Prefix Latch (R/W) + case 0x218B: + BSX.sat_pf_latch1_enable = (byte != 0); + break; + + // Data Latch (R/W) + case 0x218C: + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch1_enable = (byte != 0); + break; + + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) + case 0x218E: + if (BSX.PPU[0x218E - BSXPPUBASE] == byte) + { + BSX.sat_stream2_count = 0; + } + BSX.PPU[0x218E - BSXPPUBASE] = byte; + break; + + // Logical Channel 2 (R/W) [6bit] + case 0x218F: + if (BSX.PPU[0x218F - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream2_count = 0; + } + BSX.PPU[0x218F - BSXPPUBASE] = byte & 0x3F; + break; + + // Prefix Latch (R/W) + case 0x2191: + BSX.sat_pf_latch2_enable = (byte != 0); + break; + + // Data Latch (R/W) + case 0x2192: + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch2_enable = (byte != 0); + break; + + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] + case 0x2194: + BSX.PPU[0x2194 - BSXPPUBASE] = byte & 0x0F; + break; + + // Soundlink Settings (R/W) + case 0x2197: + BSX.PPU[0x2197 - 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 = FLASH_SIZE; + + // Fix Block Allocation Flags + // (for games that don't have it setup properly, + // for exemple when taken seperately from the upper memory of the Memory Pack, + // else the game will error out on BS-X) + for (; (((header[0x10] & 1) == 0) && header[0x10] != 0); (header[0x10] >>= 1)); + +#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 + BSX.MMC[0x02] = BSX.MMC[0x03] = BSX.MMC[0x05] = BSX.MMC[0x06] = 0x80; + BSX.MMC[0x09] = BSX.MMC[0x0B] = 0x80; + + BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; + BSX.MMC[0x0E] = 0x80; + + // default register values + BSX.PPU[0x2196 - BSXPPUBASE] = 0x10; + BSX.PPU[0x2197 - BSXPPUBASE] = 0x80; + + // stream reset + BSX.sat_pf_latch1_enable = BSX.sat_dt_latch1_enable = FALSE; + BSX.sat_pf_latch2_enable = BSX.sat_dt_latch2_enable = FALSE; + + BSX.sat_stream1_loaded = BSX.sat_stream2_loaded = FALSE; + BSX.sat_stream1_first = BSX.sat_stream2_first = FALSE; + BSX.sat_stream1_count = BSX.sat_stream2_count = 0; + + if (BSX.sat_stream1.is_open()) + BSX.sat_stream1.close(); + + if (BSX.sat_stream2.is_open()) + BSX.sat_stream2.close(); + + if (Settings.BS) + 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); +} diff --git a/snes9x/bsx.h b/snes9x/bsx.h new file mode 100644 index 0000000..b7d3919 --- /dev/null +++ b/snes9x/bsx.h @@ -0,0 +1,58 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _BSX_H_ +#define _BSX_H_ + +#include + +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]; + + bool flash_csr; + bool flash_gsr; + bool flash_bsr; + bool flash_cmd_done; + + std::ifstream sat_stream1; + std::ifstream sat_stream2; + + bool sat_pf_latch1_enable, sat_dt_latch1_enable; + bool sat_pf_latch2_enable, sat_dt_latch2_enable; + + bool sat_stream1_loaded, sat_stream2_loaded; + bool sat_stream1_first, sat_stream2_first; + uint8 sat_stream1_count, sat_stream2_count; + uint16 sat_stream1_queue, sat_stream2_queue; +}; + +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 diff --git a/snes9x/c4.cpp b/snes9x/c4.cpp new file mode 100644 index 0000000..98a1d4c --- /dev/null +++ b/snes9x/c4.cpp @@ -0,0 +1,158 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); + 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)); +} diff --git a/snes9x/c4.h b/snes9x/c4.h new file mode 100644 index 0000000..f840651 --- /dev/null +++ b/snes9x/c4.h @@ -0,0 +1,40 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/c4emu.cpp b/snes9x/c4emu.cpp new file mode 100644 index 0000000..708acab --- /dev/null +++ b/snes9x/c4emu.cpp @@ -0,0 +1,1075 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 = (int64)READ_3WORD(Memory.C4RAM + 0x1f80); + a |= 0xffffffffff000000 * ((a >> 23) & 1); + //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)); + } +} diff --git a/snes9x/cheats.cpp b/snes9x/cheats.cpp new file mode 100644 index 0000000..0b54a0f --- /dev/null +++ b/snes9x/cheats.cpp @@ -0,0 +1,410 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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."); + + // Correct GoldFinger Address + address = (address & 0x7FFF) | ((address & 0x7F8000) << 1) | 0x8000; + + 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, 0x80000); + 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]); + } +} diff --git a/snes9x/cheats.h b/snes9x/cheats.h new file mode 100644 index 0000000..7fbabd7 --- /dev/null +++ b/snes9x/cheats.h @@ -0,0 +1,103 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _CHEATS_H_ +#define _CHEATS_H_ + +#include "port.h" +#include + +struct SCheat +{ + uint32 address; + uint8 byte; + uint8 saved_byte; + bool8 conditional; + bool8 cond_true; + uint8 cond_byte; + bool8 enabled; +}; + +struct SCheatGroup +{ + char *name; + bool8 enabled; + std::vector c; +}; + +struct SCheatData +{ + std::vector g; + bool8 enabled; + uint8 CWRAM[0x20000]; + uint8 CSRAM[0x80000]; + 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]; + +int S9xAddCheatGroup (const char *name, const char *cheat); +int S9xModifyCheatGroup (uint32 index, const char *name, const char *cheat); +void S9xEnableCheatGroup (uint32 index); +void S9xDisableCheatGroup (uint32 index); +void S9xDeleteCheats (void); +char *S9xCheatGroupToText (uint32 index); +void S9xDeleteCheatGroup (uint32 index); +bool8 S9xLoadCheatFile (const char *filename); +bool8 S9xSaveCheatFile (const char *filename); +void S9xUpdateCheatsInMemory (void); +int S9xImportCheatsFromDatabase(const char *filename); +void S9xCheatsDisable (void); +void S9xCheatsEnable (void); +char *S9xCheatValidate (const char *cheat); + +void S9xInitCheatData (void); +void S9xInitWatchedAddress (void); +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 diff --git a/snes9x/cheats2.cpp b/snes9x/cheats2.cpp new file mode 100644 index 0000000..83a2969 --- /dev/null +++ b/snes9x/cheats2.cpp @@ -0,0 +1,767 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include + +#include "snes9x.h" +#include "memmap.h" +#include "cheats.h" +#include "bml.h" + +static inline char *trim (char *string) +{ + int start; + int end; + + for (start = 0; string[start] && isspace (string[start]); start++) {} + for (end = start; string[end] && !isspace (string[end]); end++) {} + string[end] = '\0'; + return &string[start]; +} + +static inline uint8 S9xGetByteFree (uint32 Address) +{ + int block = (Address & 0xffffff) >> MEMMAP_SHIFT; + uint8 *GetAddress = Memory.Map[block]; + uint8 byte; + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { + byte = *(GetAddress + (Address & 0xffff)); + return (byte); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_CPU: + byte = S9xGetCPU(Address & 0xffff); + return (byte); + + case CMemory::MAP_PPU: + if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) + return (OpenBus); + + byte = S9xGetPPU(Address & 0xffff); + 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)); + 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 & 0x1f0000) >> 3)) & Memory.SRAMMask)); + return (byte); + + case CMemory::MAP_BWRAM: + byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); + return (byte); + + case CMemory::MAP_DSP: + byte = S9xGetDSP(Address & 0xffff); + return (byte); + + case CMemory::MAP_SPC7110_ROM: + byte = S9xGetSPC7110Byte(Address); + return (byte); + + case CMemory::MAP_SPC7110_DRAM: + byte = S9xGetSPC7110(0x4800); + return (byte); + + case CMemory::MAP_C4: + byte = S9xGetC4(Address & 0xffff); + return (byte); + + case CMemory::MAP_OBC_RAM: + byte = S9xGetOBC1(Address & 0xffff); + return (byte); + + case CMemory::MAP_SETA_DSP: + byte = S9xGetSetaDSP(Address); + return (byte); + + case CMemory::MAP_SETA_RISC: + byte = S9xGetST018(Address); + return (byte); + + case CMemory::MAP_BSX: + byte = S9xGetBSX(Address); + return (byte); + + case CMemory::MAP_NONE: + default: + byte = OpenBus; + return (byte); + } +} + +static inline void S9xSetByteFree (uint8 Byte, uint32 Address) +{ + int block = (Address & 0xffffff) >> MEMMAP_SHIFT; + uint8 *SetAddress = Memory.Map[block]; + + if (SetAddress >= (uint8 *) CMemory::MAP_LAST) + { + *(SetAddress + (Address & 0xffff)) = Byte; + return; + } + + switch ((pint) SetAddress) + { + case CMemory::MAP_CPU: + S9xSetCPU(Byte, Address & 0xffff); + return; + + case CMemory::MAP_PPU: + if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) + return; + + S9xSetPPU(Byte, Address & 0xffff); + return; + + case CMemory::MAP_LOROM_SRAM: + if (Memory.SRAMMask) + { + *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = Byte; + CPU.SRAMModified = TRUE; + } + + return; + + case CMemory::MAP_LOROM_SRAM_B: + if (Multi.sramMaskB) + { + *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = Byte; + CPU.SRAMModified = TRUE; + } + + return; + + case CMemory::MAP_HIROM_SRAM: + if (Memory.SRAMMask) + { + *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0x1f0000) >> 3)) & Memory.SRAMMask)) = Byte; + CPU.SRAMModified = TRUE; + } + return; + + case CMemory::MAP_BWRAM: + *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte; + CPU.SRAMModified = TRUE; + return; + + case CMemory::MAP_SA1RAM: + *(Memory.SRAM + (Address & 0xffff)) = Byte; + return; + + case CMemory::MAP_DSP: + S9xSetDSP(Byte, Address & 0xffff); + return; + + case CMemory::MAP_C4: + S9xSetC4(Byte, Address & 0xffff); + return; + + case CMemory::MAP_OBC_RAM: + S9xSetOBC1(Byte, Address & 0xffff); + return; + + case CMemory::MAP_SETA_DSP: + S9xSetSetaDSP(Byte, Address); + return; + + case CMemory::MAP_SETA_RISC: + S9xSetST018(Byte, Address); + return; + + case CMemory::MAP_BSX: + S9xSetBSX(Byte, Address); + return; + + case CMemory::MAP_NONE: + default: + return; + } +} + +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 S9xUpdateCheatInMemory (SCheat *c) +{ + uint8 byte; + + if (!c->enabled) + return; + + byte = S9xGetByteFree (c->address); + + if (byte != c->byte) + { + /* The game wrote a different byte to the address, update saved_byte */ + c->saved_byte = byte; + + if (c->conditional) + { + if (c->saved_byte != c->cond_byte && c->cond_true) + { + /* Condition is now false, let the byte stand */ + c->cond_true = false; + } + else if (c->saved_byte == c->cond_byte && !c->cond_true) + { + c->cond_true = true; + S9xSetByteFree (c->byte, c->address); + } + } + else + S9xSetByteFree (c->byte, c->address); + } + else if (c->conditional) + { + if (byte == c->cond_byte) + { + c->cond_true = true; + c->saved_byte = byte; + S9xSetByteFree (c->byte, c->address); + } + } +} + +void S9xDisableCheat (SCheat *c) +{ + if (!c->enabled) + return; + + if (!Cheat.enabled) + { + c->enabled = false; + return; + } + + /* Make sure we restore the up-to-date written byte */ + S9xUpdateCheatInMemory (c); + c->enabled = false; + + if (c->conditional && !c->cond_true) + return; + + S9xSetByteFree (c->saved_byte, c->address); + c->cond_true = false; +} + +void S9xDeleteCheatGroup (uint32 g) +{ + unsigned int i; + + if (g >= Cheat.g.size ()) + return; + + for (i = 0; i < Cheat.g[g].c.size (); i++) + { + S9xDisableCheat (&Cheat.g[g].c[i]); + } + + delete[] Cheat.g[g].name; + + Cheat.g.erase (Cheat.g.begin () + g); +} + +void S9xDeleteCheats (void) +{ + unsigned int i; + + for (i = 0; i < Cheat.g.size (); i++) + { + S9xDisableCheatGroup (i); + + delete[] Cheat.g[i].name; + } + + Cheat.g.clear (); +} + +void S9xEnableCheat (SCheat *c) +{ + uint8 byte; + + if (c->enabled) + return; + + c->enabled = true; + + if (!Cheat.enabled) + return; + + byte = S9xGetByteFree(c->address); + + if (c->conditional) + { + if (byte != c->cond_byte) + return; + + c->cond_true = true; + } + + c->saved_byte = byte; + S9xSetByteFree (c->byte, c->address); +} + +void S9xEnableCheatGroup (uint32 num) +{ + unsigned int i; + + for (i = 0; i < Cheat.g[num].c.size (); i++) + { + S9xEnableCheat (&Cheat.g[num].c[i]); + } + + Cheat.g[num].enabled = true; +} + +void S9xDisableCheatGroup (uint32 num) +{ + unsigned int i; + + for (i = 0; i < Cheat.g[num].c.size (); i++) + { + S9xDisableCheat (&Cheat.g[num].c[i]); + } + + Cheat.g[num].enabled = false; +} + +SCheat S9xTextToCheat (char *text) +{ + SCheat c; + unsigned int byte = 0; + unsigned int cond_byte = 0; + + c.enabled = false; + c.conditional = false; + + if (!S9xGameGenieToRaw (text, c.address, c.byte)) + { + byte = c.byte; + } + + else if (!S9xProActionReplayToRaw (text, c.address, c.byte)) + { + byte = c.byte; + } + + else if (sscanf (text, "%x = %x ? %x", &c.address, &cond_byte, &byte) == 3) + { + c.conditional = true; + } + + else if (sscanf (text, "%x = %x", &c.address, &byte) == 2) + { + } + + else if (sscanf (text, "%x / %x / %x", &c.address, &cond_byte, &byte) == 3) + { + c.conditional = true; + } + + else if (sscanf (text, "%x / %x", &c.address, &byte) == 2) + { + } + + else + { + c.address = 0; + byte = 0; + } + + c.byte = byte; + c.cond_byte = cond_byte; + + return c; +} + +SCheatGroup S9xCreateCheatGroup (const char *name, const char *cheat) +{ + SCheatGroup g; + char *code_string = strdup (cheat); + char *code_ptr = code_string; + int len; + + g.name = strdup (name); + g.enabled = false; + + for (len = strcspn (code_ptr, "+"); len; len = strcspn (code_ptr, "+")) + { + char *code = code_ptr; + code_ptr += len + (code_ptr[len] == '\0' ? 0 : 1); + code[len] = '\0'; + code = trim (code); + + SCheat c = S9xTextToCheat (code); + if (c.address) + g.c.push_back (c); + } + + free(code_string); + + return g; +} + +int S9xAddCheatGroup (const char *name, const char *cheat) +{ + SCheatGroup g = S9xCreateCheatGroup (name, cheat); + if (g.c.size () == 0) + return -1; + + Cheat.g.push_back (g); + + return Cheat.g.size () - 1; +} + +int S9xModifyCheatGroup (uint32 num, const char *name, const char *cheat) +{ + if (num >= Cheat.g.size()) + return -1; + + S9xDisableCheatGroup (num); + delete[] Cheat.g[num].name; + + Cheat.g[num] = S9xCreateCheatGroup (name, cheat); + + return num; +} + +char *S9xCheatToText (SCheat *c) +{ + int size = 10; /* 6 address, 1 =, 2 byte, 1 NUL */ + char *text; + + if (c->conditional) + size += 3; /* additional 2 byte, 1 ? */ + + text = new char[size]; + + if (c->conditional) + snprintf (text, size, "%06x=%02x?%02x", c->address, c->cond_byte, c->byte); + else + snprintf (text, size, "%06x=%02x", c->address, c->byte); + + return text; +} + +char *S9xCheatGroupToText (SCheatGroup *g) +{ + std::string text = ""; + unsigned int i; + + if (g->c.size () == 0) + return NULL; + + for (i = 0; i < g->c.size (); i++) + { + char *tmp = S9xCheatToText (&g->c[i]); + if (i != 0) + text += " + "; + text += tmp; + delete[] tmp; + } + + return strdup (text.c_str ()); +} + +char *S9xCheatValidate (const char *code_string) +{ + SCheatGroup g = S9xCreateCheatGroup ("temp", code_string); + + delete[] g.name; + + if (g.c.size() > 0) + { + return S9xCheatGroupToText (&g); + } + + return NULL; +} + +char *S9xCheatGroupToText (uint32 num) +{ + if (num >= Cheat.g.size ()) + return NULL; + + return S9xCheatGroupToText (&Cheat.g[num]); +} + +void S9xUpdateCheatsInMemory (void) +{ + unsigned int i; + unsigned int j; + + if (!Cheat.enabled) + return; + + for (i = 0; i < Cheat.g.size (); i++) + { + for (j = 0; j < Cheat.g[i].c.size (); j++) + { + S9xUpdateCheatInMemory (&Cheat.g[i].c[j]); + } + } +} + +static int S9xCheatIsDuplicate (const char *name, const char *code) +{ + unsigned int i; + + for (i = 0; i < Cheat.g.size(); i++) + { + if (!strcmp (name, Cheat.g[i].name)) + { + char *code_string = S9xCheatGroupToText (i); + char *validated = S9xCheatValidate (code); + + if (validated && !strcmp (code_string, validated)) + { + free (code_string); + free (validated); + return TRUE; + } + + free (code_string); + free (validated); + } + } + + return FALSE; +} + +static void S9xLoadCheatsFromBMLNode (bml_node *n) +{ + unsigned int i; + + for (i = 0; i < n->child.size (); i++) + { + if (!strcasecmp (n->child[i].name.c_str(), "cheat")) + { + const char *desc = NULL; + const char *code = NULL; + bool8 enabled = false; + + bml_node *c = &n->child[i]; + bml_node *tmp = NULL; + + tmp = c->find_subnode("name"); + if (!tmp) + desc = (char *) ""; + else + desc = tmp->data.c_str(); + + tmp = c->find_subnode("code"); + if (tmp) + code = tmp->data.c_str(); + + if (c->find_subnode("enable")) + enabled = true; + + if (code && !S9xCheatIsDuplicate (desc, code)) + { + int index = S9xAddCheatGroup (desc, code); + + if (enabled) + S9xEnableCheatGroup (index); + } + } + } + + return; +} + +static bool8 S9xLoadCheatFileClassic (const char *filename) +{ + FILE *fs; + uint8 data[28]; + + fs = fopen(filename, "rb"); + if (!fs) + return (FALSE); + + while (fread ((void *) data, 1, 28, fs) == 28) + { + SCheat c; + char name[21]; + char cheat[10]; + c.enabled = (data[0] & 4) == 0; + c.byte = data[1]; + c.address = data[2] | (data[3] << 8) | (data[4] << 16); + memcpy (name, &data[8], 20); + name[20] = 0; + + snprintf (cheat, 10, "%x=%x", c.address, c.byte); + S9xAddCheatGroup (name, cheat); + + if (c.enabled) + S9xEnableCheatGroup (Cheat.g.size () - 1); + } + + fclose(fs); + + return (TRUE); +} + +bool8 S9xLoadCheatFile (const char *filename) +{ + bml_node bml; + if (!bml.parse_file(filename)) + { + return S9xLoadCheatFileClassic (filename); + } + + bml_node *n = bml.find_subnode("cheat"); + if (n) + { + S9xLoadCheatsFromBMLNode (&bml); + } + + if (!n) + { + return S9xLoadCheatFileClassic (filename); + } + + return (TRUE); +} + +bool8 S9xSaveCheatFile (const char *filename) +{ + unsigned int i; + FILE *file = NULL; + + if (Cheat.g.size () == 0) + { + remove (filename); + return TRUE; + } + + file = fopen (filename, "w"); + + if (!file) + return FALSE; + + for (i = 0; i < Cheat.g.size (); i++) + { + char *txt = S9xCheatGroupToText (i); + + fprintf (file, + "cheat\n" + " name: %s\n" + " code: %s\n" + "%s\n", + Cheat.g[i].name ? Cheat.g[i].name : "", + txt, + Cheat.g[i].enabled ? " enable\n" : "" + ); + + delete[] txt; + } + + fclose (file); + + return TRUE; +} + +void S9xCheatsDisable (void) +{ + unsigned int i; + + if (!Cheat.enabled) + return; + + for (i = 0; i < Cheat.g.size (); i++) + { + if (Cheat.g[i].enabled) + { + S9xDisableCheatGroup (i); + Cheat.g[i].enabled = TRUE; + } + } + + Cheat.enabled = FALSE; +} + +void S9xCheatsEnable (void) +{ + unsigned int i; + + if (Cheat.enabled) + return; + + Cheat.enabled = TRUE; + + for (i = 0; i < Cheat.g.size (); i++) + { + if (Cheat.g[i].enabled) + { + Cheat.g[i].enabled = FALSE; + S9xEnableCheatGroup (i); + } + } +} + +int S9xImportCheatsFromDatabase (const char *filename) +{ + char sha256_txt[65]; + char hextable[] = "0123456789abcdef"; + unsigned int i; + + bml_node bml; + if (!bml.parse_file(filename)) + return -1; // No file + + for (i = 0; i < 32; i++) + { + sha256_txt[i * 2] = hextable[Memory.ROMSHA256[i] >> 4]; + sha256_txt[i * 2 + 1] = hextable[Memory.ROMSHA256[i] & 0xf]; + } + sha256_txt[64] = '\0'; + + for (i = 0; i < bml.child.size (); i++) + { + if (!strcasecmp (bml.child[i].name.c_str(), "cartridge")) + { + bml_node *n; + + if ((n = bml.child[i].find_subnode ("sha256"))) + { + if (!strcasecmp (n->data.c_str(), sha256_txt)) + { + S9xLoadCheatsFromBMLNode (&bml.child[i]); + return 0; + } + } + } + } + + return -2; /* No codes */ +} diff --git a/snes9x/clip.cpp b/snes9x/clip.cpp new file mode 100644 index 0000000..2578fd5 --- /dev/null +++ b/snes9x/clip.cpp @@ -0,0 +1,234 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); + } + } +} diff --git a/snes9x/compat.cpp b/snes9x/compat.cpp new file mode 100644 index 0000000..e03d3d8 --- /dev/null +++ b/snes9x/compat.cpp @@ -0,0 +1,67 @@ +#include +#include "port.h" + +void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext) +{ + char *slash = strrchr((char *)path, SLASH_CHAR); + char *dot = strrchr((char *)path, '.'); + + *drive = '\0'; + + if (dot && slash && dot < slash) + { + dot = 0; + } + + 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 *drive, const char *dir, const char *fname, const char *ext) +{ + if (dir && *dir) + { + strcpy(path, dir); + strcat(path, "/"); + } + else + *path = '\0'; + + strcat(path, fname); + + if (ext && *ext) + { + if (*ext != '.') + strcat(path, "."); + strcat(path, ext); + } +} diff --git a/snes9x/conffile.cpp b/snes9x/conffile.cpp new file mode 100644 index 0000000..fa7de3f --- /dev/null +++ b/snes9x/conffile.cpp @@ -0,0 +1,486 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + fStream fS(s); + LoadFile(&fS, 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)) + { + printf ("Error writing config file %s\n", filename); + } + + 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) const{ + 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 +#include + +#ifdef UNZIP_SUPPORT +# ifdef SYSTEM_ZIP +# include +# else +# include "unzip/unzip.h" +# endif +#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) const; + }; + + 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 diff --git a/snes9x/controls.cpp b/snes9x/controls.cpp new file mode 100644 index 0000000..2ef629f --- /dev/null +++ b/snes9x/controls.cpp @@ -0,0 +1,3748 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 MACSRIFLE 13 +#define NUMCTLS 14 // 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 MACSRIFLE_TRIGGER 0x01 + +#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 struct +{ + int16 x, y; + uint8 buttons; + uint32 ID; + struct crosshair crosshair; +} macsrifle; + +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 void DoMacsRifleLatch (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 void DoMacsRifleLatch (int x, int y) +{ + PPU.GunVLatch = (uint16) (y + 42);// + (int16) macsrifle.adjust_y; + PPU.GunHLatch = (uint16) (x + 76);// + (int16) macsrifle.adjust_x; +} + +static int maptype (int t) +{ + switch (t) + { + case S9xNoMapping: + return (MAP_NONE); + + case S9xButtonJoypad: + case S9xButtonMouse: + case S9xButtonSuperscope: + case S9xButtonJustifier: + case S9xButtonMacsRifle: + 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; + macsrifle.buttons = 0; +} + +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; + + curcontrollers[0] = newcontrollers[0]; + curcontrollers[1] = newcontrollers[1]; +} + +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; + + macsrifle.x = macsrifle.y = 0; + macsrifle.buttons = 0; + macsrifle.ID = InvalidControlID; + + if (!(macsrifle.crosshair.set & 1)) + macsrifle.crosshair.img = 2; + if (!(macsrifle.crosshair.set & 2)) + macsrifle.crosshair.fg = 5; + if (!(macsrifle.crosshair.set & 4)) + macsrifle.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_MACSRIFLE: + if (!Settings.MacsRifleMaster) + { + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled"); + break; + } + + newcontrollers[port] = MACSRIFLE; + 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 MACSRIFLE: + if (!Settings.MacsRifleMaster) + { + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES M.A.C.S. Rifle: MacsRifleMaster disabled"); + newcontrollers[port] = NONE; + ret = true; + break; + } + + if (used[i]++ > 0) + { + snprintf(buf, sizeof(buf), "M.A.C.S. Rifle 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; + + case MACSRIFLE: + *controller = CTL_MACSRIFLE; + *id1 = 1; + 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; + + case MACSRIFLE: + if (port == 0) + c += sprintf(c, "M.A.C.S. Rifle (cannot fire). "); + else + c += sprintf(c, "M.A.C.S. Rifle. "); + 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 S9xButtonMacsRifle: + if (!command.button.macsrifle.trigger) + return (strdup("None")); + + s = "MacsRifle"; + + c = ' '; + if (command.button.macsrifle.trigger) { s += c; s += "Trigger"; 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 && !command.pointer.aim_macsrifle) + 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 = '+'; } + if (command.pointer.aim_macsrifle) { s += c; s += "MacsRifle"; 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, "MacsRifle ", 10)) + { + s = name + 10; + i = 0; + + if ((cmd.button.macsrifle.trigger = strncmp(s, "Trigger", 7) ? 0 : 1)) { s += i = 7; } + + if (i == 0 || *s != 0 || *(s - 1) == '+') + return (cmd); + + cmd.type = S9xButtonMacsRifle; + } + 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 (*s == '+') s++; } + if ((cmd.pointer.aim_macsrifle = strncmp(s, "MacsRifle", 9) ? 0 : 1)) { s += i = 9; } + + 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 (macsrifle.ID == id) macsrifle.ID = 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 S9xButtonMacsRifle: + t = MACSRIFLE; + 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); + } + + if (mapping.pointer.aim_macsrifle && macsrifle.ID != InvalidControlID && macsrifle.ID != id) + { + fprintf(stderr, "ERROR: Rejecting attempt to control M.A.C.S. Rifle 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); + if (mapping.pointer.aim_macsrifle ) pollmap[MACSRIFLE ].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; + if (mapping.pointer.aim_macsrifle ) macsrifle.ID = 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; + + 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 S9xButtonMacsRifle: + i = 0; + if (cmd.button.macsrifle.trigger) i |= MACSRIFLE_TRIGGER; + + if(data1) + macsrifle.buttons |= i; + else + macsrifle.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: + break; + + case SaveFreezeFile: + 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)) + { + snprintf(buf, 256, "%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)) + { + snprintf(buf, 256, "%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); + + snprintf(buf, 256, "%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; + } + +#ifdef NETPLAY_SUPPORT + if (Settings.NetPlay && data2 != 1) { //data2 == 1 means it's sent by the netplay code + if (Settings.NetPlayServer) { + S9xNPSendJoypadSwap(); + } else { + S9xSetInfoString("Netplay Client cannot swap pads."); + break; + } + } +#endif + + 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; + } + + if (cmd.pointer.aim_macsrifle) + { + macsrifle.x = data1; + macsrifle.y = 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 = false; + if (S9xPollButton(*itr, &pressed)) + S9xReportButton(*itr, pressed); + break; + } + + case MAP_AXIS: + { + int16 value = 0; + if (S9xPollAxis(*itr, &value)) + S9xReportAxis(*itr, value); + 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; j < 4; ++j) + { + 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; + + case MACSRIFLE: + do_polling(i); + break; + + default: + break; + } + } + } + + FLAG_LATCH = latch; +} + +// prevent read_idx from overflowing (only latching resets it) +// otherwise $4016/7 reads will start returning input data again +static inline uint8 IncreaseReadIdxPost(uint8 &var) +{ + uint8 oldval = var; + if (var < 255) + var++; + return oldval; +} + +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); + + case MACSRIFLE: + do_polling(i); + return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0)); + + default: + return (bits); + } + } + else + { + switch (i = curcontrollers[n]) + { + case MP5: + r = IncreaseReadIdxPost(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) + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits | 1); + } + else + return (bits | ((joypad[i - JOYPAD0].buttons & (0x8000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + + case MOUSE0: + case MOUSE1: + if (read_idx[n][0] < 8) + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits); + } + else + if (read_idx[n][0] < 16) + return (bits | ((mouse[i - MOUSE0].buttons & (0x8000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + if (read_idx[n][0] < 24) + return (bits | ((mouse[i - MOUSE0].delta_y & (0x800000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + if (read_idx[n][0] < 32) + return (bits | ((mouse[i - MOUSE0].delta_x & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits | 1); + } + + case SUPERSCOPE: + if (read_idx[n][0] < 8) + return (bits | ((superscope.read_buttons & (0x80 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits | 1); + } + + case ONE_JUSTIFIER: + if (read_idx[n][0] < 24) + return (bits | ((0xaa7000 >> IncreaseReadIdxPost(read_idx[n][0])) & 1)); + else + if (read_idx[n][0] < 32) + return (bits | ((justifier.buttons & (JUSTIFIER_TRIGGER | JUSTIFIER_START | JUSTIFIER_SELECT) & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits | 1); + } + + case TWO_JUSTIFIERS: + if (read_idx[n][0] < 24) + return (bits | ((0xaa7000 >> IncreaseReadIdxPost(read_idx[n][0])) & 1)); + else + if (read_idx[n][0] < 32) + return (bits | ((justifier.buttons & (0x80000000 >> IncreaseReadIdxPost(read_idx[n][0]))) ? 1 : 0)); + else + { + IncreaseReadIdxPost(read_idx[n][0]); + return (bits | 1); + } + + case MACSRIFLE: + do_polling(i); + return (bits | ((macsrifle.buttons & 0x01) ? 1 : 0)); + + default: + IncreaseReadIdxPost(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; + + case MACSRIFLE: + read_idx[n][0] = 16; + Memory.FillRAM[0x4218 + n * 2] = 0xff; + Memory.FillRAM[0x4219 + n * 2] = macsrifle.buttons; + 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; j < 4; ++j) + { + 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; + + case MACSRIFLE: + if (n == 1) + { + DoMacsRifleLatch(macsrifle.x, macsrifle.y); + + c = &macsrifle.crosshair; + if (IPPU.RenderThisFrame) + S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, macsrifle.x, macsrifle.y); + } + + 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); + + 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; + case X_MACSRIFLE: c = &macsrifle.crosshair; 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; + case X_MACSRIFLE: c = &macsrifle.crosshair; 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 = 4; + + 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 + #define COPY(x) { memcpy((char *) s->internal_macs + i, &(x), sizeof(x)); i += sizeof(x); } + i = 0; + + COPY(macsrifle.x); + COPY(macsrifle.y); + COPY(macsrifle.buttons); + + assert(i == sizeof(s->internal_macs)); + +#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)); + + if (s->ver > 3) + { + #undef COPY + #define COPY(x) { memcpy(&(x), (char *) s->internal_macs + i, sizeof(x)); i += sizeof(x); } + i = 0; + + COPY(macsrifle.x); + COPY(macsrifle.y); + COPY(macsrifle.buttons); + + assert(i == sizeof(s->internal_macs)); + } + + #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; +} + +bool MovieGetMacsRifle (int i, uint8 out[5]) +{ + if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE) + return (false); + + uint8 *ptr = out; + + WRITE_WORD(ptr, macsrifle.x); ptr += 2; + WRITE_WORD(ptr, macsrifle.y); ptr += 2; + *ptr = macsrifle.buttons; + + return (true); +} + +void MovieSetMacsRifle (int i, uint8 in[5]) +{ + if (i < 0 || i > 1 || curcontrollers[i] != MACSRIFLE) + return; + + uint8 *ptr = in; + + macsrifle.x = READ_WORD(ptr); ptr += 2; + macsrifle.y = READ_WORD(ptr); ptr += 2; + macsrifle.buttons = *ptr; +} + diff --git a/snes9x/controls.h b/snes9x/controls.h new file mode 100644 index 0000000..a96d586 --- /dev/null +++ b/snes9x/controls.h @@ -0,0 +1,291 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 S9xButtonMacsRifle 7 +#define S9xAxisJoypad 8 +#define S9xPointer 9 + +#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; + + struct + { + uint8 trigger:1; + } macsrifle; + + 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; + uint16 aim_macsrifle: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) + CTL_MACSRIFLE +}; + +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! + uint8 internal_macs[5]; +}; + +void S9xControlPreSaveState (struct SControlSnapshot *s); +void S9xControlPostLoadState (struct SControlSnapshot *s); + +#endif diff --git a/snes9x/cpu.cpp b/snes9x/cpu.cpp new file mode 100644 index 0000000..f77f149 --- /dev/null +++ b/snes9x/cpu.cpp @@ -0,0 +1,172 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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.NMIPending = FALSE; + CPU.IRQLine = FALSE; + CPU.IRQTransition = FALSE; + CPU.IRQExternal = FALSE; + 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; + Timings.NextIRQTimer = 0x0fffffff; + Timings.IRQFlagChanging = IRQ_NONE; + + 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); + + S9xResetBSX(); + S9xResetCPU(); + S9xResetPPU(); + S9xResetDMA(); + S9xResetAPU(); + S9xResetMSU(); + + 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(); + if (Settings.MSU1) + S9xMSU1Init(); + + S9xInitCheatData(); +} + +void S9xSoftReset (void) +{ + S9xResetSaveTimer(FALSE); + + memset(Memory.FillRAM, 0, 0x8000); + + if (Settings.BS) + S9xResetBSX(); + + S9xSoftResetCPU(); + S9xSoftResetPPU(); + S9xResetDMA(); + S9xSoftResetAPU(); + S9xResetMSU(); + + 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(); + if (Settings.MSU1) + S9xMSU1Init(); + + S9xInitCheatData(); +} diff --git a/snes9x/cpuaddr.h b/snes9x/cpuaddr.h new file mode 100644 index 0000000..47e1aa6 --- /dev/null +++ b/snes9x/cpuaddr.h @@ -0,0 +1,521 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); + + 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 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 diff --git a/snes9x/cpuexec.cpp b/snes9x/cpuexec.cpp new file mode 100644 index 0000000..cd2b1ba --- /dev/null +++ b/snes9x/cpuexec.cpp @@ -0,0 +1,425 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "memmap.h" +#include "cpuops.h" +#include "dma.h" +#include "apu/apu.h" +#include "fxemu.h" +#include "snapshot.h" +#include "movie.h" +#ifdef DEBUGGER +#include "debug.h" +#include "missing.h" +#endif + +static inline void S9xReschedule (void); + +void S9xMainLoop (void) +{ + #define CHECK_FOR_IRQ_CHANGE() \ + if (Timings.IRQFlagChanging) \ + { \ + if (Timings.IRQFlagChanging & IRQ_TRIGGER_NMI) \ + { \ + CPU.NMIPending = TRUE; \ + Timings.NMITriggerPos = CPU.Cycles + 6; \ + } \ + if (Timings.IRQFlagChanging & IRQ_CLEAR_FLAG) \ + ClearIRQ(); \ + else if (Timings.IRQFlagChanging & IRQ_SET_FLAG) \ + SetIRQ(); \ + Timings.IRQFlagChanging = IRQ_NONE; \ + } + + if (CPU.Flags & SCAN_KEYS_FLAG) + { + CPU.Flags &= ~SCAN_KEYS_FLAG; + S9xMovieUpdate(); + } + + for (;;) + { + if (CPU.NMIPending) + { + #ifdef DEBUGGER + if (Settings.TraceHCEvent) + S9xTraceFormattedMessage ("Comparing %d to %d\n", Timings.NMITriggerPos, CPU.Cycles); + #endif + if (Timings.NMITriggerPos <= CPU.Cycles) + { + CPU.NMIPending = FALSE; + Timings.NMITriggerPos = 0xffff; + if (CPU.WaitingForInterrupt) + { + CPU.WaitingForInterrupt = FALSE; + Registers.PCw++; + CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2; + while (CPU.Cycles >= CPU.NextEvent) + S9xDoHEventProcessing(); + } + + CHECK_FOR_IRQ_CHANGE(); + S9xOpcode_NMI(); + } + } + + if (CPU.Cycles >= Timings.NextIRQTimer) + { + #ifdef DEBUGGER + S9xTraceMessage ("Timer triggered\n"); + #endif + + S9xUpdateIRQPositions(false); + CPU.IRQLine = TRUE; + } + + if (CPU.IRQLine || CPU.IRQExternal) + { + if (CPU.WaitingForInterrupt) + { + CPU.WaitingForInterrupt = FALSE; + Registers.PCw++; + CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2; + while (CPU.Cycles >= CPU.NextEvent) + S9xDoHEventProcessing(); + } + + if (!CheckFlag(IRQ)) + { + /* The flag pushed onto the stack is the new value */ + CHECK_FOR_IRQ_CHANGE(); + S9xOpcode_IRQ(); + } + } + + /* Change IRQ flag for instructions that set it only on last cycle */ + CHECK_FOR_IRQ_CHANGE(); + + #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) + { + #ifdef DEBUGGER + if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) + #endif + { + S9xSyncSpeed(); + } + + break; + } + + uint8 Op; + struct SOpcodes *Opcodes; + + if (CPU.PCBase) + { + Op = CPU.PCBase[Registers.PCw]; + CPU.Cycles += CPU.MemSpeed; + 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; + } + + Registers.PCw++; + (*Opcodes[Op].S9xOpcode)(); + + if (Settings.SA1) + S9xSA1MainLoop(); + } + + S9xPackStatus(); +} + +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 VC:%04d", + eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles, CPU.V_Counter); +#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; + if (Timings.NMITriggerPos != 0xffff) + Timings.NMITriggerPos -= Timings.H_Max; + if (Timings.NextIRQTimer != 0x0fffffff) + Timings.NextIRQTimer -= Timings.H_Max; + S9xAPUSetReferenceTime(CPU.Cycles); + + if (Settings.SA1) + SA1.Cycles -= Timings.H_Max * 3; + + 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; + + ICPU.Frame++; + PPU.HVBeamCounterLatched = 0; + } + + // 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(); + + CPU.Flags |= SCAN_KEYS_FLAG; + + 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) + { +#ifdef DEBUGGER + if (Settings.TraceHCEvent) + S9xTraceFormattedMessage ("NMI Scheduled for next scanline."); +#endif + // FIXME: triggered at HC=6, checked just before the final CPU cycle, + // then, when to call S9xOpcode_NMI()? + CPU.NMIPending = 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.Cycles += SNES_WRAM_REFRESH_CYCLES; + + 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 +} diff --git a/snes9x/cpuexec.h b/snes9x/cpuexec.h new file mode 100644 index 0000000..ed02555 --- /dev/null +++ b/snes9x/cpuexec.h @@ -0,0 +1,102 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + } + } +} + +#endif diff --git a/snes9x/cpumacro.h b/snes9x/cpumacro.h new file mode 100644 index 0000000..e2bf7a3 --- /dev/null +++ b/snes9x/cpumacro.h @@ -0,0 +1,674 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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()) + { + uint32 result; + uint32 carry = CheckCarry(); + + result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry; + if (result > 0x0009) + result += 0x0006; + carry = (result > 0x000F); + + result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10; + if (result > 0x009F) + result += 0x0060; + carry = (result > 0x00FF); + + result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100; + if (result > 0x09FF) + result += 0x0600; + carry = (result > 0x0FFF); + + result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000; + + if ((Registers.A.W & 0x8000) == (Work16 & 0x8000) && (Registers.A.W & 0x8000) != (result & 0x8000)) + SetOverflow(); + else + ClearOverflow(); + + if (result > 0x9FFF) + result += 0x6000; + + if (result > 0xFFFF) + SetCarry(); + else + ClearCarry(); + + Registers.A.W = result & 0xFFFF; + 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()) + { + uint32 result; + uint32 carry = CheckCarry(); + + result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry; + if ( result > 0x09 ) + result += 0x06; + carry = (result > 0x0F); + + result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + (carry * 0x10); + + if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80)) + SetOverflow(); + else + ClearOverflow(); + + if (result > 0x9F) + result += 0x60; + + if (result > 0xFF) + SetCarry(); + else + ClearCarry(); + + Registers.AL = result & 0xFF; + 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()) + { + int result; + int carry = CheckCarry(); + + Work16 ^= 0xFFFF; + + result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry; + if (result < 0x0010) + result -= 0x0006; + carry = (result > 0x000F); + + result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10; + if (result < 0x0100) + result -= 0x0060; + carry = (result > 0x00FF); + + result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100; + if (result < 0x1000) + result -= 0x0600; + carry = (result > 0x0FFF); + + result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000; + + if (((Registers.A.W ^ Work16) & 0x8000) == 0 && ((Registers.A.W ^ result) & 0x8000)) + SetOverflow(); + else + ClearOverflow(); + + if (result < 0x10000) + result -= 0x6000; + + if (result > 0xFFFF) + SetCarry(); + else + ClearCarry(); + + Registers.A.W = result & 0xFFFF; + 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()) + { + int result; + int carry = CheckCarry(); + + Work8 ^= 0xFF; + + result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry; + if (result < 0x10) + result -= 0x06; + carry = (result > 0x0F); + + result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + carry * 0x10; + + if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80)) + SetOverflow(); + else + ClearOverflow(); + + if (result < 0x100 ) + result -= 0x60; + + if (result > 0xFF) + SetCarry(); + else + ClearCarry(); + + Registers.AL = result & 0xFF; + 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 diff --git a/snes9x/cpuops.cpp b/snes9x/cpuops.cpp new file mode 100644 index 0000000..b2342ba --- /dev/null +++ b/snes9x/cpuops.cpp @@ -0,0 +1,3736 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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.Cycles += (n); 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) +{ + AddCycles(ONE_CYCLE); + +#ifndef SA1_OPCODES + Timings.IRQFlagChanging |= IRQ_CLEAR_FLAG; +#else + ClearIRQ(); +#endif +} + +// SEI +static void Op78 (void) +{ + AddCycles(ONE_CYCLE); + +#ifndef SA1_OPCODES + Timings.IRQFlagChanging |= IRQ_SET_FLAG; +#else + SetIRQ(); +#endif +} + +// 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 * ONE_CYCLE); + S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8)); + #else + if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40)) + { + OpenBus = Memory.FillRAM[0x220f]; + AddCycles(2 * 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 * ONE_CYCLE); + S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8)); + #else + if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40)) + { + OpenBus = Memory.FillRAM[0x220f]; + AddCycles(2 * 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 * ONE_CYCLE); + S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8)); + #else + if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10)) + { + OpenBus = Memory.FillRAM[0x220d]; + AddCycles(2 * 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 * ONE_CYCLE); + S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8)); + #else + if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10)) + { + OpenBus = Memory.FillRAM[0x220d]; + AddCycles(2 * 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)); +#ifdef SA1_OPCODES + AddCycles(ONE_CYCLE); +#endif +} + +static void OpDCSlow (void) +{ + S9xSetPCBase(AbsoluteIndirectLongSlow(JUMP)); +#ifdef SA1_OPCODES + AddCycles(ONE_CYCLE); +#endif +} + +static void Op5C (void) +{ + S9xSetPCBase(AbsoluteLong(JUMP)); +#ifdef SA1_OPCODES + AddCycles(ONE_CYCLE); +#endif +} + +static void Op5CSlow (void) +{ + S9xSetPCBase(AbsoluteLongSlow(JUMP)); +#ifdef SA1_OPCODES + AddCycles(ONE_CYCLE); +#endif +} + +/* 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(ONE_CYCLE); +#endif +} + +// STP +static void OpDB (void) +{ + Registers.PCw--; + CPU.Flags |= DEBUG_MODE_FLAG | HALTED_FLAG; +} + +/* 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 } +}; diff --git a/snes9x/cpuops.h b/snes9x/cpuops.h new file mode 100644 index 0000000..ae48f0e --- /dev/null +++ b/snes9x/cpuops.h @@ -0,0 +1,18 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/crosshairs.cpp b/snes9x/crosshairs.cpp new file mode 100644 index 0000000..4c99065 --- /dev/null +++ b/snes9x/crosshairs.cpp @@ -0,0 +1,511 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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]); +} diff --git a/snes9x/crosshairs.h b/snes9x/crosshairs.h new file mode 100644 index 0000000..59ea59a --- /dev/null +++ b/snes9x/crosshairs.h @@ -0,0 +1,64 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 +// Macs Rifle: 2 White 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, + X_MACSRIFLE +}; + +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 diff --git a/snes9x/debug.cpp b/snes9x/debug.cpp new file mode 100644 index 0000000..bbd1f73 --- /dev/null +++ b/snes9x/debug.cpp @@ -0,0 +1,2453 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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" + +#include "apu/bapu/snes/snes.hpp" + +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 trace.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_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 %c%c%c %c%c%c %c%c HT:%d VT:%d C:%d", + 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 ? 'E' : ' ', PPU.HTimerEnabled ? 'H' : ' ', PPU.VTimerEnabled ? 'V' : ' ', + CPU.NMIPending ? 'N' : '.', + Memory.FillRAM[0x4200] & 0x80 ? 'n' : '.', + Memory.FillRAM[0x4210] & 0x80 ? '+' : '.', + CPU.IRQTransition ? 'T' : ' ', + CPU.IRQLine ? 'L' : ' ', + PPU.HTimerPosition, PPU.VTimerPosition, Timings.NextIRQTimer); + + 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 %c%c", + 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, + CPU.NMIPending ? 'P' : ' ', + Memory.FillRAM[0x4210] & 0x80 ? 'N' : ' '); + + 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); +} + +void S9xDebugProcessCommand(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"); + } + + // TODO: reactivate once APU debugger works again + if (*Line == 'A') + { + Settings.TraceSMP = !Settings.TraceSMP; + printf("SMP tracing %s\n", Settings.TraceSMP ? "enabled" : "disabled"); + } + +/* + 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("S-CPU-side ports S-CPU writes these, S-SMP reads: %02X %02X %02X %02X\n", SNES::cpu.port_read(0), SNES::cpu.port_read(1), SNES::cpu.port_read(2), SNES::cpu.port_read(3)); + printf("S-SMP-side ports S-SMP writes these, S-CPU reads: %02X %02X %02X %02X\n", SNES::smp.port_read(0), SNES::smp.port_read(1), SNES::smp.port_read(2), SNES::smp.port_read(3)); + } +/* + 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"); + S9xDebugProcessCommand(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; + S9xDebugProcessCommand(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 diff --git a/snes9x/debug.h b/snes9x/debug.h new file mode 100644 index 0000000..c4f7f2b --- /dev/null +++ b/snes9x/debug.h @@ -0,0 +1,41 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 *); +void S9xDebugProcessCommand(char *); + +#endif + +#endif diff --git a/snes9x/display.h b/snes9x/display.h new file mode 100644 index 0000000..a2f1267 --- /dev/null +++ b/snes9x/display.h @@ -0,0 +1,66 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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, + PATCH_DIR, + BIOS_DIR, + LOG_DIR, + SAT_DIR, + LAST_DIR +}; + +void S9xUsage (void); +char * S9xParseArgs (char **, int); +void S9xParseArgsForCheats (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 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 * 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 diff --git a/snes9x/dma.cpp b/snes9x/dma.cpp new file mode 100644 index 0000000..e1ad324 --- /dev/null +++ b/snes9x/dma.cpp @@ -0,0 +1,1635 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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.Cycles += (n); } + +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--; + // Fall through + 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; + } + // Fall through + case 1: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU(Work, 0x2100 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 2; + break; + } + // Fall through + case 2: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU(Work, 0x2101 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 3; + break; + } + // Fall through + 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; + } + // Fall through + case 1: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU(Work, 0x2101 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 2; + break; + } + // Fall through + case 2: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU(Work, 0x2102 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 3; + break; + } + // Fall through + 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--; + // Fall through + case 1: + OpenBus = *(base + p); + REGISTER_2119_linear(OpenBus); + 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--; + // Fall through + 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--; + // Fall through + 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; + } + // Fall through + case 1: + Work = *(base + p); + S9xSetPPU(Work, 0x2100 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 2; + break; + } + // Fall through + case 2: + Work = *(base + p); + S9xSetPPU(Work, 0x2101 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 3; + break; + } + // Fall through + 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; + } + // Fall through + case 1: + Work = *(base + p); + S9xSetPPU(Work, 0x2101 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 2; + break; + } + // Fall through + case 2: + Work = *(base + p); + S9xSetPPU(Work, 0x2102 + d->BAddress); + UPDATE_COUNTERS; + if (--count <= 0) + { + b = 3; + break; + } + // Fall through + 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.NMIPending && (Timings.NMITriggerPos != 0xffff)) + { + Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay; + } + + // 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; + + uint32 ShiftedIBank; + uint16 IAddr; + bool8 temp; + int32 tmpch; + int d; + uint8 mask; + + 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 (mask = 1, p = &DMA[0], d = 0; 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); + // XXX: All HDMA should read to MDR first. This one just + // happens to fix Speedy Gonzales. + OpenBus = *(HDMAMemPointers[d] + 1); + S9xSetPPU(OpenBus, 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 + } + } + } + } + + for (mask = 1, p = &DMA[0], d = 0; mask; mask <<= 1, p++, d++) + { + if (byte & mask) + { + if (p->DoTransfer) + { + 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; + } + } + 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; + } +} diff --git a/snes9x/dma.h b/snes9x/dma.h new file mode 100644 index 0000000..93c993a --- /dev/null +++ b/snes9x/dma.h @@ -0,0 +1,40 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/docs/changes.txt b/snes9x/docs/changes.txt new file mode 100644 index 0000000..c4bd31a --- /dev/null +++ b/snes9x/docs/changes.txt @@ -0,0 +1,2829 @@ +Snes9x 1.60 +- Fixed subscreen blending with master brightness < 100%. +- Fixed NMI timing when toggling enable bit. Fixes Chou Aniki--hack removed. +- Reverted an IPL map optimization that misses a weird edge case that caused + The Great Battle III to lock up. +- Clamp MSU1 addition to max amplitude instead of wrapping. Proper MSU1 tracks + will not be affected by this. +- Save mipmap_input parameter with customized GLSL and slang shaders. +- Actually use mipmap_input parameter. +- Optimized subscreen math with help from Dwedit. +- Revert to measured APU clock speed instead of nominal speed. Fixes An + American Tail. +- Fixed broken BPS patch support. (ArtiiP) +- Fixed MSU1 track restarting on load state. + +Win32: +- Changed window flags to allow NVIDIA cards to auto-enable exclusive + fullscreen mode in OpenGL. +- Added a hidden option "DWMSync" that allows OpenGL to sync to the window + manager while in windowed or borderless windowed mode. +- The automatic frame skip option no longer limits to 59.94Hz. +- Fixed bad icon scaling. +- Added a hacks dialog to enable settings for older hacks to run. + +libretro: +- Added ability to use Satellaview data in same directory as ROM. +- Fixed deviation from proper libretro spec. +- Added option to use the software NTSC filter. (stellarporter) + +GTK: +- Added icons to the entries to clear binding assignments. +- Fixed overlap in xBRZ multithreading. +- Changed glFenceSync option to an OML_sync option that works better. +- Fixed accumulation of partial pixel data on mouse motion when we update the + mouse position more than once per frame. +- Allow one key to be bound to many controller buttons on the same controller. +- Force menu and button icons. +- Add the view menu to right-click when SNES mouse isn't used. +- Remove unused status bar option. +- Startup background can be changed in snes9x.conf. +- Improved PortAudio driver. + +Unix: +- Fixed sound output that broke with APU refactor. + +Snes9x 1.59.2 +- Fix out-of-bounds access on APU memory. + +Snes9x 1.59.1 +- Fix sound core breakage. + +Snes9x 1.59 +- Count clock cycles to synchronize SA1 with S-CPU properly. Based mostly on + work by Vitor Vilela. +- Only allow instant IRQ when toggling IRQ. Fixes WWF - Wrestlemania. +- Refactored APU output code to buffer less on the client side. Removed 8-bit, + Mono, and Reverse Stereo options. +- Consistently handle interlacing when we skip frames. +- Changed APU clock to reflect nominal values for original hardware. +- Fix C4 square instruction regression. + +Win32: +- Don't display Joypad 2 pressed keys if disabled. +- Add support for libretro ".slang" shaders to OpenGL driver. +- Removed glitch-prone DirectSound audio driver in favor of a generic Wave Out + driver. +- Moved sound sync to drivers to be more reactive. This makes sound sync and + dynamic resampling work more reliably. +- Cleaned up dialog boxes to be more consistently spaced. +- Fixed TVMode filter in Direct3D and OpenGL modes. +- Fixed an interaction slowdown with OpenGL and Blargg NTSC filters. + +libretro: +- Fix multiline cheats. + +GTK+: +- Switch from autotools to Meson build system. +- Readd glFinish option as alternative to glFenceSync. +- Fix size fallthrough with xBRZ filter. +- Fix loading of key bindings with spaces in them and modifier keys used alone. +- Add support for libretro ".slang" shaders to OpenGL driver. +- Use a cleaner onscreen font. +- Trap errors to allow OpenGL <= 2.1 to run again. +- Break display settings up to make it easier to access hardware accel section. + + +Snes9x 1.58 +- Move the LICENSE file to the base directory and use a stub + in all the source files referring to it. +- Adjust Chou Aniki timing hack. +- Use 1-based numbering when displaying pressed keys. +- Hide controller port if disabled when displaying keys. +- Fix movie playback. (OV2, BearOso) + + libretro: +- Fix interlaced modes when overscan crop is enabled. +- Allow overriding -flto. (orbea) + + GTK+: +- Use shared snes_ntsc implementation. +- Remove extra LGPL licensing to avoid confusion. +- Don't translate config file entries. Fixes breakage on + non-C languages. +- Fix issue where config file doesn't contain all configurable + entries. +- Remove config options for Netplay, Joystick, and JMA. SDL 2.0 + is now mandatory. +- Updated gettext and removed intltool. update-po should now catch + all translatable strings. +- If available, reduce input lag option will now use fences instead + of glFinish to prevent hogging the CPU. +- Onscreen text can be variable width and will show up in some more + cases now. + + Win32: +- Add audio device selection (XAudio2 only) + +Snes9x 1.57 +- Various seta010 emulation fixes. (kps501) +- Pass blargg OAM tests with proper write behavior. (BearOso) +- Prevent interlacing in BG modes 1-4. (BearOso) +- Corrected IRQ and NMI emulation to allow more games to + work properly. (BearOso, OV2) +- Use 1 instead of 0 for initial PPU left window coordinate, + fixing garbage in left column of pixels in some games. (turhope) +- Added interpolation option hack for DSP. (kps501, mudlord, + BearOso) +- Added sprite-tile limit disabling hack. (Tatsuya79) +- Added libretro's fast snapshot support. (OV2) +- Add overclocking hack that increases IPC (retrotalker) +- Fix controller initialization issues preventing some games + from using multitap. (retrotalker) +- Proper write behavior for register $2122. (BearOso) +- Fix transparency issue with Star Fox asteroids. (redguy, BearOso) +- Increase SuperFX speed to more accurately represent + hardware, and fix bugs with Stunt Race FX and Yoshi's + Island. (BearOso) +- Resize viewport on state load. (retrotalker) +- Many fixes to variables not saved or saved incorrectly in + save states. (Dwedit) +- Pass decimal tests in blargg's math test ROMs. (BearOso) +- Remove memory leak in loadzip.cpp. (bonimy) +- Fix screen size not reverting when overscan is turned on + then off mid-frame. (BearOso) + + Win32: +- Include DirectDraw libraries and compile with DirectDraw + support by default. (OV2) +- Add a link to DirectX installer in error message displayed + when the needed DirectX libraries can't be found. (OV2) +- Save window position when exiting via menu (OV2) +- Make custom ROM dialog resizable. (OV2) +- Fix various cheat dialog issues. (OV2) +- Remove d3d9x DLL dependency by using DirectXMath. (OV2) +- Remove rarely-used HLSL shader option. (OV2) +- Add InitialSnapshotFilename support. (BearOso) +- Disable BG toggle keys by default. (BearOso) +- Proper centering and cropping for overscanned and + regular height modes. (OV2) +- Remove ability to disable the SNES's hires modes. (OV2) +- Added a Super Famicom-style icon resource to the EXE. (BearOso) + + MacOS: +- Partial support for new cheats format. (OV2) +- Fix MacOS build. (marconett) +- Set default for new config options. (tmkk) +- Fix compilation on Mac OS Mojave (meepingsnesroms) + + libretro: +- Massive update of libretro code to latest downstream. (fr500, kps501, + OV2, twinaphex, + BearOso, + hiddenasbestos, + m4xw, kxyxz, + claudiuslollarius) + + GTK+: +- Use datarootdir instead of datadir on install. (orbea) +- Fix --with-system-zip configure flag. (BearOso) +- Draw interlaced fields when ready. (BearOso) +- Initial Wayland support. (remicalixte) +- Allow XV only in X11. (BearOso) +- Add Wayland support via EGL. (BearOso) +- Significant rewrite of OpenGL driver to support newer + standards. This won't work on cards < OpenGL ~1.5. (BearOso) +- Changed frameskip option to speed throttling option with + simpler, but more relevant methods of speed control. (BearOso) +- Add support for relative-style save slots. (ichigo-0, BearOso) +- Remove XML config file format in favor of one more like + Win32. Make joystick bindings and more options human- + readable and editable. (BearOso) +- Try more device nodes when initializing OSS. (BearOso) + +Snes9x 1.56.2 +- Fixed IRQ corner case that caused Umihara Kawase's water + to cover the whole screen. (BearOso) +- Adjusted IRQ timing slightly. Fixes Dragon Ball Z - Super + Butouden 2. (BearOso) +- Clear WAI when IRQLine is active. Fixes Top Gear 3000. (BearOso) +- Fix reading the wrong tile data in mosaic drawing. Gets + rid of glitch at top of FF6 battle transitions. (BearOso) +- Break a specific opcode into cycles. Fixes Little Magic. (BearOso) +- Win32: Don't mix garbage into the last line with NTSC + filter. (OV2) +- Win32: Allow disabling scanlines in NTSC filter. (BearOso) +- GTK+: Added an undo load state option. (BearOso) +- GTK+: Fixed compilation on big-endian systems. (OV2) +- Win32, GTK+: Added integer scaling option. (BearOso) +- GTK+, Unix: Preserve current joypad state when rewinding. (BearOso) + +Snes9x 1.56.1 +- Automatic input rate now only works for close multiples (BearOso) + of 60Hz. +- Win32: Cheats are now shown in the correct order in the (BearOso) + list view. +- GTK+: Check for version greater than 3.22 when using GTK+ (BearOso) + 3. +- GTK+: Don't resize code and description field in GTK+ 2. (BearOso) + +Snes9x 1.56 +- Increased the speed of SA1 emulation to match hardware (BearOso) + more closely. +- Fixed negative SA1 division (BearOso, Jonas Quinn) +- Changed the location where we poll input to potentially (Brunnis, BearOso) + reduce lag. +- Fixed the interlace fields being swapped after skipping (BearOso) + frames. +- More updates for BS-X support. (LuigiBlood) +- Updated xBRZ to version 1.6. (zenju, OV2) +- Added a DMA timing hack for rpgone's Koryu no Mimi (OV2) + translation. +- Updated HDMA to not update indirect addresses until after (BearOso) + transfers are completed. +- Improved cheats support. This stores cheats in a human- (BearOso, OV2) + readable and editable format as gamename.cht. Cheats are + converted from the old format on load. They can be added + in many different formats, but they will convert to the + simple address=condition?byte format. + Also, now included is mightymo's cheat database, and the + ability to match a game and automatically load cheats + from it. +- Don't reset a pending NMI on vblank end. Fixes Super (furrykef) + Punch-Out. +- Redo NMI timing. Fixes Secret of Evermore (PAL). (BearOso) +- Test for transparency before dithering on SuperFX. This (RedGuy(yyy)) + fixes some graphical artifacts in Star Fox. +- Change some of the SDD1 guesswork mapping. Fixes a Tales (BearOso) + of Phantasia hack. +- Return PPU1 MDR for reads of $2137 instead of CPU MDR. (BearOso) + Fixes Mario's Time Machine graphical glitch. +- Memset less memory for sprite calculations. (Nebuleon) +- Don't spuriously update register 14 when running SuperFX. (BearOso) + Fixes graphical glitches in Doom. +- Added a SuperFX clock modifier variable. (BearOso) +- Write CPU MDR during some DMA and HDMA transfers. Fixes (BearOso) + Speedy Gonzales and Funaki Masakatsu Hybrid Wrestler. +- Calculate next IRQ time in advance instead of continously (BearOso, OV2) + checking for it. +- Added some IRQ timing quirks. Fixes at least Marko's (BearOso, OV2) + Magic Football. +- Fixed wrong tile selection in offset-per-tile mode. (BearOso) +- Advance the VRAM pointer even if VRAM writes at the time (kps501) + are invalid. +- Return 0x80 instead of 0xff in DSP1 simulation. Fixes (kps501) + Powerfest '94 Mario Kart. +- Initialize controllers on reset. Fixes Looney Tunes (kps501) + B-Ball multitap. +- Attached APU instruction tracer and made some additions (BearOso) + to debugging output. +- Fix line doubling in interlaced mode. (kps501) +- Added support for M.A.C.S. rifle peripheral. (kps501) +- Fixed a bug where the MSU1 channels were reversed. (qwertymodo) +- Win32: Added dynamic rate control support for XAudio2 (OV2) +- Win32: Added different volume level configuration for (OV2) + regular and turbo speed. +- Win32: Added option to disable EPX scaling for messages (OV2) +- Win32: Improve multi-rom loading. (OV2) +- Win32: Add libpng and zlib dependencies as submodules for (qwertymodo, OV2) + easier compiling from source. +- Win32: Fixed icon registration. (OV2) +- Win32: Better support for running while unfocused. (OV2) +- Win32: Changed icon. (BearOso) +- Win32: Report hidpi support. (BearOso) +- Win32: Added mute hotkey and hotkeys for saving/loading (OV2) + from file. +- Win32: Disabled hotplugging in favor of a menu option to (OV2) + reconfigure joysticks. +- Win32: Added a reduce input lag option. (BearOso) +- Win32: Added ability to use GLSLP shaders with OpenGL, (OV2) + including a dialog to tweak custom parameters. +- GTK+: Added dynamic rate control support for audio to (BearOso) + reduce buffer overflows and underflows. +- GTK+: Increased SDL requirement to version 2.0. This (BearOso) + improves joystick compatibility. +- GTK+: Improved GTK+ 3.0 support and made it the default. (BearOso) +- GTK+: Added ability to start from a snapshot on the (julien2512) + command line. +- GTK+: Added automatic input rate handling. (BearOso) +- GTK+: Use 16-bit 5-6-5 pixel format for better colors. (BearOso) +- GTK+: Now disables the compositor in fullscreen mode. (BearOso) +- GTK+: Changed icon. (BearOso) +- GTK+: Require libepoxy for OpenGL support. (BearOso) +- GTK+: Add full compatibility with GLSLP shaders, with a (BearOso) + parameters dialog to configure them. +- Unix: Add xinerama support and window position hints. (Francesco149) + +Snes9x 1.55 +- Added support for the MSU-1 coprocessor. (qwertymodo) +- Added support for MSU-1 distribution pack. (qwertymodo) +- Added support for BS-X Satellaview memory packs and data (LuigiBlood) + files. +- Improved BS-X memory mapping accuracy. (LuigiBlood) +- Fixed APU error causing issues with some games. (byuu, qwertymodo) +- Added option to ignore patch checksums. (qwertymodo) +- Fixed build warnings / undefined behavior. (bonimy) +- Correct pixel placement in hires. (BearOso, OV2) +- Fixed RAM mapping for Light Fantasy. (hex_usr, BearOso) +- Added Circuit USA APU timing hack. (BearOso) +- libretro: Merged some changes from downstream repository. (OV2) +- GTK+: Allow use of XDG config directory. (BearOso) +- GTK+: Add 10th save slot. (YamashitaRen) +- GTK+: Updated Spanish translation. (jristz) +- Win32: Switched to Studio 2017. (OV2) +- Win32: Fixed problems when minimized in d3d. (OV2) +- Win32: Split Patch/Rom directory. (OV2) +- Win32: Simplified compilation by removing or including + some dependencies (included CG headers, completely + removed FMOD and FMOD_EX, moved direct draw to compile + switch) and reworking solution/configurations. (bonimy, OV2) +- Win32: Fixed crash with movie dialog (OV2) +- Win32: Changed hotplugging (OV2) + +Snes9x 1.54.1 +- GTK+: Properly use --std=c++11 when compiling xBRZ. (BearOso) +- Win32: Save window position when toggling fullscreen. (OV2) +- Win32: Do not assign down-left binding to down-right. (OV2) + +Snes9x 1.54 +- Changed the S-SMP core module to one written by byuu. (byuu, BearOso) + This has the effect of increased accuracy, fewer + speed hacks, but also regresses a few speed-hack games. +- Improved IRQ emulation in several cases. (OV2) +- Added rewind support. (Themaister, OV2) +- Included libretro port. (OV2, libretro team) +- Added bps soft-patching support (OV2) +- Fixed MMC bank register bit 7, restored 64mbit ExLoRom + map (FuSoYa) +- GTK+, Windows: Added xBRZ filter (Zenju, OV2, nmagre) +- GTK+: Fixed several issues with GTK+3. (BearOso) +- GTK+: Added extra aspect ratio options. (BearOso) +- GTK+: Added option to mute sound when using turbo mode. (BearOso) +- GTK+: Fixed expose handling to reduce overdraw and (BearOso) + improve performance. +- GTK+: Updated and universalized Spanish translation. (jristz) +- Unix: Added Xv support and fixed several bugs. (greg-kennedy) +- Win32: Added CG meta shader support (OV2, Themaister) +- Win32: Added support to detect joypad changes (OV2) +- Win32: Fixed unicode command line parameters, + Fixed controller command line parameters (OV2) +- Win32: Added quit hotkey (OV2) +- Win32: Fixed custom rom dialog (OV2) +- Win32: Fixed various cheat dialog issues (gocha, OV2) +- Win32: Added hotkey for fast forward toggling (gocha) +- Win32: Added drag and drop support for movies (gocha) +- Win32: Fixed blargg filter for regular width hires (OV2) +- Win32: Fixed snapshot loading from unicode paths (OV2) +- Win32: Changed open-with file-association method, should + no longer change explorer icons for otherwise + unassociated extensions; removed legacy extensions (OV2) + +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. diff --git a/snes9x/docs/control-inputs.txt b/snes9x/docs/control-inputs.txt new file mode 100644 index 0000000..1a44667 --- /dev/null +++ b/snes9x/docs/control-inputs.txt @@ -0,0 +1,68 @@ +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. diff --git a/snes9x/docs/controls.txt b/snes9x/docs/controls.txt new file mode 100644 index 0000000..309360d --- /dev/null +++ b/snes9x/docs/controls.txt @@ -0,0 +1,97 @@ +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 diff --git a/snes9x/docs/porting.html b/snes9x/docs/porting.html new file mode 100644 index 0000000..86e5d12 --- /dev/null +++ b/snes9x/docs/porting.html @@ -0,0 +1,369 @@ + + + + + + + + Porting Snes9x + + +

How to Port Snes9x to a New Platform

+
+ Version: 1.60
+
+

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. +

+

+ Snes9x outputs 16-bit stereo digital sound data. Ports may convert it from there to 8-bit or mono. 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, before 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. Checking and reporting input immediately before S9xMainLoop is preferred to minimize input latency. +

+

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

+

+ 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)

+

+ 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.SoundPlaybackRate, and Settings.SoundInputRate. (see section below)
+ buffer_ms, given in milliseconds, is the memory buffer size for queueing sound data. Leave this at 0 to use the suggested default.
+

+

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. The buffer will be filled with an array of sample_count int16. Samples are in pairs, first a left channel sample followed by the right channel sample.
+ If there are fewer queued samples than you request by sample_count, the function fills buffer with silent sound data and returns false. +

+

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. Inside this function is the only time that it is safe to access Snes9x's sound data. Ideally, all samples reported available will be removed from Snes9x's buffer when this function is called and moved to either the sound driver output or a separate buffer that can be locked in a thread-safe fashion. If you are using a callback-oriented sound API, it is recommended to set up a separate buffer that can accumulate at least enough samples to fulfill more than one host sound driver callback request.
+ 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. +

+

bool8 S9xSyncSound (void)

+

+ Call this function to synchronize the sound buffers to the game state. This will call the samples_available function to try and move sound data out of Snes9x. If Snes9x is unable to make enough space to accumulate the sound data for a whole video frame, 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 cause the S9xMixSamples to fill the output buffer with silence, instead of filling the output buffer with 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 is 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 *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 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.SoundPlaybackRate = 32040;
+ Settings.SoundInputRate = 31947;
+ 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. +

+

+ On a NTSC SNES, the video refresh rate is usually 60.09881Hz, while the audio output is 32040Hz. This means for every video frame displayed, 532.4565 sound frames are produced. A modern computer display or television will usually provide one of two video rates, 60.00Hz exactly or 59.94Hz to support broadcast television. The sound output, however, is usually fixed at exact values like 32000Hz, 44100Hz, or 48000Hz. This means that the closest video-to-sound ratio we can achieve, with 60.00Hz and 32000Hz, is 1.0/533.3333. This discrepancy means if we wait for vertical sync and update once per refresh, we will experience a sound deficit of 0.87 samples every frame, eventually causing a sound underrun and producing audio problems.
+

+

+ Settings.SoundInputRate can be set to a value such that the ratio with the video rate matches the SNES output. A 60.00Hz display, for example, should be set to 60.00 / 60.09881 * 32040, which is about 31987. The Snes9x resampler will then stretch the sound samples to fit this ratio. 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. 31915hz for 59.94Hz) 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. However, this concept is difficult for most users to understand. If possible, read the display's refresh rate and automatically calculate the appropriate input rate by default. In practice, few displays exceed a target of 60.00Hz, so a good default would be no greater than 31950Hz, but probably lower. +

+

Settings.DynamicRateControl and S9xUpdateDynamicRate(int numerator, int denominator)

+

+ To eliminate buffer overflows and underflows, dynamic rate control can be implemented and used. While this can accommodate for Settings.SoundInputRate not being set correctly, it works better the closer that value is to ideal. +

+

+ To implement, set Settings.DynamicRateControl to true. At the beginning of your samples_available callback, check the hardware output buffer's fill level. Report the amount of free space in the buffer as a fraction of total buffer size to S9xUpdateDynamicRate, and Snes9x will try and keep the buffer close to 50% full. To tune this, Settings.DynamicRateLimit can be changed. A larger value will increase the range of frequencies it can use, but will also cause more noticeable pitch changes. +

+
+ Original document (c) Copyright 1998 Gary Henderson; +Updated most recently by: 2019/2/26 BearOso +
+ + diff --git a/snes9x/docs/portsofsnes9x.txt b/snes9x/docs/portsofsnes9x.txt new file mode 100644 index 0000000..1d5ee76 --- /dev/null +++ b/snes9x/docs/portsofsnes9x.txt @@ -0,0 +1,135 @@ +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_link diff --git a/snes9x/docs/snapshots.txt b/snes9x/docs/snapshots.txt new file mode 100644 index 0000000..ef0d1fd --- /dev/null +++ b/snes9x/docs/snapshots.txt @@ -0,0 +1,84 @@ +***** 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. diff --git a/snes9x/dsp.cpp b/snes9x/dsp.cpp new file mode 100644 index 0000000..27db64a --- /dev/null +++ b/snes9x/dsp.cpp @@ -0,0 +1,58 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); +} diff --git a/snes9x/dsp.h b/snes9x/dsp.h new file mode 100644 index 0000000..0044fa7 --- /dev/null +++ b/snes9x/dsp.h @@ -0,0 +1,447 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/dsp1.cpp b/snes9x/dsp1.cpp new file mode 100644 index 0000000..392b44d --- /dev/null +++ b/snes9x/dsp1.cpp @@ -0,0 +1,1724 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +/* +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; // Fall through + 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 = 0x80; + } + else + t = 0x80; + + return (t); +} diff --git a/snes9x/dsp2.cpp b/snes9x/dsp2.cpp new file mode 100644 index 0000000..77c7734 --- /dev/null +++ b/snes9x/dsp2.cpp @@ -0,0 +1,361 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); +} diff --git a/snes9x/dsp3.cpp b/snes9x/dsp3.cpp new file mode 100644 index 0000000..47d16f8 --- /dev/null +++ b/snes9x/dsp3.cpp @@ -0,0 +1,1097 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; // FIXME? +} + +/* +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; +} diff --git a/snes9x/dsp4.cpp b/snes9x/dsp4.cpp new file mode 100644 index 0000000..73bcf01 --- /dev/null +++ b/snes9x/dsp4.cpp @@ -0,0 +1,2050 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +/* + 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); +} diff --git a/snes9x/filter/2xsai.cpp b/snes9x/filter/2xsai.cpp new file mode 100644 index 0000000..386e6b2 --- /dev/null +++ b/snes9x/filter/2xsai.cpp @@ -0,0 +1,468 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "2xsai.h" + +#define ALL_COLOR_MASK (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) + +#define colorMask (((~RGB_LOW_BITS_MASK & ALL_COLOR_MASK) << 16) | (~RGB_LOW_BITS_MASK & ALL_COLOR_MASK)) +#define qcolorMask (((~TWO_LOW_BITS_MASK & ALL_COLOR_MASK) << 16) | (~TWO_LOW_BITS_MASK & ALL_COLOR_MASK)) +#define lowPixelMask ((RGB_LOW_BITS_MASK << 16) | RGB_LOW_BITS_MASK) +#define qlowpixelMask ((TWO_LOW_BITS_MASK << 16) | TWO_LOW_BITS_MASK) + +static inline int GetResult (uint32, uint32, uint32, uint32); +static inline int GetResult1 (uint32, uint32, uint32, uint32, uint32); +static inline int GetResult2 (uint32, uint32, uint32, uint32, uint32); +static inline uint32 INTERPOLATE (uint32, uint32); +static inline uint32 Q_INTERPOLATE (uint32, uint32, uint32, uint32); + + +static inline int GetResult (uint32 A, uint32 B, uint32 C, uint32 D) +{ + int x = 0, y = 0, r = 0; + + if (A == C) x += 1; else if (B == C) y += 1; + if (A == D) x += 1; else if (B == D) y += 1; + if (x <= 1) r += 1; + if (y <= 1) r -= 1; + + return (r); +} + +static inline int GetResult1 (uint32 A, uint32 B, uint32 C, uint32 D, uint32 E) +{ + int x = 0, y = 0, r = 0; + + if (A == C) x += 1; else if (B == C) y += 1; + if (A == D) x += 1; else if (B == D) y += 1; + if (x <= 1) r += 1; + if (y <= 1) r -= 1; + + return (r); +} + +static inline int GetResult2 (uint32 A, uint32 B, uint32 C, uint32 D, uint32 E) +{ + int x = 0, y = 0, r = 0; + + if (A == C) x += 1; else if (B == C) y += 1; + if (A == D) x += 1; else if (B == D) y += 1; + if (x <= 1) r -= 1; + if (y <= 1) r += 1; + + return (r); +} + +static inline uint32 INTERPOLATE (uint32 A, uint32 B) +{ + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)); +} + +static inline uint32 Q_INTERPOLATE (uint32 A, uint32 B, uint32 C, uint32 D) +{ + uint32 x = ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + uint32 y = (A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask); + + y = (y >> 2) & qlowpixelMask; + + return (x + y); +} + +bool8 S9xBlit2xSaIFilterInit (void) +{ + return (TRUE); +} + +void S9xBlit2xSaIFilterDeinit (void) +{ + return; +} + +void SuperEagle (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint16 *bP; + uint32 *dP; + uint32 nextline = srcRowBytes >> 1; + + for (; height; height--) + { + bP = (uint16 *) srcPtr; + dP = (uint32 *) dstPtr; + + for (int i = 0; i < width; i++) + { + uint32 color1, color2, color3, color4, color5, color6; + uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + + colorB1 = *(bP - nextline ); + colorB2 = *(bP - nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP ); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextline - 1); + color2 = *(bP + nextline ); + color3 = *(bP + nextline + 1); + colorS1 = *(bP + nextline + 2); + + colorA1 = *(bP + nextline + nextline ); + colorA2 = *(bP + nextline + nextline + 1); + + if (color2 == color6 && color5 != color3) + { + product1b = product2a = color2; + if ((color1 == color2 && color6 == colorS2) || (color2 == colorA1 && color6 == colorB2)) + { + product1a = INTERPOLATE(color2, color5); + product1a = INTERPOLATE(color2, product1a); + product2b = INTERPOLATE(color2, color3); + product2b = INTERPOLATE(color2, product2b); + } + else + { + product1a = INTERPOLATE(color5, color6); + product2b = INTERPOLATE(color2, color3); + } + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1a = color5; + if ((colorB1 == color5 && color3 == colorA2) || (color4 == color5 && color3 == colorS1)) + { + product1b = INTERPOLATE(color5, color6); + product1b = INTERPOLATE(color5, product1b); + product2a = INTERPOLATE(color5, color2); + product2a = INTERPOLATE(color5, product2a); + } + else + { + product1b = INTERPOLATE(color5, color6); + product2a = INTERPOLATE(color2, color3); + } + } + else + if (color5 == color3 && color2 == color6 && color5 != color6) + { + int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) + { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE(color5, color6); + } + else + if (r < 0) + { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE(color5, color6); + } + else + { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + else + { + if ((color2 == color5) || (color3 == color6)) + { + product1a = color5; + product2a = color2; + product1b = color6; + product2b = color3; + } + else + { + product1b = product1a = INTERPOLATE(color5, color6); + product1a = INTERPOLATE(color5, product1a); + product1b = INTERPOLATE(color6, product1b); + + product2a = product2b = INTERPOLATE(color2, color3); + product2a = INTERPOLATE(color2, product2a); + product2b = INTERPOLATE(color3, product2b); + } + } + + #ifdef MSB_FIRST + product1a = (product1a << 16) | product1b; + product2a = (product2a << 16) | product2b; + #else + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + #endif + + *(dP) = product1a; + *(dP + (dstRowBytes >> 2)) = product2a; + + bP++; + dP++; + } + + dstPtr += dstRowBytes << 1; + srcPtr += srcRowBytes; + } +} + +void _2xSaI (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint16 *bP; + uint32 *dP; + uint32 nextline = srcRowBytes >> 1; + + for (; height; height--) + { + bP = (uint16 *) srcPtr; + dP = (uint32 *) dstPtr; + + for (int i = 0; i < width; i++) + { + uint32 colorA, colorB, colorC, colorD, colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP; + uint32 product, product1, product2; + + colorI = *(bP - nextline - 1); + colorE = *(bP - nextline ); + colorF = *(bP - nextline + 1); + colorJ = *(bP - nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP ); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + nextline - 1); + colorC = *(bP + nextline ); + colorD = *(bP + nextline + 1); + colorL = *(bP + nextline + 2); + + colorM = *(bP + nextline + nextline - 1); + colorN = *(bP + nextline + nextline ); + colorO = *(bP + nextline + nextline + 1); + colorP = *(bP + nextline + nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) + { + if (((colorA == colorE) && (colorB == colorL)) || ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) + product = colorA; + else + product = INTERPOLATE(colorA, colorB); + + if (((colorA == colorG) && (colorC == colorO)) || ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) + product1 = colorA; + else + product1 = INTERPOLATE(colorA, colorC); + + product2 = colorA; + } + else + if ((colorB == colorC) && (colorA != colorD)) + { + if (((colorB == colorF) && (colorA == colorH)) || ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) + product = colorB; + else + product = INTERPOLATE(colorA, colorB); + + if (((colorC == colorH) && (colorA == colorF)) || ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) + product1 = colorC; + else + product1 = INTERPOLATE(colorA, colorC); + + product2 = colorB; + } + else + if ((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + int r = 0; + + product1 = INTERPOLATE(colorA, colorC); + product = INTERPOLATE(colorA, colorB); + + r += GetResult1(colorA, colorB, colorG, colorE, colorI); + r += GetResult2(colorB, colorA, colorK, colorF, colorJ); + r += GetResult2(colorB, colorA, colorH, colorN, colorM); + r += GetResult1(colorA, colorB, colorL, colorO, colorP); + + if (r > 0) + product2 = colorA; + else + if (r < 0) + product2 = colorB; + else + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + } + } + else + { + product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ)) + product = colorA; + else + if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI)) + product = colorB; + else + product = INTERPOLATE(colorA, colorB); + + if ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM)) + product1 = colorA; + else + if ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI)) + product1 = colorC; + else + product1 = INTERPOLATE(colorA, colorC); + } + + #ifdef MSB_FIRST + product = (colorA << 16) | product; + product1 = (product1 << 16) | product2; + #else + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); + #endif + + *(dP) = product; + *(dP + (dstRowBytes >> 2)) = product1; + + bP++; + dP++; + } + + dstPtr += dstRowBytes << 1; + srcPtr += srcRowBytes; + } +} + +void Super2xSaI (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint16 *bP; + uint32 *dP; + uint32 nextline = srcRowBytes >> 1; + + for (; height; height--) + { + bP = (uint16 *) srcPtr; + dP = (uint32 *) dstPtr; + + for (int i = 0; i < width; i++) + { + uint32 color1, color2, color3, color4, color5, color6; + uint32 colorA0, colorA1, colorA2, colorA3, colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + uint32 product1a, product1b, product2a, product2b; + + colorB0 = *(bP - nextline - 1); + colorB1 = *(bP - nextline ); + colorB2 = *(bP - nextline + 1); + colorB3 = *(bP - nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP ); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + nextline - 1); + color2 = *(bP + nextline ); + color3 = *(bP + nextline + 1); + colorS1 = *(bP + nextline + 2); + + colorA0 = *(bP + nextline + nextline - 1); + colorA1 = *(bP + nextline + nextline ); + colorA2 = *(bP + nextline + nextline + 1); + colorA3 = *(bP + nextline + nextline + 2); + + if (color2 == color6 && color5 != color3) + product2b = product1b = color2; + else + if (color5 == color3 && color2 != color6) + product2b = product1b = color5; + else + if (color5 == color3 && color2 == color6 && color5 != color6) + { + int r = 0; + + r += GetResult(color6, color5, color1, colorA1); + r += GetResult(color6, color5, color4, colorB1); + r += GetResult(color6, color5, colorA2, colorS1); + r += GetResult(color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else + if (r < 0) + product2b = product1b = color5; + else + product2b = product1b = INTERPOLATE(color5, color6); + } + else + { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE(color3, color3, color3, color2); + else + if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE(color2, color2, color2, color3); + else + product2b = INTERPOLATE(color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE(color6, color6, color6, color5); + else + if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE(color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE(color2, color5); + else + if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE(color2, color5); + else + if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE(color2, color5); + else + product1a = color5; + + #ifdef MSB_FIRST + product1a = (product1a << 16) | product1b; + product2a = (product2a << 16) | product2b; + #else + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + #endif + + *(dP) = product1a; + *(dP +(dstRowBytes >> 2)) = product2a; + + bP++; + dP++; + } + + dstPtr += dstRowBytes << 1; + srcPtr += srcRowBytes; + } +} diff --git a/snes9x/filter/2xsai.h b/snes9x/filter/2xsai.h new file mode 100644 index 0000000..f20ba5d --- /dev/null +++ b/snes9x/filter/2xsai.h @@ -0,0 +1,16 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _2xsai_h_ +#define _2xsai_h_ + +bool8 S9xBlit2xSaIFilterInit (void); +void S9xBlit2xSaIFilterDeinit (void); +void SuperEagle (uint8 *, int, uint8 *, int, int, int); +void _2xSaI (uint8 *, int, uint8 *, int, int, int); +void Super2xSaI (uint8 *, int, uint8 *, int, int, int); + +#endif diff --git a/snes9x/filter/blit.cpp b/snes9x/filter/blit.cpp new file mode 100644 index 0000000..27c8fc1 --- /dev/null +++ b/snes9x/filter/blit.cpp @@ -0,0 +1,529 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "blit.h" + +#define ALL_COLOR_MASK (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) + +#define lowPixelMask (RGB_LOW_BITS_MASK) +#define qlowPixelMask ((RGB_HI_BITS_MASK >> 3) | TWO_LOW_BITS_MASK) +#define highBitsMask (ALL_COLOR_MASK & RGB_REMOVE_LOW_BITS_MASK) +#define colorMask (((~RGB_HI_BITS_MASK & ALL_COLOR_MASK) << 16) | (~RGB_HI_BITS_MASK & ALL_COLOR_MASK)) + +static snes_ntsc_t *ntsc = NULL; +static uint8 *XDelta = NULL; + + +bool8 S9xBlitFilterInit (void) +{ + XDelta = new uint8[SNES_WIDTH * SNES_HEIGHT_EXTENDED * 4]; + if (!XDelta) + return (FALSE); + + S9xBlitClearDelta(); + + return (TRUE); +} + +void S9xBlitFilterDeinit (void) +{ + if (XDelta) + { + delete[] XDelta; + XDelta = NULL; + } +} + +void S9xBlitClearDelta (void) +{ + uint32 *d = (uint32 *) XDelta; + + for (int y = 0; y < SNES_HEIGHT_EXTENDED; y++) + for (int x = 0; x < SNES_WIDTH; x++) + *d++ = 0x80008000; +} + +bool8 S9xBlitNTSCFilterInit (void) +{ + ntsc = (snes_ntsc_t *) malloc(sizeof(snes_ntsc_t)); + if (!ntsc) + return (FALSE); + + snes_ntsc_init(ntsc, &snes_ntsc_composite); + return (TRUE); +} + +void S9xBlitNTSCFilterDeinit (void) +{ + if (ntsc) + { + free(ntsc); + ntsc = NULL; + } +} + +void S9xBlitNTSCFilterSet (const snes_ntsc_setup_t *setup) +{ + snes_ntsc_init(ntsc, setup); +} + +void S9xBlitPixSimple1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + width <<= 1; + + for (; height; height--) + { + memcpy(dstPtr, srcPtr, width); + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + } +} + +void S9xBlitPixSimple1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + width <<= 1; + + for (; height; height--) + { + memcpy(dstPtr, srcPtr, width); + dstPtr += dstRowBytes; + memcpy(dstPtr, srcPtr, width); + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + } +} + +void S9xBlitPixSimple2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + for (; height; height--) + { + uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; + + for (int i = 0; i < (width >> 1); i++) + { + *dP++ = *bP; + *dP++ = *bP++; + + *dP++ = *bP; + *dP++ = *bP++; + } + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + } +} + +void S9xBlitPixSimple2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; + dstRowBytes <<= 1; + + for (; height; height--) + { + uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; + uint32 currentPixel, lastPixel, currentPixA, currentPixB, colorA, colorB; + + for (int i = 0; i < (width >> 1); i++) + { + currentPixel = *bP; + lastPixel = *xP; + + if (currentPixel != lastPixel) + { + #ifdef MSB_FIRST + colorA = (currentPixel >> 16) & 0xFFFF; + colorB = (currentPixel ) & 0xFFFF; + #else + colorA = (currentPixel ) & 0xFFFF; + colorB = (currentPixel >> 16) & 0xFFFF; + #endif + + currentPixA = (colorA << 16) | colorA; + currentPixB = (colorB << 16) | colorB; + + dP1[0] = currentPixA; + dP1[1] = currentPixB; + dP2[0] = currentPixA; + dP2[1] = currentPixB; + + *xP = *bP; + } + + bP++; + xP++; + dP1 += 2; + dP2 += 2; + } + + srcPtr += srcRowBytes; + deltaPtr += srcRowBytes; + dstPtr += dstRowBytes; + dstPtr2 += dstRowBytes; + } +} + +void S9xBlitPixBlend1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + for (; height; height--) + { + uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; + uint16 prev, curr; + + prev = *bP; + + for (int i = 0; i < (width >> 1); i++) + { + curr = *bP++; + *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); + prev = curr; + + curr = *bP++; + *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); + prev = curr; + } + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + } +} + +void S9xBlitPixBlend2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + for (; height; height--) + { + uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; + uint16 prev, curr; + + prev = *bP; + + for (int i = 0; i < (width >> 1); i++) + { + curr = *bP++; + *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); + *dP++ = curr; + prev = curr; + + curr = *bP++; + *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); + *dP++ = curr; + prev = curr; + } + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + } +} + +void S9xBlitPixTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint8 *dstPtr2 = dstPtr + dstRowBytes; + dstRowBytes <<= 1; + + for (; height; height--) + { + uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr; + uint32 product, darkened; + + for (int i = 0; i < (width >> 1); i++) + { + product = *dP1++ = *bP++; + darkened = (product = (product >> 1) & colorMask); + darkened += (product = (product >> 1) & colorMask); + *dP2++ = darkened; + } + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes; + dstPtr2 += dstRowBytes; + } +} + +void S9xBlitPixTV2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; + dstRowBytes <<= 1; + + for (; height; height--) + { + uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; + uint32 currentPixel, nextPixel, currentDelta, nextDelta, colorA, colorB, product, darkened; + + for (int i = 0; i < (width >> 1) - 1; i++) + { + currentPixel = *bP; + currentDelta = *xP; + nextPixel = *(bP + 1); + nextDelta = *(xP + 1); + + if ((currentPixel != currentDelta) || (nextPixel != nextDelta)) + { + *xP = *bP; + + #ifdef MSB_FIRST + colorA = (currentPixel >> 16) & 0xFFFF; + colorB = (currentPixel ) & 0xFFFF; + #else + colorA = (currentPixel ) & 0xFFFF; + colorB = (currentPixel >> 16) & 0xFFFF; + #endif + + #ifdef MSB_FIRST + *dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); + #else + *dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); + #endif + + darkened = (product = ((product >> 1) & colorMask)); + darkened += (product = ((product >> 1) & colorMask)); + darkened += (product >> 1) & colorMask; + + *dP2 = darkened; + + #ifdef MSB_FIRST + colorA = (nextPixel >> 16) & 0xFFFF; + #else + colorA = (nextPixel ) & 0xFFFF; + #endif + + #ifdef MSB_FIRST + *(dP1 + 1) = product = (colorB << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); + #else + *(dP1 + 1) = product = (colorB ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); + #endif + + darkened = (product = ((product >> 1) & colorMask)); + darkened += (product = ((product >> 1) & colorMask)); + darkened += (product >> 1) & colorMask; + + *(dP2 + 1) = darkened; + } + + bP++; + xP++; + dP1 += 2; + dP2 += 2; + } + + // Last 2 Pixels + + currentPixel = *bP; + currentDelta = *xP; + + if (currentPixel != currentDelta) + { + *xP = *bP; + + #ifdef MSB_FIRST + colorA = (currentPixel >> 16) & 0xFFFF; + colorB = (currentPixel ) & 0xFFFF; + #else + colorA = (currentPixel ) & 0xFFFF; + colorB = (currentPixel >> 16) & 0xFFFF; + #endif + + #ifdef MSB_FIRST + *dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); + #else + *dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); + #endif + + darkened = (product = ((product >> 1) & colorMask)); + darkened += (product = ((product >> 1) & colorMask)); + darkened += (product >> 1) & colorMask; + + *dP2 = darkened; + + *(dP1 + 1) = product = (colorB << 16) | colorB; + + darkened = (product = ((product >> 1) & colorMask)); + darkened += (product = ((product >> 1) & colorMask)); + darkened += (product >> 1) & colorMask; + + *(dP2 + 1) = darkened; + } + + srcPtr += srcRowBytes; + deltaPtr += srcRowBytes; + dstPtr += dstRowBytes; + dstPtr2 += dstRowBytes; + } +} + +void S9xBlitPixMixedTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint8 *dstPtr2 = dstPtr + dstRowBytes, *srcPtr2 = srcPtr + srcRowBytes; + dstRowBytes <<= 1; + + for (; height > 1; height--) + { + uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr, *bP2 = (uint16 *) srcPtr2; + uint16 prev, next, mixed; + + for (int i = 0; i < width; i++) + { + prev = *bP1++; + next = *bP2++; + mixed = prev + next + ((prev ^ next) & lowPixelMask); + + *dP1++ = prev; + *dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask); + } + + srcPtr += srcRowBytes; + srcPtr2 += srcRowBytes; + dstPtr += dstRowBytes; + dstPtr2 += dstRowBytes; + } + + // Last 1 line + + uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr; + uint16 prev, mixed; + + for (int i = 0; i < width; i++) + { + prev = *bP1++; + mixed = prev + ((prev ^ 0) & lowPixelMask); + + *dP1++ = prev; + *dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask); + } +} + +void S9xBlitPixSmooth2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; + uint32 lastLinePix[SNES_WIDTH << 1]; + uint8 lastLineChg[SNES_WIDTH >> 1]; + int lineBytes = width << 1; + + dstRowBytes <<= 1; + + memset(lastLinePix, 0, sizeof(lastLinePix)); + memset(lastLineChg, 0, sizeof(lastLineChg)); + + for (; height; height--) + { + uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; + uint32 *lL = lastLinePix; + uint8 *lC = lastLineChg; + uint32 currentPixel, nextPixel, currentDelta, nextDelta, lastPix, lastChg, thisChg, currentPixA, currentPixB, colorA, colorB, colorC; + uint16 savePixel; + + savePixel = *(uint16 *) (srcPtr + lineBytes); + *(uint16 *) (srcPtr + lineBytes) = *(uint16 *) (srcPtr + lineBytes - 2); + *(uint32 *) (deltaPtr + lineBytes) = *(uint32 *) (srcPtr + lineBytes); + + nextPixel = *bP++; + nextDelta = *xP++; + + for (int i = 0; i < (width >> 1); i++) + { + currentPixel = nextPixel; + currentDelta = nextDelta; + nextPixel = *bP++; + nextDelta = *xP++; + lastChg = *lC; + thisChg = (nextPixel - nextDelta) | (currentPixel - currentDelta); + + #ifdef MSB_FIRST + colorA = (currentPixel >> 16) & 0xFFFF; + colorB = (currentPixel ) & 0xFFFF; + colorC = (nextPixel >> 16) & 0xFFFF; + + currentPixA = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); + currentPixB = (colorB << 16) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) ); + #else + colorA = (currentPixel ) & 0xFFFF; + colorB = (currentPixel >> 16) & 0xFFFF; + colorC = (nextPixel ) & 0xFFFF; + + currentPixA = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); + currentPixB = (colorB ) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) << 16); + #endif + + if (thisChg | lastChg) + { + xP[-2] = currentPixel; + + lastPix = lL[0]; + dP1[0] = ((currentPixA >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixA & lastPix & lowPixelMask); + dP2[0] = currentPixA; + lL[0] = currentPixA; + + lastPix = lL[1]; + dP1[1] = ((currentPixB >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixB & lastPix & lowPixelMask); + dP2[1] = currentPixB; + lL[1] = currentPixB; + + *lC++ = (thisChg != 0); + } + else + { + lL[0] = currentPixA; + lL[1] = currentPixB; + *lC++ = 0; + } + + lL += 2; + dP2 += 2; + dP1 += 2; + } + + *(uint16 *) (srcPtr + lineBytes) = savePixel; + + srcPtr += srcRowBytes; + deltaPtr += srcRowBytes; + dstPtr += dstRowBytes; + dstPtr2 += dstRowBytes; + } +} + +void S9xBlitPixSuper2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + Super2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPix2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + _2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixSuperEagle16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + SuperEagle(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixEPX16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + EPX_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixHQ2x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + HQ2X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixHQ3x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + HQ3X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixHQ4x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + HQ4X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); +} + +void S9xBlitPixNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + snes_ntsc_blit(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes); +} + +void S9xBlitPixHiResNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + snes_ntsc_blit_hires(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes); +} diff --git a/snes9x/filter/blit.h b/snes9x/filter/blit.h new file mode 100644 index 0000000..f3a7b57 --- /dev/null +++ b/snes9x/filter/blit.h @@ -0,0 +1,41 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _blit_h_ +#define _blit_h_ + +#include "2xsai.h" +#include "epx.h" +#include "hq2x.h" +#include "snes_ntsc.h" + +bool8 S9xBlitFilterInit (void); +void S9xBlitFilterDeinit (void); +void S9xBlitClearDelta (void); +bool8 S9xBlitNTSCFilterInit (void); +void S9xBlitNTSCFilterDeinit (void); +void S9xBlitNTSCFilterSet (const snes_ntsc_setup_t *); +void S9xBlitPixSimple1x1 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSimple1x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSimple2x1 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSimple2x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixBlend1x1 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixBlend2x1 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixTV1x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixTV2x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixMixedTV1x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSmooth2x2 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSuperEagle16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPix2xSaI16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixSuper2xSaI16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixEPX16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixHQ2x16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixHQ3x16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixHQ4x16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixNTSC16 (uint8 *, int, uint8 *, int, int, int); +void S9xBlitPixHiResNTSC16 (uint8 *, int, uint8 *, int, int, int); + +#endif diff --git a/snes9x/filter/epx.cpp b/snes9x/filter/epx.cpp new file mode 100644 index 0000000..533da13 --- /dev/null +++ b/snes9x/filter/epx.cpp @@ -0,0 +1,258 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "epx.h" + + +void EPX_16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) +{ + uint16 colorX, colorA, colorB, colorC, colorD; + uint16 *sP, *uP, *lP; + uint32 *dP1, *dP2; + int w; + + height -= 2; + + // D + // A X C + // B + + // top edge + + sP = (uint16 *) srcPtr; + lP = (uint16 *) (srcPtr + srcRowBytes); + dP1 = (uint32 *) dstPtr; + dP2 = (uint32 *) (dstPtr + dstRowBytes); + + // left edge + + colorX = *sP; + colorC = *++sP; + colorB = *lP++; + + if ((colorX != colorC) && (colorB != colorX)) + { + #ifdef MSB_FIRST + *dP1 = (colorX << 16) + colorX; + *dP2 = (colorX << 16) + ((colorB == colorC) ? colorB : colorX); + #else + *dP1 = colorX + (colorX << 16); + *dP2 = colorX + (((colorB == colorC) ? colorB : colorX) << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + + // + + for (w = width - 2; w; w--) + { + colorA = colorX; + colorX = colorC; + colorC = *++sP; + colorB = *lP++; + + if ((colorA != colorC) && (colorB != colorX)) + { + #ifdef MSB_FIRST + *dP1 = (colorX << 16) + colorX; + *dP2 = (((colorA == colorB) ? colorA : colorX) << 16) + ((colorB == colorC) ? colorB : colorX); + #else + *dP1 = colorX + (colorX << 16); + *dP2 = ((colorA == colorB) ? colorA : colorX) + (((colorB == colorC) ? colorB : colorX) << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + } + + // right edge + + colorA = colorX; + colorX = colorC; + colorB = *lP; + + if ((colorA != colorX) && (colorB != colorX)) + { + #ifdef MSB_FIRST + *dP1 = (colorX << 16) + colorX; + *dP2 = (((colorA == colorB) ? colorA : colorX) << 16) + colorX; + #else + *dP1 = colorX + (colorX << 16); + *dP2 = ((colorA == colorB) ? colorA : colorX) + (colorX << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes << 1; + + // + + for (; height; height--) + { + sP = (uint16 *) srcPtr; + uP = (uint16 *) (srcPtr - srcRowBytes); + lP = (uint16 *) (srcPtr + srcRowBytes); + dP1 = (uint32 *) dstPtr; + dP2 = (uint32 *) (dstPtr + dstRowBytes); + + // left edge + + colorX = *sP; + colorC = *++sP; + colorB = *lP++; + colorD = *uP++; + + if ((colorX != colorC) && (colorB != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (colorX << 16) + ((colorC == colorD) ? colorC : colorX); + *dP2 = (colorX << 16) + ((colorB == colorC) ? colorB : colorX); + #else + *dP1 = colorX + (((colorC == colorD) ? colorC : colorX) << 16); + *dP2 = colorX + (((colorB == colorC) ? colorB : colorX) << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + + // + + for (w = width - 2; w; w--) + { + colorA = colorX; + colorX = colorC; + colorC = *++sP; + colorB = *lP++; + colorD = *uP++; + + if ((colorA != colorC) && (colorB != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (((colorD == colorA) ? colorD : colorX) << 16) + ((colorC == colorD) ? colorC : colorX); + *dP2 = (((colorA == colorB) ? colorA : colorX) << 16) + ((colorB == colorC) ? colorB : colorX); + #else + *dP1 = ((colorD == colorA) ? colorD : colorX) + (((colorC == colorD) ? colorC : colorX) << 16); + *dP2 = ((colorA == colorB) ? colorA : colorX) + (((colorB == colorC) ? colorB : colorX) << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + } + + // right edge + + colorA = colorX; + colorX = colorC; + colorB = *lP; + colorD = *uP; + + if ((colorA != colorX) && (colorB != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (((colorD == colorA) ? colorD : colorX) << 16) + colorX; + *dP2 = (((colorA == colorB) ? colorA : colorX) << 16) + colorX; + #else + *dP1 = ((colorD == colorA) ? colorD : colorX) + (colorX << 16); + *dP2 = ((colorA == colorB) ? colorA : colorX) + (colorX << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + srcPtr += srcRowBytes; + dstPtr += dstRowBytes << 1; + } + + // bottom edge + + sP = (uint16 *) srcPtr; + uP = (uint16 *) (srcPtr - srcRowBytes); + dP1 = (uint32 *) dstPtr; + dP2 = (uint32 *) (dstPtr + dstRowBytes); + + // left edge + + colorX = *sP; + colorC = *++sP; + colorD = *uP++; + + if ((colorX != colorC) && (colorX != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (colorX << 16) + ((colorC == colorD) ? colorC : colorX); + *dP2 = (colorX << 16) + colorX; + #else + *dP1 = colorX + (((colorC == colorD) ? colorC : colorX) << 16); + *dP2 = colorX + (colorX << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + + // + + for (w = width - 2; w; w--) + { + colorA = colorX; + colorX = colorC; + colorC = *++sP; + colorD = *uP++; + + if ((colorA != colorC) && (colorX != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (((colorD == colorA) ? colorD : colorX) << 16) + ((colorC == colorD) ? colorC : colorX); + *dP2 = (colorX << 16) + colorX; + #else + *dP1 = ((colorD == colorA) ? colorD : colorX) + (((colorC == colorD) ? colorC : colorX) << 16); + *dP2 = colorX + (colorX << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; + + dP1++; + dP2++; + } + + // right edge + + colorA = colorX; + colorX = colorC; + colorD = *uP; + + if ((colorA != colorX) && (colorX != colorD)) + { + #ifdef MSB_FIRST + *dP1 = (((colorD == colorA) ? colorD : colorX) << 16) + colorX; + *dP2 = (colorX << 16) + colorX; + #else + *dP1 = ((colorD == colorA) ? colorD : colorX) + (colorX << 16); + *dP2 = colorX + (colorX << 16); + #endif + } + else + *dP1 = *dP2 = (colorX << 16) + colorX; +} diff --git a/snes9x/filter/epx.h b/snes9x/filter/epx.h new file mode 100644 index 0000000..a8b2e78 --- /dev/null +++ b/snes9x/filter/epx.h @@ -0,0 +1,12 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _epx_h_ +#define _epx_h_ + +void EPX_16 (uint8 *, int, uint8 *, int, int, int); + +#endif diff --git a/snes9x/filter/hq2x.cpp b/snes9x/filter/hq2x.cpp new file mode 100644 index 0000000..bbe5072 --- /dev/null +++ b/snes9x/filter/hq2x.cpp @@ -0,0 +1,11795 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "gfx.h" +#include "hq2x.h" + +#define Ymask 0xFF0000 +#define Umask 0x00FF00 +#define Vmask 0x0000FF +#define trY 0x300000 +#define trU 0x000700 +#define trV 0x000006 + +#define Mask_2 SECOND_COLOR_MASK +#define Mask13 FIRST_THIRD_COLOR_MASK + +#define Interp01(c1, c2) \ +(c1 == c2) ? c1 : \ +(((((c1 & Mask_2) * 3 + (c2 & Mask_2) ) >> 2) & Mask_2) + \ + ((((c1 & Mask13) * 3 + (c2 & Mask13) ) >> 2) & Mask13)) + +#define Interp02(c1, c2, c3) \ +(((((c1 & Mask_2) * 2 + (c2 & Mask_2) + (c3 & Mask_2) ) >> 2) & Mask_2) + \ + ((((c1 & Mask13) * 2 + (c2 & Mask13) + (c3 & Mask13) ) >> 2) & Mask13)) + +#define Interp03(c1, c2) \ +(c1 == c2) ? c1 : \ +(((((c1 & Mask_2) * 7 + (c2 & Mask_2) ) >> 3) & Mask_2) + \ + ((((c1 & Mask13) * 7 + (c2 & Mask13) ) >> 3) & Mask13)) + +#define Interp04(c1, c2, c3) \ +(((((c1 & Mask_2) * 2 + (c2 & Mask_2) * 7 + (c3 & Mask_2) * 7) >> 4) & Mask_2) + \ + ((((c1 & Mask13) * 2 + (c2 & Mask13) * 7 + (c3 & Mask13) * 7) >> 4) & Mask13)) + +#define Interp05(c1, c2) \ +(c1 == c2) ? c1 : \ +(((((c1 & Mask_2) + (c2 & Mask_2)) >> 1) & Mask_2) + \ + ((((c1 & Mask13) + (c2 & Mask13)) >> 1) & Mask13)) + +#define Interp06(c1, c2, c3) \ +(((((c1 & Mask_2) * 5 + (c2 & Mask_2) * 2 + (c3 & Mask_2) ) >> 3) & Mask_2) + \ + ((((c1 & Mask13) * 5 + (c2 & Mask13) * 2 + (c3 & Mask13) ) >> 3) & Mask13)) + +#define Interp07(c1, c2, c3) \ +(((((c1 & Mask_2) * 6 + (c2 & Mask_2) + (c3 & Mask_2) ) >> 3) & Mask_2) + \ + ((((c1 & Mask13) * 6 + (c2 & Mask13) + (c3 & Mask13) ) >> 3) & Mask13)) + +#define Interp08(c1, c2) \ +(c1 == c2) ? c1 : \ +(((((c1 & Mask_2) * 5 + (c2 & Mask_2) * 3) >> 3) & Mask_2) + \ + ((((c1 & Mask13) * 5 + (c2 & Mask13) * 3) >> 3) & Mask13)) + +#define Interp09(c1, c2, c3) \ +(((((c1 & Mask_2) * 2 + (c2 & Mask_2) * 3 + (c3 & Mask_2) * 3) >> 3) & Mask_2) + \ + ((((c1 & Mask13) * 2 + (c2 & Mask13) * 3 + (c3 & Mask13) * 3) >> 3) & Mask13)) + +#define Interp10(c1, c2, c3) \ +(((((c1 & Mask_2) * 14 + (c2 & Mask_2) + (c3 & Mask_2) ) >> 4) & Mask_2) + \ + ((((c1 & Mask13) * 14 + (c2 & Mask13) + (c3 & Mask13) ) >> 4) & Mask13)) + +#define X2PIXEL00_0 *(dp) = w5; +#define X2PIXEL00_10 *(dp) = Interp01(w5, w1); +#define X2PIXEL00_11 *(dp) = Interp01(w5, w4); +#define X2PIXEL00_12 *(dp) = Interp01(w5, w2); +#define X2PIXEL00_20 *(dp) = Interp02(w5, w4, w2); +#define X2PIXEL00_21 *(dp) = Interp02(w5, w1, w2); +#define X2PIXEL00_22 *(dp) = Interp02(w5, w1, w4); +#define X2PIXEL00_60 *(dp) = Interp06(w5, w2, w4); +#define X2PIXEL00_61 *(dp) = Interp06(w5, w4, w2); +#define X2PIXEL00_70 *(dp) = Interp07(w5, w4, w2); +#define X2PIXEL00_90 *(dp) = Interp09(w5, w4, w2); +#define X2PIXEL00_100 *(dp) = Interp10(w5, w4, w2); + +#define X2PIXEL01_0 *(dp + 1) = w5; +#define X2PIXEL01_10 *(dp + 1) = Interp01(w5, w3); +#define X2PIXEL01_11 *(dp + 1) = Interp01(w5, w2); +#define X2PIXEL01_12 *(dp + 1) = Interp01(w5, w6); +#define X2PIXEL01_20 *(dp + 1) = Interp02(w5, w2, w6); +#define X2PIXEL01_21 *(dp + 1) = Interp02(w5, w3, w6); +#define X2PIXEL01_22 *(dp + 1) = Interp02(w5, w3, w2); +#define X2PIXEL01_60 *(dp + 1) = Interp06(w5, w6, w2); +#define X2PIXEL01_61 *(dp + 1) = Interp06(w5, w2, w6); +#define X2PIXEL01_70 *(dp + 1) = Interp07(w5, w2, w6); +#define X2PIXEL01_90 *(dp + 1) = Interp09(w5, w2, w6); +#define X2PIXEL01_100 *(dp + 1) = Interp10(w5, w2, w6); + +#define X2PIXEL10_0 *(dp + dst1line) = w5; +#define X2PIXEL10_10 *(dp + dst1line) = Interp01(w5, w7); +#define X2PIXEL10_11 *(dp + dst1line) = Interp01(w5, w8); +#define X2PIXEL10_12 *(dp + dst1line) = Interp01(w5, w4); +#define X2PIXEL10_20 *(dp + dst1line) = Interp02(w5, w8, w4); +#define X2PIXEL10_21 *(dp + dst1line) = Interp02(w5, w7, w4); +#define X2PIXEL10_22 *(dp + dst1line) = Interp02(w5, w7, w8); +#define X2PIXEL10_60 *(dp + dst1line) = Interp06(w5, w4, w8); +#define X2PIXEL10_61 *(dp + dst1line) = Interp06(w5, w8, w4); +#define X2PIXEL10_70 *(dp + dst1line) = Interp07(w5, w8, w4); +#define X2PIXEL10_90 *(dp + dst1line) = Interp09(w5, w8, w4); +#define X2PIXEL10_100 *(dp + dst1line) = Interp10(w5, w8, w4); + +#define X2PIXEL11_0 *(dp + dst1line + 1) = w5; +#define X2PIXEL11_10 *(dp + dst1line + 1) = Interp01(w5, w9); +#define X2PIXEL11_11 *(dp + dst1line + 1) = Interp01(w5, w6); +#define X2PIXEL11_12 *(dp + dst1line + 1) = Interp01(w5, w8); +#define X2PIXEL11_20 *(dp + dst1line + 1) = Interp02(w5, w6, w8); +#define X2PIXEL11_21 *(dp + dst1line + 1) = Interp02(w5, w9, w8); +#define X2PIXEL11_22 *(dp + dst1line + 1) = Interp02(w5, w9, w6); +#define X2PIXEL11_60 *(dp + dst1line + 1) = Interp06(w5, w8, w6); +#define X2PIXEL11_61 *(dp + dst1line + 1) = Interp06(w5, w6, w8); +#define X2PIXEL11_70 *(dp + dst1line + 1) = Interp07(w5, w6, w8); +#define X2PIXEL11_90 *(dp + dst1line + 1) = Interp09(w5, w6, w8); +#define X2PIXEL11_100 *(dp + dst1line + 1) = Interp10(w5, w6, w8); + +#define X3PIXEL00_1M *(dp) = Interp01(w5, w1); +#define X3PIXEL00_1U *(dp) = Interp01(w5, w2); +#define X3PIXEL00_1L *(dp) = Interp01(w5, w4); +#define X3PIXEL00_2 *(dp) = Interp02(w5, w4, w2); +#define X3PIXEL00_4 *(dp) = Interp04(w5, w4, w2); +#define X3PIXEL00_5 *(dp) = Interp05(w4, w2); +#define X3PIXEL00_C *(dp) = w5; + +#define X3PIXEL01_1 *(dp + 1) = Interp01(w5, w2); +#define X3PIXEL01_3 *(dp + 1) = Interp03(w5, w2); +#define X3PIXEL01_6 *(dp + 1) = Interp01(w2, w5); +#define X3PIXEL01_C *(dp + 1) = w5; + +#define X3PIXEL02_1M *(dp + 2) = Interp01(w5, w3); +#define X3PIXEL02_1U *(dp + 2) = Interp01(w5, w2); +#define X3PIXEL02_1R *(dp + 2) = Interp01(w5, w6); +#define X3PIXEL02_2 *(dp + 2) = Interp02(w5, w2, w6); +#define X3PIXEL02_4 *(dp + 2) = Interp04(w5, w2, w6); +#define X3PIXEL02_5 *(dp + 2) = Interp05(w2, w6); +#define X3PIXEL02_C *(dp + 2) = w5; + +#define X3PIXEL10_1 *(dp + dst1line) = Interp01(w5, w4); +#define X3PIXEL10_3 *(dp + dst1line) = Interp03(w5, w4); +#define X3PIXEL10_6 *(dp + dst1line) = Interp01(w4, w5); +#define X3PIXEL10_C *(dp + dst1line) = w5; + +#define X3PIXEL11 *(dp + dst1line + 1) = w5; + +#define X3PIXEL12_1 *(dp + dst1line + 2) = Interp01(w5, w6); +#define X3PIXEL12_3 *(dp + dst1line + 2) = Interp03(w5, w6); +#define X3PIXEL12_6 *(dp + dst1line + 2) = Interp01(w6, w5); +#define X3PIXEL12_C *(dp + dst1line + 2) = w5; + +#define X3PIXEL20_1M *(dp + dst1line + dst1line) = Interp01(w5, w7); +#define X3PIXEL20_1D *(dp + dst1line + dst1line) = Interp01(w5, w8); +#define X3PIXEL20_1L *(dp + dst1line + dst1line) = Interp01(w5, w4); +#define X3PIXEL20_2 *(dp + dst1line + dst1line) = Interp02(w5, w8, w4); +#define X3PIXEL20_4 *(dp + dst1line + dst1line) = Interp04(w5, w8, w4); +#define X3PIXEL20_5 *(dp + dst1line + dst1line) = Interp05(w8, w4); +#define X3PIXEL20_C *(dp + dst1line + dst1line) = w5; + +#define X3PIXEL21_1 *(dp + dst1line + dst1line + 1) = Interp01(w5, w8); +#define X3PIXEL21_3 *(dp + dst1line + dst1line + 1) = Interp03(w5, w8); +#define X3PIXEL21_6 *(dp + dst1line + dst1line + 1) = Interp01(w8, w5); +#define X3PIXEL21_C *(dp + dst1line + dst1line + 1) = w5; + +#define X3PIXEL22_1M *(dp + dst1line + dst1line + 2) = Interp01(w5, w9); +#define X3PIXEL22_1D *(dp + dst1line + dst1line + 2) = Interp01(w5, w8); +#define X3PIXEL22_1R *(dp + dst1line + dst1line + 2) = Interp01(w5, w6); +#define X3PIXEL22_2 *(dp + dst1line + dst1line + 2) = Interp02(w5, w6, w8); +#define X3PIXEL22_4 *(dp + dst1line + dst1line + 2) = Interp04(w5, w6, w8); +#define X3PIXEL22_5 *(dp + dst1line + dst1line + 2) = Interp05(w6, w8); +#define X3PIXEL22_C *(dp + dst1line + dst1line + 2) = w5; + +#define X4PIXEL00_0 *(dp) = w5; +#define X4PIXEL00_11 *(dp) = Interp01(w5, w4); +#define X4PIXEL00_12 *(dp) = Interp01(w5, w2); +#define X4PIXEL00_20 *(dp) = Interp02(w5, w2, w4); +#define X4PIXEL00_50 *(dp) = Interp05(w2, w4); +#define X4PIXEL00_80 *(dp) = Interp08(w5, w1); +#define X4PIXEL00_81 *(dp) = Interp08(w5, w4); +#define X4PIXEL00_82 *(dp) = Interp08(w5, w2); + +#define X4PIXEL01_0 *(dp + 1) = w5; +#define X4PIXEL01_10 *(dp + 1) = Interp01(w5, w1); +#define X4PIXEL01_12 *(dp + 1) = Interp01(w5, w2); +#define X4PIXEL01_14 *(dp + 1) = Interp01(w2, w5); +#define X4PIXEL01_21 *(dp + 1) = Interp02(w2, w5, w4); +#define X4PIXEL01_31 *(dp + 1) = Interp03(w5, w4); +#define X4PIXEL01_50 *(dp + 1) = Interp05(w2, w5); +#define X4PIXEL01_60 *(dp + 1) = Interp06(w5, w2, w4); +#define X4PIXEL01_61 *(dp + 1) = Interp06(w5, w2, w1); +#define X4PIXEL01_82 *(dp + 1) = Interp08(w5, w2); +#define X4PIXEL01_83 *(dp + 1) = Interp08(w2, w4); + +#define X4PIXEL02_0 *(dp + 2) = w5; +#define X4PIXEL02_10 *(dp + 2) = Interp01(w5, w3); +#define X4PIXEL02_11 *(dp + 2) = Interp01(w5, w2); +#define X4PIXEL02_13 *(dp + 2) = Interp01(w2, w5); +#define X4PIXEL02_21 *(dp + 2) = Interp02(w2, w5, w6); +#define X4PIXEL02_32 *(dp + 2) = Interp03(w5, w6); +#define X4PIXEL02_50 *(dp + 2) = Interp05(w2, w5); +#define X4PIXEL02_60 *(dp + 2) = Interp06(w5, w2, w6); +#define X4PIXEL02_61 *(dp + 2) = Interp06(w5, w2, w3); +#define X4PIXEL02_81 *(dp + 2) = Interp08(w5, w2); +#define X4PIXEL02_83 *(dp + 2) = Interp08(w2, w6); + +#define X4PIXEL03_0 *(dp + 3) = w5; +#define X4PIXEL03_11 *(dp + 3) = Interp01(w5, w2); +#define X4PIXEL03_12 *(dp + 3) = Interp01(w5, w6); +#define X4PIXEL03_20 *(dp + 3) = Interp02(w5, w2, w6); +#define X4PIXEL03_50 *(dp + 3) = Interp05(w2, w6); +#define X4PIXEL03_80 *(dp + 3) = Interp08(w5, w3); +#define X4PIXEL03_81 *(dp + 3) = Interp08(w5, w2); +#define X4PIXEL03_82 *(dp + 3) = Interp08(w5, w6); + +#define X4PIXEL10_0 *(dp + dst1line) = w5; +#define X4PIXEL10_10 *(dp + dst1line) = Interp01(w5, w1); +#define X4PIXEL10_11 *(dp + dst1line) = Interp01(w5, w4); +#define X4PIXEL10_13 *(dp + dst1line) = Interp01(w4, w5); +#define X4PIXEL10_21 *(dp + dst1line) = Interp02(w4, w5, w2); +#define X4PIXEL10_32 *(dp + dst1line) = Interp03(w5, w2); +#define X4PIXEL10_50 *(dp + dst1line) = Interp05(w4, w5); +#define X4PIXEL10_60 *(dp + dst1line) = Interp06(w5, w4, w2); +#define X4PIXEL10_61 *(dp + dst1line) = Interp06(w5, w4, w1); +#define X4PIXEL10_81 *(dp + dst1line) = Interp08(w5, w4); +#define X4PIXEL10_83 *(dp + dst1line) = Interp08(w4, w2); + +#define X4PIXEL11_0 *(dp + dst1line + 1) = w5; +#define X4PIXEL11_30 *(dp + dst1line + 1) = Interp03(w5, w1); +#define X4PIXEL11_31 *(dp + dst1line + 1) = Interp03(w5, w4); +#define X4PIXEL11_32 *(dp + dst1line + 1) = Interp03(w5, w2); +#define X4PIXEL11_70 *(dp + dst1line + 1) = Interp07(w5, w4, w2); + +#define X4PIXEL12_0 *(dp + dst1line + 2) = w5; +#define X4PIXEL12_30 *(dp + dst1line + 2) = Interp03(w5, w3); +#define X4PIXEL12_31 *(dp + dst1line + 2) = Interp03(w5, w2); +#define X4PIXEL12_32 *(dp + dst1line + 2) = Interp03(w5, w6); +#define X4PIXEL12_70 *(dp + dst1line + 2) = Interp07(w5, w6, w2); + +#define X4PIXEL13_0 *(dp + dst1line + 3) = w5; +#define X4PIXEL13_10 *(dp + dst1line + 3) = Interp01(w5, w3); +#define X4PIXEL13_12 *(dp + dst1line + 3) = Interp01(w5, w6); +#define X4PIXEL13_14 *(dp + dst1line + 3) = Interp01(w6, w5); +#define X4PIXEL13_21 *(dp + dst1line + 3) = Interp02(w6, w5, w2); +#define X4PIXEL13_31 *(dp + dst1line + 3) = Interp03(w5, w2); +#define X4PIXEL13_50 *(dp + dst1line + 3) = Interp05(w6, w5); +#define X4PIXEL13_60 *(dp + dst1line + 3) = Interp06(w5, w6, w2); +#define X4PIXEL13_61 *(dp + dst1line + 3) = Interp06(w5, w6, w3); +#define X4PIXEL13_82 *(dp + dst1line + 3) = Interp08(w5, w6); +#define X4PIXEL13_83 *(dp + dst1line + 3) = Interp08(w6, w2); + +#define X4PIXEL20_0 *(dp + dst1line + dst1line) = w5; +#define X4PIXEL20_10 *(dp + dst1line + dst1line) = Interp01(w5, w7); +#define X4PIXEL20_12 *(dp + dst1line + dst1line) = Interp01(w5, w4); +#define X4PIXEL20_14 *(dp + dst1line + dst1line) = Interp01(w4, w5); +#define X4PIXEL20_21 *(dp + dst1line + dst1line) = Interp02(w4, w5, w8); +#define X4PIXEL20_31 *(dp + dst1line + dst1line) = Interp03(w5, w8); +#define X4PIXEL20_50 *(dp + dst1line + dst1line) = Interp05(w4, w5); +#define X4PIXEL20_60 *(dp + dst1line + dst1line) = Interp06(w5, w4, w8); +#define X4PIXEL20_61 *(dp + dst1line + dst1line) = Interp06(w5, w4, w7); +#define X4PIXEL20_82 *(dp + dst1line + dst1line) = Interp08(w5, w4); +#define X4PIXEL20_83 *(dp + dst1line + dst1line) = Interp08(w4, w8); + +#define X4PIXEL21_0 *(dp + dst1line + dst1line + 1) = w5; +#define X4PIXEL21_30 *(dp + dst1line + dst1line + 1) = Interp03(w5, w7); +#define X4PIXEL21_31 *(dp + dst1line + dst1line + 1) = Interp03(w5, w8); +#define X4PIXEL21_32 *(dp + dst1line + dst1line + 1) = Interp03(w5, w4); +#define X4PIXEL21_70 *(dp + dst1line + dst1line + 1) = Interp07(w5, w4, w8); + +#define X4PIXEL22_0 *(dp + dst1line + dst1line + 2) = w5; +#define X4PIXEL22_30 *(dp + dst1line + dst1line + 2) = Interp03(w5, w9); +#define X4PIXEL22_31 *(dp + dst1line + dst1line + 2) = Interp03(w5, w6); +#define X4PIXEL22_32 *(dp + dst1line + dst1line + 2) = Interp03(w5, w8); +#define X4PIXEL22_70 *(dp + dst1line + dst1line + 2) = Interp07(w5, w6, w8); + +#define X4PIXEL23_0 *(dp + dst1line + dst1line + 3) = w5; +#define X4PIXEL23_10 *(dp + dst1line + dst1line + 3) = Interp01(w5, w9); +#define X4PIXEL23_11 *(dp + dst1line + dst1line + 3) = Interp01(w5, w6); +#define X4PIXEL23_13 *(dp + dst1line + dst1line + 3) = Interp01(w6, w5); +#define X4PIXEL23_21 *(dp + dst1line + dst1line + 3) = Interp02(w6, w5, w8); +#define X4PIXEL23_32 *(dp + dst1line + dst1line + 3) = Interp03(w5, w8); +#define X4PIXEL23_50 *(dp + dst1line + dst1line + 3) = Interp05(w6, w5); +#define X4PIXEL23_60 *(dp + dst1line + dst1line + 3) = Interp06(w5, w6, w8); +#define X4PIXEL23_61 *(dp + dst1line + dst1line + 3) = Interp06(w5, w6, w9); +#define X4PIXEL23_81 *(dp + dst1line + dst1line + 3) = Interp08(w5, w6); +#define X4PIXEL23_83 *(dp + dst1line + dst1line + 3) = Interp08(w6, w8); + +#define X4PIXEL30_0 *(dp + dst1line + dst1line + dst1line) = w5; +#define X4PIXEL30_11 *(dp + dst1line + dst1line + dst1line) = Interp01(w5, w8); +#define X4PIXEL30_12 *(dp + dst1line + dst1line + dst1line) = Interp01(w5, w4); +#define X4PIXEL30_20 *(dp + dst1line + dst1line + dst1line) = Interp02(w5, w8, w4); +#define X4PIXEL30_50 *(dp + dst1line + dst1line + dst1line) = Interp05(w8, w4); +#define X4PIXEL30_80 *(dp + dst1line + dst1line + dst1line) = Interp08(w5, w7); +#define X4PIXEL30_81 *(dp + dst1line + dst1line + dst1line) = Interp08(w5, w8); +#define X4PIXEL30_82 *(dp + dst1line + dst1line + dst1line) = Interp08(w5, w4); + +#define X4PIXEL31_0 *(dp + dst1line + dst1line + dst1line + 1) = w5; +#define X4PIXEL31_10 *(dp + dst1line + dst1line + dst1line + 1) = Interp01(w5, w7); +#define X4PIXEL31_11 *(dp + dst1line + dst1line + dst1line + 1) = Interp01(w5, w8); +#define X4PIXEL31_13 *(dp + dst1line + dst1line + dst1line + 1) = Interp01(w8, w5); +#define X4PIXEL31_21 *(dp + dst1line + dst1line + dst1line + 1) = Interp02(w8, w5, w4); +#define X4PIXEL31_32 *(dp + dst1line + dst1line + dst1line + 1) = Interp03(w5, w4); +#define X4PIXEL31_50 *(dp + dst1line + dst1line + dst1line + 1) = Interp05(w8, w5); +#define X4PIXEL31_60 *(dp + dst1line + dst1line + dst1line + 1) = Interp06(w5, w8, w4); +#define X4PIXEL31_61 *(dp + dst1line + dst1line + dst1line + 1) = Interp06(w5, w8, w7); +#define X4PIXEL31_81 *(dp + dst1line + dst1line + dst1line + 1) = Interp08(w5, w8); +#define X4PIXEL31_83 *(dp + dst1line + dst1line + dst1line + 1) = Interp08(w8, w4); + +#define X4PIXEL32_0 *(dp + dst1line + dst1line + dst1line + 2) = w5; +#define X4PIXEL32_10 *(dp + dst1line + dst1line + dst1line + 2) = Interp01(w5, w9); +#define X4PIXEL32_12 *(dp + dst1line + dst1line + dst1line + 2) = Interp01(w5, w8); +#define X4PIXEL32_14 *(dp + dst1line + dst1line + dst1line + 2) = Interp01(w8, w5); +#define X4PIXEL32_21 *(dp + dst1line + dst1line + dst1line + 2) = Interp02(w8, w5, w6); +#define X4PIXEL32_31 *(dp + dst1line + dst1line + dst1line + 2) = Interp03(w5, w6); +#define X4PIXEL32_50 *(dp + dst1line + dst1line + dst1line + 2) = Interp05(w8, w5); +#define X4PIXEL32_60 *(dp + dst1line + dst1line + dst1line + 2) = Interp06(w5, w8, w6); +#define X4PIXEL32_61 *(dp + dst1line + dst1line + dst1line + 2) = Interp06(w5, w8, w9); +#define X4PIXEL32_82 *(dp + dst1line + dst1line + dst1line + 2) = Interp08(w5, w8); +#define X4PIXEL32_83 *(dp + dst1line + dst1line + dst1line + 2) = Interp08(w8, w6); + +#define X4PIXEL33_0 *(dp + dst1line + dst1line + dst1line + 3) = w5; +#define X4PIXEL33_11 *(dp + dst1line + dst1line + dst1line + 3) = Interp01(w5, w6); +#define X4PIXEL33_12 *(dp + dst1line + dst1line + dst1line + 3) = Interp01(w5, w8); +#define X4PIXEL33_20 *(dp + dst1line + dst1line + dst1line + 3) = Interp02(w5, w8, w6); +#define X4PIXEL33_50 *(dp + dst1line + dst1line + dst1line + 3) = Interp05(w8, w6); +#define X4PIXEL33_80 *(dp + dst1line + dst1line + dst1line + 3) = Interp08(w5, w9); +#define X4PIXEL33_81 *(dp + dst1line + dst1line + dst1line + 3) = Interp08(w5, w6); +#define X4PIXEL33_82 *(dp + dst1line + dst1line + dst1line + 3) = Interp08(w5, w8); + +#define Absolute(c) \ +(!(c & (1 << 31)) ? c : (~c + 1)) + +static int *RGBtoYUV = NULL; + +static void InitLUTs (void); +static inline bool Diff (int, int); + + +bool8 S9xBlitHQ2xFilterInit (void) +{ + uint32 n = 1 << ((FIRST_COLOR_MASK & 0x8000) ? 16 : 15); + RGBtoYUV = new int[n]; + if (!RGBtoYUV) + return (FALSE); + + InitLUTs(); + + return (TRUE); +} + +void S9xBlitHQ2xFilterDeinit (void) +{ + if (RGBtoYUV) + { + delete[] RGBtoYUV; + RGBtoYUV = NULL; + } +} + +static void InitLUTs (void) +{ + uint32 r, g, b; + int y, u, v; + + uint32 n = 1 << ((FIRST_COLOR_MASK & 0x8000) ? 16 : 15); + for (uint32 c = 0 ; c < n ; c++) + { + DECOMPOSE_PIXEL(c, r, g, b); + r <<= 3; + g <<= 3; + b <<= 3; + + y = (int) ( 0.256788f * r + 0.504129f * g + 0.097906f * b + 0.5f) + 16; + u = (int) (-0.148223f * r - 0.290993f * g + 0.439216f * b + 0.5f) + 128; + v = (int) ( 0.439216f * r - 0.367788f * g - 0.071427f * b + 0.5f) + 128; + + RGBtoYUV[c] = (y << 16) + (u << 8) + v; + } +} + +static inline bool Diff (int c1, int c2) +{ + int c1y = (c1 & Ymask) - (c2 & Ymask); + if (Absolute(c1y) > trY) + return (true); + + int c1u = (c1 & Umask) - (c2 & Umask); + if (Absolute(c1u) > trU) + return (true); + + int c1v = (c1 & Vmask) - (c2 & Vmask); + if (Absolute(c1v) > trV) + return (true); + + return (false); +} + +void HQ2X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +{ + int w1, w2, w3, w4, w5, w6, w7, w8, w9; + uint32 src1line = srcPitch >> 1; + uint32 dst1line = dstPitch >> 1; + uint16 *sp = (uint16 *) srcPtr; + uint16 *dp = (uint16 *) dstPtr; + + uint32 pattern; + int l, y; + + while (height--) + { + sp--; + + w1 = *(sp - src1line); + w4 = *(sp); + w7 = *(sp + src1line); + + sp++; + + w2 = *(sp - src1line); + w5 = *(sp); + w8 = *(sp + src1line); + + for (l = width; l; l--) + { + sp++; + + w3 = *(sp - src1line); + w6 = *(sp); + w9 = *(sp + src1line); + + y = RGBtoYUV[w5]; + pattern = 0; + + if ((w1 != w5) && (Diff(y, RGBtoYUV[w1]))) pattern |= (1 << 0); + if ((w2 != w5) && (Diff(y, RGBtoYUV[w2]))) pattern |= (1 << 1); + if ((w3 != w5) && (Diff(y, RGBtoYUV[w3]))) pattern |= (1 << 2); + if ((w4 != w5) && (Diff(y, RGBtoYUV[w4]))) pattern |= (1 << 3); + if ((w6 != w5) && (Diff(y, RGBtoYUV[w6]))) pattern |= (1 << 4); + if ((w7 != w5) && (Diff(y, RGBtoYUV[w7]))) pattern |= (1 << 5); + if ((w8 != w5) && (Diff(y, RGBtoYUV[w8]))) pattern |= (1 << 6); + if ((w9 != w5) && (Diff(y, RGBtoYUV[w9]))) pattern |= (1 << 7); + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + X2PIXEL00_22 + X2PIXEL01_21 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + X2PIXEL00_20 + X2PIXEL01_22 + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 64: + case 65: + case 68: + case 69: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_21 + X2PIXEL11_22 + break; + } + case 8: + case 12: + case 136: + case 140: + { + X2PIXEL00_21 + X2PIXEL01_20 + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + X2PIXEL00_11 + X2PIXEL01_21 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + X2PIXEL00_22 + X2PIXEL01_12 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + X2PIXEL00_20 + X2PIXEL01_11 + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 144: + case 145: + case 176: + case 177: + { + X2PIXEL00_20 + X2PIXEL01_22 + X2PIXEL10_20 + X2PIXEL11_12 + break; + } + case 192: + case 193: + case 196: + case 197: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_21 + X2PIXEL11_11 + break; + } + case 96: + case 97: + case 100: + case 101: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_12 + X2PIXEL11_22 + break; + } + case 40: + case 44: + case 168: + case 172: + { + X2PIXEL00_21 + X2PIXEL01_20 + X2PIXEL10_11 + X2PIXEL11_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + X2PIXEL00_12 + X2PIXEL01_20 + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 18: + case 50: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 80: + case 81: + { + X2PIXEL00_20 + X2PIXEL01_22 + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_20 + } + break; + } + case 72: + case 76: + { + X2PIXEL00_21 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 10: + case 138: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 66: + { + X2PIXEL00_22 + X2PIXEL01_21 + X2PIXEL10_21 + X2PIXEL11_22 + break; + } + case 24: + { + X2PIXEL00_21 + X2PIXEL01_22 + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 7: + case 39: + case 135: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 148: + case 149: + case 180: + { + X2PIXEL00_20 + X2PIXEL01_11 + X2PIXEL10_20 + X2PIXEL11_12 + break; + } + case 224: + case 228: + case 225: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 41: + case 169: + case 45: + { + X2PIXEL00_12 + X2PIXEL01_20 + X2PIXEL10_11 + X2PIXEL11_20 + break; + } + case 22: + case 54: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 208: + case 209: + { + X2PIXEL00_20 + X2PIXEL01_22 + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 104: + case 108: + { + X2PIXEL00_21 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 11: + case 139: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 19: + case 51: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL00_11 + X2PIXEL01_10 + } + else + { + X2PIXEL00_60 + X2PIXEL01_90 + } + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 146: + case 178: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + X2PIXEL11_12 + } + else + { + X2PIXEL01_90 + X2PIXEL11_61 + } + X2PIXEL10_20 + break; + } + case 84: + case 85: + { + X2PIXEL00_20 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL01_11 + X2PIXEL11_10 + } + else + { + X2PIXEL01_60 + X2PIXEL11_90 + } + X2PIXEL10_21 + break; + } + case 112: + case 113: + { + X2PIXEL00_20 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL10_12 + X2PIXEL11_10 + } + else + { + X2PIXEL10_61 + X2PIXEL11_90 + } + break; + } + case 200: + case 204: + { + X2PIXEL00_21 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + X2PIXEL11_11 + } + else + { + X2PIXEL10_90 + X2PIXEL11_60 + } + break; + } + case 73: + case 77: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL00_12 + X2PIXEL10_10 + } + else + { + X2PIXEL00_61 + X2PIXEL10_90 + } + X2PIXEL01_20 + X2PIXEL11_22 + break; + } + case 42: + case 170: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + X2PIXEL10_11 + } + else + { + X2PIXEL00_90 + X2PIXEL10_60 + } + X2PIXEL01_21 + X2PIXEL11_20 + break; + } + case 14: + case 142: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + X2PIXEL01_12 + } + else + { + X2PIXEL00_90 + X2PIXEL01_61 + } + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 67: + { + X2PIXEL00_11 + X2PIXEL01_21 + X2PIXEL10_21 + X2PIXEL11_22 + break; + } + case 70: + { + X2PIXEL00_22 + X2PIXEL01_12 + X2PIXEL10_21 + X2PIXEL11_22 + break; + } + case 28: + { + X2PIXEL00_21 + X2PIXEL01_11 + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 152: + { + X2PIXEL00_21 + X2PIXEL01_22 + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 194: + { + X2PIXEL00_22 + X2PIXEL01_21 + X2PIXEL10_21 + X2PIXEL11_11 + break; + } + case 98: + { + X2PIXEL00_22 + X2PIXEL01_21 + X2PIXEL10_12 + X2PIXEL11_22 + break; + } + case 56: + { + X2PIXEL00_21 + X2PIXEL01_22 + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 25: + { + X2PIXEL00_12 + X2PIXEL01_22 + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 26: + case 31: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 82: + case 214: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 88: + case 248: + { + X2PIXEL00_21 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 74: + case 107: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 27: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_10 + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 86: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_21 + X2PIXEL11_10 + break; + } + case 216: + { + X2PIXEL00_21 + X2PIXEL01_22 + X2PIXEL10_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 106: + { + X2PIXEL00_10 + X2PIXEL01_21 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 30: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 210: + { + X2PIXEL00_22 + X2PIXEL01_10 + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 120: + { + X2PIXEL00_21 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_10 + break; + } + case 75: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + X2PIXEL10_10 + X2PIXEL11_22 + break; + } + case 29: + { + X2PIXEL00_12 + X2PIXEL01_11 + X2PIXEL10_22 + X2PIXEL11_21 + break; + } + case 198: + { + X2PIXEL00_22 + X2PIXEL01_12 + X2PIXEL10_21 + X2PIXEL11_11 + break; + } + case 184: + { + X2PIXEL00_21 + X2PIXEL01_22 + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 99: + { + X2PIXEL00_11 + X2PIXEL01_21 + X2PIXEL10_12 + X2PIXEL11_22 + break; + } + case 57: + { + X2PIXEL00_12 + X2PIXEL01_22 + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 71: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_21 + X2PIXEL11_22 + break; + } + case 156: + { + X2PIXEL00_21 + X2PIXEL01_11 + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 226: + { + X2PIXEL00_22 + X2PIXEL01_21 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 60: + { + X2PIXEL00_21 + X2PIXEL01_11 + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 195: + { + X2PIXEL00_11 + X2PIXEL01_21 + X2PIXEL10_21 + X2PIXEL11_11 + break; + } + case 102: + { + X2PIXEL00_22 + X2PIXEL01_12 + X2PIXEL10_12 + X2PIXEL11_22 + break; + } + case 153: + { + X2PIXEL00_12 + X2PIXEL01_22 + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 58: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 83: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 92: + { + X2PIXEL00_21 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 202: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + X2PIXEL01_21 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + X2PIXEL11_11 + break; + } + case 78: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + X2PIXEL11_22 + break; + } + case 154: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 114: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 89: + { + X2PIXEL00_12 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 90: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 55: + case 23: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL00_11 + X2PIXEL01_0 + } + else + { + X2PIXEL00_60 + X2PIXEL01_90 + } + X2PIXEL10_20 + X2PIXEL11_21 + break; + } + case 182: + case 150: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + X2PIXEL11_12 + } + else + { + X2PIXEL01_90 + X2PIXEL11_61 + } + X2PIXEL10_20 + break; + } + case 213: + case 212: + { + X2PIXEL00_20 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL01_11 + X2PIXEL11_0 + } + else + { + X2PIXEL01_60 + X2PIXEL11_90 + } + X2PIXEL10_21 + break; + } + case 241: + case 240: + { + X2PIXEL00_20 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL10_12 + X2PIXEL11_0 + } + else + { + X2PIXEL10_61 + X2PIXEL11_90 + } + break; + } + case 236: + case 232: + { + X2PIXEL00_21 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + X2PIXEL11_11 + } + else + { + X2PIXEL10_90 + X2PIXEL11_60 + } + break; + } + case 109: + case 105: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL00_12 + X2PIXEL10_0 + } + else + { + X2PIXEL00_61 + X2PIXEL10_90 + } + X2PIXEL01_20 + X2PIXEL11_22 + break; + } + case 171: + case 43: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + X2PIXEL10_11 + } + else + { + X2PIXEL00_90 + X2PIXEL10_60 + } + X2PIXEL01_21 + X2PIXEL11_20 + break; + } + case 143: + case 15: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + X2PIXEL01_12 + } + else + { + X2PIXEL00_90 + X2PIXEL01_61 + } + X2PIXEL10_22 + X2PIXEL11_20 + break; + } + case 124: + { + X2PIXEL00_21 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_10 + break; + } + case 203: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + X2PIXEL10_10 + X2PIXEL11_11 + break; + } + case 62: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 211: + { + X2PIXEL00_11 + X2PIXEL01_10 + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 118: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_12 + X2PIXEL11_10 + break; + } + case 217: + { + X2PIXEL00_12 + X2PIXEL01_22 + X2PIXEL10_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 110: + { + X2PIXEL00_10 + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 155: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_10 + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 188: + { + X2PIXEL00_21 + X2PIXEL01_11 + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 185: + { + X2PIXEL00_12 + X2PIXEL01_22 + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 61: + { + X2PIXEL00_12 + X2PIXEL01_11 + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 157: + { + X2PIXEL00_12 + X2PIXEL01_11 + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 103: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_12 + X2PIXEL11_22 + break; + } + case 227: + { + X2PIXEL00_11 + X2PIXEL01_21 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 230: + { + X2PIXEL00_22 + X2PIXEL01_12 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 199: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_21 + X2PIXEL11_11 + break; + } + case 220: + { + X2PIXEL00_21 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 158: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 234: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + X2PIXEL01_21 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_11 + break; + } + case 242: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 59: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 121: + { + X2PIXEL00_12 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 87: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 79: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + X2PIXEL11_22 + break; + } + case 122: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 94: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 218: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 91: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 229: + { + X2PIXEL00_20 + X2PIXEL01_20 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 167: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_20 + X2PIXEL11_20 + break; + } + case 173: + { + X2PIXEL00_12 + X2PIXEL01_20 + X2PIXEL10_11 + X2PIXEL11_20 + break; + } + case 181: + { + X2PIXEL00_20 + X2PIXEL01_11 + X2PIXEL10_20 + X2PIXEL11_12 + break; + } + case 186: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 115: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 93: + { + X2PIXEL00_12 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 206: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + X2PIXEL11_11 + break; + } + case 205: + case 201: + { + X2PIXEL00_12 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_10 + } + else + { + X2PIXEL10_70 + } + X2PIXEL11_11 + break; + } + case 174: + case 46: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_10 + } + else + { + X2PIXEL00_70 + } + X2PIXEL01_12 + X2PIXEL10_11 + X2PIXEL11_20 + break; + } + case 179: + case 147: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_10 + } + else + { + X2PIXEL01_70 + } + X2PIXEL10_20 + X2PIXEL11_12 + break; + } + case 117: + case 116: + { + X2PIXEL00_20 + X2PIXEL01_11 + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_10 + } + else + { + X2PIXEL11_70 + } + break; + } + case 189: + { + X2PIXEL00_12 + X2PIXEL01_11 + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 231: + { + X2PIXEL00_11 + X2PIXEL01_12 + X2PIXEL10_12 + X2PIXEL11_11 + break; + } + case 126: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_10 + break; + } + case 219: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_10 + X2PIXEL10_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 125: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL00_12 + X2PIXEL10_0 + } + else + { + X2PIXEL00_61 + X2PIXEL10_90 + } + X2PIXEL01_11 + X2PIXEL11_10 + break; + } + case 221: + { + X2PIXEL00_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL01_11 + X2PIXEL11_0 + } + else + { + X2PIXEL01_60 + X2PIXEL11_90 + } + X2PIXEL10_10 + break; + } + case 207: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + X2PIXEL01_12 + } + else + { + X2PIXEL00_90 + X2PIXEL01_61 + } + X2PIXEL10_10 + X2PIXEL11_11 + break; + } + case 238: + { + X2PIXEL00_10 + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + X2PIXEL11_11 + } + else + { + X2PIXEL10_90 + X2PIXEL11_60 + } + break; + } + case 190: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + X2PIXEL11_12 + } + else + { + X2PIXEL01_90 + X2PIXEL11_61 + } + X2PIXEL10_11 + break; + } + case 187: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + X2PIXEL10_11 + } + else + { + X2PIXEL00_90 + X2PIXEL10_60 + } + X2PIXEL01_10 + X2PIXEL11_12 + break; + } + case 243: + { + X2PIXEL00_11 + X2PIXEL01_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL10_12 + X2PIXEL11_0 + } + else + { + X2PIXEL10_61 + X2PIXEL11_90 + } + break; + } + case 119: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL00_11 + X2PIXEL01_0 + } + else + { + X2PIXEL00_60 + X2PIXEL01_90 + } + X2PIXEL10_12 + X2PIXEL11_10 + break; + } + case 237: + case 233: + { + X2PIXEL00_12 + X2PIXEL01_20 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + X2PIXEL11_11 + break; + } + case 175: + case 47: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + X2PIXEL01_12 + X2PIXEL10_11 + X2PIXEL11_20 + break; + } + case 183: + case 151: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_20 + X2PIXEL11_12 + break; + } + case 245: + case 244: + { + X2PIXEL00_20 + X2PIXEL01_11 + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 250: + { + X2PIXEL00_10 + X2PIXEL01_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 123: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_10 + break; + } + case 95: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_10 + X2PIXEL11_10 + break; + } + case 222: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 252: + { + X2PIXEL00_21 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 249: + { + X2PIXEL00_12 + X2PIXEL01_22 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 235: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_21 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + X2PIXEL11_11 + break; + } + case 111: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_22 + break; + } + case 63: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_11 + X2PIXEL11_21 + break; + } + case 159: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_22 + X2PIXEL11_12 + break; + } + case 215: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_21 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 246: + { + X2PIXEL00_22 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 254: + { + X2PIXEL00_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 253: + { + X2PIXEL00_12 + X2PIXEL01_11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 251: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + X2PIXEL01_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 239: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + X2PIXEL01_12 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + X2PIXEL11_11 + break; + } + case 127: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_20 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_20 + } + X2PIXEL11_10 + break; + } + case 191: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_11 + X2PIXEL11_12 + break; + } + case 223: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_20 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_10 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_20 + } + break; + } + case 247: + { + X2PIXEL00_11 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + X2PIXEL10_12 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + case 255: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X2PIXEL00_0 + } + else + { + X2PIXEL00_100 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X2PIXEL01_0 + } + else + { + X2PIXEL01_100 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X2PIXEL10_0 + } + else + { + X2PIXEL10_100 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X2PIXEL11_0 + } + else + { + X2PIXEL11_100 + } + break; + } + } + + w1 = w2; w4 = w5; w7 = w8; + w2 = w3; w5 = w6; w8 = w9; + + dp += 2; + } + + dp += (dst1line - width) * 2; + sp += (src1line - width); + } +} + +void HQ3X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +{ + int w1, w2, w3, w4, w5, w6, w7, w8, w9; + uint32 src1line = srcPitch >> 1; + uint32 dst1line = dstPitch >> 1; + uint16 *sp = (uint16 *) srcPtr; + uint16 *dp = (uint16 *) dstPtr; + + uint32 pattern; + int l, y; + + while (height--) + { + sp--; + + w1 = *(sp - src1line); + w4 = *(sp); + w7 = *(sp + src1line); + + sp++; + + w2 = *(sp - src1line); + w5 = *(sp); + w8 = *(sp + src1line); + + for (l = width; l; l--) + { + sp++; + + w3 = *(sp - src1line); + w6 = *(sp); + w9 = *(sp + src1line); + + y = RGBtoYUV[w5]; + pattern = 0; + + if ((w1 != w5) && (Diff(y, RGBtoYUV[w1]))) pattern |= (1 << 0); + if ((w2 != w5) && (Diff(y, RGBtoYUV[w2]))) pattern |= (1 << 1); + if ((w3 != w5) && (Diff(y, RGBtoYUV[w3]))) pattern |= (1 << 2); + if ((w4 != w5) && (Diff(y, RGBtoYUV[w4]))) pattern |= (1 << 3); + if ((w6 != w5) && (Diff(y, RGBtoYUV[w6]))) pattern |= (1 << 4); + if ((w7 != w5) && (Diff(y, RGBtoYUV[w7]))) pattern |= (1 << 5); + if ((w8 != w5) && (Diff(y, RGBtoYUV[w8]))) pattern |= (1 << 6); + if ((w9 != w5) && (Diff(y, RGBtoYUV[w9]))) pattern |= (1 << 7); + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 2: + case 34: + case 130: + case 162: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 16: + case 17: + case 48: + case 49: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 64: + case 65: + case 68: + case 69: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 8: + case 12: + case 136: + case 140: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 3: + case 35: + case 131: + case 163: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 6: + case 38: + case 134: + case 166: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 20: + case 21: + case 52: + case 53: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 144: + case 145: + case 176: + case 177: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 192: + case 193: + case 196: + case 197: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 96: + case 97: + case 100: + case 101: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 40: + case 44: + case 168: + case 172: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 9: + case 13: + case 137: + case 141: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 18: + case 50: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 80: + case 81: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_1M + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 72: + case 76: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_1M + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 10: + case 138: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 66: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 24: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 7: + case 39: + case 135: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 148: + case 149: + case 180: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 224: + case 228: + case 225: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 41: + case 169: + case 45: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 22: + case 54: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 208: + case 209: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 104: + case 108: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 11: + case 139: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 19: + case 51: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL12_C + } + else + { + X3PIXEL00_2 + X3PIXEL01_6 + X3PIXEL02_5 + X3PIXEL12_1 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 146: + case 178: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL12_C + X3PIXEL22_1D + } + else + { + X3PIXEL01_1 + X3PIXEL02_5 + X3PIXEL12_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + break; + } + case 84: + case 85: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL02_1U + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_1M + } + else + { + X3PIXEL02_2 + X3PIXEL12_6 + X3PIXEL21_1 + X3PIXEL22_5 + } + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + break; + } + case 112: + case 113: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + } + else + { + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_6 + X3PIXEL22_5 + } + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + break; + } + case 200: + case 204: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + } + else + { + X3PIXEL10_1 + X3PIXEL20_5 + X3PIXEL21_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + break; + } + case 73: + case 77: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL00_1U + X3PIXEL10_C + X3PIXEL20_1M + X3PIXEL21_C + } + else + { + X3PIXEL00_2 + X3PIXEL10_6 + X3PIXEL20_5 + X3PIXEL21_1 + } + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL22_1M + break; + } + case 42: + case 170: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL10_C + X3PIXEL20_1D + } + else + { + X3PIXEL00_5 + X3PIXEL01_1 + X3PIXEL10_6 + X3PIXEL20_2 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 14: + case 142: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + } + else + { + X3PIXEL00_5 + X3PIXEL01_6 + X3PIXEL02_2 + X3PIXEL10_1 + } + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 67: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 70: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 28: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 152: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 194: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 98: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 56: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 25: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 26: + case 31: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL10_3 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 82: + case 214: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 88: + case 248: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL22_4 + } + break; + } + case 74: + case 107: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + } + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 27: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 86: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 216: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 106: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 30: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 210: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 120: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 75: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 29: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 198: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 184: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 99: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 57: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 71: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 156: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 226: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 60: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 195: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 102: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 153: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 58: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 83: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 92: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 202: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 78: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 154: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 114: + { + X3PIXEL00_1M + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 89: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 90: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 55: + case 23: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL00_2 + X3PIXEL01_6 + X3PIXEL02_5 + X3PIXEL12_1 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 182: + case 150: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + X3PIXEL22_1D + } + else + { + X3PIXEL01_1 + X3PIXEL02_5 + X3PIXEL12_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_2 + X3PIXEL21_1 + break; + } + case 213: + case 212: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL02_1U + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL02_2 + X3PIXEL12_6 + X3PIXEL21_1 + X3PIXEL22_5 + } + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + break; + } + case 241: + case 240: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_6 + X3PIXEL22_5 + } + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + break; + } + case 236: + case 232: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + X3PIXEL22_1R + } + else + { + X3PIXEL10_1 + X3PIXEL20_5 + X3PIXEL21_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + break; + } + case 109: + case 105: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL00_1U + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL00_2 + X3PIXEL10_6 + X3PIXEL20_5 + X3PIXEL21_1 + } + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL22_1M + break; + } + case 171: + case 43: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + X3PIXEL20_1D + } + else + { + X3PIXEL00_5 + X3PIXEL01_1 + X3PIXEL10_6 + X3PIXEL20_2 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 143: + case 15: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + } + else + { + X3PIXEL00_5 + X3PIXEL01_6 + X3PIXEL02_2 + X3PIXEL10_1 + } + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 124: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 203: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 62: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 211: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 118: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 217: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 110: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 155: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 188: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 185: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 61: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 157: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 103: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 227: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 230: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 199: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 220: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 158: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 234: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1R + break; + } + case 242: + { + X3PIXEL00_1M + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1L + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 59: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 121: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 87: + { + X3PIXEL00_1L + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 79: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1R + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 122: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 94: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_C + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 218: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 91: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 229: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 167: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 173: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 181: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 186: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 115: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 93: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 206: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 205: + case 201: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_1M + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 174: + case 46: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_1M + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 179: + case 147: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_1M + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 117: + case 116: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_1M + } + else + { + X3PIXEL22_2 + } + break; + } + case 189: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 231: + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 126: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 219: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + X3PIXEL10_3 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 125: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL00_1U + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL00_2 + X3PIXEL10_6 + X3PIXEL20_5 + X3PIXEL21_1 + } + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL11 + X3PIXEL12_C + X3PIXEL22_1M + break; + } + case 221: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL02_1U + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL02_2 + X3PIXEL12_6 + X3PIXEL21_1 + X3PIXEL22_5 + } + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1M + break; + } + case 207: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + } + else + { + X3PIXEL00_5 + X3PIXEL01_6 + X3PIXEL02_2 + X3PIXEL10_1 + } + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 238: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + X3PIXEL22_1R + } + else + { + X3PIXEL10_1 + X3PIXEL20_5 + X3PIXEL21_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL11 + X3PIXEL12_1 + break; + } + case 190: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + X3PIXEL22_1D + } + else + { + X3PIXEL01_1 + X3PIXEL02_5 + X3PIXEL12_6 + X3PIXEL22_2 + } + X3PIXEL00_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1D + X3PIXEL21_1 + break; + } + case 187: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + X3PIXEL20_1D + } + else + { + X3PIXEL00_5 + X3PIXEL01_1 + X3PIXEL10_6 + X3PIXEL20_2 + } + X3PIXEL02_1M + X3PIXEL11 + X3PIXEL12_C + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 243: + { + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_1 + X3PIXEL20_2 + X3PIXEL21_6 + X3PIXEL22_5 + } + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL10_1 + X3PIXEL11 + break; + } + case 119: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL00_1L + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL00_2 + X3PIXEL01_6 + X3PIXEL02_5 + X3PIXEL12_1 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL20_1L + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 237: + case 233: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_2 + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 175: + case 47: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_2 + break; + } + case 183: + case 151: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_2 + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 245: + case 244: + { + X3PIXEL00_2 + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + case 250: + { + X3PIXEL00_1M + X3PIXEL01_C + X3PIXEL02_1M + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL22_4 + } + break; + } + case 123: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + } + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 95: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL10_3 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL11 + X3PIXEL20_1M + X3PIXEL21_C + X3PIXEL22_1M + break; + } + case 222: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 252: + { + X3PIXEL00_1M + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + case 249: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL22_4 + } + break; + } + case 235: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + } + X3PIXEL02_1M + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 111: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 63: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1M + break; + } + case 159: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL10_3 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 215: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 246: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + case 254: + { + X3PIXEL00_1M + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_4 + } + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_4 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL21_3 + X3PIXEL22_2 + } + break; + } + case 253: + { + X3PIXEL00_1U + X3PIXEL01_1 + X3PIXEL02_1U + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + case 251: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + } + else + { + X3PIXEL00_4 + X3PIXEL01_3 + } + X3PIXEL02_1M + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL10_C + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL10_3 + X3PIXEL20_2 + X3PIXEL21_3 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL12_C + X3PIXEL22_C + } + else + { + X3PIXEL12_3 + X3PIXEL22_4 + } + break; + } + case 239: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + X3PIXEL02_1R + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_1 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + X3PIXEL22_1R + break; + } + case 127: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL01_C + X3PIXEL10_C + } + else + { + X3PIXEL00_2 + X3PIXEL01_3 + X3PIXEL10_3 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL02_4 + X3PIXEL12_3 + } + X3PIXEL11 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + X3PIXEL21_C + } + else + { + X3PIXEL20_4 + X3PIXEL21_3 + } + X3PIXEL22_1M + break; + } + case 191: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1D + X3PIXEL21_1 + X3PIXEL22_1D + break; + } + case 223: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + X3PIXEL10_C + } + else + { + X3PIXEL00_4 + X3PIXEL10_3 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL01_C + X3PIXEL02_C + X3PIXEL12_C + } + else + { + X3PIXEL01_3 + X3PIXEL02_2 + X3PIXEL12_3 + } + X3PIXEL11 + X3PIXEL20_1M + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL21_C + X3PIXEL22_C + } + else + { + X3PIXEL21_3 + X3PIXEL22_4 + } + break; + } + case 247: + { + X3PIXEL00_1L + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_1 + X3PIXEL11 + X3PIXEL12_C + X3PIXEL20_1L + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + case 255: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X3PIXEL00_C + } + else + { + X3PIXEL00_2 + } + X3PIXEL01_C + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X3PIXEL02_C + } + else + { + X3PIXEL02_2 + } + X3PIXEL10_C + X3PIXEL11 + X3PIXEL12_C + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X3PIXEL20_C + } + else + { + X3PIXEL20_2 + } + X3PIXEL21_C + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X3PIXEL22_C + } + else + { + X3PIXEL22_2 + } + break; + } + } + + w1 = w2; w4 = w5; w7 = w8; + w2 = w3; w5 = w6; w8 = w9; + + dp += 3; + } + + dp += (dst1line - width) * 3; + sp += (src1line - width); + } +} + +void HQ4X_16 (uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) +{ + int w1, w2, w3, w4, w5, w6, w7, w8, w9; + uint32 src1line = srcPitch >> 1; + uint32 dst1line = dstPitch >> 1; + uint16 *sp = (uint16 *) srcPtr; + uint16 *dp = (uint16 *) dstPtr; + + uint32 pattern; + int l, y; + + while (height--) + { + sp--; + + w1 = *(sp - src1line); + w4 = *(sp); + w7 = *(sp + src1line); + + sp++; + + w2 = *(sp - src1line); + w5 = *(sp); + w8 = *(sp + src1line); + + for (l = width; l; l--) + { + sp++; + + w3 = *(sp - src1line); + w6 = *(sp); + w9 = *(sp + src1line); + + y = RGBtoYUV[w5]; + pattern = 0; + + if ((w1 != w5) && (Diff(y, RGBtoYUV[w1]))) pattern |= (1 << 0); + if ((w2 != w5) && (Diff(y, RGBtoYUV[w2]))) pattern |= (1 << 1); + if ((w3 != w5) && (Diff(y, RGBtoYUV[w3]))) pattern |= (1 << 2); + if ((w4 != w5) && (Diff(y, RGBtoYUV[w4]))) pattern |= (1 << 3); + if ((w6 != w5) && (Diff(y, RGBtoYUV[w6]))) pattern |= (1 << 4); + if ((w7 != w5) && (Diff(y, RGBtoYUV[w7]))) pattern |= (1 << 5); + if ((w8 != w5) && (Diff(y, RGBtoYUV[w8]))) pattern |= (1 << 6); + if ((w9 != w5) && (Diff(y, RGBtoYUV[w9]))) pattern |= (1 << 7); + + switch (pattern) + { + case 0: + case 1: + case 4: + case 32: + case 128: + case 5: + case 132: + case 160: + case 33: + case 129: + case 36: + case 133: + case 164: + case 161: + case 37: + case 165: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 2: + case 34: + case 130: + case 162: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 16: + case 17: + case 48: + case 49: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 64: + case 65: + case 68: + case 69: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 8: + case 12: + case 136: + case 140: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 3: + case 35: + case 131: + case 163: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 6: + case 38: + case 134: + case 166: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 20: + case 21: + case 52: + case 53: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 144: + case 145: + case 176: + case 177: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 192: + case 193: + case 196: + case 197: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 96: + case 97: + case 100: + case 101: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 40: + case 44: + case 168: + case 172: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 9: + case 13: + case 137: + case 141: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 18: + case 50: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL12_0 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 80: + case 81: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_61 + X4PIXEL21_30 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 72: + case 76: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_50 + X4PIXEL21_0 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 10: + case 138: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + X4PIXEL11_0 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 66: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 24: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 7: + case 39: + case 135: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 148: + case 149: + case 180: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 224: + case 228: + case 225: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 41: + case 169: + case 45: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 22: + case 54: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 208: + case 209: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 104: + case 108: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 11: + case 139: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 19: + case 51: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL00_12 + X4PIXEL01_14 + X4PIXEL02_83 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_21 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 146: + case 178: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL23_32 + X4PIXEL33_82 + } + else + { + X4PIXEL02_21 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_83 + X4PIXEL23_13 + X4PIXEL33_11 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + break; + } + case 84: + case 85: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL03_81 + X4PIXEL13_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL03_12 + X4PIXEL13_14 + X4PIXEL22_70 + X4PIXEL23_83 + X4PIXEL32_21 + X4PIXEL33_50 + } + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 112: + case 113: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_70 + X4PIXEL23_21 + X4PIXEL30_11 + X4PIXEL31_13 + X4PIXEL32_83 + X4PIXEL33_50 + } + break; + } + case 200: + case 204: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + } + else + { + X4PIXEL20_21 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_83 + X4PIXEL32_14 + X4PIXEL33_12 + } + X4PIXEL22_31 + X4PIXEL23_81 + break; + } + case 73: + case 77: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL00_82 + X4PIXEL10_32 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL00_11 + X4PIXEL10_13 + X4PIXEL20_83 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_21 + } + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 42: + case 170: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL20_31 + X4PIXEL30_81 + } + else + { + X4PIXEL00_50 + X4PIXEL01_21 + X4PIXEL10_83 + X4PIXEL11_70 + X4PIXEL20_14 + X4PIXEL30_12 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 14: + case 142: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_50 + X4PIXEL01_83 + X4PIXEL02_13 + X4PIXEL03_11 + X4PIXEL10_21 + X4PIXEL11_70 + } + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 67: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 70: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 28: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 152: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 194: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 98: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 56: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 25: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 26: + case 31: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 82: + case 214: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 88: + case 248: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + break; + } + case 74: + case 107: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_61 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 27: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 86: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 216: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 106: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 30: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 210: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 120: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 75: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 29: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 198: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 184: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 99: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 57: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 71: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 156: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 226: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 60: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 195: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 102: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 153: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 58: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 83: + { + X4PIXEL00_81 + X4PIXEL01_31 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_61 + X4PIXEL21_30 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 92: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 202: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_61 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 78: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 154: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 114: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + X4PIXEL30_82 + X4PIXEL31_32 + break; + } + case 89: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 90: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 55: + case 23: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL12_0 + X4PIXEL13_0 + } + else + { + X4PIXEL00_12 + X4PIXEL01_14 + X4PIXEL02_83 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_21 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 182: + case 150: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL23_32 + X4PIXEL33_82 + } + else + { + X4PIXEL02_21 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_83 + X4PIXEL23_13 + X4PIXEL33_11 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + break; + } + case 213: + case 212: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL03_81 + X4PIXEL13_31 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL03_12 + X4PIXEL13_14 + X4PIXEL22_70 + X4PIXEL23_83 + X4PIXEL32_21 + X4PIXEL33_50 + } + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 241: + case 240: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL22_70 + X4PIXEL23_21 + X4PIXEL30_11 + X4PIXEL31_13 + X4PIXEL32_83 + X4PIXEL33_50 + } + break; + } + case 236: + case 232: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_70 + X4PIXEL13_60 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL30_0 + X4PIXEL31_0 + X4PIXEL32_31 + X4PIXEL33_81 + } + else + { + X4PIXEL20_21 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_83 + X4PIXEL32_14 + X4PIXEL33_12 + } + X4PIXEL22_31 + X4PIXEL23_81 + break; + } + case 109: + case 105: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL00_82 + X4PIXEL10_32 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL00_11 + X4PIXEL10_13 + X4PIXEL20_83 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_21 + } + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 171: + case 43: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL20_31 + X4PIXEL30_81 + } + else + { + X4PIXEL00_50 + X4PIXEL01_21 + X4PIXEL10_83 + X4PIXEL11_70 + X4PIXEL20_14 + X4PIXEL30_12 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 143: + case 15: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_0 + X4PIXEL11_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_83 + X4PIXEL02_13 + X4PIXEL03_11 + X4PIXEL10_21 + X4PIXEL11_70 + } + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 124: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 203: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 62: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 211: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 118: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 217: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 110: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 155: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 188: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 185: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 61: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 157: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 103: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 227: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 230: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 199: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 220: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + break; + } + case 158: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL12_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 234: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_61 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 242: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_82 + X4PIXEL31_32 + break; + } + case 59: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL11_0 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 121: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 87: + { + X4PIXEL00_81 + X4PIXEL01_31 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_0 + X4PIXEL20_61 + X4PIXEL21_30 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 79: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL11_0 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 122: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 94: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL12_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 218: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + break; + } + case 91: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL11_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 229: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 167: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 173: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 181: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 186: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 115: + { + X4PIXEL00_81 + X4PIXEL01_31 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + X4PIXEL30_82 + X4PIXEL31_32 + break; + } + case 93: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + break; + } + case 206: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 205: + case 201: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + } + else + { + X4PIXEL20_12 + X4PIXEL21_0 + X4PIXEL30_20 + X4PIXEL31_11 + } + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 174: + case 46: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL10_10 + X4PIXEL11_30 + } + else + { + X4PIXEL00_20 + X4PIXEL01_12 + X4PIXEL10_11 + X4PIXEL11_0 + } + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 179: + case 147: + { + X4PIXEL00_81 + X4PIXEL01_31 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + } + else + { + X4PIXEL02_11 + X4PIXEL03_20 + X4PIXEL12_0 + X4PIXEL13_12 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 117: + case 116: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + } + else + { + X4PIXEL22_0 + X4PIXEL23_11 + X4PIXEL32_12 + X4PIXEL33_20 + } + X4PIXEL30_82 + X4PIXEL31_32 + break; + } + case 189: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 231: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 126: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 219: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 125: + { + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL00_82 + X4PIXEL10_32 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL00_11 + X4PIXEL10_13 + X4PIXEL20_83 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_21 + } + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 221: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL03_81 + X4PIXEL13_31 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL03_12 + X4PIXEL13_14 + X4PIXEL22_70 + X4PIXEL23_83 + X4PIXEL32_21 + X4PIXEL33_50 + } + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 207: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_0 + X4PIXEL11_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_83 + X4PIXEL02_13 + X4PIXEL03_11 + X4PIXEL10_21 + X4PIXEL11_70 + } + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_31 + X4PIXEL23_81 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 238: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL30_0 + X4PIXEL31_0 + X4PIXEL32_31 + X4PIXEL33_81 + } + else + { + X4PIXEL20_21 + X4PIXEL21_70 + X4PIXEL30_50 + X4PIXEL31_83 + X4PIXEL32_14 + X4PIXEL33_12 + } + X4PIXEL22_31 + X4PIXEL23_81 + break; + } + case 190: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL23_32 + X4PIXEL33_82 + } + else + { + X4PIXEL02_21 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_83 + X4PIXEL23_13 + X4PIXEL33_11 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + break; + } + case 187: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL20_31 + X4PIXEL30_81 + } + else + { + X4PIXEL00_50 + X4PIXEL01_21 + X4PIXEL10_83 + X4PIXEL11_70 + X4PIXEL20_14 + X4PIXEL30_12 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 243: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_82 + X4PIXEL21_32 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL22_70 + X4PIXEL23_21 + X4PIXEL30_11 + X4PIXEL31_13 + X4PIXEL32_83 + X4PIXEL33_50 + } + break; + } + case 119: + { + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL12_0 + X4PIXEL13_0 + } + else + { + X4PIXEL00_12 + X4PIXEL01_14 + X4PIXEL02_83 + X4PIXEL03_50 + X4PIXEL12_70 + X4PIXEL13_21 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 237: + case 233: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_60 + X4PIXEL03_20 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_70 + X4PIXEL13_60 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_31 + X4PIXEL23_81 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 175: + case 47: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_70 + X4PIXEL23_60 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_60 + X4PIXEL33_20 + break; + } + case 183: + case 151: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_60 + X4PIXEL21_70 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_20 + X4PIXEL31_60 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 245: + case 244: + { + X4PIXEL00_20 + X4PIXEL01_60 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_60 + X4PIXEL11_70 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 250: + { + X4PIXEL00_80 + X4PIXEL01_10 + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + break; + } + case 123: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_10 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 95: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_80 + X4PIXEL31_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 222: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 252: + { + X4PIXEL00_80 + X4PIXEL01_61 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_31 + X4PIXEL13_31 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 249: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_61 + X4PIXEL03_80 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + break; + } + case 235: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_61 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_31 + X4PIXEL23_81 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 111: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_32 + X4PIXEL13_82 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_61 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 63: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_61 + X4PIXEL33_80 + break; + } + case 159: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_80 + X4PIXEL31_61 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 215: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_61 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 246: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_61 + X4PIXEL11_30 + X4PIXEL12_0 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 254: + { + X4PIXEL00_80 + X4PIXEL01_10 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_10 + X4PIXEL11_30 + X4PIXEL12_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 253: + { + X4PIXEL00_82 + X4PIXEL01_82 + X4PIXEL02_81 + X4PIXEL03_81 + X4PIXEL10_32 + X4PIXEL11_32 + X4PIXEL12_31 + X4PIXEL13_31 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_0 + X4PIXEL23_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 251: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_10 + X4PIXEL03_80 + X4PIXEL11_0 + X4PIXEL12_30 + X4PIXEL13_10 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + break; + } + case 239: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + X4PIXEL02_32 + X4PIXEL03_82 + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_32 + X4PIXEL13_82 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_31 + X4PIXEL23_81 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + X4PIXEL32_31 + X4PIXEL33_81 + break; + } + case 127: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL02_0 + X4PIXEL03_0 + X4PIXEL13_0 + } + else + { + X4PIXEL02_50 + X4PIXEL03_50 + X4PIXEL13_50 + } + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL20_0 + X4PIXEL30_0 + X4PIXEL31_0 + } + else + { + X4PIXEL20_50 + X4PIXEL30_50 + X4PIXEL31_50 + } + X4PIXEL21_0 + X4PIXEL22_30 + X4PIXEL23_10 + X4PIXEL32_10 + X4PIXEL33_80 + break; + } + case 191: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_31 + X4PIXEL21_31 + X4PIXEL22_32 + X4PIXEL23_32 + X4PIXEL30_81 + X4PIXEL31_81 + X4PIXEL32_82 + X4PIXEL33_82 + break; + } + case 223: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + X4PIXEL01_0 + X4PIXEL10_0 + } + else + { + X4PIXEL00_50 + X4PIXEL01_50 + X4PIXEL10_50 + } + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_10 + X4PIXEL21_30 + X4PIXEL22_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL23_0 + X4PIXEL32_0 + X4PIXEL33_0 + } + else + { + X4PIXEL23_50 + X4PIXEL32_50 + X4PIXEL33_50 + } + X4PIXEL30_80 + X4PIXEL31_10 + break; + } + case 247: + { + X4PIXEL00_81 + X4PIXEL01_31 + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL10_81 + X4PIXEL11_31 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_82 + X4PIXEL21_32 + X4PIXEL22_0 + X4PIXEL23_0 + X4PIXEL30_82 + X4PIXEL31_32 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + case 255: + { + if (Diff(RGBtoYUV[w4], RGBtoYUV[w2])) + { + X4PIXEL00_0 + } + else + { + X4PIXEL00_20 + } + X4PIXEL01_0 + X4PIXEL02_0 + if (Diff(RGBtoYUV[w2], RGBtoYUV[w6])) + { + X4PIXEL03_0 + } + else + { + X4PIXEL03_20 + } + X4PIXEL10_0 + X4PIXEL11_0 + X4PIXEL12_0 + X4PIXEL13_0 + X4PIXEL20_0 + X4PIXEL21_0 + X4PIXEL22_0 + X4PIXEL23_0 + if (Diff(RGBtoYUV[w8], RGBtoYUV[w4])) + { + X4PIXEL30_0 + } + else + { + X4PIXEL30_20 + } + X4PIXEL31_0 + X4PIXEL32_0 + if (Diff(RGBtoYUV[w6], RGBtoYUV[w8])) + { + X4PIXEL33_0 + } + else + { + X4PIXEL33_20 + } + break; + } + } + + w1 = w2; w4 = w5; w7 = w8; + w2 = w3; w5 = w6; w8 = w9; + + dp += 4; + } + + dp += (dst1line - width) * 4; + sp += (src1line - width); + } +} diff --git a/snes9x/filter/hq2x.h b/snes9x/filter/hq2x.h new file mode 100644 index 0000000..ad9b08a --- /dev/null +++ b/snes9x/filter/hq2x.h @@ -0,0 +1,16 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _hq2x_h_ +#define _hq2x_h_ + +bool8 S9xBlitHQ2xFilterInit (void); +void S9xBlitHQ2xFilterDeinit (void); +void HQ2X_16 (uint8 *, uint32, uint8 *, uint32, int, int); +void HQ3X_16 (uint8 *, uint32, uint8 *, uint32, int, int); +void HQ4X_16 (uint8 *, uint32, uint8 *, uint32, int, int); + +#endif diff --git a/snes9x/filter/snes_ntsc-license.txt b/snes9x/filter/snes_ntsc-license.txt new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/snes9x/filter/snes_ntsc-license.txt @@ -0,0 +1,504 @@ + 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! + + diff --git a/snes9x/filter/snes_ntsc.c b/snes9x/filter/snes_ntsc.c new file mode 100644 index 0000000..6ca9675 --- /dev/null +++ b/snes9x/filter/snes_ntsc.c @@ -0,0 +1,390 @@ +/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ + +#include "snes_ntsc.h" + +/* Copyright (C) 2006-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 */ + +snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 }; +snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 }; + +#define alignment_count 3 +#define burst_count 3 +#define rescale_in 8 +#define rescale_out 7 + +#define artifacts_mid 1.0f +#define fringing_mid 1.0f +#define std_decoder_hue 0 + +#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */ +#define gamma_size 32 + +#include "snes_ntsc_impl.h" + +unsigned int snes_ntsc_scanline_offset = 0; +unsigned short snes_ntsc_scanline_mask = 0xffff; + +/* 3 input pixels -> 8 composite samples */ +pixel_info_t const snes_ntsc_pixels [alignment_count] = { + { PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } }, + { PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } }, + { PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } }, +}; + +static void merge_kernel_fields( snes_ntsc_rgb_t* io ) +{ + int n; + for ( n = burst_size; n; --n ) + { + snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias; + snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias; + snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias; + /* merge colors without losing precision */ + io [burst_size * 0] = + ((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io [burst_size * 1] = + ((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + io [burst_size * 2] = + ((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias; + ++io; + } +} + +static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ) +{ + int n; + for ( n = burst_count; n; --n ) + { + unsigned i; + for ( i = 0; i < rgb_kernel_size / 2; i++ ) + { + snes_ntsc_rgb_t error = color - + out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] - + out [i + 7] - out [i + 5 +14] - out [i + 3 +28]; + DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 ); + } + out += alignment_count * rgb_kernel_size; + } +} + +void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ) +{ + int merge_fields; + int entry; + init_t impl; + if ( !setup ) + setup = &snes_ntsc_composite; + init( &impl, setup ); + + merge_fields = setup->merge_fields; + if ( setup->artifacts <= -1 && setup->fringing <= -1 ) + merge_fields = 1; + + for ( entry = 0; entry < snes_ntsc_palette_size; entry++ ) + { + /* Reduce number of significant bits of source color. Clearing the + low bits of R and B were least notictable. Modifying green was too + noticeable. */ + int ir = entry >> 8 & 0x1E; + int ig = entry >> 4 & 0x1F; + int ib = entry << 1 & 0x1E; + + #if SNES_NTSC_BSNES_COLORTBL + if ( setup->bsnes_colortbl ) + { + int bgr15 = (ib << 10) | (ig << 5) | ir; + unsigned long rgb16 = setup->bsnes_colortbl [bgr15]; + ir = rgb16 >> 11 & 0x1E; + ig = rgb16 >> 6 & 0x1F; + ib = rgb16 & 0x1E; + } + #endif + + { + float rr = impl.to_float [ir]; + float gg = impl.to_float [ig]; + float bb = impl.to_float [ib]; + + float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i ); + + int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g ); + snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b ); + + snes_ntsc_rgb_t* out = ntsc->table [entry]; + gen_kernel( &impl, y, i, q, out ); + if ( merge_fields ) + merge_kernel_fields( out ); + correct_errors( rgb, out ); + } + } +} + +#ifndef SNES_NTSC_NO_BLITTERS + +void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + int n; + ++line_in; + + for ( n = chunk_count; n; --n ) + { + /* order of input and output pixels must not be altered */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + line_in += 3; + line_out += 7; + } + + /* finish final pixels */ + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch; + } +} + +void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_HIRES_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, + SNES_NTSC_ADJ_IN( line_in [0] ), + SNES_NTSC_ADJ_IN( line_in [1] ) ); + snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out; + int n; + line_in += 2; + + for ( n = chunk_count; n; --n ) + { + /* twice as many input pixels per chunk */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); + SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); + SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); + SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + line_in += 6; + line_out += 7; + } + + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH ); + + SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); + SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH ); + SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH ); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch; + } +} + +/* 12.5% scanlines like in snes_ntsc example instead of zsnes's 25% */ +#define PIXEL_OUT( x ) \ + SNES_NTSC_RGB_OUT( x, value, SNES_NTSC_OUT_DEPTH ); \ + line_outa[x] = value; \ + line_outb[x] = value - (value >> snes_ntsc_scanline_offset & snes_ntsc_scanline_mask); + +void snes_ntsc_blit_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + unsigned value; + int chunk_count = (in_width - 1) / snes_ntsc_in_chunk; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_BEGIN_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) ); + snes_ntsc_out_t * restrict line_outa = (snes_ntsc_out_t *) rgb_out; + snes_ntsc_out_t * restrict line_outb = (snes_ntsc_out_t *) ((char *) line_outa + out_pitch); + int n; + ++line_in; + + for ( n = chunk_count; n; --n ) + { + /* order of input and output pixels must not be altered */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + PIXEL_OUT (0); + PIXEL_OUT (1); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + PIXEL_OUT (2); + PIXEL_OUT (3); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + PIXEL_OUT (4); + PIXEL_OUT (5); + PIXEL_OUT (6); + + line_in += 3; + line_outa += 7; + line_outb += 7; + } + + /* finish final pixels */ + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + PIXEL_OUT (0); + PIXEL_OUT (1); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + PIXEL_OUT (2); + PIXEL_OUT (3); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + PIXEL_OUT (4); + PIXEL_OUT (5); + PIXEL_OUT (6); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + 2 * out_pitch; + } +} + +#define PIXEL_OUT_HIRES( x ) \ + SNES_NTSC_HIRES_OUT( x, value, SNES_NTSC_OUT_DEPTH ); \ + line_outa[x] = value; \ + line_outb[x] = value - (value >> snes_ntsc_scanline_offset & snes_ntsc_scanline_mask); + +void snes_ntsc_blit_hires_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width, + int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch ) +{ + int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2); + unsigned value; + for ( ; in_height; --in_height ) + { + SNES_NTSC_IN_T const* line_in = input; + SNES_NTSC_HIRES_ROW( ntsc, burst_phase, + snes_ntsc_black, snes_ntsc_black, snes_ntsc_black, + SNES_NTSC_ADJ_IN( line_in [0] ), + SNES_NTSC_ADJ_IN( line_in [1] ) ); + snes_ntsc_out_t* restrict line_outa = (snes_ntsc_out_t*) rgb_out; + snes_ntsc_out_t* restrict line_outb = (snes_ntsc_out_t*) ((char *) line_outa + out_pitch); + int n; + line_in += 2; + + for ( n = chunk_count; n; --n ) + { + /* twice as many input pixels per chunk */ + SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) ); + PIXEL_OUT_HIRES (0); + + SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) ); + PIXEL_OUT_HIRES (1); + + SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) ); + PIXEL_OUT_HIRES (2); + + SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) ); + PIXEL_OUT_HIRES (3); + + SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) ); + PIXEL_OUT_HIRES (4); + + SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) ); + PIXEL_OUT_HIRES (5); + PIXEL_OUT_HIRES (6); + + line_in += 6; + line_outa += 7; + line_outb += 7; + } + + SNES_NTSC_COLOR_IN( 0, snes_ntsc_black ); + PIXEL_OUT_HIRES (0); + + SNES_NTSC_COLOR_IN( 1, snes_ntsc_black ); + PIXEL_OUT_HIRES (1); + + SNES_NTSC_COLOR_IN( 2, snes_ntsc_black ); + PIXEL_OUT_HIRES (2); + + SNES_NTSC_COLOR_IN( 3, snes_ntsc_black ); + PIXEL_OUT_HIRES (3); + + SNES_NTSC_COLOR_IN( 4, snes_ntsc_black ); + PIXEL_OUT_HIRES (4); + + SNES_NTSC_COLOR_IN( 5, snes_ntsc_black ); + PIXEL_OUT_HIRES (5); + PIXEL_OUT_HIRES (6); + + burst_phase = (burst_phase + 1) % snes_ntsc_burst_count; + input += in_row_width; + rgb_out = (char*) rgb_out + out_pitch * 2; + } +} + +#endif diff --git a/snes9x/filter/snes_ntsc.h b/snes9x/filter/snes_ntsc.h new file mode 100644 index 0000000..601bfee --- /dev/null +++ b/snes9x/filter/snes_ntsc.h @@ -0,0 +1,222 @@ +/* SNES NTSC video filter */ + +/* snes_ntsc 0.2.2 */ +#ifndef SNES_NTSC_H +#define SNES_NTSC_H + +#include "snes_ntsc_config.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown +in parenthesis and should remain fairly stable in future versions. */ +typedef struct snes_ntsc_setup_t +{ + /* Basic parameters */ + double hue; /* -1 = -180 degrees +1 = +180 degrees */ + double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */ + double contrast; /* -1 = dark (0.5) +1 = light (1.5) */ + double brightness; /* -1 = dark (0.5) +1 = light (1.5) */ + double sharpness; /* edge contrast enhancement/blurring */ + + /* Advanced parameters */ + double gamma; /* -1 = dark (1.5) +1 = light (0.5) */ + double resolution; /* image resolution */ + double artifacts; /* artifacts caused by color changes */ + double fringing; /* color artifacts caused by brightness changes */ + double bleed; /* color bleed (color resolution reduction) */ + int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */ + float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */ + + unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */ +} snes_ntsc_setup_t; + +/* Video format presets */ +extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */ +extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */ +extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */ +extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */ + +/* Scanline values */ +extern unsigned int snes_ntsc_scanline_offset; +extern unsigned short snes_ntsc_scanline_mask; + +/* Initializes and adjusts parameters. Can be called multiple times on the same +snes_ntsc_t object. Can pass NULL for either parameter. */ +typedef struct snes_ntsc_t snes_ntsc_t; +void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup ); + +/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT +and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB. +In_row_width is the number of pixels to get to the next input row. Out_pitch +is the number of *bytes* to get to the next output row. */ +void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +void snes_ntsc_blit_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +void snes_ntsc_blit_hires_scanlines( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, + long in_row_width, int burst_phase, int in_width, int in_height, + void* rgb_out, long out_pitch ); + +/* Number of output pixels written by low-res blitter for given input width. Width +might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded +value. Guaranteed not to round 256 down at all. */ +#define SNES_NTSC_OUT_WIDTH( in_width ) \ + ((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk) + +/* Number of low-res input pixels that will fit within given output width. Might be +rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded +value. */ +#define SNES_NTSC_IN_WIDTH( out_width ) \ + (((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1) + + +/* Interface for user-defined custom blitters */ + +enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */ +enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */ +enum { snes_ntsc_black = 0 }; /* palette index for black */ +enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */ + +/* Begins outputting row and starts three pixels. First pixel will be cut off a bit. +Use snes_ntsc_black for unused pixels. Declares variables, so must be before first +statement in a block (unless you're using C++). */ +#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \ + char const* ktable = \ + (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ + SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable ) + +/* Begins input pixel */ +#define SNES_NTSC_COLOR_IN( index, color ) \ + SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable ) + +/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0: +24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB) +16: RRRRRGGG GGGBBBBB (5-6-5 RGB) +15: RRRRRGG GGGBBBBB (5-5-5 RGB) +14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format) + 0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */ +#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \ + SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 ) + +/* Hires equivalents */ +#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \ + char const* ktable = \ + (char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\ + unsigned const snes_ntsc_pixel1_ = (pixel1);\ + snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\ + unsigned const snes_ntsc_pixel2_ = (pixel2);\ + snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\ + unsigned const snes_ntsc_pixel3_ = (pixel3);\ + snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\ + unsigned const snes_ntsc_pixel4_ = (pixel4);\ + snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\ + unsigned const snes_ntsc_pixel5_ = (pixel5);\ + snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\ + snes_ntsc_rgb_t const* kernel0 = kernel1;\ + snes_ntsc_rgb_t const* kernelx0;\ + snes_ntsc_rgb_t const* kernelx1 = kernel1;\ + snes_ntsc_rgb_t const* kernelx2 = kernel1;\ + snes_ntsc_rgb_t const* kernelx3 = kernel1;\ + snes_ntsc_rgb_t const* kernelx4 = kernel1;\ + snes_ntsc_rgb_t const* kernelx5 = kernel1 + +#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\ + snes_ntsc_rgb_t raw_ =\ + kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\ + kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\ + kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\ + kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\ + SNES_NTSC_CLAMP_( raw_, 0 );\ + SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\ +} + + +/* private */ +enum { snes_ntsc_entry_size = 128 }; +enum { snes_ntsc_palette_size = 0x2000 }; +typedef unsigned long snes_ntsc_rgb_t; +struct snes_ntsc_t { + snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size]; +}; +enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count }; + +#define SNES_NTSC_RGB16( ktable, n ) \ + (snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \ + (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) + +#define SNES_NTSC_RGB15( ktable, n ) \ + (snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 0 & 0x03E0) | (n >> 1 & 0x3C00)) * \ + (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) + +#define SNES_NTSC_BGR15( ktable, n ) \ + (snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \ + (snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t))) + +/* common 3->7 ntsc macros */ +#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \ + unsigned const snes_ntsc_pixel0_ = (pixel0);\ + snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\ + unsigned const snes_ntsc_pixel1_ = (pixel1);\ + snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\ + unsigned const snes_ntsc_pixel2_ = (pixel2);\ + snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\ + snes_ntsc_rgb_t const* kernelx0;\ + snes_ntsc_rgb_t const* kernelx1 = kernel0;\ + snes_ntsc_rgb_t const* kernelx2 = kernel0 + +#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\ + snes_ntsc_rgb_t raw_ =\ + kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\ + kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\ + SNES_NTSC_CLAMP_( raw_, shift );\ + SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\ +} + +/* common ntsc macros */ +#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1)) +#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2) +#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101) +#define SNES_NTSC_CLAMP_( io, shift ) {\ + snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\ + snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\ + io |= clamp;\ + clamp -= sub;\ + io &= clamp;\ +} + +#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\ + unsigned color_;\ + kernelx##index = kernel##index;\ + kernel##index = (color_ = (color), ENTRY( table, color_ ));\ +} + +/* x is always zero except in snes_ntsc library */ +#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\ + if ( bits == 16 )\ + rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\ + if ( bits == 24 || bits == 32 )\ + rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\ + if ( bits == 15 )\ + rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\ + if ( bits == 14 )\ + rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\ + if ( bits == 0 )\ + rgb_out = raw_ << x;\ +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/snes9x/filter/snes_ntsc_config.h b/snes9x/filter/snes_ntsc_config.h new file mode 100644 index 0000000..467c7ec --- /dev/null +++ b/snes9x/filter/snes_ntsc_config.h @@ -0,0 +1,32 @@ +/* Configure library by modifying this file */ + +#ifndef SNES_NTSC_CONFIG_H +#define SNES_NTSC_CONFIG_H + +#if !defined(SNES9X_GTK) && !defined(_WIN32) && !defined(__LIBRETRO__) +/* Format of source pixels */ +#define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB15 +/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */ +/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15 */ + +/* The following affect the built-in blitter only; a custom blitter can +handle things however it wants. */ + +/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */ +#define SNES_NTSC_OUT_DEPTH 15 +#else +#define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 +#define SNES_NTSC_OUT_DEPTH 16 +#endif + +/* Type of input pixel values */ +#define SNES_NTSC_IN_T unsigned short + +/* Each raw pixel input value is passed through this. You might want to mask +the pixel index if you use the high bits as flags, etc. */ +#define SNES_NTSC_ADJ_IN( in ) in + +/* For each pixel, this is the basic operation: +output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */ + +#endif diff --git a/snes9x/filter/snes_ntsc_impl.h b/snes9x/filter/snes_ntsc_impl.h new file mode 100644 index 0000000..c10dcbe --- /dev/null +++ b/snes9x/filter/snes_ntsc_impl.h @@ -0,0 +1,439 @@ +/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */ + +/* Common implementation of NTSC filters */ + +#include +#include + +/* Copyright (C) 2006 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 */ + +#define DISABLE_CORRECTION 0 + +#undef PI +#define PI 3.14159265358979323846f + +#ifndef LUMA_CUTOFF + #define LUMA_CUTOFF 0.20 +#endif +#ifndef gamma_size + #define gamma_size 1 +#endif +#ifndef rgb_bits + #define rgb_bits 8 +#endif +#ifndef artifacts_max + #define artifacts_max (artifacts_mid * 1.5f) +#endif +#ifndef fringing_max + #define fringing_max (fringing_mid * 2) +#endif +#ifndef STD_HUE_CONDITION + #define STD_HUE_CONDITION( setup ) 1 +#endif + +#define ext_decoder_hue (std_decoder_hue + 15) +#define rgb_unit (1 << rgb_bits) +#define rgb_offset (rgb_unit * 2 + 0.5f) + +enum { burst_size = snes_ntsc_entry_size / burst_count }; +enum { kernel_half = 16 }; +enum { kernel_size = kernel_half * 2 + 1 }; + +typedef struct init_t +{ + float to_rgb [burst_count * 6]; + float to_float [gamma_size]; + float contrast; + float brightness; + float artifacts; + float fringing; + float kernel [rescale_out * kernel_size * 2]; +} init_t; + +#define ROTATE_IQ( i, q, sin_b, cos_b ) {\ + float t;\ + t = i * cos_b - q * sin_b;\ + q = i * sin_b + q * cos_b;\ + i = t;\ +} + +static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup ) +{ +#if rescale_out > 1 + float kernels [kernel_size * 2]; +#else + float* const kernels = impl->kernel; +#endif + + /* generate luma (y) filter using sinc kernel */ + { + /* sinc with rolloff (dsf) */ + float const rolloff = 1 + (float) setup->sharpness * (float) 0.032; + float const maxh = 32; + float const pow_a_n = (float) pow( rolloff, maxh ); + float sum; + int i; + /* quadratic mapping to reduce negative (blurring) range */ + float to_angle = (float) setup->resolution + 1; + to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1); + + kernels [kernel_size * 3 / 2] = maxh; /* default center value */ + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + int x = i - kernel_half; + float angle = x * to_angle; + /* instability occurs at center point with rolloff very close to 1.0 */ + if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 ) + { + float rolloff_cos_a = rolloff * (float) cos( angle ); + float num = 1 - rolloff_cos_a - + pow_a_n * (float) cos( maxh * angle ) + + pow_a_n * rolloff * (float) cos( (maxh - 1) * angle ); + float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; + float dsf = num / den; + kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5; + } + } + + /* apply blackman window and find sum */ + sum = 0; + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + float x = PI * 2 / (kernel_half * 2) * i; + float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 ); + sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); + } + + /* normalize kernel */ + sum = 1.0f / sum; + for ( i = 0; i < kernel_half * 2 + 1; i++ ) + { + int x = kernel_size * 3 / 2 - kernel_half + i; + kernels [x] *= sum; + /* assert( kernels [x] == kernels [x] ); catch numerical instability */ + } + } + + /* generate chroma (iq) filter using gaussian kernel */ + { + float const cutoff_factor = -0.03125f; + float cutoff = (float) setup->bleed; + int i; + + if ( cutoff < 0 ) + { + /* keep extreme value accessible only near upper end of scale (1.0) */ + cutoff *= cutoff; + cutoff *= cutoff; + cutoff *= cutoff; + cutoff *= -30.0f / 0.65f; + } + cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; + + for ( i = -kernel_half; i <= kernel_half; i++ ) + kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff ); + + /* normalize even and odd phases separately */ + for ( i = 0; i < 2; i++ ) + { + float sum = 0; + int x; + for ( x = i; x < kernel_size; x += 2 ) + sum += kernels [x]; + + sum = 1.0f / sum; + for ( x = i; x < kernel_size; x += 2 ) + { + kernels [x] *= sum; + /* assert( kernels [x] == kernels [x] ); catch numerical instability */ + } + } + } + + /* + printf( "luma:\n" ); + for ( i = kernel_size; i < kernel_size * 2; i++ ) + printf( "%f\n", kernels [i] ); + printf( "chroma:\n" ); + for ( i = 0; i < kernel_size; i++ ) + printf( "%f\n", kernels [i] ); + */ + + /* generate linear rescale kernels */ + #if rescale_out > 1 + { + float weight = 1.0f; + float* out = impl->kernel; + int n = rescale_out; + do + { + float remain = 0; + int i; + weight -= 1.0f / rescale_in; + for ( i = 0; i < kernel_size * 2; i++ ) + { + float cur = kernels [i]; + float m = cur * weight; + *out++ = m + remain; + remain = cur - m; + } + } + while ( --n ); + } + #endif +} + +static float const default_decoder [6] = + { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; + +static void init( init_t* impl, snes_ntsc_setup_t const* setup ) +{ + impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset; + impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit; + #ifdef default_palette_contrast + if ( !setup->palette ) + impl->contrast *= default_palette_contrast; + #endif + + impl->artifacts = (float) setup->artifacts; + if ( impl->artifacts > 0 ) + impl->artifacts *= artifacts_max - artifacts_mid; + impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid; + + impl->fringing = (float) setup->fringing; + if ( impl->fringing > 0 ) + impl->fringing *= fringing_max - fringing_mid; + impl->fringing = impl->fringing * fringing_mid + fringing_mid; + + init_filters( impl, setup ); + + /* generate gamma table */ + if ( gamma_size > 1 ) + { + float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); + float const gamma = 1.1333f - (float) setup->gamma * 0.5f; + /* match common PC's 2.2 gamma to TV's 2.65 gamma */ + int i; + for ( i = 0; i < gamma_size; i++ ) + impl->to_float [i] = + (float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness; + } + + /* setup decoder matricies */ + { + float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue; + float sat = (float) setup->saturation + 1; + float const* decoder = setup->decoder_matrix; + if ( !decoder ) + { + decoder = default_decoder; + if ( STD_HUE_CONDITION( setup ) ) + hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); + } + + { + float s = (float) sin( hue ) * sat; + float c = (float) cos( hue ) * sat; + float* out = impl->to_rgb; + int n; + + n = burst_count; + do + { + float const* in = decoder; + int n = 3; + do + { + float i = *in++; + float q = *in++; + *out++ = i * c - q * s; + *out++ = i * s + q * c; + } + while ( --n ); + if ( burst_count <= 1 ) + break; + ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ + } + while ( --n ); + } + } +} + +/* kernel generation */ + +#define RGB_TO_YIQ( r, g, b, y, i ) (\ + (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ + (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ + ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ +) + +#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ + r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ + g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ + (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ +) + +#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) + +enum { rgb_kernel_size = burst_size / alignment_count }; +enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder }; + +typedef struct pixel_info_t +{ + int offset; + float negate; + float kernel [4]; +} pixel_info_t; + +#if rescale_in > 1 + #define PIXEL_OFFSET_( ntsc, scaled ) \ + (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ + (kernel_size * 2 * scaled)) + + #define PIXEL_OFFSET( ntsc, scaled ) \ + PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ + (((scaled) + rescale_out * 10) % rescale_out) ),\ + (1.0f - (((ntsc) + 100) & 2)) +#else + #define PIXEL_OFFSET( ntsc, scaled ) \ + (kernel_size / 2 + (ntsc) - (scaled)),\ + (1.0f - (((ntsc) + 100) & 2)) +#endif + +extern pixel_info_t const snes_ntsc_pixels [alignment_count]; + +/* Generate pixel at all burst phases and column alignments */ +static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out ) +{ + /* generate for each scanline burst phase */ + float const* to_rgb = impl->to_rgb; + int burst_remain = burst_count; + y -= rgb_offset; + do + { + /* Encode yiq into *two* composite signals (to allow control over artifacting). + Convolve these with kernels which: filter respective components, apply + sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack + into integer. Based on algorithm by NewRisingSun. */ + pixel_info_t const* pixel = snes_ntsc_pixels; + int alignment_remain = alignment_count; + do + { + /* negate is -1 when composite starts at odd multiple of 2 */ + float const yy = y * impl->fringing * pixel->negate; + float const ic0 = (i + yy) * pixel->kernel [0]; + float const qc1 = (q + yy) * pixel->kernel [1]; + float const ic2 = (i - yy) * pixel->kernel [2]; + float const qc3 = (q - yy) * pixel->kernel [3]; + + float const factor = impl->artifacts * pixel->negate; + float const ii = i * factor; + float const yc0 = (y + ii) * pixel->kernel [0]; + float const yc2 = (y - ii) * pixel->kernel [2]; + + float const qq = q * factor; + float const yc1 = (y + qq) * pixel->kernel [1]; + float const yc3 = (y - qq) * pixel->kernel [3]; + + float const* k = &impl->kernel [pixel->offset]; + int n; + ++pixel; + for ( n = rgb_kernel_size; n; --n ) + { + float i = k[0]*ic0 + k[2]*ic2; + float q = k[1]*qc1 + k[3]*qc3; + float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + + k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; + if ( rescale_out <= 1 ) + k--; + else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] ) + k += kernel_size * 2 - 1; + else + k -= kernel_size * 2 * (rescale_out - 1) + 2; + { + int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g ); + *out++ = PACK_RGB( r, g, b ) - rgb_bias; + } + } + } + while ( alignment_count > 1 && --alignment_remain ); + + if ( burst_count <= 1 ) + break; + + to_rgb += 6; + + ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */ + } + while ( --burst_remain ); +} + +static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out ); + +#if DISABLE_CORRECTION + #define CORRECT_ERROR( a ) { out [i] += rgb_bias; } + #define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; } +#else + #define CORRECT_ERROR( a ) { out [a] += error; } + #define DISTRIBUTE_ERROR( a, b, c ) {\ + snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\ + fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\ + fourth -= rgb_bias >> 2;\ + out [a] += fourth;\ + out [b] += fourth;\ + out [c] += fourth;\ + out [i] += error - (fourth * 3);\ + } +#endif + +#define RGB_PALETTE_OUT( rgb, out_ )\ +{\ + unsigned char* out = (out_);\ + snes_ntsc_rgb_t clamped = (rgb);\ + SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ + out [0] = (unsigned char) (clamped >> 21);\ + out [1] = (unsigned char) (clamped >> 11);\ + out [2] = (unsigned char) (clamped >> 1);\ +} + +/* blitter related */ + +#ifndef restrict + #if defined (__GNUC__) + #define restrict __restrict__ + #elif defined (_MSC_VER) && _MSC_VER > 1300 + #define restrict __restrict + #else + /* no support for restricted pointers */ + #define restrict + #endif +#endif + +#include + +#if SNES_NTSC_OUT_DEPTH <= 16 + #if USHRT_MAX == 0xFFFF + typedef unsigned short snes_ntsc_out_t; + #else + #error "Need 16-bit int type" + #endif + +#else + #if UINT_MAX == 0xFFFFFFFF + typedef unsigned int snes_ntsc_out_t; + #elif ULONG_MAX == 0xFFFFFFFF + typedef unsigned long snes_ntsc_out_t; + #else + #error "Need 32-bit int type" + #endif + +#endif diff --git a/snes9x/filter/xbrz-license.txt b/snes9x/filter/xbrz-license.txt new file mode 100644 index 0000000..94a0453 --- /dev/null +++ b/snes9x/filter/xbrz-license.txt @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/snes9x/filter/xbrz.cpp b/snes9x/filter/xbrz.cpp new file mode 100644 index 0000000..9033c0d --- /dev/null +++ b/snes9x/filter/xbrz.cpp @@ -0,0 +1,1263 @@ +// **************************************************************************** +// * This file is part of the xBRZ project. It is distributed under * +// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the following libraries * +// * (or with modified versions that use the same licenses), and distribute * +// * linked combinations including the two: MAME, FreeFileSync, Snes9x * +// * You must obey the GNU General Public License in all respects for all of * +// * the code used other than MAME, FreeFileSync, Snes9x. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#include "xbrz.h" +#include +#include +#include +#include //std::sqrt +#include "xbrz_tools.h" + +using namespace xbrz; + + +namespace +{ +template inline +uint32_t gradientRGB(uint32_t pixFront, uint32_t pixBack) //blend front color with opacity M / N over opaque background: http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending +{ + static_assert(0 < M && M < N && N <= 1000, ""); + + auto calcColor = [](unsigned char colFront, unsigned char colBack) -> unsigned char { return (colFront * M + colBack * (N - M)) / N; }; + + return makePixel(calcColor(getRed (pixFront), getRed (pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue (pixFront), getBlue (pixBack))); +} + + +template inline +uint32_t gradientARGB(uint32_t pixFront, uint32_t pixBack) //find intermediate color between two colors with alpha channels (=> NO alpha blending!!!) +{ + static_assert(0 < M && M < N && N <= 1000, ""); + + const unsigned int weightFront = getAlpha(pixFront) * M; + const unsigned int weightBack = getAlpha(pixBack) * (N - M); + const unsigned int weightSum = weightFront + weightBack; + if (weightSum == 0) + return 0; + + auto calcColor = [=](unsigned char colFront, unsigned char colBack) + { + return static_cast((colFront * weightFront + colBack * weightBack) / weightSum); + }; + + return makePixel(static_cast(weightSum / N), + calcColor(getRed (pixFront), getRed (pixBack)), + calcColor(getGreen(pixFront), getGreen(pixBack)), + calcColor(getBlue (pixFront), getBlue (pixBack))); +} + + +//inline +//double fastSqrt(double n) +//{ +// __asm //speeds up xBRZ by about 9% compared to std::sqrt which internally uses the same assembler instructions but adds some "fluff" +// { +// fld n +// fsqrt +// } +//} +// + + +enum RotationDegree //clock-wise +{ + ROT_0, + ROT_90, + ROT_180, + ROT_270 +}; + +//calculate input matrix coordinates after rotation at compile time +template +struct MatrixRotation; + +template +struct MatrixRotation +{ + static const size_t I_old = I; + static const size_t J_old = J; +}; + +template //(i, j) = (row, col) indices, N = size of (square) matrix +struct MatrixRotation +{ + static const size_t I_old = N - 1 - MatrixRotation(rotDeg - 1), I, J, N>::J_old; //old coordinates before rotation! + static const size_t J_old = MatrixRotation(rotDeg - 1), I, J, N>::I_old; // +}; + + +template +class OutputMatrix +{ +public: + OutputMatrix(uint32_t* out, int outWidth) : //access matrix area, top-left at position "out" for image with given width + out_(out), + outWidth_(outWidth) {} + + template + uint32_t& ref() const + { + static const size_t I_old = MatrixRotation::I_old; + static const size_t J_old = MatrixRotation::J_old; + return *(out_ + J_old + I_old * outWidth_); + } + +private: + uint32_t* out_; + const int outWidth_; +}; + + +template inline +T square(T value) { return value * value; } + + +#if 0 +inline +double distRGB(uint32_t pix1, uint32_t pix2) +{ + const double r_diff = static_cast(getRed (pix1)) - getRed (pix2); + const double g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); + const double b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); + + //euklidean RGB distance + return std::sqrt(square(r_diff) + square(g_diff) + square(b_diff)); +} +#endif + + +inline +double distYCbCr(uint32_t pix1, uint32_t pix2, double lumaWeight) +{ + //http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + //YCbCr conversion is a matrix multiplication => take advantage of linearity by subtracting first! + const int r_diff = static_cast(getRed (pix1)) - getRed (pix2); //we may delay division by 255 to after matrix multiplication + const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); // + const int b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); //substraction for int is noticeable faster than for double! + + //const double k_b = 0.0722; //ITU-R BT.709 conversion + //const double k_r = 0.2126; // + const double k_b = 0.0593; //ITU-R BT.2020 conversion + const double k_r = 0.2627; // + const double k_g = 1 - k_b - k_r; + + const double scale_b = 0.5 / (1 - k_b); + const double scale_r = 0.5 / (1 - k_r); + + const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! + const double c_b = scale_b * (b_diff - y); + const double c_r = scale_r * (r_diff - y); + + //we skip division by 255 to have similar range like other distance functions + return std::sqrt(square(lumaWeight * y) + square(c_b) + square(c_r)); +} + + +inline +double distYCbCrBuffered(uint32_t pix1, uint32_t pix2) +{ + //30% perf boost compared to plain distYCbCr()! + //consumes 64 MB memory; using double is only 2% faster, but takes 128 MB + static const std::vector diffToDist = [] + { + std::vector tmp; + + for (uint32_t i = 0; i < 256 * 256 * 256; ++i) //startup time: 114 ms on Intel Core i5 (four cores) + { + const int r_diff = getByte<2>(i) * 2 - 0xFF; + const int g_diff = getByte<1>(i) * 2 - 0xFF; + const int b_diff = getByte<0>(i) * 2 - 0xFF; + + const double k_b = 0.0593; //ITU-R BT.2020 conversion + const double k_r = 0.2627; // + const double k_g = 1 - k_b - k_r; + + const double scale_b = 0.5 / (1 - k_b); + const double scale_r = 0.5 / (1 - k_r); + + const double y = k_r * r_diff + k_g * g_diff + k_b * b_diff; //[!], analog YCbCr! + const double c_b = scale_b * (b_diff - y); + const double c_r = scale_r * (r_diff - y); + + tmp.push_back(static_cast(std::sqrt(square(y) + square(c_b) + square(c_r)))); + } + return tmp; + }(); + + //if (pix1 == pix2) -> 8% perf degradation! + // return 0; + //if (pix1 < pix2) + // std::swap(pix1, pix2); -> 30% perf degradation!!! +#if 1 + const int r_diff = static_cast(getRed (pix1)) - getRed (pix2); + const int g_diff = static_cast(getGreen(pix1)) - getGreen(pix2); + const int b_diff = static_cast(getBlue (pix1)) - getBlue (pix2); + + return diffToDist[(((r_diff + 0xFF) / 2) << 16) | //slightly reduce precision (division by 2) to squeeze value into single byte + (((g_diff + 0xFF) / 2) << 8) | + (( b_diff + 0xFF) / 2)]; +#else //not noticeably faster: + const int r_diff_tmp = ((pix1 & 0xFF0000) + 0xFF0000 - (pix2 & 0xFF0000)) / 2; + const int g_diff_tmp = ((pix1 & 0x00FF00) + 0x00FF00 - (pix2 & 0x00FF00)) / 2; //slightly reduce precision (division by 2) to squeeze value into single byte + const int b_diff_tmp = ((pix1 & 0x0000FF) + 0x0000FF - (pix2 & 0x0000FF)) / 2; + + return diffToDist[(r_diff_tmp & 0xFF0000) | (g_diff_tmp & 0x00FF00) | (b_diff_tmp & 0x0000FF)]; +#endif +} + + +enum BlendType +{ + BLEND_NONE = 0, + BLEND_NORMAL, //a normal indication to blend + BLEND_DOMINANT, //a strong indication to blend + //attention: BlendType must fit into the value range of 2 bit!!! +}; + +struct BlendResult +{ + BlendType + /**/blend_f, blend_g, + /**/blend_j, blend_k; +}; + + +struct Kernel_4x4 //kernel for preprocessing step +{ + uint32_t + /**/a, b, c, d, + /**/e, f, g, h, + /**/i, j, k, l, + /**/m, n, o, p; +}; + +/* +input kernel area naming convention: +----------------- +| A | B | C | D | +----|---|---|---| +| E | F | G | H | //evaluate the four corners between F, G, J, K +----|---|---|---| //input pixel is at position F +| I | J | K | L | +----|---|---|---| +| M | N | O | P | +----------------- +*/ +template +alwaysinline //detect blend direction +BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType" +{ + BlendResult result = {}; + + if ((ker.f == ker.g && + ker.j == ker.k) || + (ker.f == ker.j && + ker.g == ker.k)) + return result; + + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + + const int weight = 4; + double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + weight * dist(ker.j, ker.g); + double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + weight * dist(ker.f, ker.k); + + if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8 + { + const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk; + if (ker.f != ker.g && ker.f != ker.j) + result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + + if (ker.k != ker.j && ker.k != ker.g) + result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + else if (fk < jg) + { + const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg; + if (ker.j != ker.f && ker.j != ker.k) + result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + + if (ker.g != ker.f && ker.g != ker.k) + result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL; + } + return result; +} + +struct Kernel_3x3 +{ + uint32_t + /**/a, b, c, + /**/d, e, f, + /**/g, h, i; +}; + +#define DEF_GETTER(x) template uint32_t inline get_##x(const Kernel_3x3& ker) { return ker.x; } +//we cannot and NEED NOT write "ker.##x" since ## concatenates preprocessor tokens but "." is not a token +DEF_GETTER(a) DEF_GETTER(b) DEF_GETTER(c) +DEF_GETTER(d) DEF_GETTER(e) DEF_GETTER(f) +DEF_GETTER(g) DEF_GETTER(h) DEF_GETTER(i) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } + DEF_GETTER(b, d) DEF_GETTER(c, a) +DEF_GETTER(d, h) DEF_GETTER(e, e) DEF_GETTER(f, b) +DEF_GETTER(g, i) DEF_GETTER(h, f) DEF_GETTER(i, c) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } + DEF_GETTER(b, h) DEF_GETTER(c, g) +DEF_GETTER(d, f) DEF_GETTER(e, e) DEF_GETTER(f, d) +DEF_GETTER(g, c) DEF_GETTER(h, b) DEF_GETTER(i, a) +#undef DEF_GETTER + +#define DEF_GETTER(x, y) template <> inline uint32_t get_##x(const Kernel_3x3& ker) { return ker.y; } + DEF_GETTER(b, f) DEF_GETTER(c, i) +DEF_GETTER(d, b) DEF_GETTER(e, e) DEF_GETTER(f, h) +DEF_GETTER(g, a) DEF_GETTER(h, d) DEF_GETTER(i, g) +#undef DEF_GETTER + + +//compress four blend types into a single byte +//inline BlendType getTopL (unsigned char b) { return static_cast(0x3 & b); } +inline BlendType getTopR (unsigned char b) { return static_cast(0x3 & (b >> 2)); } +inline BlendType getBottomR(unsigned char b) { return static_cast(0x3 & (b >> 4)); } +inline BlendType getBottomL(unsigned char b) { return static_cast(0x3 & (b >> 6)); } + +inline void setTopL (unsigned char& b, BlendType bt) { b |= bt; } //buffer is assumed to be initialized before preprocessing! +inline void setTopR (unsigned char& b, BlendType bt) { b |= (bt << 2); } +inline void setBottomR(unsigned char& b, BlendType bt) { b |= (bt << 4); } +inline void setBottomL(unsigned char& b, BlendType bt) { b |= (bt << 6); } + +inline bool blendingNeeded(unsigned char b) { return b != 0; } + +template inline +unsigned char rotateBlendInfo(unsigned char b) { return b; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 2) | (b >> 6)) & 0xff; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 4) | (b >> 4)) & 0xff; } +template <> inline unsigned char rotateBlendInfo(unsigned char b) { return ((b << 6) | (b >> 2)) & 0xff; } + +#ifdef WIN32 +#ifndef NDEBUG + int debugPixelX = -1; + int debugPixelY = 12; + __declspec(thread) bool breakIntoDebugger = false; +#endif +#endif + +/* +input kernel area naming convention: +------------- +| A | B | C | +----|---|---| +| D | E | F | //input pixel is at position E +----|---|---| +| G | H | I | +------------- +*/ +template +alwaysinline //perf: quite worth it! +void blendPixel(const Kernel_3x3& ker, + uint32_t* target, int trgWidth, + unsigned char blendInfo, //result of preprocessing all four corners of pixel "e" + const xbrz::ScalerCfg& cfg) +{ +#define a get_a(ker) +#define b get_b(ker) +#define c get_c(ker) +#define d get_d(ker) +#define e get_e(ker) +#define f get_f(ker) +#define g get_g(ker) +#define h get_h(ker) +#define i get_i(ker) + +#ifdef WIN32 +#ifndef NDEBUG + if (breakIntoDebugger) + __debugbreak(); //__asm int 3; +#endif +#endif + + const unsigned char blend = rotateBlendInfo(blendInfo); + + if (getBottomR(blend) >= BLEND_NORMAL) + { + auto eq = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight) < cfg.equalColorTolerance; }; + auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); }; + + const bool doLineBlend = [&]() -> bool + { + if (getBottomR(blend) >= BLEND_DOMINANT) + return true; + + //make sure there is no second blending in an adjacent rotation for this pixel: handles insular pixels, mario eyes + if (getTopR(blend) != BLEND_NONE && !eq(e, g)) //but support double-blending for 90 degree corners + return false; + if (getBottomL(blend) != BLEND_NONE && !eq(e, c)) + return false; + + //no full blending for L-shapes; blend corner only (handles "mario mushroom eyes") + if (!eq(e, i) && eq(g, h) && eq(h, i) && eq(i, f) && eq(f, c)) + return false; + + return true; + }(); + + const uint32_t px = dist(e, f) <= dist(e, h) ? f : h; //choose most similar color + + OutputMatrix out(target, trgWidth); + + if (doLineBlend) + { + const double fg = dist(f, g); //test sample: 70% of values max(fg, hc) / min(fg, hc) are between 1.1 and 3.7 with median being 1.9 + const double hc = dist(h, c); // + + const bool haveShallowLine = cfg.steepDirectionThreshold * fg <= hc && e != g && d != g; + const bool haveSteepLine = cfg.steepDirectionThreshold * hc <= fg && e != c && b != c; + + if (haveShallowLine) + { + if (haveSteepLine) + Scaler::blendLineSteepAndShallow(px, out); + else + Scaler::blendLineShallow(px, out); + } + else + { + if (haveSteepLine) + Scaler::blendLineSteep(px, out); + else + Scaler::blendLineDiagonal(px, out); + } + } + else + Scaler::blendCorner(px, out); + } + +#undef a +#undef b +#undef c +#undef d +#undef e +#undef f +#undef g +#undef h +#undef i +} + + +template //scaler policy: see "Scaler2x" reference implementation +void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +{ + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || srcWidth <= 0) + return; + + const int trgWidth = srcWidth * Scaler::scale; + + //"use" space at the end of the image as temporary buffer for "on the fly preprocessing": we even could use larger area of + //"sizeof(uint32_t) * srcWidth * (yLast - yFirst)" bytes without risk of accidental overwriting before accessing + const int bufferSize = srcWidth; + unsigned char* preProcBuffer = reinterpret_cast(trg + yLast * Scaler::scale * trgWidth) - bufferSize; + std::fill(preProcBuffer, preProcBuffer + bufferSize, '\0'); + static_assert(BLEND_NONE == 0, ""); + + //initialize preprocessing buffer for first row of current stripe: detect upper left and right corner blending + //this cannot be optimized for adjacent processing stripes; we must not allow for a memory race condition! + if (yFirst > 0) + { + const int y = yFirst - 1; + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + for (int x = 0; x < srcWidth; ++x) + { + const int x_m1 = std::max(x - 1, 0); + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker = {}; //perf: initialization is negligible + ker.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker.b = s_m1[x]; + ker.c = s_m1[x_p1]; + ker.d = s_m1[x_p2]; + + ker.e = s_0[x_m1]; + ker.f = s_0[x]; + ker.g = s_0[x_p1]; + ker.h = s_0[x_p2]; + + ker.i = s_p1[x_m1]; + ker.j = s_p1[x]; + ker.k = s_p1[x_p1]; + ker.l = s_p1[x_p2]; + + ker.m = s_p2[x_m1]; + ker.n = s_p2[x]; + ker.o = s_p2[x_p1]; + ker.p = s_p2[x_p2]; + + const BlendResult res = preProcessCorners(ker, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //input pixel is at position F + | J | K | + --------- + */ + setTopR(preProcBuffer[x], res.blend_j); + + if (x + 1 < bufferSize) + setTopL(preProcBuffer[x + 1], res.blend_k); + } + } + //------------------------------------------------------------------------------------ + + for (int y = yFirst; y < yLast; ++y) + { + uint32_t* out = trg + Scaler::scale * y * trgWidth; //consider MT "striped" access + + const uint32_t* s_m1 = src + srcWidth * std::max(y - 1, 0); + const uint32_t* s_0 = src + srcWidth * y; //center line + const uint32_t* s_p1 = src + srcWidth * std::min(y + 1, srcHeight - 1); + const uint32_t* s_p2 = src + srcWidth * std::min(y + 2, srcHeight - 1); + + unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position + + for (int x = 0; x < srcWidth; ++x, out += Scaler::scale) + { +#ifdef WIN32 +#ifndef NDEBUG + breakIntoDebugger = debugPixelX == x && debugPixelY == y; +#endif +#endif + //all those bounds checks have only insignificant impact on performance! + const int x_m1 = std::max(x - 1, 0); //perf: prefer array indexing to additional pointers! + const int x_p1 = std::min(x + 1, srcWidth - 1); + const int x_p2 = std::min(x + 2, srcWidth - 1); + + Kernel_4x4 ker4 = {}; //perf: initialization is negligible + + ker4.a = s_m1[x_m1]; //read sequentially from memory as far as possible + ker4.b = s_m1[x]; + ker4.c = s_m1[x_p1]; + ker4.d = s_m1[x_p2]; + + ker4.e = s_0[x_m1]; + ker4.f = s_0[x]; + ker4.g = s_0[x_p1]; + ker4.h = s_0[x_p2]; + + ker4.i = s_p1[x_m1]; + ker4.j = s_p1[x]; + ker4.k = s_p1[x_p1]; + ker4.l = s_p1[x_p2]; + + ker4.m = s_p2[x_m1]; + ker4.n = s_p2[x]; + ker4.o = s_p2[x_p1]; + ker4.p = s_p2[x_p2]; + + //evaluate the four corners on bottom-right of current pixel + unsigned char blend_xy = 0; //for current (x, y) position + { + const BlendResult res = preProcessCorners(ker4, cfg); + /* + preprocessing blend result: + --------- + | F | G | //evalute corner between F, G, J, K + ----|---| //current input pixel is at position F + | J | K | + --------- + */ + blend_xy = preProcBuffer[x]; + setBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence! + + setTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1) + preProcBuffer[x] = blend_xy1; //store on current buffer position for use on next row + + blend_xy1 = 0; + setTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column + + if (x + 1 < bufferSize) //set 3rd known corner for (x + 1, y) + setBottomL(preProcBuffer[x + 1], res.blend_g); + } + + //fill block of size scale * scale with the given color + fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale); + //place *after* preprocessing step, to not overwrite the results while processing the the last pixel! + + //blend four corners of current pixel + if (blendingNeeded(blend_xy)) //good 5% perf-improvement + { + Kernel_3x3 ker3 = {}; //perf: initialization is negligible + + ker3.a = ker4.a; + ker3.b = ker4.b; + ker3.c = ker4.c; + + ker3.d = ker4.e; + ker3.e = ker4.f; + ker3.f = ker4.g; + + ker3.g = ker4.i; + ker3.h = ker4.j; + ker3.i = ker4.k; + + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + blendPixel(ker3, out, trgWidth, blend_xy, cfg); + } + } + } +} + +//------------------------------------------------------------------------------------ + +template +struct Scaler2x : public ColorGradient +{ + static const int scale = 2; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<1, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 1>(), col); + alphaGrad<5, 6>(out.template ref<1, 1>(), col); //[!] fixes 7/8 used in xBR + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref<1, 1>(), col); + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<21, 100>(out.template ref<1, 1>(), col); //exact: 1 - pi/4 = 0.2146018366 + } +}; + + +template +struct Scaler3x : public ColorGradient +{ + static const int scale = 3; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + out.template ref<2, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<2, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 2>(), col); + alphaGrad<3, 4>(out.template ref<2, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 2>(), col); + out.template ref<2, 2>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref<1, 2>(), col); //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref<2, 1>(), col); + alphaGrad<7, 8>(out.template ref<2, 2>(), col); // + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598 + //alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254 + } +}; + + +template +struct Scaler4x : public ColorGradient +{ + static const int scale = 4; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<3, 4>(out.template ref<3, 1>(), col); + alphaGrad<3, 4>(out.template ref<1, 3>(), col); + alphaGrad<1, 4>(out.template ref<3, 0>(), col); + alphaGrad<1, 4>(out.template ref<0, 3>(), col); + + alphaGrad<1, 3>(out.template ref<2, 2>(), col); //[!] fixes 1/4 used in xBR + + out.template ref<3, 3>() = col; + out.template ref<3, 2>() = col; + out.template ref<2, 3>() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<68, 100>(out.template ref<3, 3>(), col); //exact: 0.6848532563 + alphaGrad< 9, 100>(out.template ref<3, 2>(), col); //0.08677704501 + alphaGrad< 9, 100>(out.template ref<2, 3>(), col); //0.08677704501 + } +}; + + +template +struct Scaler5x : public ColorGradient +{ + static const int scale = 5; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<4, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + alphaGrad<2, 3>(out.template ref<3, 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 8>(out.template ref(), col); //conflict with other rotations for this odd scale + alphaGrad<1, 8>(out.template ref(), col); + alphaGrad<1, 8>(out.template ref(), col); // + + alphaGrad<7, 8>(out.template ref<4, 3>(), col); + alphaGrad<7, 8>(out.template ref<3, 4>(), col); + + out.template ref<4, 4>() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088 + alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731 + alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731 + //alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale + //alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367 + } +}; + + +template +struct Scaler6x : public ColorGradient +{ + static const int scale = 6; + + template //bring template function into scope for GCC + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) { ColorGradient::template alphaGrad(pixBack, pixFront); } + + + template + static void blendLineShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineSteep(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<1, 4>(out.template ref<4, scale - 3>(), col); + + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<5, scale - 3>(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + } + + template + static void blendLineSteepAndShallow(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 4>(out.template ref<0, scale - 1>(), col); + alphaGrad<1, 4>(out.template ref<2, scale - 2>(), col); + alphaGrad<3, 4>(out.template ref<1, scale - 1>(), col); + alphaGrad<3, 4>(out.template ref<3, scale - 2>(), col); + + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<1, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + alphaGrad<3, 4>(out.template ref(), col); + + out.template ref<2, scale - 1>() = col; + out.template ref<3, scale - 1>() = col; + out.template ref<4, scale - 1>() = col; + out.template ref<5, scale - 1>() = col; + + out.template ref<4, scale - 2>() = col; + out.template ref<5, scale - 2>() = col; + + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendLineDiagonal(uint32_t col, OutputMatrix& out) + { + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + alphaGrad<1, 2>(out.template ref(), col); + + out.template ref() = col; + out.template ref() = col; + out.template ref() = col; + } + + template + static void blendCorner(uint32_t col, OutputMatrix& out) + { + //model a round corner + alphaGrad<97, 100>(out.template ref<5, 5>(), col); //exact: 0.9711013910 + alphaGrad<42, 100>(out.template ref<4, 5>(), col); //0.4236372243 + alphaGrad<42, 100>(out.template ref<5, 4>(), col); //0.4236372243 + alphaGrad< 6, 100>(out.template ref<5, 3>(), col); //0.05652034508 + alphaGrad< 6, 100>(out.template ref<3, 5>(), col); //0.05652034508 + } +}; + +//------------------------------------------------------------------------------------ + +struct ColorDistanceRGB +{ + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + return distYCbCrBuffered(pix1, pix2); + + //if (pix1 == pix2) //about 4% perf boost + // return 0; + //return distYCbCr(pix1, pix2, luminanceWeight); + } +}; + +struct ColorDistanceARGB +{ + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + const double a1 = getAlpha(pix1) / 255.0 ; + const double a2 = getAlpha(pix2) / 255.0 ; + /* + Requirements for a color distance handling alpha channel: with a1, a2 in [0, 1] + + 1. if a1 = a2, distance should be: a1 * distYCbCr() + 2. if a1 = 0, distance should be: a2 * distYCbCr(black, white) = a2 * 255 + 3. if a1 = 1, ??? maybe: 255 * (1 - a2) + a2 * distYCbCr() + */ + + //return std::min(a1, a2) * distYCbCrBuffered(pix1, pix2) + 255 * abs(a1 - a2); + //=> following code is 15% faster: + const double d = distYCbCrBuffered(pix1, pix2); + if (a1 < a2) + return a1 * d + 255 * (a2 - a1); + else + return a2 * d + 255 * (a1 - a2); + + //alternative? return std::sqrt(a1 * a2 * square(distYCbCrBuffered(pix1, pix2)) + square(255 * (a1 - a2))); + } +}; + + +struct ColorDistanceUnbufferedARGB +{ + static double dist(uint32_t pix1, uint32_t pix2, double luminanceWeight) + { + const double a1 = getAlpha(pix1) / 255.0 ; + const double a2 = getAlpha(pix2) / 255.0 ; + + const double d = distYCbCr(pix1, pix2, luminanceWeight); + if (a1 < a2) + return a1 * d + 255 * (a2 - a1); + else + return a2 * d + 255 * (a1 - a2); + } +}; + + +struct ColorGradientRGB +{ + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientRGB(pixFront, pixBack); + } +}; + +struct ColorGradientARGB +{ + template + static void alphaGrad(uint32_t& pixBack, uint32_t pixFront) + { + pixBack = gradientARGB(pixFront, pixBack); + } +}; +} + + +void xbrz::scale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) +{ + static_assert(SCALE_FACTOR_MAX == 6, ""); + switch (colFmt) + { + case ColorFormat::RGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceRGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + + case ColorFormat::ARGB: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + + case ColorFormat::ARGB_UNBUFFERED: + switch (factor) + { + case 2: + return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 3: + return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 4: + return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 5: + return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + case 6: + return scaleImage, ColorDistanceUnbufferedARGB>(src, trg, srcWidth, srcHeight, cfg, yFirst, yLast); + } + break; + } + assert(false); +} + + +bool xbrz::equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance) +{ + switch (colFmt) + { + case ColorFormat::RGB: + return ColorDistanceRGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + case ColorFormat::ARGB: + return ColorDistanceARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + case ColorFormat::ARGB_UNBUFFERED: + return ColorDistanceUnbufferedARGB::dist(col1, col2, luminanceWeight) < equalColorTolerance; + } + assert(false); + return false; +} + + +void xbrz::bilinearScale(const uint32_t* src, int srcWidth, int srcHeight, + /**/ uint32_t* trg, int trgWidth, int trgHeight) +{ + bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), + trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), + 0, trgHeight, [](uint32_t pix) { return pix; }); +} + + +void xbrz::nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + /**/ uint32_t* trg, int trgWidth, int trgHeight) +{ + nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), + trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), + 0, trgHeight, [](uint32_t pix) { return pix; }); +} + + +#if 0 +//#include +void bilinearScaleCpu(const uint32_t* src, int srcWidth, int srcHeight, + /**/ uint32_t* trg, int trgWidth, int trgHeight) +{ + const int TASK_GRANULARITY = 16; + + concurrency::task_group tg; + + for (int i = 0; i < trgHeight; i += TASK_GRANULARITY) + tg.run([=] + { + const int iLast = std::min(i + TASK_GRANULARITY, trgHeight); + xbrz::bilinearScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t), + trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t), + i, iLast, [](uint32_t pix) { return pix; }); + }); + tg.wait(); +} + + +//Perf: AMP vs CPU: merely ~10% shorter runtime (scaling 1280x800 -> 1920x1080) +//#include +void bilinearScaleAmp(const uint32_t* src, int srcWidth, int srcHeight, //throw concurrency::runtime_exception + /**/ uint32_t* trg, int trgWidth, int trgHeight) +{ + //C++ AMP reference: https://msdn.microsoft.com/en-us/library/hh289390.aspx + //introduction to C++ AMP: https://msdn.microsoft.com/en-us/magazine/hh882446.aspx + using namespace concurrency; + //TODO: pitch + + if (srcHeight <= 0 || srcWidth <= 0) return; + + const float scaleX = static_cast(trgWidth ) / srcWidth; + const float scaleY = static_cast(trgHeight) / srcHeight; + + array_view srcView(srcHeight, srcWidth, src); + array_view< uint32_t, 2> trgView(trgHeight, trgWidth, trg); + trgView.discard_data(); + + parallel_for_each(trgView.extent, [=](index<2> idx) restrict(amp) //throw ? + { + const int y = idx[0]; + const int x = idx[1]; + //Perf notes: + // -> float-based calculation is (almost 2x) faster than double! + // -> no noticeable improvement via tiling: https://msdn.microsoft.com/en-us/magazine/hh882447.aspx + // -> no noticeable improvement with restrict(amp,cpu) + // -> iterating over y-axis only is significantly slower! + // -> pre-calculating x,y-dependent variables in a buffer + array_view<> is ~ 20 % slower! + const int y1 = srcHeight * y / trgHeight; + int y2 = y1 + 1; + if (y2 == srcHeight) --y2; + + const float yy1 = y / scaleY - y1; + const float y2y = 1 - yy1; + //------------------------------------- + const int x1 = srcWidth * x / trgWidth; + int x2 = x1 + 1; + if (x2 == srcWidth) --x2; + + const float xx1 = x / scaleX - x1; + const float x2x = 1 - xx1; + //------------------------------------- + const float x2xy2y = x2x * y2y; + const float xx1y2y = xx1 * y2y; + const float x2xyy1 = x2x * yy1; + const float xx1yy1 = xx1 * yy1; + + auto interpolate = [=](int offset) + { + /* + https://en.wikipedia.org/wiki/Bilinear_interpolation + (c11(x2 - x) + c21(x - x1)) * (y2 - y ) + + (c12(x2 - x) + c22(x - x1)) * (y - y1) + */ + const auto c11 = (srcView(y1, x1) >> (8 * offset)) & 0xff; + const auto c21 = (srcView(y1, x2) >> (8 * offset)) & 0xff; + const auto c12 = (srcView(y2, x1) >> (8 * offset)) & 0xff; + const auto c22 = (srcView(y2, x2) >> (8 * offset)) & 0xff; + + return c11 * x2xy2y + c21 * xx1y2y + + c12 * x2xyy1 + c22 * xx1yy1; + }; + + const float bi = interpolate(0); + const float gi = interpolate(1); + const float ri = interpolate(2); + const float ai = interpolate(3); + + const auto b = static_cast(bi + 0.5f); + const auto g = static_cast(gi + 0.5f); + const auto r = static_cast(ri + 0.5f); + const auto a = static_cast(ai + 0.5f); + + trgView(y, x) = (a << 24) | (r << 16) | (g << 8) | b; + }); + trgView.synchronize(); //throw ? +} +#endif diff --git a/snes9x/filter/xbrz.h b/snes9x/filter/xbrz.h new file mode 100644 index 0000000..6a6bac7 --- /dev/null +++ b/snes9x/filter/xbrz.h @@ -0,0 +1,80 @@ +// **************************************************************************** +// * This file is part of the xBRZ project. It is distributed under * +// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the following libraries * +// * (or with modified versions that use the same licenses), and distribute * +// * linked combinations including the two: MAME, FreeFileSync, Snes9x * +// * You must obey the GNU General Public License in all respects for all of * +// * the code used other than MAME, FreeFileSync, Snes9x. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#ifndef XBRZ_HEADER_3847894708239054 +#define XBRZ_HEADER_3847894708239054 + +#include "port.h" +//#include //size_t +//#include //uint32_t +#include +#include "xbrz_config.h" + +namespace xbrz +{ +/* +------------------------------------------------------------------------- +| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju | +------------------------------------------------------------------------- +using a modified approach of xBR: +http://board.byuu.org/viewtopic.php?f=10&t=2248 +- new rule set preserving small image features +- highly optimized for performance +- support alpha channel +- support multithreading +- support 64-bit architectures +- support processing image slices +- support scaling up to 6xBRZ +*/ + +enum class ColorFormat //from high bits -> low bits, 8 bit per channel +{ + RGB, //8 bit for each red, green, blue, upper 8 bits unused + ARGB, //including alpha channel, BGRA byte order on little-endian machines + ARGB_UNBUFFERED, //like ARGB, but without the one-time buffer creation overhead (ca. 100 - 300 ms) at the expense of a slightly slower scaling time +}; + +const int SCALE_FACTOR_MAX = 6; + +/* +-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only +-> support for source/target pitch in bytes! +-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image: + Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis) + CAVEAT: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition + in the target image data if you are using multiple threads for processing each enlarged slice! + +THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap! + - there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process at least 8-16 rows +*/ +void scale(size_t factor, //valid range: 2 - SCALE_FACTOR_MAX + const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, + ColorFormat colFmt, + const ScalerCfg& cfg = ScalerCfg(), + int yFirst = 0, int yLast = std::numeric_limits::max()); //slice of source image + +void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight, + /**/ uint32_t* trg, int trgWidth, int trgHeight); + +void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, + /**/ uint32_t* trg, int trgWidth, int trgHeight); + + +//parameter tuning +bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance); +} + +#endif diff --git a/snes9x/filter/xbrz_config.h b/snes9x/filter/xbrz_config.h new file mode 100644 index 0000000..a3fcefb --- /dev/null +++ b/snes9x/filter/xbrz_config.h @@ -0,0 +1,34 @@ +// **************************************************************************** +// * This file is part of the xBRZ project. It is distributed under * +// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the following libraries * +// * (or with modified versions that use the same licenses), and distribute * +// * linked combinations including the two: MAME, FreeFileSync, Snes9x * +// * You must obey the GNU General Public License in all respects for all of * +// * the code used other than MAME, FreeFileSync, Snes9x. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#ifndef XBRZ_CONFIG_HEADER_284578425345 +#define XBRZ_CONFIG_HEADER_284578425345 + +//do NOT include any headers here! used by xBRZ_dll!!! + +namespace xbrz +{ +struct ScalerCfg +{ + double luminanceWeight = 1; + double equalColorTolerance = 30; + double dominantDirectionThreshold = 3.6; + double steepDirectionThreshold = 2.2; + double newTestAttribute = 0; //unused; test new parameters +}; +} + +#endif \ No newline at end of file diff --git a/snes9x/filter/xbrz_tools.h b/snes9x/filter/xbrz_tools.h new file mode 100644 index 0000000..df7134b --- /dev/null +++ b/snes9x/filter/xbrz_tools.h @@ -0,0 +1,272 @@ +// **************************************************************************** +// * This file is part of the xBRZ project. It is distributed under * +// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * +// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * +// * * +// * Additionally and as a special exception, the author gives permission * +// * to link the code of this program with the following libraries * +// * (or with modified versions that use the same licenses), and distribute * +// * linked combinations including the two: MAME, FreeFileSync, Snes9x * +// * You must obey the GNU General Public License in all respects for all of * +// * the code used other than MAME, FreeFileSync, Snes9x. * +// * If you modify this file, you may extend this exception to your version * +// * of the file, but you are not obligated to do so. If you do not wish to * +// * do so, delete this exception statement from your version. * +// **************************************************************************** + +#ifndef XBRZ_TOOLS_H_825480175091875 +#define XBRZ_TOOLS_H_825480175091875 + +#include +#include +#include + + +namespace xbrz +{ +template inline +unsigned char getByte(uint32_t val) { return static_cast((val >> (8 * N)) & 0xff); } + +inline unsigned char getAlpha(uint32_t pix) { return getByte<3>(pix); } +inline unsigned char getRed (uint32_t pix) { return getByte<2>(pix); } +inline unsigned char getGreen(uint32_t pix) { return getByte<1>(pix); } +inline unsigned char getBlue (uint32_t pix) { return getByte<0>(pix); } + +inline uint32_t makePixel(unsigned char a, unsigned char r, unsigned char g, unsigned char b) { return (a << 24) | (r << 16) | (g << 8) | b; } +inline uint32_t makePixel( unsigned char r, unsigned char g, unsigned char b) { return (r << 16) | (g << 8) | b; } + +inline uint32_t rgb555to888(uint16_t pix) { return ((pix & 0x7C00) << 9) | ((pix & 0x03E0) << 6) | ((pix & 0x001F) << 3); } +inline uint32_t rgb565to888(uint16_t pix) { return ((pix & 0xF800) << 8) | ((pix & 0x07E0) << 5) | ((pix & 0x001F) << 3); } + +inline uint16_t rgb888to555(uint32_t pix) { return static_cast(((pix & 0xF80000) >> 9) | ((pix & 0x00F800) >> 6) | ((pix & 0x0000F8) >> 3)); } +inline uint16_t rgb888to565(uint32_t pix) { return static_cast(((pix & 0xF80000) >> 8) | ((pix & 0x00FC00) >> 5) | ((pix & 0x0000F8) >> 3)); } + + +template inline +Pix* byteAdvance(Pix* ptr, int bytes) +{ + using PixNonConst = typename std::remove_cv::type; + using PixByte = typename std::conditional::value, char, const char>::type; + + static_assert(std::is_integral::value, "Pix* is expected to be cast-able to char*"); + + return reinterpret_cast(reinterpret_cast(ptr) + bytes); +} + + +//fill block with the given color +template inline +void fillBlock(Pix* trg, int pitch, Pix col, int blockWidth, int blockHeight) +{ + //for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + // std::fill(trg, trg + blockWidth, col); + + for (int y = 0; y < blockHeight; ++y, trg = byteAdvance(trg, pitch)) + for (int x = 0; x < blockWidth; ++x) + trg[x] = col; +} + + +//nearest-neighbor (going over target image - slow for upscaling, since source is read multiple times missing out on cache! Fast for similar image sizes!) +template +void nearestNeighborScale(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch, + /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, + int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/) +{ + static_assert(std::is_integral::value, "PixSrc* is expected to be cast-able to char*"); + static_assert(std::is_integral::value, "PixTrg* is expected to be cast-able to char*"); + + static_assert(std::is_same::value, "PixConverter returning wrong pixel format"); + + if (srcPitch < srcWidth * static_cast(sizeof(PixSrc)) || + trgPitch < trgWidth * static_cast(sizeof(PixTrg))) + { + assert(false); + return; + } + + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, trgHeight); + if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; + + for (int y = yFirst; y < yLast; ++y) + { + const int ySrc = srcHeight * y / trgHeight; + const PixSrc* const srcLine = byteAdvance(src, ySrc * srcPitch); + PixTrg* const trgLine = byteAdvance(trg, y * trgPitch); + + for (int x = 0; x < trgWidth; ++x) + { + const int xSrc = srcWidth * x / trgWidth; + trgLine[x] = pixCvrt(srcLine[xSrc]); + } + } +} + + +//nearest-neighbor (going over source image - fast for upscaling, since source is read only once +template +void nearestNeighborScaleOverSource(const PixSrc* src, int srcWidth, int srcHeight, int srcPitch, + /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, + int yFirst, int yLast, PixConverter pixCvrt /*convert PixSrc to PixTrg*/) +{ + static_assert(std::is_integral::value, "PixSrc* is expected to be cast-able to char*"); + static_assert(std::is_integral::value, "PixTrg* is expected to be cast-able to char*"); + + static_assert(std::is_same::value, "PixConverter returning wrong pixel format"); + + if (srcPitch < srcWidth * static_cast(sizeof(PixSrc)) || + trgPitch < trgWidth * static_cast(sizeof(PixTrg))) + { + assert(false); + return; + } + + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, srcHeight); + if (yFirst >= yLast || trgWidth <= 0 || trgHeight <= 0) return; + + for (int y = yFirst; y < yLast; ++y) + { + //mathematically: ySrc = floor(srcHeight * yTrg / trgHeight) + // => search for integers in: [ySrc, ySrc + 1) * trgHeight / srcHeight + + //keep within for loop to support MT input slices! + const int yTrgFirst = ( y * trgHeight + srcHeight - 1) / srcHeight; //=ceil(y * trgHeight / srcHeight) + const int yTrgLast = ((y + 1) * trgHeight + srcHeight - 1) / srcHeight; //=ceil(((y + 1) * trgHeight) / srcHeight) + const int blockHeight = yTrgLast - yTrgFirst; + + if (blockHeight > 0) + { + const PixSrc* srcLine = byteAdvance(src, y * srcPitch); + /**/ PixTrg* trgLine = byteAdvance(trg, yTrgFirst * trgPitch); + int xTrgFirst = 0; + + for (int x = 0; x < srcWidth; ++x) + { + const int xTrgLast = ((x + 1) * trgWidth + srcWidth - 1) / srcWidth; + const int blockWidth = xTrgLast - xTrgFirst; + if (blockWidth > 0) + { + xTrgFirst = xTrgLast; + + const auto trgPix = pixCvrt(srcLine[x]); + fillBlock(trgLine, trgPitch, trgPix, blockWidth, blockHeight); + trgLine += blockWidth; + } + } + } + } +} + + +template +void bilinearScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, + /**/ PixTrg* trg, int trgWidth, int trgHeight, int trgPitch, + int yFirst, int yLast, PixConverter pixCvrt /*convert uint32_t to PixTrg*/) +{ + static_assert(std::is_integral::value, "PixTrg* is expected to be cast-able to char*"); + static_assert(std::is_same::value, "PixConverter returning wrong pixel format"); + + if (srcPitch < srcWidth * static_cast(sizeof(uint32_t)) || + trgPitch < trgWidth * static_cast(sizeof(PixTrg))) + { + assert(false); + return; + } + + yFirst = std::max(yFirst, 0); + yLast = std::min(yLast, trgHeight); + if (yFirst >= yLast || srcHeight <= 0 || srcWidth <= 0) return; + + const double scaleX = static_cast(trgWidth ) / srcWidth; + const double scaleY = static_cast(trgHeight) / srcHeight; + + //perf notes: + // -> double-based calculation is (slightly) faster than float + // -> precalculation gives significant boost; std::vector<> memory allocation is negligible! + struct CoeffsX + { + int x1 = 0; + int x2 = 0; + double xx1 = 0; + double x2x = 0; + }; + std::vector buf(trgWidth); + for (int x = 0; x < trgWidth; ++x) + { + const int x1 = srcWidth * x / trgWidth; + int x2 = x1 + 1; + if (x2 == srcWidth) --x2; + + const double xx1 = x / scaleX - x1; + const double x2x = 1 - xx1; + CoeffsX tmp; + tmp.x1 = x1; + tmp.x2 = x2; + tmp.xx1 = xx1; + tmp.x2x = x2x; + buf[x] = tmp; + } + + for (int y = yFirst; y < yLast; ++y) + { + const int y1 = srcHeight * y / trgHeight; + int y2 = y1 + 1; + if (y2 == srcHeight) --y2; + + const double yy1 = y / scaleY - y1; + const double y2y = 1 - yy1; + + const uint32_t* const srcLine = byteAdvance(src, y1 * srcPitch); + const uint32_t* const srcLineNext = byteAdvance(src, y2 * srcPitch); + PixTrg* const trgLine = byteAdvance(trg, y * trgPitch); + + for (int x = 0; x < trgWidth; ++x) + { + //perf: do NOT "simplify" the variable layout without measurement! + const int x1 = buf[x].x1; + const int x2 = buf[x].x2; + const double xx1 = buf[x].xx1; + const double x2x = buf[x].x2x; + + const double x2xy2y = x2x * y2y; + const double xx1y2y = xx1 * y2y; + const double x2xyy1 = x2x * yy1; + const double xx1yy1 = xx1 * yy1; + + auto interpolate = [=](int offset) + { + /* + https://en.wikipedia.org/wiki/Bilinear_interpolation + (c11(x2 - x) + c21(x - x1)) * (y2 - y ) + + (c12(x2 - x) + c22(x - x1)) * (y - y1) + */ + const auto c11 = (srcLine [x1] >> (8 * offset)) & 0xff; + const auto c21 = (srcLine [x2] >> (8 * offset)) & 0xff; + const auto c12 = (srcLineNext[x1] >> (8 * offset)) & 0xff; + const auto c22 = (srcLineNext[x2] >> (8 * offset)) & 0xff; + + return c11 * x2xy2y + c21 * xx1y2y + + c12 * x2xyy1 + c22 * xx1yy1; + }; + + const double bi = interpolate(0); + const double gi = interpolate(1); + const double ri = interpolate(2); + const double ai = interpolate(3); + + const auto b = static_cast(bi + 0.5); + const auto g = static_cast(gi + 0.5); + const auto r = static_cast(ri + 0.5); + const auto a = static_cast(ai + 0.5); + + const uint32_t trgPix = (a << 24) | (r << 16) | (g << 8) | b; + + trgLine[x] = pixCvrt(trgPix); + } + } +} +} + +#endif //XBRZ_TOOLS_H_825480175091875 diff --git a/snes9x/font.h b/snes9x/font.h new file mode 100644 index 0000000..c94ce24 --- /dev/null +++ b/snes9x/font.h @@ -0,0 +1,154 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/fxdbg.cpp b/snes9x/fxdbg.cpp new file mode 100644 index 0000000..b32d175 --- /dev/null +++ b/snes9x/fxdbg.cpp @@ -0,0 +1,1254 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/fxemu.cpp b/snes9x/fxemu.cpp new file mode 100644 index 0000000..2e0bdb3 --- /dev/null +++ b/snes9x/fxemu.cpp @@ -0,0 +1,815 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 only runs the SuperFX at the end of every line. + // 5823405 is a magic number that seems to work for most games. + SuperFX.speedPerLine = (uint32) (5823405 * ((1.0 / (float) 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 * 5 / 2) : SuperFX.speedPerLine) * Settings.SuperFXClockMultiplier / 100); + + 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); +} +*/ diff --git a/snes9x/fxemu.h b/snes9x/fxemu.h new file mode 100644 index 0000000..9f4bad9 --- /dev/null +++ b/snes9x/fxemu.h @@ -0,0 +1,37 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/fxinst.cpp b/snes9x/fxinst.cpp new file mode 100644 index 0000000..a32a4c1 --- /dev/null +++ b/snes9x/fxinst.cpp @@ -0,0 +1,4252 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 & 0x01) && !(COLR & 0xf)) + return; + + if (GSU.vPlotOptionReg & 0x02) + c = ((x ^ y) & 1) ? (uint8) (GSU.vColorReg >> 4) : (uint8) GSU.vColorReg; + else + c = (uint8) GSU.vColorReg; + + 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 & 0x01) && !(COLR & 0xf)) + return; + + if (GSU.vPlotOptionReg & 0x02) + c = ((x ^ y) & 1) ? (uint8) (GSU.vColorReg >> 4) : (uint8) GSU.vColorReg; + else + c = (uint8) GSU.vColorReg; + + 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 || ((GSU.vPlotOptionReg & 0x08) && !(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; + 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 +}; diff --git a/snes9x/fxinst.h b/snes9x/fxinst.h new file mode 100644 index 0000000..5abac4e --- /dev/null +++ b/snes9x/fxinst.h @@ -0,0 +1,371 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/getset.h b/snes9x/getset.h new file mode 100644 index 0000000..ec55ea9 --- /dev/null +++ b/snes9x/getset.h @@ -0,0 +1,857 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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" +#include "msu1.h" + +#define addCyclesInMemoryAccess \ + if (!CPU.InDMAorHDMA) \ + { \ + CPU.Cycles += speed; \ + while (CPU.Cycles >= CPU.NextEvent) \ + S9xDoHEventProcessing(); \ + } + +#define addCyclesInMemoryAccess_x2 \ + if (!CPU.InDMAorHDMA) \ + { \ + CPU.Cycles += speed << 1; \ + 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 & 0x1f0000) >> 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) +{ + uint16 word; + + uint32 mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); + if ((Address & mask) == mask) + { + PC_t a; + + word = OpenBus = S9xGetByte(Address); + + switch (w) + { + case WRAP_PAGE: + a.xPBPC = Address; + a.B.xPCl++; + return (word | (S9xGetByte(a.xPBPC) << 8)); + + case WRAP_BANK: + a.xPBPC = Address; + a.W.xPC++; + return (word | (S9xGetByte(a.xPBPC) << 8)); + + case WRAP_NONE: + default: + return (word | (S9xGetByte(Address + 1) << 8)); + } + } + + int block = (Address & 0xffffff) >> MEMMAP_SHIFT; + uint8 *GetAddress = Memory.Map[block]; + int32 speed = memory_speed(Address); + + 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) + { + word = OpenBus = S9xGetByte(Address); + return (word | (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 & 0x1f0000) >> 3)) & Memory.SRAMMask)); + else + word = (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0x1f0000) >> 3)) & Memory.SRAMMask)) | + (*(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0x1f0000) >> 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 & 0x1f0000) >> 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 & 0x1f0000) >> 3)) & Memory.SRAMMask), Word); + else + { + *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0x1f0000) >> 3)) & Memory.SRAMMask)) = (uint8) Word; + *(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0x1f0000) >> 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; + + uint8 *GetAddress = Memory.Map[(int)((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 & 0x1f0000) >> 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 & 0x1f0000) >> 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 & 0x1f0000) >> 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 diff --git a/snes9x/gfx.cpp b/snes9x/gfx.cpp new file mode 100644 index 0000000..bbeae22 --- /dev/null +++ b/snes9x/gfx.cpp @@ -0,0 +1,2145 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; +void (*S9xCustomDisplayString) (const char *, int, int, bool, int) = NULL; + +static void SetupOBJ (void); +static void DrawOBJS (int); +static void DisplayTime (void); +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); +static void S9xDisplayStringType (const char *, int, int, bool, int); + +#define TILE_PLUS(t, x) (((t) & 0xfc00) | ((t + x) & 0x3ff)) + + +bool8 S9xGraphicsInit (void) +{ + S9xInitTileRenderer(); + memset(BlackColourMap, 0, 256 * sizeof(uint16)); + + GFX.RealPPL = GFX.Pitch >> 1; + IPPU.OBJChanged = TRUE; + Settings.BG_Forced = 0; + S9xFixColourBrightness(); + S9xBuildDirectColourMaps(); + + 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.ZERO || !GFX.SubScreen || !GFX.ZBuffer || !GFX.SubZBuffer) + { + S9xGraphicsDeinit(); + return (FALSE); + } + + // 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.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 S9xGraphicsScreenResize (void) +{ + 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; + } +} + +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)]); +} + +void S9xStartScreenRefresh (void) +{ + GFX.InterlaceFrame = !GFX.InterlaceFrame; + if (GFX.DoInterlace) + GFX.DoInterlace--; + + if (IPPU.RenderThisFrame) + { + if (!GFX.DoInterlace || !GFX.InterlaceFrame) + { + if (!S9xInitUpdate()) + { + IPPU.RenderThisFrame = FALSE; + return; + } + + S9xGraphicsScreenResize(); + + 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; + 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(); + + S9xUpdateCheatsInMemory (); + +#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 (int32 y = (int32) GFX.StartY - 1; y >= 0; y--) + { + uint16 *p = GFX.Screen + y * GFX.PPL + 255; + uint16 *q = GFX.Screen + y * GFX.RealPPL + 510; + + for (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 (uint32 y = 0; y < GFX.StartY; y++) + { + uint16 *p = GFX.Screen + y * GFX.PPL + 255; + uint16 *q = GFX.Screen + y * GFX.PPL + 510; + + for (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 (int32 y = (int32) GFX.StartY - 2; y >= 0; y--) + memmove(GFX.Screen + (y + 1) * GFX.PPL, GFX.Screen + y * GFX.RealPPL, GFX.PPL * 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; + int sprite_limit = (Settings.MaxSpriteTilesPerLine == 128) ? 128 : 32; + + 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 = Settings.MaxSpriteTilesPerLine; + for (int j = 0; j < sprite_limit; 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] >= sprite_limit) + { + 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 = Settings.MaxSpriteTilesPerLine; + + uint8 FirstSprite = (PPU.FirstSprite + Y) & 0x7f; + S = FirstSprite; + j = 0; + + if (AnyOBJOnLine[Y]) + { + do + { + if (OBJOnLine[Y][S]) + { + if (j >= sprite_limit) + { + 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 < sprite_limit) + GFX.OBJLines[Y].OBJ[j].Sprite = -1; + } + } + + IPPU.OBJChanged = FALSE; +} + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC push_options +#pragma GCC optimize ("no-tree-vrp") +#endif +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; + int sprite_limit = (Settings.MaxSpriteTilesPerLine == 128) ? 128 : 32; + + 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 < sprite_limit; 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; + } + } + } + } + } +} +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC pop_options +#endif + +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 + MosaicStart].BG[bg].VOffset + (HiresInterlace ? 1 : 0); + uint32 HOffset = LineData[Y + MosaicStart].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 (*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)) + { + DrawClippedTile = GFX.DrawClippedTileMath; + } + else + { + 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 HScroll = LineData[Y].BG[bg].HOffset; + bool8 left_edge = (Left < (8 - (HScroll & 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 = HScroll; + 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) | (HScroll & 7); + else + HOffset = HScroll; + } + + 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 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 + MosaicStart].BG[2].VOffset - 1; + uint32 HOff = LineData[Y + MosaicStart].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 HScroll = LineData[Y + MosaicStart].BG[bg].HOffset; + uint32 Width = Right - Left; + + while (Left < Right) + { + uint32 VOffset, HOffset; + + if (Left < (8 - (HScroll & 7))) + { + // SNES cannot do OPT for leftmost tile column + VOffset = LineData[Y + MosaicStart].BG[bg].VOffset; + HOffset = HScroll; + } + else + { + int HOffTile = (((Left + (HScroll & 7)) - 8) + (HOff & ~7)) >> 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 + MosaicStart].BG[bg].VOffset; + + if (HCellOffset & OffsetEnableMask) + HOffset = (HCellOffset & ~7) | (HScroll & 7); + else + HOffset = HScroll; + } + + 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 (S9xCustomDisplayString) + { + S9xCustomDisplayString (string, linesFromBottom, pixelsFromLeft, allowWrap, S9X_NO_INFO); + return; + } + + 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 S9xDisplayStringType (const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap, int type) +{ + if (S9xCustomDisplayString) + { + S9xCustomDisplayString (string, linesFromBottom, pixelsFromLeft, allowWrap, type); + return; + } + + S9xDisplayString (string, linesFromBottom, pixelsFromLeft, allowWrap); +} + +static void DisplayTime (void) +{ + char string[10]; + + time_t rawtime; + struct tm *timeinfo; + + time (&rawtime); + timeinfo = localtime(&rawtime); + + sprintf(string, "%02u:%02u", timeinfo->tm_hour, timeinfo->tm_min); + S9xDisplayString(string, 0, 0, false); +} + +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 unsigned char KeyMap[] = { '0', '1', '2', 'R', 'L', 'X', 'A', 225, 224, 227, 226, '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]; + if (!MovieGetMouse(port, buf)) + break; + int16 x = READ_WORD(buf); + int16 y = READ_WORD(buf + 2); + uint8 buttons = buf[4]; + sprintf(string, "#%d %d: (%03d,%03d) %c%c", port + 1, ids[0] + 1, x, y, + (buttons & 0x40) ? 'L' : ' ', (buttons & 0x80) ? 'R' : ' '); + S9xDisplayStringType(string, line++, 1, false, S9X_PRESSED_KEYS_INFO); + break; + } + + case CTL_SUPERSCOPE: + { + uint8 buf[6]; + if (!MovieGetScope(port, buf)) + break; + int16 x = READ_WORD(buf); + int16 y = READ_WORD(buf + 2); + uint8 buttons = buf[4]; + sprintf(string, "#%d %d: (%03d,%03d) %c%c%c%c", port + 1, ids[0] + 1, x, y, + (buttons & 0x80) ? 'F' : ' ', (buttons & 0x40) ? 'C' : ' ', + (buttons & 0x20) ? 'T' : ' ', (buttons & 0x10) ? 'P' : ' '); + S9xDisplayStringType(string, line++, 1, false, S9X_PRESSED_KEYS_INFO); + break; + } + + case CTL_JUSTIFIER: + { + uint8 buf[11]; + if (!MovieGetJustifier(port, buf)) + break; + int16 x1 = READ_WORD(buf); + int16 x2 = READ_WORD(buf + 2); + int16 y1 = READ_WORD(buf + 4); + int16 y2 = READ_WORD(buf + 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 + 1, ids[0] + 1, + x1, y1, (buttons & 0x80) ? 'T' : ' ', (buttons & 0x20) ? 'S' : ' ', offscreen1 ? 'O' : ' ', + x2, y2, (buttons & 0x40) ? 'T' : ' ', (buttons & 0x10) ? 'S' : ' ', offscreen2 ? 'O' : ' '); + S9xDisplayStringType(string, line++, 1, false, S9X_PRESSED_KEYS_INFO); + break; + } + + case CTL_JOYPAD: + { + sprintf(string, "#%d %d: ", port + 1, ids[0] + 1); + 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] : ' '; + } + + S9xDisplayStringType(string, line++, 1, false, S9X_PRESSED_KEYS_INFO); + break; + } + + case CTL_MP5: + { + for (int n = 0; n < 4; n++) + { + if (ids[n] != -1) + { + sprintf(string, "#%d %d: ", port + 1, ids[n] + 1); + 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] : ' '; + } + + S9xDisplayStringType(string, line++, 1, false, S9X_PRESSED_KEYS_INFO); + } + } + + break; + } + + case CTL_MACSRIFLE: + { + /* + 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_NONE: + { + // Display Nothing + 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.DisplayTime) + DisplayTime(); + + 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_ADD::fn1_2(fg, *s) : fg; + else + if (p == '.' && bgcolor) + *s = (bgcolor & 0x10) ? COLOR_ADD::fn1_2(*s, bg) : bg; + } + } +} + diff --git a/snes9x/gfx.h b/snes9x/gfx.h new file mode 100644 index 0000000..f4deca3 --- /dev/null +++ b/snes9x/gfx.h @@ -0,0 +1,224 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include "port.h" + +struct SGFX +{ + uint16 *Screen; + uint16 *SubScreen; + uint8 *ZBuffer; + uint8 *SubZBuffer; + uint32 Pitch; + uint32 ScreenSize; + uint16 *S; + uint8 *DB; + 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[128]; + } OBJLines[SNES_HEIGHT_EXTENDED]; + + 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 uint8 brightness_cap[64]; +extern struct SBG BG; +extern struct SGFX GFX; + +#define H_FLIP 0x4000 +#define V_FLIP 0x8000 +#define BLANK_TILE 2 + +struct COLOR_ADD +{ + static alwaysinline uint16 fn(uint16 C1, uint16 C2) + { + const int RED_MASK = 0x1F << RED_SHIFT_BITS; + const int GREEN_MASK = 0x1F << GREEN_SHIFT_BITS; + const int BLUE_MASK = 0x1F; + + int rb = C1 & (RED_MASK | BLUE_MASK); + rb += C2 & (RED_MASK | BLUE_MASK); + int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0)); + int g = (C1 & (GREEN_MASK)) + (C2 & (GREEN_MASK)); + int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f; + uint16 retval = (rb & (RED_MASK | BLUE_MASK)) | (g & GREEN_MASK) | rgbsaturate; +#if GREEN_SHIFT_BITS == 6 + retval |= (retval & 0x0400) >> 5; +#endif + return retval; + } + + static alwaysinline uint16 fn1_2(uint16 C1, uint16 C2) + { + return ((((C1 & RGB_REMOVE_LOW_BITS_MASK) + + (C2 & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + + (C1 & C2 & RGB_LOW_BITS_MASK)) | ALPHA_BITS_MASK; + } +}; + +struct COLOR_ADD_BRIGHTNESS +{ + static alwaysinline uint16 fn(uint16 C1, uint16 C2) + { + return ((brightness_cap[ (C1 >> RED_SHIFT_BITS) + (C2 >> RED_SHIFT_BITS) ] << RED_SHIFT_BITS) | + (brightness_cap[((C1 >> GREEN_SHIFT_BITS) & 0x1f) + ((C2 >> GREEN_SHIFT_BITS) & 0x1f)] << GREEN_SHIFT_BITS) | + // Proper 15->16bit color conversion moves the high bit of green into the low bit. + #if GREEN_SHIFT_BITS == 6 + ((brightness_cap[((C1 >> 6) & 0x1f) + ((C2 >> 6) & 0x1f)] & 0x10) << 1) | + #endif + (brightness_cap[ (C1 & 0x1f) + (C2 & 0x1f)] )); + } + + static alwaysinline uint16 fn1_2(uint16 C1, uint16 C2) + { + return COLOR_ADD::fn1_2(C1, C2); + } +}; + + +struct COLOR_SUB +{ + static alwaysinline uint16 fn(uint16 C1, uint16 C2) + { + int rb1 = (C1 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | ((0x20 << 0) | (0x20 << RED_SHIFT_BITS)); + int rb2 = C2 & (THIRD_COLOR_MASK | FIRST_COLOR_MASK); + int rb = rb1 - rb2; + int rbcarry = rb & ((0x20 << RED_SHIFT_BITS) | (0x20 << 0)); + int g = ((C1 & (SECOND_COLOR_MASK)) | (0x20 << GREEN_SHIFT_BITS)) - (C2 & (SECOND_COLOR_MASK)); + int rgbsaturate = (((g & (0x20 << GREEN_SHIFT_BITS)) | rbcarry) >> 5) * 0x1f; + uint16 retval = ((rb & (THIRD_COLOR_MASK | FIRST_COLOR_MASK)) | (g & SECOND_COLOR_MASK)) & rgbsaturate; +#if GREEN_SHIFT_BITS == 6 + retval |= (retval & 0x0400) >> 5; +#endif + return retval; + } + + static alwaysinline uint16 fn1_2(uint16 C1, uint16 C2) + { + return GFX.ZERO[((C1 | RGB_HI_BITS_MASKx2) - + (C2 & RGB_REMOVE_LOW_BITS_MASK)) >> 1]; + } +}; + +void S9xStartScreenRefresh (void); +void S9xEndScreenRefresh (void); +void S9xBuildDirectColourMaps (void); +void RenderLine (uint8); +void S9xComputeClipWindows (void); +void S9xDisplayChar (uint16 *, uint8); +void S9xGraphicsScreenResize (void); +// called automatically unless Settings.AutoDisplayMessages is false +void S9xDisplayMessages (uint16 *, int, int, int, int); + +// 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 S9xSyncSpeed (void); + +// called instead of S9xDisplayString if set to non-NULL +extern void (*S9xCustomDisplayString) (const char *, int, int, bool, int type); + +#endif diff --git a/snes9x/globals.cpp b/snes9x/globals.cpp new file mode 100644 index 0000000..104c0c2 --- /dev/null +++ b/snes9x/globals.cpp @@ -0,0 +1,206 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 SMSU1 MSU1; +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; + +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 brightness_cap[64]; + +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 +}; diff --git a/snes9x/jma/7z.h b/snes9x/jma/7z.h new file mode 100644 index 0000000..40b9251 --- /dev/null +++ b/snes9x/jma/7z.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __7Z_H +#define __7Z_H + +#include "iiostrm.h" + +bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw (); +bool decompress_lzma_7z(const unsigned char* in_data, unsigned in_size, unsigned char* out_data, unsigned out_size) throw (); + +#endif + diff --git a/snes9x/jma/7zlzma.cpp b/snes9x/jma/7zlzma.cpp new file mode 100644 index 0000000..ddaa395 --- /dev/null +++ b/snes9x/jma/7zlzma.cpp @@ -0,0 +1,50 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "7z.h" + +#include "lzmadec.h" + +bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw () +{ + try + { + NCompress::NLZMA::CDecoder cc; + + UINT64 in_size_l = in_size; + UINT64 out_size_l = out_size; + + if (cc.ReadCoderProperties(&in) != S_OK) { return(false); } + if (cc.Code(&in, &out, &in_size_l, &out_size_l) != S_OK) { return(false); } + if (out.size_get() != out_size || out.overflow_get()) { return(false); } + + return(true); + } + catch (...) + { + return(false); + } +} + +bool decompress_lzma_7z(const unsigned char* in_data, unsigned int in_size, unsigned char* out_data, unsigned int out_size) throw () +{ + ISequentialInStream_Array in(reinterpret_cast(in_data), in_size); + ISequentialOutStream_Array out(reinterpret_cast(out_data), out_size); + + return(decompress_lzma_7z(in, in_size, out, out_size)); +} diff --git a/snes9x/jma/aribitcd.h b/snes9x/jma/aribitcd.h new file mode 100644 index 0000000..1fb421b --- /dev/null +++ b/snes9x/jma/aribitcd.h @@ -0,0 +1,73 @@ +#ifndef __COMPRESSION_BITCODER_H +#define __COMPRESSION_BITCODER_H + +#include "rngcoder.h" + +namespace NCompression { +namespace NArithmetic { + +const int kNumBitModelTotalBits = 11; +const UINT32 kBitModelTotal = (1 << kNumBitModelTotalBits); + +const int kNumMoveReducingBits = 2; + +///////////////////////////// +// CBitModel + +template +class CBitModel +{ +public: + UINT32 m_Probability; + void UpdateModel(UINT32 aSymbol) + { + /* + m_Probability -= (m_Probability + ((aSymbol - 1) & ((1 << aNumMoveBits) - 1))) >> aNumMoveBits; + m_Probability += (1 - aSymbol) << (kNumBitModelTotalBits - aNumMoveBits); + */ + if (aSymbol == 0) + m_Probability += (kBitModelTotal - m_Probability) >> aNumMoveBits; + else + m_Probability -= (m_Probability) >> aNumMoveBits; + } +public: + void Init() { m_Probability = kBitModelTotal / 2; } +}; + +template +class CBitDecoder: public CBitModel +{ +public: + UINT32 Decode(CRangeDecoder *aRangeDecoder) + { + UINT32 aNewBound = (aRangeDecoder->m_Range >> kNumBitModelTotalBits) * CBitModel::m_Probability; + if (aRangeDecoder->m_Code < aNewBound) + { + aRangeDecoder->m_Range = aNewBound; + CBitModel::m_Probability += (kBitModelTotal - CBitModel::m_Probability) >> aNumMoveBits; + if (aRangeDecoder->m_Range < kTopValue) + { + aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte(); + aRangeDecoder->m_Range <<= 8; + } + return 0; + } + else + { + aRangeDecoder->m_Range -= aNewBound; + aRangeDecoder->m_Code -= aNewBound; + CBitModel::m_Probability -= (CBitModel::m_Probability) >> aNumMoveBits; + if (aRangeDecoder->m_Range < kTopValue) + { + aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte(); + aRangeDecoder->m_Range <<= 8; + } + return 1; + } + } +}; + +}} + + +#endif diff --git a/snes9x/jma/ariconst.h b/snes9x/jma/ariconst.h new file mode 100644 index 0000000..751b2b7 --- /dev/null +++ b/snes9x/jma/ariconst.h @@ -0,0 +1,29 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __ARICONST_H +#define __ARICONST_H + +#include "aribitcd.h" + + +typedef NCompression::NArithmetic::CRangeDecoder CMyRangeDecoder; +template class CMyBitDecoder: + public NCompression::NArithmetic::CBitDecoder {}; + +#endif diff --git a/snes9x/jma/ariprice.h b/snes9x/jma/ariprice.h new file mode 100644 index 0000000..ccc398e --- /dev/null +++ b/snes9x/jma/ariprice.h @@ -0,0 +1,12 @@ +#ifndef __COMPRESSION_ARIPRICE_H +#define __COMPRESSION_ARIPRICE_H + +namespace NCompression { +namespace NArithmetic { + +const UINT32 kNumBitPriceShiftBits = 6; +const UINT32 kBitPrice = 1 << kNumBitPriceShiftBits; + +}} + +#endif diff --git a/snes9x/jma/btreecd.h b/snes9x/jma/btreecd.h new file mode 100644 index 0000000..acce366 --- /dev/null +++ b/snes9x/jma/btreecd.h @@ -0,0 +1,126 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __BITTREECODER_H +#define __BITTREECODER_H + +#include "aribitcd.h" +#include "rcdefs.h" + + +////////////////////////// +// CBitTreeDecoder + +template +class CBitTreeDecoder +{ + CMyBitDecoder m_Models[1 << m_NumBitLevels]; +public: + void Init() + { + for(UINT32 i = 1; i < (1 << m_NumBitLevels); i++) + m_Models[i].Init(); + } + UINT32 Decode(CMyRangeDecoder *aRangeDecoder) + { + UINT32 aModelIndex = 1; + RC_INIT_VAR + for(UINT32 aBitIndex = m_NumBitLevels; aBitIndex > 0; aBitIndex--) + { + // aModelIndex = (aModelIndex << 1) + m_Models[aModelIndex].Decode(aRangeDecoder); + RC_GETBIT(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex) + } + RC_FLUSH_VAR + return aModelIndex - (1 << m_NumBitLevels); + }; +}; + +//////////////////////////////// +// CReverseBitTreeDecoder + +template +class CReverseBitTreeDecoder2 +{ + CMyBitDecoder *m_Models; + UINT32 m_NumBitLevels; +public: + CReverseBitTreeDecoder2(): m_Models(0) { } + ~CReverseBitTreeDecoder2() { delete []m_Models; } + bool Create(UINT32 aNumBitLevels) + { + m_NumBitLevels = aNumBitLevels; + m_Models = new CMyBitDecoder[1 << aNumBitLevels]; + return (m_Models != 0); + } + void Init() + { + UINT32 aNumModels = 1 << m_NumBitLevels; + for(UINT32 i = 1; i < aNumModels; i++) + m_Models[i].Init(); + } + UINT32 Decode(CMyRangeDecoder *aRangeDecoder) + { + UINT32 aModelIndex = 1; + UINT32 aSymbol = 0; + RC_INIT_VAR + for(UINT32 aBitIndex = 0; aBitIndex < m_NumBitLevels; aBitIndex++) + { + // UINT32 aBit = m_Models[aModelIndex].Decode(aRangeDecoder); + // aModelIndex <<= 1; + // aModelIndex += aBit; + // aSymbol |= (aBit << aBitIndex); + RC_GETBIT2(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex, ; , aSymbol |= (1 << aBitIndex)) + } + RC_FLUSH_VAR + return aSymbol; + }; +}; +//////////////////////////// +// CReverseBitTreeDecoder2 + +template +class CReverseBitTreeDecoder +{ + CMyBitDecoder m_Models[1 << m_NumBitLevels]; +public: + void Init() + { + for(UINT32 i = 1; i < (1 << m_NumBitLevels); i++) + m_Models[i].Init(); + } + UINT32 Decode(CMyRangeDecoder *aRangeDecoder) + { + UINT32 aModelIndex = 1; + UINT32 aSymbol = 0; + RC_INIT_VAR + for(UINT32 aBitIndex = 0; aBitIndex < m_NumBitLevels; aBitIndex++) + { + // UINT32 aBit = m_Models[aModelIndex].Decode(aRangeDecoder); + // aModelIndex <<= 1; + // aModelIndex += aBit; + // aSymbol |= (aBit << aBitIndex); + RC_GETBIT2(aNumMoveBits, m_Models[aModelIndex].m_Probability, aModelIndex, ; , aSymbol |= (1 << aBitIndex)) + } + RC_FLUSH_VAR + return aSymbol; + } +}; + + + +#endif diff --git a/snes9x/jma/crc32.cpp b/snes9x/jma/crc32.cpp new file mode 100644 index 0000000..0460477 --- /dev/null +++ b/snes9x/jma/crc32.cpp @@ -0,0 +1,81 @@ +/* +Copyright (C) 2004-2006 NSRT Team ( http://nsrt.edgeemu.com ) + +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 +#include "crc32.h" + +namespace CRC32lib +{ + //Don't ask questions, this is the PKZip CRC32 table + const unsigned int 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 }; + + + //CRC32 for char arrays + unsigned int CRC32(const unsigned char *array, size_t size, unsigned int crc32) + { + const unsigned char *end_p = array+size; + for (const unsigned char *p = array; p < end_p; p++) + { + crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ *p) & 0xFF]; + } + + return(~crc32); + } +} diff --git a/snes9x/jma/crc32.h b/snes9x/jma/crc32.h new file mode 100644 index 0000000..4e8f7d0 --- /dev/null +++ b/snes9x/jma/crc32.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 2004-2006 NSRT Team ( http://nsrt.edgeemu.com ) + +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. +*/ + +#ifndef CRC32_H +#define CRC32_H + +namespace CRC32lib +{ + unsigned int CRC32(const unsigned char *, size_t, unsigned int crc32 = 0xFFFFFFFF); +} + +#endif diff --git a/snes9x/jma/iiostrm.cpp b/snes9x/jma/iiostrm.cpp new file mode 100644 index 0000000..0d27b9c --- /dev/null +++ b/snes9x/jma/iiostrm.cpp @@ -0,0 +1,132 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "portable.h" +#include "iiostrm.h" +#include "crc32.h" + +HRESULT ISequentialInStream_Array::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + if (aSize > size) + { + aSize = size; + } + + *aProcessedSize = aSize; + memcpy(aData, data, aSize); + size -= aSize; + data += aSize; + return(S_OK); +} + +HRESULT ISequentialOutStream_Array::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + if (aSize > size) + { + overflow = true; + aSize = size; + } + + *aProcessedSize = aSize; + memcpy(data, aData, aSize); + size -= aSize; + data += aSize; + total += aSize; + return(S_OK); +} + +HRESULT ISequentialInStream_String::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + if (aSize > data.size()) + { + aSize = data.size(); + } + + *aProcessedSize = aSize; + memcpy(aData, data.c_str(), aSize); + data.erase(0, aSize); + return(S_OK); +} + +HRESULT ISequentialOutStream_String::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + *aProcessedSize = aSize; + data.append((const char *)aData, aSize); + total += aSize; + return(S_OK); +} + +HRESULT ISequentialInStream_Istream::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + data.read((char *)aData, aSize); + *aProcessedSize = data.gcount(); + return(S_OK); +} + +HRESULT ISequentialOutStream_Ostream::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + *aProcessedSize = aSize; + data.write((char *)aData, aSize); + total += aSize; + return(S_OK); +} + + + +HRESULT ISequentialInStreamCRC32_Array::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialInStream_Array::Read(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} + +HRESULT ISequentialOutStreamCRC32_Array::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialOutStream_Array::Write(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} + +HRESULT ISequentialInStreamCRC32_String::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialInStream_String::Read(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} + +HRESULT ISequentialOutStreamCRC32_String::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialOutStream_String::Write(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} + +HRESULT ISequentialInStreamCRC32_Istream::Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialInStream_Istream::Read(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} + +HRESULT ISequentialOutStreamCRC32_Ostream::Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize) +{ + ISequentialOutStream_Ostream::Write(aData, aSize, aProcessedSize); + crc32 = CRC32lib::CRC32((const unsigned char *)aData, *aProcessedSize, ~crc32); + return(S_OK); +} diff --git a/snes9x/jma/iiostrm.h b/snes9x/jma/iiostrm.h new file mode 100644 index 0000000..bef0f00 --- /dev/null +++ b/snes9x/jma/iiostrm.h @@ -0,0 +1,210 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __IINOUTSTREAMS_H +#define __IINOUTSTREAMS_H + +#include +#include + +#include "portable.h" + + +class ISequentialInStream +{ +public: + virtual HRESULT Read(void *, UINT32, UINT32 *) = 0; + + virtual ~ISequentialInStream() {} +}; + + +class ISequentialInStream_Array : public ISequentialInStream +{ + const char *data; + unsigned int size; +public: + ISequentialInStream_Array(const char *Adata, unsigned Asize) : data(Adata), size(Asize) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStream_Array() {} +}; + +class ISequentialInStream_String : public ISequentialInStream +{ + std::string& data; +public: + ISequentialInStream_String(std::string& Adata) : data(Adata) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStream_String() {} +}; + +class ISequentialInStream_Istream : public ISequentialInStream +{ + std::istream& data; +public: + ISequentialInStream_Istream(std::istream& Adata) : data(Adata) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStream_Istream() {} +}; + + + +class ISequentialOutStream +{ +public: + virtual bool overflow_get() const = 0; + virtual unsigned int size_get() const = 0; + + virtual HRESULT Write(const void *, UINT32, UINT32 *) = 0; + + virtual ~ISequentialOutStream() {} +}; + + +class ISequentialOutStream_Array : public ISequentialOutStream +{ + char *data; + unsigned int size; + bool overflow; + unsigned int total; +public: + ISequentialOutStream_Array(char *Adata, unsigned Asize) : data(Adata), size(Asize), overflow(false), total(0) { } + + bool overflow_get() const { return(overflow); } + unsigned int size_get() const { return(total); } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStream_Array() {} +}; + +class ISequentialOutStream_String : public ISequentialOutStream +{ + std::string& data; + unsigned int total; +public: + ISequentialOutStream_String(std::string& Adata) : data(Adata), total(0) { } + + bool overflow_get() const { return(false); } + unsigned int size_get() const { return(total); } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStream_String() {} +}; + + +class ISequentialOutStream_Ostream : public ISequentialOutStream +{ + std::ostream& data; + unsigned int total; +public: + ISequentialOutStream_Ostream(std::ostream& Adata) : data(Adata), total(0) { } + + bool overflow_get() const { return(false); } + unsigned int size_get() const { return(total); } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStream_Ostream() {} +}; + + + +class ISequentialStreamCRC32 +{ +protected: + unsigned int crc32; +public: + ISequentialStreamCRC32() : crc32(0) {} + unsigned int crc32_get() const { return(crc32); } + + virtual ~ISequentialStreamCRC32() {} +}; + + +class ISequentialInStreamCRC32_Array : public ISequentialInStream_Array, public ISequentialStreamCRC32 +{ +public: + ISequentialInStreamCRC32_Array(const char *Adata, unsigned Asize) : ISequentialInStream_Array(Adata, Asize) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStreamCRC32_Array() {} +}; + +class ISequentialInStreamCRC32_String : public ISequentialInStream_String, public ISequentialStreamCRC32 +{ +public: + ISequentialInStreamCRC32_String(std::string& Adata) : ISequentialInStream_String(Adata) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStreamCRC32_String() {} +}; + +class ISequentialInStreamCRC32_Istream : public ISequentialInStream_Istream, public ISequentialStreamCRC32 +{ +public: + ISequentialInStreamCRC32_Istream(std::istream& Adata) : ISequentialInStream_Istream(Adata) { } + + HRESULT Read(void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialInStreamCRC32_Istream() {} +}; + + +class ISequentialOutStreamCRC32_Array : public ISequentialOutStream_Array, public ISequentialStreamCRC32 +{ +public: + ISequentialOutStreamCRC32_Array(char *Adata, unsigned Asize) : ISequentialOutStream_Array(Adata, Asize) { } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStreamCRC32_Array() {} +}; + +class ISequentialOutStreamCRC32_String : public ISequentialOutStream_String, public ISequentialStreamCRC32 +{ +public: + ISequentialOutStreamCRC32_String(std::string& Adata) : ISequentialOutStream_String(Adata) { } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStreamCRC32_String() {} +}; + + +class ISequentialOutStreamCRC32_Ostream : public ISequentialOutStream_Ostream, public ISequentialStreamCRC32 +{ +public: + ISequentialOutStreamCRC32_Ostream(std::ostream& Adata) : ISequentialOutStream_Ostream(Adata) { } + + HRESULT Write(const void *aData, UINT32 aSize, UINT32 *aProcessedSize); + + virtual ~ISequentialOutStreamCRC32_Ostream() {} +}; + +#endif diff --git a/snes9x/jma/inbyte.cpp b/snes9x/jma/inbyte.cpp new file mode 100644 index 0000000..d4bc389 --- /dev/null +++ b/snes9x/jma/inbyte.cpp @@ -0,0 +1,60 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "inbyte.h" + +namespace NStream{ + +CInByte::CInByte(UINT32 aBufferSize): + m_BufferBase(0), + m_BufferSize(aBufferSize) +{ + m_BufferBase = new BYTE[m_BufferSize]; +} + +CInByte::~CInByte() +{ + delete []m_BufferBase; +} + +void CInByte::Init(ISequentialInStream *aStream) +{ + m_Stream = aStream; + m_ProcessedSize = 0; + m_Buffer = m_BufferBase; + m_BufferLimit = m_Buffer; + m_StreamWasExhausted = false; +} + +bool CInByte::ReadBlock() +{ + if (m_StreamWasExhausted) + return false; + m_ProcessedSize += (m_Buffer - m_BufferBase); + UINT32 aNumProcessedBytes; + HRESULT aResult = m_Stream->Read(m_BufferBase, m_BufferSize, &aNumProcessedBytes); + if (aResult != S_OK) + throw aResult; + m_Buffer = m_BufferBase; + m_BufferLimit = m_Buffer + aNumProcessedBytes; + m_StreamWasExhausted = (aNumProcessedBytes == 0); + return (!m_StreamWasExhausted); +} + +} diff --git a/snes9x/jma/inbyte.h b/snes9x/jma/inbyte.h new file mode 100644 index 0000000..53afa17 --- /dev/null +++ b/snes9x/jma/inbyte.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __STREAM_INBYTE_H +#define __STREAM_INBYTE_H + +#include "iiostrm.h" + +namespace NStream { + +class CInByte +{ + UINT64 m_ProcessedSize; + BYTE *m_BufferBase; + UINT32 m_BufferSize; + BYTE *m_Buffer; + BYTE *m_BufferLimit; + ISequentialInStream* m_Stream; + bool m_StreamWasExhausted; + + bool ReadBlock(); + +public: + CInByte(UINT32 aBufferSize = 0x100000); + ~CInByte(); + + void Init(ISequentialInStream *aStream); + + bool ReadByte(BYTE &aByte) + { + if(m_Buffer >= m_BufferLimit) + if(!ReadBlock()) + return false; + aByte = *m_Buffer++; + return true; + } + BYTE ReadByte() + { + if(m_Buffer >= m_BufferLimit) + if(!ReadBlock()) + return 0x0; + return *m_Buffer++; + } + void ReadBytes(void *aData, UINT32 aSize, UINT32 &aProcessedSize) + { + for(aProcessedSize = 0; aProcessedSize < aSize; aProcessedSize++) + if (!ReadByte(((BYTE *)aData)[aProcessedSize])) + return; + } + bool ReadBytes(void *aData, UINT32 aSize) + { + UINT32 aProcessedSize; + ReadBytes(aData, aSize, aProcessedSize); + return (aProcessedSize == aSize); + } + UINT64 GetProcessedSize() const { return m_ProcessedSize + (m_Buffer - m_BufferBase); } +}; + +} + +#endif diff --git a/snes9x/jma/jma.cpp b/snes9x/jma/jma.cpp new file mode 100644 index 0000000..9696be2 --- /dev/null +++ b/snes9x/jma/jma.cpp @@ -0,0 +1,528 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) + +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 +#include "jma.h" +using namespace std; + +#include "portable.h" +#include "7z.h" +#include "crc32.h" + +namespace JMA +{ + const char jma_magic[] = { 'J', 'M', 'A', 0, 'N' }; + const unsigned int jma_header_length = 5; + const unsigned char jma_version = 1; + const unsigned int jma_version_length = 1; + const unsigned int jma_total_header_length = jma_header_length + jma_version_length + UINT_SIZE; + + //Convert DOS/zip/JMA integer time to to time_t + time_t uint_to_time(unsigned short date, unsigned short time) + { + tm formatted_time; + + formatted_time.tm_mday = date & 0x1F; + formatted_time.tm_mon = ((date >> 5) & 0xF) - 1; + formatted_time.tm_year = ((date >> 9) & 0x7f) + 80; + formatted_time.tm_sec = (time & 0x1F) * 2; + formatted_time.tm_min = (time >> 5) & 0x3F; + formatted_time.tm_hour = (time >> 11) & 0x1F; + + return(mktime(&formatted_time)); + } + + + //Retreive the file block, what else? + void jma_open::retrieve_file_block() + { + unsigned char uint_buffer[UINT_SIZE]; + unsigned char ushort_buffer[USHORT_SIZE]; + + //File block size is the last UINT in the file + stream.seekg(-UINT_SIZE,ios::end); + stream.read((char *)uint_buffer, UINT_SIZE); + size_t file_block_size = charp_to_uint(uint_buffer); + + //Currently at the end of the file, so that's the file size + size_t jma_file_size = (size_t) stream.tellg(); + + //The file block can't be larger than the JMA file without it's header. + //This if can probably be improved + if (file_block_size >= jma_file_size-jma_total_header_length) + { + throw(JMA_BAD_FILE); + } + + //Seek to before file block so we can read the file block + stream.seekg(-((int)file_block_size+UINT_SIZE),ios::end); + + //This is needed if the file block is compressed + stringstream decompressed_file_block; + //Pointer to where to read file block from (file or decompressed buffer) + istream *file_block_stream; + + //Setup file info buffer and byte to read with + jma_file_info file_info; + char byte; + + stream.get(byte); + if (!byte) //If file block is compressed + { + //Compressed size isn't counting the byte we just read or the UINT for compressed size + size_t compressed_size = file_block_size - (1+UINT_SIZE); + + //Read decompressed size / true file block size + stream.read((char *)uint_buffer, UINT_SIZE); + file_block_size = charp_to_uint(uint_buffer); + + //Setup access methods for decompression + ISequentialInStream_Istream compressed_data(stream); + ISequentialOutStream_Ostream decompressed_data(decompressed_file_block); + + //Decompress the data + if (!decompress_lzma_7z(compressed_data, compressed_size, decompressed_data, file_block_size)) + { + throw(JMA_DECOMPRESS_FAILED); + } + + //Go to beginning, setup pointer to buffer + decompressed_file_block.seekg(0, ios::beg); + file_block_stream = &decompressed_file_block; + } + else + { + stream.putback(byte); //Putback byte, byte is part of filename, not compressed indicator + file_block_stream = &stream; + } + + + //Minimum file name length is 2 bytes, a char and a null + //Minimum comment length is 1 byte, a null + //There are currently 2 UINTs and 2 USHORTs per file + while (file_block_size >= 2+1+UINT_SIZE*2+USHORT_SIZE*2) //This does allow for a gap, but that's okay + { + //First stored in the file block is the file name null terminated + file_info.name = ""; + + file_block_stream->get(byte); + while (byte) + { + file_info.name += byte; + file_block_stream->get(byte); + } + + //There must be a file name or the file is bad + if (!file_info.name.length()) + { + throw(JMA_BAD_FILE); + } + + //Same trick as above for the comment + file_info.comment = ""; + + file_block_stream->get(byte); + while (byte) + { + file_info.comment += byte; + file_block_stream->get(byte); + } + + //Next is a UINT representing the file's size + file_block_stream->read((char *)uint_buffer, UINT_SIZE); + file_info.size = charp_to_uint(uint_buffer); + + //Followed by CRC32 + file_block_stream->read((char *)uint_buffer, UINT_SIZE); + file_info.crc32 = charp_to_uint(uint_buffer); + + //Special USHORT representation of file's date + file_block_stream->read((char *)ushort_buffer, USHORT_SIZE); + file_info.date = charp_to_ushort(ushort_buffer); + + //Special USHORT representation of file's time + file_block_stream->read((char *)ushort_buffer, USHORT_SIZE); + file_info.time = charp_to_ushort(ushort_buffer); + + file_info.buffer = 0; //Pointing to null till we decompress files + + files.push_back(file_info); //Put file info into our structure + + //Subtract size of the file info we just read + file_block_size -= file_info.name.length()+file_info.comment.length()+2+UINT_SIZE*2+USHORT_SIZE*2; + } + } + + //Constructor for opening JMA files for reading + jma_open::jma_open(const char *compressed_file_name) + { + decompressed_buffer = 0; + compressed_buffer = 0; + + stream.open(compressed_file_name, ios::in | ios::binary); + if (!stream.is_open()) + { + throw(JMA_NO_OPEN); + } + + //Header is "JMA\0N" + unsigned char header[jma_header_length]; + stream.read((char *)header, jma_header_length); + if (memcmp(jma_magic, header, jma_header_length)) + { + throw(JMA_BAD_FILE); + } + + //Not the cleanest code but logical + stream.read((char *)header, 5); + if (*header <= jma_version) + { + chunk_size = charp_to_uint(header+1); //Chunk size is a UINT that follows version # + retrieve_file_block(); + } + else + { + throw(JMA_UNSUPPORTED_VERSION); + } + } + + //Destructor only has to close the stream if neccesary + jma_open::~jma_open() + { + if (stream.is_open()) + { + stream.close(); + } + } + + //Return a vector containing useful info about the files in the JMA + vector jma_open::get_files_info() + { + vector file_info_vector; + jma_public_file_info file_info; + + for (vector::iterator i = files.begin(); i != files.end(); i++) + { + file_info.name = i->name; + file_info.comment = i->comment; + file_info.size = i->size; + file_info.datetime = uint_to_time(i->date, i->time); + file_info.crc32 = i->crc32; + file_info_vector.push_back(file_info); + } + + return(file_info_vector); + } + + //Skip forward a given number of chunks + void jma_open::chunk_seek(unsigned int chunk_num) + { + //Check the stream is open + if (!stream.is_open()) + { + throw(JMA_NO_OPEN); + } + + //Clear possible errors so the seek will work + stream.clear(); + + //Move forward over header + stream.seekg(jma_total_header_length, ios::beg); + + unsigned char int4_buffer[UINT_SIZE]; + + while (chunk_num--) + { + //Read in size of chunk + stream.read((char *)int4_buffer, UINT_SIZE); + + //Skip chunk plus it's CRC32 + stream.seekg(charp_to_uint(int4_buffer)+UINT_SIZE, ios::cur); + } + } + + //Return a vector of pointers to each file in the JMA, the buffer to hold all the files + //must be initilized outside. + vector jma_open::get_all_files(unsigned char *buffer) + { + //If there's no stream we can't read from it, so exit + if (!stream.is_open()) + { + throw(JMA_NO_OPEN); + } + + //Seek to the first chunk + chunk_seek(0); + + //Set the buffer that decompressed data goes to + decompressed_buffer = buffer; + + //If the JMA is not solid + if (chunk_size) + { + unsigned char int4_buffer[UINT_SIZE]; + size_t size = get_total_size(files); + + //For each chunk in the file... + for (size_t remaining_size = size; remaining_size; remaining_size -= chunk_size) + { + //Read the compressed size + stream.read((char *)int4_buffer, UINT_SIZE); + size_t compressed_size = charp_to_uint(int4_buffer); + + compressed_buffer = new unsigned char[compressed_size]; + + //Read all the compressed data in + stream.read((char *)compressed_buffer, compressed_size); + + //Read the expected CRC of compressed data from the file + stream.read((char *)int4_buffer, UINT_SIZE); + + //If it doesn't match, throw error and cleanup memory + if (CRC32lib::CRC32(compressed_buffer, compressed_size) != charp_to_uint(int4_buffer)) + { + delete[] compressed_buffer; + throw(JMA_BAD_FILE); + } + + //Decompress the data, cleanup memory on failure + if (!decompress_lzma_7z(compressed_buffer, compressed_size, + decompressed_buffer+size-remaining_size, + (remaining_size > chunk_size) ? chunk_size : remaining_size)) + { + delete[] compressed_buffer; + throw(JMA_DECOMPRESS_FAILED); + } + delete[] compressed_buffer; + + if (remaining_size <= chunk_size) //If we just decompressed the remainder + { + break; + } + } + } + else //Solidly compressed JMA + { + unsigned char int4_buffer[UINT_SIZE]; + + //Read the size of the compressed data + stream.read((char *)int4_buffer, UINT_SIZE); + size_t compressed_size = charp_to_uint(int4_buffer); + + //Get decompressed size + size_t size = get_total_size(files); + + //Setup access methods for decompression + ISequentialInStream_Istream compressed_data(stream); + ISequentialOutStream_Array decompressed_data(reinterpret_cast(decompressed_buffer), size); + + //Decompress the data + if (!decompress_lzma_7z(compressed_data, compressed_size, decompressed_data, size)) + { + throw(JMA_DECOMPRESS_FAILED); + } + + /* + //Allocate memory of the right size to hold the compressed data in the JMA + try + { + compressed_buffer = new unsigned char[compressed_size]; + } + catch (bad_alloc xa) + { + throw(JMA_NO_MEM_ALLOC); + } + + //Copy the compressed data into memory + stream.read((char *)compressed_buffer, compressed_size); + size_t size = get_total_size(files); + + //Read the CRC of the compressed data + stream.read((char *)int4_buffer, UINT_SIZE); + + //If it doesn't match, complain + if (CRC32lib::CRC32(compressed_buffer, compressed_size) != charp_to_uint(int4_buffer)) + { + delete[] compressed_buffer; + throw(JMA_BAD_FILE); + } + + //Decompress the data + if (!decompress_lzma_7z(compressed_buffer, compressed_size, decompressed_buffer, size)) + { + delete[] compressed_buffer; + throw(JMA_DECOMPRESS_FAILED); + } + delete[] compressed_buffer; + */ + } + + vector file_pointers; + size_t size = 0; + + //For each file, add it's pointer to the vector, size is pointer offset in the buffer + for (vector::iterator i = files.begin(); i != files.end(); i++) + { + i->buffer = decompressed_buffer+size; + file_pointers.push_back(decompressed_buffer+size); + size += i->size; + } + + //Return the vector of pointers + return(file_pointers); + } + + //Extracts the file with a given name found in the archive to the given buffer + void jma_open::extract_file(string& name, unsigned char *buffer) + { + if (!stream.is_open()) + { + throw(JMA_NO_OPEN); + } + + size_t size_to_skip = 0; + size_t our_file_size = 0; + + //Search through the vector of file information + for (vector::iterator i = files.begin(); i != files.end(); i++) + { + if (i->name == name) + { + //Set the variable so we can tell we found it + our_file_size = i->size; + break; + } + + //Keep a running total of size + size_to_skip += i->size; + } + + if (!our_file_size) //File with the specified name was not found in the archive + { + throw(JMA_FILE_NOT_FOUND); + } + + //If the JMA only contains one file, we can skip a lot of overhead + if (files.size() == 1) + { + get_all_files(buffer); + return; + } + + if (chunk_size) //we are using non-solid archive.. + { + unsigned int chunks_to_skip = size_to_skip / chunk_size; + + //skip over requisite number of chunks + chunk_seek(chunks_to_skip); + + //Allocate memory for compressed and decompressed data + unsigned char *comp_buffer = 0, *decomp_buffer = 0; + + //Compressed data size is <= non compressed size + unsigned char *combined_buffer = new unsigned char[chunk_size*2]; + comp_buffer = combined_buffer; + decomp_buffer = combined_buffer+chunk_size; + + size_t first_chunk_offset = size_to_skip % chunk_size; + unsigned char int4_buffer[UINT_SIZE]; + for (size_t i = 0; i < our_file_size;) + { + //Get size + stream.read((char *)int4_buffer, UINT_SIZE); + size_t compressed_size = charp_to_uint(int4_buffer); + + //Read all the compressed data in + stream.read((char *)comp_buffer, compressed_size); + + //Read the CRC of the compressed data + stream.read((char *)int4_buffer, UINT_SIZE); + + //If it doesn't match, complain + if (CRC32lib::CRC32(comp_buffer, compressed_size) != charp_to_uint(int4_buffer)) + { + delete[] comp_buffer; + throw(JMA_BAD_FILE); + } + + //Decompress chunk + if (!decompress_lzma_7z(comp_buffer, compressed_size, decomp_buffer, chunk_size)) + { + delete[] comp_buffer; + throw(JMA_DECOMPRESS_FAILED); + } + + size_t copy_amount = our_file_size-i > chunk_size-first_chunk_offset ? chunk_size-first_chunk_offset : our_file_size-i; + + memcpy(buffer+i, decomp_buffer+first_chunk_offset, copy_amount); + first_chunk_offset = 0; //Set to zero since this is only for the first iteration + i += copy_amount; + } + delete[] comp_buffer; + } + else //Solid JMA + { + unsigned char *decomp_buffer = 0; + decomp_buffer = new unsigned char[get_total_size(files)]; + + get_all_files(decomp_buffer); + + memcpy(buffer, decomp_buffer+size_to_skip, our_file_size); + + delete[] decomp_buffer; + } + } + + bool jma_open::is_solid() + { + return(chunk_size ? false : true); + } + + const char *jma_error_text(jma_errors error) + { + switch (error) + { + case JMA_NO_CREATE: + return("JMA could not be created"); + + case JMA_NO_MEM_ALLOC: + return("Memory for JMA could be allocated"); + + case JMA_NO_OPEN: + return("JMA could not be opened"); + + case JMA_BAD_FILE: + return("Invalid/Corrupt JMA"); + + case JMA_UNSUPPORTED_VERSION: + return("JMA version not supported"); + + case JMA_COMPRESS_FAILED: + return("JMA compression failed"); + + case JMA_DECOMPRESS_FAILED: + return("JMA decompression failed"); + + case JMA_FILE_NOT_FOUND: + return("File not found in JMA"); + } + return("Unknown error"); + } + +} + + diff --git a/snes9x/jma/jma.h b/snes9x/jma/jma.h new file mode 100644 index 0000000..8e6a5f2 --- /dev/null +++ b/snes9x/jma/jma.h @@ -0,0 +1,89 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) + +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. +*/ + +#ifndef JMA_H +#define JMA_H + +#include +#include +#include +#include + +namespace JMA +{ + enum jma_errors { JMA_NO_CREATE, JMA_NO_MEM_ALLOC, JMA_NO_OPEN, JMA_BAD_FILE, + JMA_UNSUPPORTED_VERSION, JMA_COMPRESS_FAILED, JMA_DECOMPRESS_FAILED, + JMA_FILE_NOT_FOUND }; + + struct jma_file_info_base + { + std::string name; + std::string comment; + size_t size; + unsigned int crc32; + }; + + struct jma_public_file_info : jma_file_info_base + { + time_t datetime; + }; + + struct jma_file_info : jma_file_info_base + { + unsigned short date; + unsigned short time; + const unsigned char *buffer; + }; + + template + inline size_t get_total_size(std::vector& files) + { + size_t size = 0; + for (typename std::vector::iterator i = files.begin(); i != files.end(); i++) + { + size += i->size; //We do have a problem if this wraps around + } + + return(size); + } + + class jma_open + { + public: + jma_open(const char *); + ~jma_open(); + + std::vector get_files_info(); + std::vector get_all_files(unsigned char *); + void extract_file(std::string& name, unsigned char *); + bool is_solid(); + + private: + std::ifstream stream; + std::vector files; + size_t chunk_size; + unsigned char *decompressed_buffer; + unsigned char *compressed_buffer; + + void chunk_seek(unsigned int); + void retrieve_file_block(); + }; + + time_t uint_to_time(unsigned short, unsigned short); + const char *jma_error_text(jma_errors); +} +#endif diff --git a/snes9x/jma/lencoder.h b/snes9x/jma/lencoder.h new file mode 100644 index 0000000..33051ee --- /dev/null +++ b/snes9x/jma/lencoder.h @@ -0,0 +1,93 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __LENCODER_H +#define __LENCODER_H + +#include "btreecd.h" + +namespace NLength { + +const UINT32 kNumPosStatesBitsMax = 4; +const int kNumPosStatesMax = (1 << kNumPosStatesBitsMax); + + +const int kNumPosStatesBitsEncodingMax = 4; +const int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); + + +const int kNumMoveBits = 5; + +const int kNumLenBits = 3; +const int kNumLowSymbols = 1 << kNumLenBits; +const int kNumMidBits = 3; +const int kNumMidSymbols = 1 << kNumMidBits; + +const int kNumHighBits = 8; + +const int kNumSymbolsTotal = kNumLowSymbols + kNumMidSymbols + (1 << kNumHighBits); + +const int kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols; + +class CDecoder +{ + CMyBitDecoder m_Choice; + CBitTreeDecoder m_LowCoder[kNumPosStatesMax]; + CMyBitDecoder m_Choice2; + CBitTreeDecoder m_MidCoder[kNumPosStatesMax]; + CBitTreeDecoder m_HighCoder; + UINT32 m_NumPosStates; +public: + void Create(UINT32 aNumPosStates) + { m_NumPosStates = aNumPosStates; } + void Init() + { + m_Choice.Init(); + for (UINT32 aPosState = 0; aPosState < m_NumPosStates; aPosState++) + { + m_LowCoder[aPosState].Init(); + m_MidCoder[aPosState].Init(); + } + m_Choice2.Init(); + m_HighCoder.Init(); + } + UINT32 Decode(CMyRangeDecoder *aRangeDecoder, UINT32 aPosState) + { + if(m_Choice.Decode(aRangeDecoder) == 0) + return m_LowCoder[aPosState].Decode(aRangeDecoder); + else + { + UINT32 aSymbol = kNumLowSymbols; + if(m_Choice2.Decode(aRangeDecoder) == 0) + aSymbol += m_MidCoder[aPosState].Decode(aRangeDecoder); + else + { + aSymbol += kNumMidSymbols; + aSymbol += m_HighCoder.Decode(aRangeDecoder); + } + return aSymbol; + } + } + +}; + +} + + +#endif diff --git a/snes9x/jma/license.txt b/snes9x/jma/license.txt new file mode 100644 index 0000000..e59ec7a --- /dev/null +++ b/snes9x/jma/license.txt @@ -0,0 +1,7 @@ +Some of the code in this directory is under the LGPL v2. + +Other bits of the code is under GPL v2. +The authors of the GPL portions have granted an exception to Snes9x (but not to Snes9x derivitives) +to use their code. + +s9x-jma.h and s9x-jma.cpp are under Snes9x license. diff --git a/snes9x/jma/litcoder.h b/snes9x/jma/litcoder.h new file mode 100644 index 0000000..639d6c5 --- /dev/null +++ b/snes9x/jma/litcoder.h @@ -0,0 +1,122 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __LITERALCODER_H +#define __LITERALCODER_H + +#include "aribitcd.h" +#include "rcdefs.h" + +namespace NLiteral { + +const int kNumMoveBits = 5; + +class CDecoder2 +{ + CMyBitDecoder m_Decoders[3][1 << 8]; +public: + void Init() + { + for (int i = 0; i < 3; i++) + for (int j = 1; j < (1 << 8); j++) + m_Decoders[i][j].Init(); + } + + BYTE DecodeNormal(CMyRangeDecoder *aRangeDecoder) + { + UINT32 aSymbol = 1; + RC_INIT_VAR + do + { + // aSymbol = (aSymbol << 1) | m_Decoders[0][aSymbol].Decode(aRangeDecoder); + RC_GETBIT(kNumMoveBits, m_Decoders[0][aSymbol].m_Probability, aSymbol) + } + while (aSymbol < 0x100); + RC_FLUSH_VAR + return aSymbol; + } + + BYTE DecodeWithMatchByte(CMyRangeDecoder *aRangeDecoder, BYTE aMatchByte) + { + UINT32 aSymbol = 1; + RC_INIT_VAR + do + { + UINT32 aMatchBit = (aMatchByte >> 7) & 1; + aMatchByte <<= 1; + // UINT32 aBit = m_Decoders[1 + aMatchBit][aSymbol].Decode(aRangeDecoder); + // aSymbol = (aSymbol << 1) | aBit; + UINT32 aBit; + RC_GETBIT2(kNumMoveBits, m_Decoders[1 + aMatchBit][aSymbol].m_Probability, aSymbol, + aBit = 0, aBit = 1) + if (aMatchBit != aBit) + { + while (aSymbol < 0x100) + { + // aSymbol = (aSymbol << 1) | m_Decoders[0][aSymbol].Decode(aRangeDecoder); + RC_GETBIT(kNumMoveBits, m_Decoders[0][aSymbol].m_Probability, aSymbol) + } + break; + } + } + while (aSymbol < 0x100); + RC_FLUSH_VAR + return aSymbol; + } +}; + +class CDecoder +{ + CDecoder2 *m_Coders; + UINT32 m_NumPrevBits; + UINT32 m_NumPosBits; + UINT32 m_PosMask; +public: + CDecoder(): m_Coders(0) {} + ~CDecoder() { Free(); } + void Free() + { + delete []m_Coders; + m_Coders = 0; + } + void Create(UINT32 aNumPosBits, UINT32 aNumPrevBits) + { + Free(); + m_NumPosBits = aNumPosBits; + m_PosMask = (1 << aNumPosBits) - 1; + m_NumPrevBits = aNumPrevBits; + UINT32 aNumStates = 1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new CDecoder2[aNumStates]; + } + void Init() + { + UINT32 aNumStates = 1 << (m_NumPrevBits + m_NumPosBits); + for (UINT32 i = 0; i < aNumStates; i++) + m_Coders[i].Init(); + } + UINT32 GetState(UINT32 aPos, BYTE aPrevByte) const + { return ((aPos & m_PosMask) << m_NumPrevBits) + (aPrevByte >> (8 - m_NumPrevBits)); } + BYTE DecodeNormal(CMyRangeDecoder *aRangeDecoder, UINT32 aPos, BYTE aPrevByte) + { return m_Coders[GetState(aPos, aPrevByte)].DecodeNormal(aRangeDecoder); } + BYTE DecodeWithMatchByte(CMyRangeDecoder *aRangeDecoder, UINT32 aPos, BYTE aPrevByte, BYTE aMatchByte) + { return m_Coders[GetState(aPos, aPrevByte)].DecodeWithMatchByte(aRangeDecoder, aMatchByte); } +}; + +} + +#endif diff --git a/snes9x/jma/lzma.cpp b/snes9x/jma/lzma.cpp new file mode 100644 index 0000000..d020ed2 --- /dev/null +++ b/snes9x/jma/lzma.cpp @@ -0,0 +1,41 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "lzma.h" + +namespace NCompress { +namespace NLZMA { + +UINT32 kDistStart[kDistTableSizeMax]; + +static class CConstInit +{ +public: + CConstInit() + { + UINT32 aStartValue = 0; + int i; + for (i = 0; i < kDistTableSizeMax; i++) + { + kDistStart[i] = aStartValue; + aStartValue += (1 << kDistDirectBits[i]); + } + } +} g_ConstInit; + +}} diff --git a/snes9x/jma/lzma.h b/snes9x/jma/lzma.h new file mode 100644 index 0000000..e7c4d5a --- /dev/null +++ b/snes9x/jma/lzma.h @@ -0,0 +1,124 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "lencoder.h" + +#ifndef __LZMA_H +#define __LZMA_H + +namespace NCompress { +namespace NLZMA { + +const UINT32 kNumRepDistances = 4; + +const BYTE kNumStates = 12; + +const BYTE kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +const BYTE kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +const BYTE kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +const BYTE kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +class CState +{ +public: + BYTE m_Index; + void Init() + { m_Index = 0; } + void UpdateChar() + { m_Index = kLiteralNextStates[m_Index]; } + void UpdateMatch() + { m_Index = kMatchNextStates[m_Index]; } + void UpdateRep() + { m_Index = kRepNextStates[m_Index]; } + void UpdateShortRep() + { m_Index = kShortRepNextStates[m_Index]; } +}; + +class CBaseCoder +{ +protected: + CState m_State; + BYTE m_PreviousByte; + bool m_PeviousIsMatch; + UINT32 m_RepDistances[kNumRepDistances]; + void Init() + { + m_State.Init(); + m_PreviousByte = 0; + m_PeviousIsMatch = false; + for(UINT32 i = 0 ; i < kNumRepDistances; i++) + m_RepDistances[i] = 0; + } +}; + +const int kNumPosSlotBits = 6; +const int kDicLogSizeMax = 28; +const int kDistTableSizeMax = kDicLogSizeMax * 2; + +extern UINT32 kDistStart[kDistTableSizeMax]; +const BYTE kDistDirectBits[kDistTableSizeMax] = +{ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, + 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26 +}; + +const UINT32 kNumLenToPosStates = 4; +inline UINT32 GetLenToPosState(UINT32 aLen) +{ + aLen -= 2; + if (aLen < kNumLenToPosStates) + return aLen; + return kNumLenToPosStates - 1; +} + +const int kMatchMinLen = 2; + +const int kMatchMaxLen = kMatchMinLen + NLength::kNumSymbolsTotal - 1; + +const int kNumAlignBits = 4; +const int kAlignTableSize = 1 << kNumAlignBits; +const UINT32 kAlignMask = (kAlignTableSize - 1); + +const int kStartPosModelIndex = 4; +const int kEndPosModelIndex = 14; +const int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; + +const int kNumFullDistances = 1 << (kEndPosModelIndex / 2); + + +const int kMainChoiceLiteralIndex = 0; +const int kMainChoiceMatchIndex = 1; + +const int kMatchChoiceDistanceIndex= 0; +const int kMatchChoiceRepetitionIndex = 1; + +const int kNumMoveBitsForMainChoice = 5; +const int kNumMoveBitsForPosCoders = 5; + +const int kNumMoveBitsForAlignCoders = 5; + +const int kNumMoveBitsForPosSlotCoder = 5; + +const int kNumLitPosStatesBitsEncodingMax = 4; +const int kNumLitContextBitsMax = 8; + +}} + +#endif diff --git a/snes9x/jma/lzmadec.cpp b/snes9x/jma/lzmadec.cpp new file mode 100644 index 0000000..d76352a --- /dev/null +++ b/snes9x/jma/lzmadec.cpp @@ -0,0 +1,298 @@ +/* +Copyright (C) 2005-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "portable.h" +#include "lzmadec.h" + +#define RETURN_E_OUTOFMEMORY_IF_FALSE(x) { if (!(x)) return E_OUTOFMEMORY; } + +namespace NCompress { +namespace NLZMA { + +HRESULT CDecoder::SetDictionarySize(UINT32 aDictionarySize) +{ + if (aDictionarySize > (1 << kDicLogSizeMax)) + return E_INVALIDARG; + + UINT32 aWindowReservSize = MyMax(aDictionarySize, UINT32(1 << 21)); + + if (m_DictionarySize != aDictionarySize) + { + m_OutWindowStream.Create(aDictionarySize, kMatchMaxLen, aWindowReservSize); + m_DictionarySize = aDictionarySize; + } + return S_OK; +} + +HRESULT CDecoder::SetLiteralProperties( + UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits) +{ + if (aLiteralPosStateBits > 8) + return E_INVALIDARG; + if (aLiteralContextBits > 8) + return E_INVALIDARG; + m_LiteralDecoder.Create(aLiteralPosStateBits, aLiteralContextBits); + return S_OK; +} + +HRESULT CDecoder::SetPosBitsProperties(UINT32 aNumPosStateBits) +{ + if (aNumPosStateBits > NLength::kNumPosStatesBitsMax) + return E_INVALIDARG; + UINT32 aNumPosStates = 1 << aNumPosStateBits; + m_LenDecoder.Create(aNumPosStates); + m_RepMatchLenDecoder.Create(aNumPosStates); + m_PosStateMask = aNumPosStates - 1; + return S_OK; +} + +CDecoder::CDecoder(): + m_DictionarySize((UINT32)-1) +{ + Create(); +} + +HRESULT CDecoder::Create() +{ + for(int i = 0; i < kNumPosModels; i++) + { + RETURN_E_OUTOFMEMORY_IF_FALSE( + m_PosDecoders[i].Create(kDistDirectBits[kStartPosModelIndex + i])); + } + return S_OK; +} + + +HRESULT CDecoder::Init(ISequentialInStream *anInStream, + ISequentialOutStream *anOutStream) +{ + m_RangeDecoder.Init(anInStream); + + m_OutWindowStream.Init(anOutStream); + + int i; + for(i = 0; i < kNumStates; i++) + { + for (UINT32 j = 0; j <= m_PosStateMask; j++) + { + m_MainChoiceDecoders[i][j].Init(); + m_MatchRepShortChoiceDecoders[i][j].Init(); + } + m_MatchChoiceDecoders[i].Init(); + m_MatchRepChoiceDecoders[i].Init(); + m_MatchRep1ChoiceDecoders[i].Init(); + m_MatchRep2ChoiceDecoders[i].Init(); + } + + m_LiteralDecoder.Init(); + + // m_RepMatchLenDecoder.Init(); + + for (i = 0; (UINT32) i < kNumLenToPosStates; i++) + m_PosSlotDecoder[i].Init(); + + for(i = 0; i < kNumPosModels; i++) + m_PosDecoders[i].Init(); + + m_LenDecoder.Init(); + m_RepMatchLenDecoder.Init(); + + m_PosAlignDecoder.Init(); + return S_OK; + +} + +HRESULT CDecoder::CodeReal(ISequentialInStream *anInStream, + ISequentialOutStream *anOutStream, + const UINT64 *anInSize, const UINT64 *anOutSize) +{ + if (anOutSize == NULL) + return E_INVALIDARG; + + Init(anInStream, anOutStream); + + CState aState; + aState.Init(); + bool aPeviousIsMatch = false; + BYTE aPreviousByte = 0; + UINT32 aRepDistances[kNumRepDistances]; + for(UINT32 i = 0 ; i < kNumRepDistances; i++) + aRepDistances[i] = 0; + + UINT64 aNowPos64 = 0; + UINT64 aSize = *anOutSize; + while(aNowPos64 < aSize) + { + UINT64 aNext = MyMin(aNowPos64 + (1 << 18), aSize); + while(aNowPos64 < aNext) + { + UINT32 aPosState = UINT32(aNowPos64) & m_PosStateMask; + if (m_MainChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == (UINT32) kMainChoiceLiteralIndex) + { + // aCounts[0]++; + aState.UpdateChar(); + if(aPeviousIsMatch) + { + BYTE aMatchByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1); + aPreviousByte = m_LiteralDecoder.DecodeWithMatchByte(&m_RangeDecoder, + UINT32(aNowPos64), aPreviousByte, aMatchByte); + aPeviousIsMatch = false; + } + else + aPreviousByte = m_LiteralDecoder.DecodeNormal(&m_RangeDecoder, + UINT32(aNowPos64), aPreviousByte); + m_OutWindowStream.PutOneByte(aPreviousByte); + aNowPos64++; + } + else + { + aPeviousIsMatch = true; + UINT32 aDistance, aLen; + if(m_MatchChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == + (UINT32) kMatchChoiceRepetitionIndex) + { + if(m_MatchRepChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0) + { + if(m_MatchRepShortChoiceDecoders[aState.m_Index][aPosState].Decode(&m_RangeDecoder) == 0) + { + aState.UpdateShortRep(); + aPreviousByte = m_OutWindowStream.GetOneByte(0 - aRepDistances[0] - 1); + m_OutWindowStream.PutOneByte(aPreviousByte); + aNowPos64++; + // aCounts[3 + 4]++; + continue; + } + // aCounts[3 + 0]++; + aDistance = aRepDistances[0]; + } + else + { + if(m_MatchRep1ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0) + { + aDistance = aRepDistances[1]; + aRepDistances[1] = aRepDistances[0]; + // aCounts[3 + 1]++; + } + else + { + if (m_MatchRep2ChoiceDecoders[aState.m_Index].Decode(&m_RangeDecoder) == 0) + { + // aCounts[3 + 2]++; + aDistance = aRepDistances[2]; + } + else + { + // aCounts[3 + 3]++; + aDistance = aRepDistances[3]; + aRepDistances[3] = aRepDistances[2]; + } + aRepDistances[2] = aRepDistances[1]; + aRepDistances[1] = aRepDistances[0]; + } + aRepDistances[0] = aDistance; + } + aLen = m_RepMatchLenDecoder.Decode(&m_RangeDecoder, aPosState) + kMatchMinLen; + // aCounts[aLen]++; + aState.UpdateRep(); + } + else + { + aLen = kMatchMinLen + m_LenDecoder.Decode(&m_RangeDecoder, aPosState); + aState.UpdateMatch(); + UINT32 aPosSlot = m_PosSlotDecoder[GetLenToPosState(aLen)].Decode(&m_RangeDecoder); + // aCounts[aPosSlot]++; + if (aPosSlot >= (UINT32) kStartPosModelIndex) + { + aDistance = kDistStart[aPosSlot]; + if (aPosSlot < (UINT32) kEndPosModelIndex) + aDistance += m_PosDecoders[aPosSlot - kStartPosModelIndex].Decode(&m_RangeDecoder); + else + { + aDistance += (m_RangeDecoder.DecodeDirectBits(kDistDirectBits[aPosSlot] - + kNumAlignBits) << kNumAlignBits); + aDistance += m_PosAlignDecoder.Decode(&m_RangeDecoder); + } + } + else + aDistance = aPosSlot; + + + aRepDistances[3] = aRepDistances[2]; + aRepDistances[2] = aRepDistances[1]; + aRepDistances[1] = aRepDistances[0]; + + aRepDistances[0] = aDistance; + // UpdateStat(aLen, aPosSlot); + } + if (aDistance >= aNowPos64) + throw E_INVALIDDATA; + m_OutWindowStream.CopyBackBlock(aDistance, aLen); + aNowPos64 += aLen; + aPreviousByte = m_OutWindowStream.GetOneByte(0 - 1); + } + } + } + return Flush(); +} + +HRESULT CDecoder::Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize) +{ + try { + return CodeReal(anInStream, anOutStream, anInSize, anOutSize); + } catch (HRESULT& e) { + return e; + } catch (...) { + return E_FAIL; + } +} + +HRESULT CDecoder::ReadCoderProperties(ISequentialInStream *anInStream) +{ + UINT32 aNumPosStateBits; + UINT32 aLiteralPosStateBits; + UINT32 aLiteralContextBits; + UINT32 aDictionarySize; + + UINT32 aProcessesedSize; + + BYTE aByte; + RETURN_IF_NOT_S_OK(anInStream->Read(&aByte, sizeof(aByte), &aProcessesedSize)); + if (aProcessesedSize != sizeof(aByte)) + return E_INVALIDARG; + + aLiteralContextBits = aByte % 9; + BYTE aRemainder = aByte / 9; + aLiteralPosStateBits = aRemainder % 5; + aNumPosStateBits = aRemainder / 5; + + UINT8 uint_buffer[UINT_SIZE]; + RETURN_IF_NOT_S_OK(anInStream->Read(uint_buffer, sizeof(aDictionarySize), &aProcessesedSize)); + aDictionarySize = charp_to_uint(uint_buffer); + + if (aProcessesedSize != sizeof(aDictionarySize)) + return E_INVALIDARG; + + RETURN_IF_NOT_S_OK(SetDictionarySize(aDictionarySize)); + RETURN_IF_NOT_S_OK(SetLiteralProperties(aLiteralPosStateBits, aLiteralContextBits)); + RETURN_IF_NOT_S_OK(SetPosBitsProperties(aNumPosStateBits)); + + return S_OK; +} + +}} diff --git a/snes9x/jma/lzmadec.h b/snes9x/jma/lzmadec.h new file mode 100644 index 0000000..bb91912 --- /dev/null +++ b/snes9x/jma/lzmadec.h @@ -0,0 +1,82 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __LZARITHMETIC_DECODER_H +#define __LZARITHMETIC_DECODER_H + +#include "winout.h" +#include "lzma.h" +#include "lencoder.h" +#include "litcoder.h" + +namespace NCompress { +namespace NLZMA { + +typedef CMyBitDecoder CMyBitDecoder2; + +class CDecoder +{ + NStream::NWindow::COut m_OutWindowStream; + CMyRangeDecoder m_RangeDecoder; + + CMyBitDecoder2 m_MainChoiceDecoders[kNumStates][NLength::kNumPosStatesMax]; + CMyBitDecoder2 m_MatchChoiceDecoders[kNumStates]; + CMyBitDecoder2 m_MatchRepChoiceDecoders[kNumStates]; + CMyBitDecoder2 m_MatchRep1ChoiceDecoders[kNumStates]; + CMyBitDecoder2 m_MatchRep2ChoiceDecoders[kNumStates]; + CMyBitDecoder2 m_MatchRepShortChoiceDecoders[kNumStates][NLength::kNumPosStatesMax]; + + CBitTreeDecoder m_PosSlotDecoder[kNumLenToPosStates]; + + CReverseBitTreeDecoder2 m_PosDecoders[kNumPosModels]; + CReverseBitTreeDecoder m_PosAlignDecoder; + // CBitTreeDecoder2 m_PosDecoders[kNumPosModels]; + // CBitTreeDecoder m_PosAlignDecoder; + + NLength::CDecoder m_LenDecoder; + NLength::CDecoder m_RepMatchLenDecoder; + + NLiteral::CDecoder m_LiteralDecoder; + + UINT32 m_DictionarySize; + + UINT32 m_PosStateMask; + + HRESULT Create(); + + HRESULT Init(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream); + + HRESULT Flush() { return m_OutWindowStream.Flush(); } + + HRESULT CodeReal(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize); + +public: + + CDecoder(); + + HRESULT Code(ISequentialInStream *anInStream, ISequentialOutStream *anOutStream, const UINT64 *anInSize, const UINT64 *anOutSize); + HRESULT ReadCoderProperties(ISequentialInStream *anInStream); + + HRESULT SetDictionarySize(UINT32 aDictionarySize); + HRESULT SetLiteralProperties(UINT32 aLiteralPosStateBits, UINT32 aLiteralContextBits); + HRESULT SetPosBitsProperties(UINT32 aNumPosStateBits); +}; + +}} + +#endif diff --git a/snes9x/jma/portable.h b/snes9x/jma/portable.h new file mode 100644 index 0000000..0f70854 --- /dev/null +++ b/snes9x/jma/portable.h @@ -0,0 +1,103 @@ +/* +Copyright (C) 2004-2006 NSRT Team ( http://nsrt.edgeemu.com ) +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) + +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. +*/ + +#ifndef __PORTABLE_H +#define __PORTABLE_H + +#include +#ifdef __GNUC__ +#include + +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; +typedef uintptr_t UINT_PTR; + +#else + +typedef signed char INT8; +typedef unsigned char UINT8; +typedef short INT16; +typedef unsigned short UINT16; +typedef int INT32; +typedef unsigned int UINT32; +#ifdef _MSC_VER +typedef __int64 INT64; +typedef unsigned __int64 UINT64; +#else +typedef long long INT64; +typedef unsigned long long UINT64; +#endif +typedef unsigned UINT_PTR; + +#endif + +typedef UINT8 BYTE; +typedef UINT16 WORD; +typedef UINT32 DWORD; + +typedef int BOOL; +#define FALSE 0 +#define TRUE 1 + +#define HRESULT int +#define S_OK 0 +#define E_INVALIDARG -1 +#define E_OUTOFMEMORY -2 +#define E_FAIL -3 +#define E_INTERNAL_ERROR -4 +#define E_INVALIDDATA -5 + +template inline T MyMin(T a, T b) { + return a < b ? a : b; +} + +template inline T MyMax(T a, T b) { + return a > b ? a : b; +} + +#define RETURN_IF_NOT_S_OK(x) { HRESULT __aResult_ = (x); if(__aResult_ != S_OK) return __aResult_; } + + +#define UINT_SIZE ((int)sizeof(unsigned int)) +#define USHORT_SIZE ((int)sizeof(unsigned short)) + +//Convert an array of 4 bytes back into an integer +inline UINT32 charp_to_uint(const UINT8 buffer[UINT_SIZE]) +{ + UINT32 num = (UINT32)buffer[3]; + num |= ((UINT32)buffer[2]) << 8; + num |= ((UINT32)buffer[1]) << 16; + num |= ((UINT32)buffer[0]) << 24; + return(num); +} + +//Convert an array of 2 bytes back into a short integer +inline UINT16 charp_to_ushort(const UINT8 buffer[USHORT_SIZE]) +{ + UINT16 num = (UINT16)buffer[1]; + num |= ((UINT16)buffer[0]) << 8; + return(num); +} + +#endif diff --git a/snes9x/jma/rcdefs.h b/snes9x/jma/rcdefs.h new file mode 100644 index 0000000..6106b57 --- /dev/null +++ b/snes9x/jma/rcdefs.h @@ -0,0 +1,60 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __RCDEFS_H +#define __RCDEFS_H + +#include "aribitcd.h" +#include "ariconst.h" + +#define RC_INIT_VAR \ + UINT32 aRange = aRangeDecoder->m_Range; \ + UINT32 aCode = aRangeDecoder->m_Code; + +#define RC_FLUSH_VAR \ + aRangeDecoder->m_Range = aRange; \ + aRangeDecoder->m_Code = aCode; + +#define RC_NORMALIZE \ + if (aRange < NCompression::NArithmetic::kTopValue) \ + { \ + aCode = (aCode << 8) | aRangeDecoder->m_Stream.ReadByte(); \ + aRange <<= 8; } + +#define RC_GETBIT2(aNumMoveBits, aProb, aModelIndex, Action0, Action1) \ + {UINT32 aNewBound = (aRange >> NCompression::NArithmetic::kNumBitModelTotalBits) * aProb; \ + if (aCode < aNewBound) \ + { \ + Action0; \ + aRange = aNewBound; \ + aProb += (NCompression::NArithmetic::kBitModelTotal - aProb) >> aNumMoveBits; \ + aModelIndex <<= 1; \ + } \ + else \ + { \ + Action1; \ + aRange -= aNewBound; \ + aCode -= aNewBound; \ + aProb -= (aProb) >> aNumMoveBits; \ + aModelIndex = (aModelIndex << 1) + 1; \ + }} \ + RC_NORMALIZE + +#define RC_GETBIT(aNumMoveBits, aProb, aModelIndex) RC_GETBIT2(aNumMoveBits, aProb, aModelIndex, ; , ;) + +#endif diff --git a/snes9x/jma/rngcoder.h b/snes9x/jma/rngcoder.h new file mode 100644 index 0000000..711c2de --- /dev/null +++ b/snes9x/jma/rngcoder.h @@ -0,0 +1,143 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __COMPRESSION_RANGECODER_H +#define __COMPRESSION_RANGECODER_H + +#include "inbyte.h" + +namespace NCompression { +namespace NArithmetic { + +const UINT32 kNumTopBits = 24; +const UINT32 kTopValue = (1 << kNumTopBits); + +class CRangeDecoder +{ +public: + NStream::CInByte m_Stream; + UINT32 m_Range; + UINT32 m_Code; + UINT32 m_Word; + void Normalize() + { + while (m_Range < kTopValue) + { + m_Code = (m_Code << 8) | m_Stream.ReadByte(); + m_Range <<= 8; + } + } + + void Init(ISequentialInStream *aStream) + { + m_Stream.Init(aStream); + m_Code = 0; + m_Range = UINT32(-1); + for(int i = 0; i < 5; i++) + m_Code = (m_Code << 8) | m_Stream.ReadByte(); + } + + UINT32 GetThreshold(UINT32 aTotal) + { + return (m_Code) / ( m_Range /= aTotal); + } + + void Decode(UINT32 aStart, UINT32 aSize, UINT32 aTotal) + { + m_Code -= aStart * m_Range; + m_Range *= aSize; + Normalize(); + } + + /* + UINT32 DecodeDirectBitsDiv(UINT32 aNumTotalBits) + { + m_Range >>= aNumTotalBits; + UINT32 aThreshold = m_Code / m_Range; + m_Code -= aThreshold * m_Range; + + Normalize(); + return aThreshold; + } + + UINT32 DecodeDirectBitsDiv2(UINT32 aNumTotalBits) + { + if (aNumTotalBits <= kNumBottomBits) + return DecodeDirectBitsDiv(aNumTotalBits); + UINT32 aResult = DecodeDirectBitsDiv(aNumTotalBits - kNumBottomBits) << kNumBottomBits; + return (aResult | DecodeDirectBitsDiv(kNumBottomBits)); + } + */ + + UINT32 DecodeDirectBits(UINT32 aNumTotalBits) + { + UINT32 aRange = m_Range; + UINT32 aCode = m_Code; + UINT32 aResult = 0; + for (UINT32 i = aNumTotalBits; i > 0; i--) + { + aRange >>= 1; + /* + aResult <<= 1; + if (aCode >= aRange) + { + aCode -= aRange; + aResult |= 1; + } + */ + UINT32 t = (aCode - aRange) >> 31; + aCode -= aRange & (t - 1); + // aRange = aRangeTmp + ((aRange & 1) & (1 - t)); + aResult = (aResult << 1) | (1 - t); + + if (aRange < kTopValue) + { + aCode = (aCode << 8) | m_Stream.ReadByte(); + aRange <<= 8; + } + } + m_Range = aRange; + m_Code = aCode; + return aResult; + } + + UINT32 DecodeBit(UINT32 aSize0, UINT32 aNumTotalBits) + { + UINT32 aNewBound = (m_Range >> aNumTotalBits) * aSize0; + UINT32 aSymbol; + if (m_Code < aNewBound) + { + aSymbol = 0; + m_Range = aNewBound; + } + else + { + aSymbol = 1; + m_Code -= aNewBound; + m_Range -= aNewBound; + } + Normalize(); + return aSymbol; + } + + UINT64 GetProcessedSize() {return m_Stream.GetProcessedSize(); } +}; + +}} + +#endif diff --git a/snes9x/jma/s9x-jma.cpp b/snes9x/jma/s9x-jma.cpp new file mode 100644 index 0000000..8db06ed --- /dev/null +++ b/snes9x/jma/s9x-jma.cpp @@ -0,0 +1,53 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +// JMA compressed file support +// (c) Copyright 2004-2006 NSRT Team (http://nsrt.edgeemu.com) + + +#include "snes9x.h" +#include "memmap.h" + +#include +using namespace std; + +#include "s9x-jma.h" +#include "jma.h" + +size_t load_jma_file(const char *filename, unsigned char *buffer) +{ + try + { + JMA::jma_open JMAFile(filename); + vector file_info = JMAFile.get_files_info(); + + string our_file_name; + size_t our_file_size = 0; + + for (vector::iterator i = file_info.begin(); i != file_info.end(); i++) + { + //Check for valid ROM based on size + if ((i->size <= CMemory::MAX_ROM_SIZE+512) && (i->size > our_file_size)) + { + our_file_name = i->name; + our_file_size = i->size; + } + } + + if (!our_file_size) + { + return(0); + } + + JMAFile.extract_file(our_file_name, buffer); + + return(our_file_size); + } + catch (JMA::jma_errors jma_error) + { + return(0); + } +} diff --git a/snes9x/jma/s9x-jma.h b/snes9x/jma/s9x-jma.h new file mode 100644 index 0000000..219bc6d --- /dev/null +++ b/snes9x/jma/s9x-jma.h @@ -0,0 +1,17 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +// JMA compressed file support +// (c) Copyright 2004-2006 NSRT Team (http://nsrt.edgeemu.com) + + +#ifdef __cplusplus +extern "C" { +#endif +size_t load_jma_file(const char *filename, unsigned char *buffer); +#ifdef __cplusplus +} +#endif diff --git a/snes9x/jma/winout.cpp b/snes9x/jma/winout.cpp new file mode 100644 index 0000000..1f33885 --- /dev/null +++ b/snes9x/jma/winout.cpp @@ -0,0 +1,89 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "winout.h" + +namespace NStream { +namespace NWindow { + +void COut::Create(UINT32 aKeepSizeBefore, UINT32 aKeepSizeAfter, UINT32 aKeepSizeReserv) +{ + m_Pos = 0; + m_PosLimit = aKeepSizeReserv + aKeepSizeBefore; + m_KeepSizeBefore = aKeepSizeBefore; + m_KeepSizeAfter = aKeepSizeAfter; + m_KeepSizeReserv = aKeepSizeReserv; + m_StreamPos = 0; + m_MoveFrom = m_KeepSizeReserv; + m_WindowSize = aKeepSizeBefore; + UINT32 aBlockSize = m_KeepSizeBefore + m_KeepSizeAfter + m_KeepSizeReserv; + delete []m_Buffer; + m_Buffer = new BYTE[aBlockSize]; +} + +COut::~COut() +{ + delete []m_Buffer; +} + +void COut::SetWindowSize(UINT32 aWindowSize) +{ + m_WindowSize = aWindowSize; + m_MoveFrom = m_KeepSizeReserv + m_KeepSizeBefore - aWindowSize; +} + +void COut::Init(ISequentialOutStream *aStream, bool aSolid) +{ + m_Stream = aStream; + + if(aSolid) + m_StreamPos = m_Pos; + else + { + m_Pos = 0; + m_PosLimit = m_KeepSizeReserv + m_KeepSizeBefore; + m_StreamPos = 0; + } +} + +HRESULT COut::Flush() +{ + UINT32 aSize = m_Pos - m_StreamPos; + if(aSize == 0) + return S_OK; + UINT32 aProcessedSize; + HRESULT aResult = m_Stream->Write(m_Buffer + m_StreamPos, aSize, &aProcessedSize); + if (aResult != S_OK) + return aResult; + if (aSize != aProcessedSize) + return E_FAIL; + m_StreamPos = m_Pos; + return S_OK; +} + +void COut::MoveBlockBackward() +{ + HRESULT aResult = Flush(); + if (aResult != S_OK) + throw aResult; + memmove(m_Buffer, m_Buffer + m_MoveFrom, m_WindowSize + m_KeepSizeAfter); + m_Pos -= m_MoveFrom; + m_StreamPos -= m_MoveFrom; +} + +}} diff --git a/snes9x/jma/winout.h b/snes9x/jma/winout.h new file mode 100644 index 0000000..0969b30 --- /dev/null +++ b/snes9x/jma/winout.h @@ -0,0 +1,90 @@ +/* +Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net ) +Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org ) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 2.1 as published by the Free Software Foundation. + +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __STREAM_WINDOWOUT_H +#define __STREAM_WINDOWOUT_H + +#include "iiostrm.h" + +namespace NStream { +namespace NWindow { + +// m_KeepSizeBefore: how mach BYTEs must be in buffer before m_Pos; +// m_KeepSizeAfter: how mach BYTEs must be in buffer after m_Pos; +// m_KeepSizeReserv: how mach BYTEs must be in buffer for Moving Reserv; +// must be >= aKeepSizeAfter; // test it + +class COut +{ + BYTE *m_Buffer; + UINT32 m_Pos; + UINT32 m_PosLimit; + UINT32 m_KeepSizeBefore; + UINT32 m_KeepSizeAfter; + UINT32 m_KeepSizeReserv; + UINT32 m_StreamPos; + + UINT32 m_WindowSize; + UINT32 m_MoveFrom; + + ISequentialOutStream *m_Stream; + + virtual void MoveBlockBackward(); +public: + COut(): m_Buffer(0), m_Stream(0) {} + virtual ~COut(); + void Create(UINT32 aKeepSizeBefore, + UINT32 aKeepSizeAfter, UINT32 aKeepSizeReserv = (1<<17)); + void SetWindowSize(UINT32 aWindowSize); + + void Init(ISequentialOutStream *aStream, bool aSolid = false); + HRESULT Flush(); + + UINT32 GetCurPos() const { return m_Pos; } + const BYTE *GetPointerToCurrentPos() const { return m_Buffer + m_Pos;}; + + void CopyBackBlock(UINT32 aDistance, UINT32 aLen) + { + if (m_Pos >= m_PosLimit) + MoveBlockBackward(); + BYTE *p = m_Buffer + m_Pos; + aDistance++; + BYTE *p2 = p - aDistance; + for(UINT32 i = 0; i < aLen; i++) + p[i] = p2[i]; + m_Pos += aLen; + } + + void PutOneByte(BYTE aByte) + { + if (m_Pos >= m_PosLimit) + MoveBlockBackward(); + m_Buffer[m_Pos++] = aByte; + } + + BYTE GetOneByte(UINT32 anIndex) const + { + return m_Buffer[m_Pos + anIndex]; + } + + BYTE *GetBuffer() const { return m_Buffer; } +}; + +}} + +#endif diff --git a/snes9x/language.h b/snes9x/language.h new file mode 100644 index 0000000..c218b3a --- /dev/null +++ b/snes9x/language.h @@ -0,0 +1,31 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 "Incompatible 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 diff --git a/snes9x/loadzip.cpp b/snes9x/loadzip.cpp new file mode 100644 index 0000000..7082bb0 --- /dev/null +++ b/snes9x/loadzip.cpp @@ -0,0 +1,162 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifdef UNZIP_SUPPORT + +#include +#include +#ifdef SYSTEM_ZIP +#include +#else +#include "unzip/unzip.h" +#endif +#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, or a file named program.rom + 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; + } + + if (strncasecmp(name, "program.rom", 11) == 0) + { + strcpy(filename, name); + filesize = info.uncompressed_size; + break; + } + + port = unzGoToNextFile(file); + } + + int len = strlen(zipname); + if (!(port == UNZ_END_OF_LIST_OF_FILE || port == UNZ_OK) || filesize == 0 || + (len > 5 && strcasecmp(zipname + len - 5, ".msu1") == 0 && strcasecmp(filename, "program.rom") != 0)) + { + if (unzClose(file) != UNZ_OK) + assert(FALSE); + 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, 0); + 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 != (int) 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, 0) != 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 diff --git a/snes9x/logger.cpp b/snes9x/logger.cpp new file mode 100644 index 0000000..5db39a6 --- /dev/null +++ b/snes9x/logger.cpp @@ -0,0 +1,98 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + + for (int i = 0; i < height; i++) + { + if (!fwrite(data + i * bytes_per_line, depth, width, video)) + printf ("Error writing video data.\n"); + } + fflush(video); + fflush(audio); + + if (Settings.DumpStreamsMaxFrames > 0 && framecounter >= Settings.DumpStreamsMaxFrames) + { + printf("Logging ended.\n"); + S9xCloseLogger(); + } + + } +} + +void S9xAudioLogger (void *samples, int length) +{ + if (audio) + { + if (!fwrite(samples, 1, length, audio)) + printf ("Error writing audio data.\n"); + } +} diff --git a/snes9x/logger.h b/snes9x/logger.h new file mode 100644 index 0000000..2a37dc2 --- /dev/null +++ b/snes9x/logger.h @@ -0,0 +1,15 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _LOGGER_H_ +#define _LOGGER_H_ + +void S9xResetLogger(void); +void S9xCloseLogger(void); +void S9xVideoLogger(void *, int, int, int, int); +void S9xAudioLogger(void *, int); + +#endif diff --git a/snes9x/memmap.cpp b/snes9x/memmap.cpp new file mode 100644 index 0000000..508f458 --- /dev/null +++ b/snes9x/memmap.cpp @@ -0,0 +1,4568 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include +#include +#include + +#ifdef UNZIP_SUPPORT +# ifdef SYSTEM_ZIP +# include +# else +# include "unzip/unzip.h" +# endif +#endif + +#ifdef JMA_SUPPORT +#include "jma/s9x-jma.h" +#endif + +#include +#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" +#include "sha256.h" + +#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_BSCart_BIOS (const uint8 *, uint32); +static bool8 is_BSCartSA1_BIOS(const uint8 *, uint32); +static bool8 is_GNEXT_Add_On (const uint8 *, uint32); +static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff); +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, bool allowExact = FALSE); +#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(0x80000); + 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, 0x80000); + 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_BSCart_BIOS(const uint8 *data, uint32 size) +{ + if ((data[0x7FB2] == 0x5A) && (data[0x7FB5] != 0x20) && (data[0x7FDA] == 0x33)) + { + Memory.LoROM = TRUE; + Memory.HiROM = FALSE; + + return (TRUE); + } + else if ((data[0xFFB2] == 0x5A) && (data[0xFFB5] != 0x20) && (data[0xFFDA] == 0x33)) + { + Memory.LoROM = FALSE; + Memory.HiROM = TRUE; + + return (TRUE); + } + else + return (FALSE); +} + +static bool8 is_BSCartSA1_BIOS (const uint8 *data, uint32 size) +{ + //Same basic check as BSCart + if (!is_BSCart_BIOS(data, size)) + return (FALSE); + + //Checks if the game is Itoi's Bass Fishing No. 1 (ZBPJ) or SD Gundam G-NEXT (ZX3J) + if (strncmp((char *)(data + 0x7fb2), "ZBPJ", 4) == 0 || strncmp((char *)(data + 0x7fb2), "ZX3J", 4) == 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; + + // Check for extended HiROM expansion used in Mother 2 Deluxe et al. + // Looks for size byte 13 (8MB) and an actual ROM size greater than 4MB + if (buf[0xd7] == 13 && CalculatedSize > 1024 * 1024 * 4) + score += 5; + + 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); +} + +int CMemory::First512BytesCountZeroes() const +{ + const uint8 *buf = ROM; + int zeroCount = 0; + for (int i = 0; i < 512; i++) + { + if (buf[i] == 0) + { + zeroCount++; + } + } + return zeroCount; +} + +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 || strcasecmp(ext, "msu1") == 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); + + 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; + int score_headered; + int score_nonheadered; + + hi_score = ScoreHiROM(FALSE); + lo_score = ScoreLoROM(FALSE); + score_nonheadered = max(hi_score, lo_score); + score_headered = max(ScoreHiROM(TRUE), ScoreLoROM(TRUE)); + + bool size_is_likely_headered = ((ROMfillSize - 512) & 0xFFFF) == 0; + if (size_is_likely_headered) { score_headered += 2; } else { score_headered -= 2; } + if (First512BytesCountZeroes() >= 0x1E0) { score_headered += 2; } else { score_headered -= 2; } + + bool headered_score_highest = score_headered > score_nonheadered; + + if (HeaderCount == 0 && !Settings.ForceNoHeader && headered_score_highest) + { + 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 + 0x1fff) / 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; + + InitROM(); + + S9xReset(); + + S9xDeleteCheats(); + S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); + + 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); + + 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); + + 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_BSCartSA1_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) + Multi.cartType = 5; + else + if (is_BSCart_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) + Multi.cartType = 3; + } + 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.cartSizeA + Multi.cartSizeB); + else if(Multi.cartOffsetB) // 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: + case 5: + r = LoadBSCart(); + 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; + + InitROM(); + + S9xReset(); + + S9xDeleteCheats(); + S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); + + 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::LoadBSCart () +{ + Multi.sramA = SRAM; + Multi.sramB = NULL; + + if (LoROM) + Multi.sramSizeA = ROM[0x7fd8]; + else + Multi.sramSizeA = ROM[0xffd8]; + + Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; + Multi.sramSizeB = 0; + Multi.sramMaskB = 0; + + CalculatedSize = Multi.cartSizeA; + + if (Multi.cartSizeB == 0 && Multi.cartSizeA <= (int32)(MAX_ROM_SIZE - 0x100000 - Multi.cartOffsetA)) + { + //Initialize 1MB Empty Memory Pack only if cart B is cleared + //It does not make a Memory Pack if game is loaded like a normal ROM + Multi.cartOffsetB = Multi.cartOffsetA + CalculatedSize; + Multi.cartSizeB = 0x100000; + memset(Memory.ROM + Multi.cartOffsetB, 0xFF, 0x100000); + } + + 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; + + fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "rb"); + if (!fp) + return (FALSE); + + if (fread(RTCData.reg, 1, 20, fp) < 20) + memset (RTCData.reg, 0, 20); + fclose(fp); + + return (TRUE); +} + +bool8 CMemory::SaveSRTC (void) +{ + FILE *fp; + + fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "wb"); + if (!fp) + return (FALSE); + + if (fwrite(RTCData.reg, 1, 20, fp) < 20) + { + printf ("Failed to save clock data.\n"); + } + 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, sizeof(SRAM)); +} + +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 (LoROM) + size = size < 0x70000 ? size : 0x70000; + else if (HiROM) + size = size < 0x40000 ? size : 0x40000; + + if (size) + { + file = fopen(sramName, "rb"); + if (file) + { + len = fread((char *) SRAM, 1, size, 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, size, 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) + { + if (!fwrite((char *) Multi.sramB, size, 1, file)) + printf ("Couldn't write to subcart SRAM file.\n"); + fclose(file); + } + + strcpy(ROMFilename, temp); + } + + size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0; + if (LoROM) + size = size < 0x70000 ? size : 0x70000; + else if (HiROM) + size = size < 0x40000 ? size : 0x40000; + + if (size) + { + file = fopen(sramName, "wb"); + if (file) + { + if (!fwrite((char *) SRAM, size, 1, file)) + printf ("Couldn't write to SRAM file.\n"); + fclose(file); + + if (Settings.SRTC || Settings.SPC7110RTC) + SaveSRTC(); + + return (TRUE); + } + } + + return (FALSE); +} + +bool8 CMemory::SaveMPAK (const char *filename) +{ + if (Settings.BS || (Multi.cartSizeB && (Multi.cartType == 3))) + { + FILE *file; + int size; + char mempakName[PATH_MAX + 1]; + + strcpy(mempakName, filename); + size = 0x100000; + if (size) + { + file = fopen(mempakName, "wb"); + if (file) + { + size_t written; + written = fwrite((char *)Memory.ROM + Multi.cartOffsetB, size, 1, file); + fclose(file); + + return (written > 0); + } + } + } + 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; + Settings.MSU1 = 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; + // Fall through + 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; + } + + // MSU1 + Settings.MSU1 = S9xMSU1ROMExists(); + + //// Map memory and calculate checksum + + Map_Initialize(); + CalculatedChecksum = 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_BSCartHiROMMap(); + 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_BSSA1LoROMMap(); + 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 (Multi.cartType == 3) + if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 || + strncmp(ROMName, "DERBY STALLION 96", 17) == 0) + Map_BSCartLoROMMap(1); + else + Map_BSCartLoROMMap(0); + 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); + sha256sum(ROM, CalculatedSize, ROMSHA256); + } + 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); + sha256sum(ROM, CalculatedSize, ROMSHA256); + // 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)) || ROMRegion == 18)) // 18 is used by "Tintin in Tibet (Europe) (En,Es,Sv)" + 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; + } + + // SRAM size + SRAMMask = SRAMSize ? ((1 << (SRAMSize + 3)) * 128) - 1 : 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); + } + + // Use slight blue tint to indicate ROM was patched. + if (Settings.IsPatched) + { + Settings.DisplayColor = BUILD_PIXEL(26, 26, 31); + SET_UI_COLOR(216, 216, 255); + } + + 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.IRQTriggerCycles = 14; + Timings.APUSpeedup = 0; + S9xAPUTimingSetSpeedup(Timings.APUSpeedup); + + 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) +{ + 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; + } + } +} + +void CMemory::map_hirom (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size) +{ + 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; + } + } +} + +void CMemory::map_lorom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset) +{ + 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; + } + } +} + +void CMemory::map_hirom_offset (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint32 size, uint32 offset) +{ + 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; + } + } +} + +void CMemory::map_space (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, uint8 *data) +{ + 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; + } + } +} + +void CMemory::map_index (uint32 bank_s, uint32 bank_e, uint32 addr_s, uint32 addr_e, int index, int type) +{ + 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 *) (pint) index; + BlockIsROM[p] = isROM; + BlockIsRAM[p] = isRAM; + } + } +} + +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) +{ + uint32 hi; + + if (SRAMSize == 0) + return; + + if (ROMSize > 11 || SRAMSize > 5) + hi = 0x7fff; + else + hi = 0xffff; + + map_index(0x70, 0x7d, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM); + map_index(0xf0, 0xff, 0x0000, hi, 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); + map_space(0xf0, 0xf3, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000); + + 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(0x60, 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_index(0xa0, 0xbf, 0x6000, 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, 0x37ff, FillRAM); + map_space(0x80, 0xbf, 0x3000, 0x37ff, 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 < 0x4f; c++) + map_space(c, c, 0x0000, 0xffff, SRAM + (c & 3) * 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 40->4f + for (int c = 0x400; c < 0x500; c++) + SA1.Map[c] = SA1.WriteMap[c] = (uint8*)MAP_HIROM_SRAM; + + // 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_BSSA1LoROMMap(void) +{ + printf("Map_BSSA1LoROMMap\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); + + 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_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); + if(Memory.ROMSize >= 13) + map_hirom_offset(0x40, 0x4f, 0x0000, 0xffff, CalculatedSize, 0x600000); + 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(); +} + +void CMemory::Map_BSCartLoROMMap(uint8 mapping) +{ + printf("Map_BSCartLoROMMap\n"); + + BSX.MMC[0x02] = 0x00; + BSX.MMC[0x0C] = 0x80; + + map_System(); + + if (mapping) + { + 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); + } + else + { + map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize); + map_lorom(0x40, 0x7f, 0x0000, 0x7fff, CalculatedSize); + map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize); + map_lorom(0xc0, 0xff, 0x0000, 0x7fff, CalculatedSize); + } + + map_LoROMSRAM(); + map_index(0xc0, 0xef, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM); + map_WRAM(); + + map_WriteProtectROM(); +} + +void CMemory::Map_BSCartHiROMMap(void) +{ + printf("Map_BSCartHiROMMap\n"); + + BSX.MMC[0x02] = 0x80; + BSX.MMC[0x0C] = 0x80; + + 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); + + if ((ROM[Multi.cartOffsetB + 0xFF00] == 0x4D) + && (ROM[Multi.cartOffsetB + 0xFF02] == 0x50) + && ((ROM[Multi.cartOffsetB + 0xFF06] & 0xF0) == 0x70)) + { + //Type 7 Memory Pack detection - if detected, emulate it as Mask ROM + map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); + } + else + { + map_index(0xe0, 0xff, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM); + } + + map_HiROMSRAM(); + 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[20]; + + 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, ""); + + if (Settings.MSU1) + sprintf(chip + strlen(chip), "+MSU-1"); + + 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; + + if (Settings.DisableGameSpecificHacks) + return; + + // APU timing hacks + if (match_na("CIRCUIT USA")) + Timings.APUSpeedup = 3; + + S9xAPUTimingSetSpeedup(Timings.APUSpeedup); + + // Other timing hacks + // The delay to sync CPU and DMA which Snes9x does not emulate. + // Some games need really severe delay timing... + if (match_na("BATTLE GRANDPRIX")) // Battle Grandprix + Timings.DMACPUSync = 20; + else if (match_na("KORYU NO MIMI ENG")) // Koryu no Mimi translation by rpgone) + { + // An infinite loop reads $4210 and checks NMI flag. This only works if LDA instruction executes before the NMI triggers, + // which doesn't work very well with s9x's default DMA timing. + Timings.DMACPUSync = 20; + } + + if (Timings.DMACPUSync != 18) + printf("DMA sync: %d\n", Timings.DMACPUSync); + + // SRAM initial value + 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 :( + // 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"); + } + + // Render Position + if (match_na("Sugoro Quest++")) + Timings.RenderPos = 128; + else if (match_na("FIREPOWER 2000") || match_na("SUPER SWIV")) + Timings.RenderPos = 32; + else if (match_na("DERBY STALLION 98")) + Timings.RenderPos = 128; + else if (match_na("AIR STRIKE PATROL") || match_na("DESERT FIGHTER")) + Timings.RenderPos = 128; // Just hides shadow + // From bsnes + else if (match_na("NHL '94") || match_na("NHL PROHOCKEY'94")) + Timings.RenderPos = 32; + else if (match_na("ADVENTURES OF FRANKEN") && Settings.PAL) + Timings.RenderPos = 32; +} + +// 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(!Settings.IgnorePatchChecksum && (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(Settings.IgnorePatchChecksum + || ((rom_crc32 == px_crc32) && (out_crc32 == py_crc32)) + || ((rom_crc32 == py_crc32) && (out_crc32 == px_crc32)) + ) { + Settings.IsPatched = 3; + 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(!Settings.IgnorePatchChecksum && rom_crc32 != source_crc32) { delete[] data; return false; } //patch is for a different ROM + + 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]; + 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(Settings.IgnorePatchChecksum || out_crc32 == target_crc32) { + memcpy(Memory.ROM, patched_rom, target_size); + rom_size = target_size; + delete[] patched_rom; + Settings.IsPatched = 2; + 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; + + Settings.IsPatched = 1; + return (1); +} + +#ifdef UNZIP_SUPPORT +static int unzFindExtension (unzFile &file, const char *ext, bool restart, bool print, bool allowExact) +{ + unz_file_info info; + int port, l = strlen(ext), e = allowExact ? 0 : 1; + + 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 + e && 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) +{ + Settings.IsPatched = false; + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadBPSPatch(s, 0, rom_size); + s->closeStream(); + + 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); + + Stream *s = new unzStream(file); + ret = ReadBPSPatch(s, offset, rom_size); + delete s; + + if (ret) + printf("!\n"); + else + printf(" failed!\n"); + } + assert(unzClose(file) == UNZ_OK); + } + } +#endif + + n = S9xGetFilename(".bps", PATCH_DIR); + + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) + { + printf("Using BPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadBPSPatch(s, 0, rom_size); + s->closeStream(); + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadUPSPatch(s, 0, rom_size); + s->closeStream(); + + 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); + + Stream *s = new unzStream(file); + ret = ReadUPSPatch(s, offset, rom_size); + delete s; + + if (ret) + printf("!\n"); + else + printf(" failed!\n"); + } + assert(unzClose(file) == UNZ_OK); + } + } +#endif + + n = S9xGetFilename(".ups", PATCH_DIR); + + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) + { + printf("Using UPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadUPSPatch(s, 0, rom_size); + s->closeStream(); + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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); + + Stream *s = new unzStream(file); + ret = ReadIPSPatch(s, offset, rom_size); + delete s; + + 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); + + Stream *s = new unzStream(file); + ret = ReadIPSPatch(s, offset, rom_size); + delete s; + + 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); + + Stream *s = new unzStream(file); + ret = ReadIPSPatch(s, offset, rom_size); + delete s; + + 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); + + Stream *s = new unzStream(file); + ret = ReadIPSPatch(s, offset, rom_size); + delete s; + + 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", PATCH_DIR); + + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) + { + printf("Using IPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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, PATCH_DIR); + + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) + break; + + printf("Using IPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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, PATCH_DIR); + + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) + break; + + printf("Using IPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + 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, PATCH_DIR); + + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) + break; + + printf("Using IPS patch %s", n); + + Stream *s = new fStream(patch_file); + ret = ReadIPSPatch(s, offset, rom_size); + s->closeStream(); + + if (ret) + { + printf("!\n"); + flag = true; + } + else + { + printf(" failed!\n"); + break; + } + } while (++i < 10); + + if (flag) + return; + } + +#ifdef UNZIP_SUPPORT + // Mercurial Magic (MSU-1 distribution pack) + if (strcasecmp(ext, "msu1") && strcasecmp(ext, ".msu1")) // ROM was *NOT* loaded from a .msu1 pack + { + Stream *s = S9xMSU1OpenFile("patch.bps", TRUE); + if (s) + { + printf("Using BPS patch %s.msu1", name); + ret = ReadBPSPatch(s, offset, rom_size); + s->closeStream(); + + if (ret) + printf("!\n"); + else + printf(" failed!\n"); + } + } +#endif +} diff --git a/snes9x/memmap.h b/snes9x/memmap.h new file mode 100644 index 0000000..aaa46de --- /dev/null +++ b/snes9x/memmap.h @@ -0,0 +1,218 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + unsigned char ROMSHA256[32]; + 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); + int First512BytesCountZeroes() const; + 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 LoadBSCart (); + bool8 LoadGNEXT (); + bool8 LoadSRAM (const char *); + bool8 SaveSRAM (const char *); + void ClearSRAM (bool8 onlyNonSavedSRAM = 0); + bool8 LoadSRTC (void); + bool8 SaveSRTC (void); + bool8 SaveMPAK (const char *); + + 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); + void map_hirom (uint32, uint32, uint32, uint32, uint32); + void map_lorom_offset (uint32, uint32, uint32, uint32, uint32, uint32); + void map_hirom_offset (uint32, uint32, uint32, uint32, uint32, uint32); + void map_space (uint32, uint32, uint32, uint32, uint8 *); + void map_index (uint32, uint32, uint32, uint32, int, int); + 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_BSSA1LoROMMap (void); + void Map_HiROMMap (void); + void Map_ExtendedHiROMMap (void); + void Map_SPC7110HiROMMap (void); + void Map_BSCartLoROMMap(uint8); + void Map_BSCartHiROMMap(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 diff --git a/snes9x/messages.h b/snes9x/messages.h new file mode 100644 index 0000000..1019e3b --- /dev/null +++ b/snes9x/messages.h @@ -0,0 +1,59 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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_NO_INFO, + 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, + S9X_PRESSED_KEYS_INFO +}; + +#endif diff --git a/snes9x/missing.h b/snes9x/missing.h new file mode 100644 index 0000000..681042d --- /dev/null +++ b/snes9x/missing.h @@ -0,0 +1,85 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/movie.cpp b/snes9x/movie.cpp new file mode 100644 index 0000000..fe41f62 --- /dev/null +++ b/snes9x/movie.cpp @@ -0,0 +1,1046 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +// 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); + + if (!fwrite(Movie.InputBuffer, 1, Movie.BytesPerSample * (Movie.MaxSample + 1), Movie.File)) + printf ("Movie flush failed.\n"); +} + +static void truncate_movie (void) +{ + if (!Movie.File || !Settings.MovieTruncate) + return; + + if (Movie.SaveStateOffset > Movie.ControllerDataOffset) + return; + + if (ftruncate(fileno(Movie.File), Movie.ControllerDataOffset + Movie.BytesPerSample * (Movie.MaxSample + 1))) + printf ("Couldn't truncate file.\n"); +} + +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); + memcpy(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); + } + + if (!fwrite(buf, 1, SMV_HEADER_SIZE, fd)) + printf ("Couldn't write movie header.\n"); +} + +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); + + 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); + + // reopen stream to access as gzipped data + 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); + + // do not close stream but close FILE * + // (msvcrt will try to close all open FILE *handles on exit - if we do CLOSE_STREAM here + // the underlying file will be closed by zlib, causing problems when msvcrt tries to do it) + delete stream; + fclose(fd); + + 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)) + { + fclose(fd); + return (WRONG_FORMAT); + } + + Movie.File = fd; + Movie.BytesPerSample = bytes_per_sample(); + Movie.InputBufferPtr = Movie.InputBuffer; + reserve_buffer_space(Movie.BytesPerSample * (Movie.MaxSample + 1)); + + if (!fread(Movie.InputBufferPtr, 1, Movie.BytesPerSample * (Movie.MaxSample + 1), fd)) + { + printf ("Failed to read from movie file.\n"); + fclose(fd); + return (WRONG_FORMAT); + } + + // 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); + } + + if (!fwrite(meta_buf, sizeof(uint16), metadata_length, fd)) + printf ("Failed writing movie metadata.\n"); + } + + 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) + { + fclose(fd); + 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; + + if (!fwrite((Movie.InputBufferPtr - Movie.BytesPerSample), 1, Movie.BytesPerSample, Movie.File)) + printf ("Error writing control data.\n"); + + 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; + + if (!fwrite((Movie.InputBufferPtr - Movie.BytesPerSample), 1, Movie.BytesPerSample, Movie.File)) + printf ("Failed writing reset data.\n"); + } +} + +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 +} diff --git a/snes9x/movie.h b/snes9x/movie.h new file mode 100644 index 0000000..28f347e --- /dev/null +++ b/snes9x/movie.h @@ -0,0 +1,80 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); + +// 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 diff --git a/snes9x/msu1.cpp b/snes9x/msu1.cpp new file mode 100644 index 0000000..f6e545e --- /dev/null +++ b/snes9x/msu1.cpp @@ -0,0 +1,432 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "snes9x.h" +#include "memmap.h" +#include "display.h" +#include "msu1.h" +#include "apu/resampler.h" +#include "apu/bapu/dsp/blargg_endian.h" +#include +#include + +STREAM dataStream = NULL; +STREAM audioStream = NULL; +uint32 audioLoopPos; +size_t partial_frames; + +// Sample buffer +static Resampler *msu_resampler = NULL; + +#ifdef UNZIP_SUPPORT +static int unzFindExtension(unzFile &file, const char *ext, bool restart = TRUE, bool print = TRUE, bool allowExact = FALSE) +{ + unz_file_info info; + int port, l = strlen(ext), e = allowExact ? 0 : 1; + + 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 + e && strcasecmp(name + len - l, ext) == 0 && unzOpenCurrentFile(file) == UNZ_OK) + { + if (print) + printf("Using msu file %s", name); + + return (port); + } + + port = unzGoToNextFile(file); + } + + return (port); +} +#endif + +STREAM S9xMSU1OpenFile(const char *msu_ext, bool skip_unpacked) +{ + const char *filename = S9xGetFilename(msu_ext, ROMFILENAME_DIR); + STREAM file = 0; + + if (!skip_unpacked) + { + file = OPEN_STREAM(filename, "rb"); + if (file) + printf("Using msu file %s.\n", filename); + } + +#ifdef UNZIP_SUPPORT + // look for msu1 pack file in the rom or patch dir if msu data file not found in rom dir + if (!file) + { + const char *zip_filename = S9xGetFilename(".msu1", ROMFILENAME_DIR); + unzFile unzFile = unzOpen(zip_filename); + + if (!unzFile) + { + zip_filename = S9xGetFilename(".msu1", PATCH_DIR); + unzFile = unzOpen(zip_filename); + } + + if (unzFile) + { + int port = unzFindExtension(unzFile, msu_ext, true, true, true); + if (port == UNZ_OK) + { + printf(" in %s.\n", zip_filename); + file = new unzStream(unzFile); + } + else + unzClose(unzFile); + } + } +#endif + + return file; +} + +static void AudioClose() +{ + if (audioStream) + { + CLOSE_STREAM(audioStream); + audioStream = NULL; + } +} + +static bool AudioOpen() +{ + MSU1.MSU1_STATUS |= AudioError; + + AudioClose(); + + char ext[_MAX_EXT]; + snprintf(ext, _MAX_EXT, "-%d.pcm", MSU1.MSU1_CURRENT_TRACK); + + audioStream = S9xMSU1OpenFile(ext); + if (audioStream) + { + if (GETC_STREAM(audioStream) != 'M') + return false; + if (GETC_STREAM(audioStream) != 'S') + return false; + if (GETC_STREAM(audioStream) != 'U') + return false; + if (GETC_STREAM(audioStream) != '1') + return false; + + READ_STREAM((char *)&audioLoopPos, 4, audioStream); + audioLoopPos = GET_LE32(&audioLoopPos); + audioLoopPos <<= 2; + audioLoopPos += 8; + + MSU1.MSU1_AUDIO_POS = 8; + + MSU1.MSU1_STATUS &= ~AudioError; + return true; + } + + return false; +} + +static void DataClose() +{ + if (dataStream) + { + CLOSE_STREAM(dataStream); + dataStream = NULL; + } +} + +static bool DataOpen() +{ + DataClose(); + + dataStream = S9xMSU1OpenFile(".msu"); + + if(!dataStream) + dataStream = S9xMSU1OpenFile("msu1.rom"); + + return dataStream != NULL; +} + +void S9xResetMSU(void) +{ + MSU1.MSU1_STATUS = 0; + MSU1.MSU1_DATA_SEEK = 0; + MSU1.MSU1_DATA_POS = 0; + MSU1.MSU1_TRACK_SEEK = 0; + MSU1.MSU1_CURRENT_TRACK = 0; + MSU1.MSU1_RESUME_TRACK = 0; + MSU1.MSU1_VOLUME = 0; + MSU1.MSU1_CONTROL = 0; + MSU1.MSU1_AUDIO_POS = 0; + MSU1.MSU1_RESUME_POS = 0; + + if (msu_resampler) + msu_resampler->clear(); + + partial_frames = 0; + + DataClose(); + + AudioClose(); + + Settings.MSU1 = S9xMSU1ROMExists(); +} + +void S9xMSU1Init(void) +{ + DataOpen(); +} + +void S9xMSU1DeInit(void) +{ + DataClose(); + AudioClose(); +} + +bool S9xMSU1ROMExists(void) +{ + STREAM s = S9xMSU1OpenFile(".msu"); + if (s) + { + CLOSE_STREAM(s); + return true; + } +#ifdef UNZIP_SUPPORT + char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1]; + _splitpath(Memory.ROMFilename, drive, dir, def, ext); + if (!strcasecmp(ext, ".msu1")) + return true; + + unzFile unzFile = unzOpen(S9xGetFilename(".msu1", ROMFILENAME_DIR)); + + if(!unzFile) + unzFile = unzOpen(S9xGetFilename(".msu1", PATCH_DIR)); + + if (unzFile) + { + unzClose(unzFile); + return true; + } +#endif + return false; +} + +void S9xMSU1Generate(size_t sample_count) +{ + partial_frames += 4410 * (sample_count / 2); + + while (partial_frames >= 3204) + { + if (MSU1.MSU1_STATUS & AudioPlaying && audioStream) + { + int32 sample; + int16* left = (int16*)&sample; + int16* right = left + 1; + + int bytes_read = READ_STREAM((char *)&sample, 4, audioStream); + if (bytes_read == 4) + { + *left = ((int32)(int16)GET_LE16(left) * MSU1.MSU1_VOLUME / 255); + *right = ((int32)(int16)GET_LE16(right) * MSU1.MSU1_VOLUME / 255); + + msu_resampler->push_sample(*left, *right); + MSU1.MSU1_AUDIO_POS += 4; + partial_frames -= 3204; + } + else + if (bytes_read >= 0) + { + if (MSU1.MSU1_STATUS & AudioRepeating) + { + MSU1.MSU1_AUDIO_POS = audioLoopPos; + REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); + } + else + { + MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); + REVERT_STREAM(audioStream, 8, 0); + } + } + else + { + MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); + } + } + else + { + MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); + partial_frames -= 3204; + msu_resampler->push_sample(0, 0); + } + } +} + + +uint8 S9xMSU1ReadPort(uint8 port) +{ + switch (port) + { + case 0: + return MSU1.MSU1_STATUS | MSU1_REVISION; + case 1: + { + if (MSU1.MSU1_STATUS & DataBusy) + return 0; + if (!dataStream) + return 0; + int data = GETC_STREAM(dataStream); + if (data >= 0) + { + MSU1.MSU1_DATA_POS++; + return data; + } + return 0; + } + case 2: + return 'S'; + case 3: + return '-'; + case 4: + return 'M'; + case 5: + return 'S'; + case 6: + return 'U'; + case 7: + return '1'; + } + + return 0; +} + + +void S9xMSU1WritePort(uint8 port, uint8 byte) +{ + switch (port) + { + case 0: + MSU1.MSU1_DATA_SEEK &= 0xFFFFFF00; + MSU1.MSU1_DATA_SEEK |= byte << 0; + break; + case 1: + MSU1.MSU1_DATA_SEEK &= 0xFFFF00FF; + MSU1.MSU1_DATA_SEEK |= byte << 8; + break; + case 2: + MSU1.MSU1_DATA_SEEK &= 0xFF00FFFF; + MSU1.MSU1_DATA_SEEK |= byte << 16; + break; + case 3: + MSU1.MSU1_DATA_SEEK &= 0x00FFFFFF; + MSU1.MSU1_DATA_SEEK |= byte << 24; + MSU1.MSU1_DATA_POS = MSU1.MSU1_DATA_SEEK; + if (dataStream) + { + REVERT_STREAM(dataStream, MSU1.MSU1_DATA_POS, 0); + } + break; + case 4: + MSU1.MSU1_TRACK_SEEK &= 0xFF00; + MSU1.MSU1_TRACK_SEEK |= byte; + break; + case 5: + MSU1.MSU1_TRACK_SEEK &= 0x00FF; + MSU1.MSU1_TRACK_SEEK |= (byte << 8); + MSU1.MSU1_CURRENT_TRACK = MSU1.MSU1_TRACK_SEEK; + + MSU1.MSU1_STATUS &= ~AudioPlaying; + MSU1.MSU1_STATUS &= ~AudioRepeating; + + if (AudioOpen()) + { + if (MSU1.MSU1_CURRENT_TRACK == MSU1.MSU1_RESUME_TRACK) + { + MSU1.MSU1_AUDIO_POS = MSU1.MSU1_RESUME_POS; + MSU1.MSU1_RESUME_POS = 0; + MSU1.MSU1_RESUME_TRACK = ~0; + } + else + { + MSU1.MSU1_AUDIO_POS = 8; + } + + REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); + } + break; + case 6: + MSU1.MSU1_VOLUME = byte; + break; + case 7: + if (MSU1.MSU1_STATUS & (AudioBusy | AudioError)) + break; + + MSU1.MSU1_STATUS = (MSU1.MSU1_STATUS & ~0x30) | ((byte & 0x03) << 4); + + if ((byte & (Play | Resume)) == Resume) + { + MSU1.MSU1_RESUME_TRACK = MSU1.MSU1_CURRENT_TRACK; + MSU1.MSU1_RESUME_POS = MSU1.MSU1_AUDIO_POS; + } + break; + } +} + +size_t S9xMSU1Samples(void) +{ + return msu_resampler->space_filled(); +} + +void S9xMSU1SetOutput(Resampler *resampler) +{ + msu_resampler = resampler; +} + +void S9xMSU1PostLoadState(void) +{ + if (DataOpen()) + { + REVERT_STREAM(dataStream, MSU1.MSU1_DATA_POS, 0); + } + + if (MSU1.MSU1_STATUS & AudioPlaying) + { + uint32 savedPosition = MSU1.MSU1_AUDIO_POS; + + if (AudioOpen()) + { + REVERT_STREAM(audioStream, 4, 0); + READ_STREAM((char *)&audioLoopPos, 4, audioStream); + audioLoopPos = GET_LE32(&audioLoopPos); + audioLoopPos <<= 2; + audioLoopPos += 8; + + MSU1.MSU1_AUDIO_POS = savedPosition; + REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0); + } + else + { + MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating); + MSU1.MSU1_STATUS |= AudioError; + } + } + + if (msu_resampler) + msu_resampler->clear(); + + partial_frames = 0; +} diff --git a/snes9x/msu1.h b/snes9x/msu1.h new file mode 100644 index 0000000..a8646ea --- /dev/null +++ b/snes9x/msu1.h @@ -0,0 +1,58 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _MSU1_H_ +#define _MSU1_H_ +#include "snes9x.h" + +#define MSU1_REVISION 0x02 + +struct SMSU1 +{ + uint8 MSU1_STATUS; + uint32 MSU1_DATA_SEEK; + uint32 MSU1_DATA_POS; + uint16 MSU1_TRACK_SEEK; + uint16 MSU1_CURRENT_TRACK; + uint32 MSU1_RESUME_TRACK; + uint8 MSU1_VOLUME; + uint8 MSU1_CONTROL; + uint32 MSU1_AUDIO_POS; + uint32 MSU1_RESUME_POS; +}; + +enum SMSU1_FLAG { + Revision = 0x07, // bitmask, not the actual version number + AudioError = 0x08, + AudioPlaying = 0x10, + AudioRepeating = 0x20, + AudioBusy = 0x40, + DataBusy = 0x80 +}; + +enum SMSU1_CMD { + Play = 0x01, + Repeat = 0x02, + Resume = 0x04 +}; + +extern struct SMSU1 MSU1; + +void S9xResetMSU(void); +void S9xMSU1Init(void); +void S9xMSU1DeInit(void); +bool S9xMSU1ROMExists(void); +STREAM S9xMSU1OpenFile(const char *msu_ext, bool skip_unpacked = FALSE); +void S9xMSU1Init(void); +void S9xMSU1Generate(size_t sample_count); +uint8 S9xMSU1ReadPort(uint8 port); +void S9xMSU1WritePort(uint8 port, uint8 byte); +size_t S9xMSU1Samples(void); +class Resampler; +void S9xMSU1SetOutput(Resampler *resampler); +void S9xMSU1PostLoadState(void); + +#endif diff --git a/snes9x/netplay.cpp b/snes9x/netplay.cpp new file mode 100644 index 0000000..f166cd0 --- /dev/null +++ b/snes9x/netplay.cpp @@ -0,0 +1,1059 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifdef NETPLAY_SUPPORT + +#include +#include +#include +#include +#include + +#include "snes9x.h" +#include "controls.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_JOYPAD_SWAP: +#ifdef NP_DEBUG + printf("CLIENT: Joypad Swap received @%ld\n", S9xGetMilliTime() - START); +#endif + S9xApplyCommand(S9xGetCommandT("SwapJoypads"), 1, 1); + 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, (WPARAM) rom_name, (LPARAM) 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 > 0x70000) + { + 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 addded 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 diff --git a/snes9x/netplay.h b/snes9x/netplay.h new file mode 100644 index 0000000..ea0b716 --- /dev/null +++ b/snes9x/netplay.h @@ -0,0 +1,209 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 + */ + +#ifdef _DEBUG +#define NP_DEBUG 1 +#endif + +#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 +// ... +#define NP_SERV_JOYPAD_SWAP 12 + +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 (); +void S9xNPSendJoypadSwap (); +#ifdef __WIN32__ +#define S9xGetMilliTime timeGetTime +#else +uint32 S9xGetMilliTime (); +#endif +#endif diff --git a/snes9x/obc1.cpp b/snes9x/obc1.cpp new file mode 100644 index 0000000..fe1d7e7 --- /dev/null +++ b/snes9x/obc1.cpp @@ -0,0 +1,105 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); +} diff --git a/snes9x/obc1.h b/snes9x/obc1.h new file mode 100644 index 0000000..686eb9b --- /dev/null +++ b/snes9x/obc1.h @@ -0,0 +1,25 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/pixform.h b/snes9x/pixform.h new file mode 100644 index 0000000..bfb05fa --- /dev/null +++ b/snes9x/pixform.h @@ -0,0 +1,117 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _PIXFORM_H_ +#define _PIXFORM_H_ + +/* RGB565 format */ +#define BUILD_PIXEL_RGB565(R, G, B) (((int)(R) << 11) | ((int)(G) << 6) | (((int)(G) & 0x10) << 1) | (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_SHIFT_BITS_RGB565 11 +#define GREEN_SHIFT_BITS_RGB565 6 +#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_SHIFT_BITS_RGB555 10 +#define GREEN_SHIFT_BITS_RGB555 5 +#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 + +#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_SHIFT_BITS_D(F) CONCAT(RED_SHIFT_BITS_, F) +#define GREEN_SHIFT_BITS_D(F) CONCAT(GREEN_SHIFT_BITS_, 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_SHIFT_BITS RED_SHIFT_BITS_D(PIXEL_FORMAT) +#define GREEN_SHIFT_BITS GREEN_SHIFT_BITS_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 // _PIXFORM_H_ diff --git a/snes9x/port.h b/snes9x/port.h new file mode 100644 index 0000000..cb010c9 --- /dev/null +++ b/snes9x/port.h @@ -0,0 +1,203 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _PORT_H_ +#define _PORT_H_ + +#include +#include +#include +#include +#ifndef __LIBRETRO__ +#include +#endif +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include + +#ifdef __WIN32__ +#define NOMINMAX 1 +#include +#endif + +#ifdef __WIN32__ +//#define RIGHTSHIFT_IS_SAR +#define RIGHTSHIFT_int8_IS_SAR +#define RIGHTSHIFT_int16_IS_SAR +#define RIGHTSHIFT_int32_IS_SAR +#ifndef __LIBRETRO__ +#define SNES_JOY_READ_CALLBACKS +#endif //__LIBRETRO__ +#endif + +#ifdef __MACOSX__ +#define PIXEL_FORMAT RGB555 +#endif + +#ifndef PIXEL_FORMAT +#define PIXEL_FORMAT RGB565 +#endif + +#if defined(__GNUC__) +#define alwaysinline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define alwaysinline __forceinline +#else +#define alwaysinline inline +#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 size_t pint; +#else // __PTR_NOT_INT +typedef size_t 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 __LIBRETRO__ +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 // __LIBRETRO__ +#define S9xDisplayString DisplayStringFromBottom +#endif // __LIBRETRO__ +#endif // __WIN32__ + +#if defined(__DJGPP) || defined(__WIN32__) +#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) || defined(__aarch64__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN__) +#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 diff --git a/snes9x/ppu.cpp b/snes9x/ppu.cpp new file mode 100644 index 0000000..50446f3 --- /dev/null +++ b/snes9x/ppu.cpp @@ -0,0 +1,1931 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + } +} + +static int CyclesUntilNext (int hc, int vc) +{ + int32 total = 0; + int vpos = CPU.V_Counter; + + if (vc - vpos > 0) + { + // It's still in this frame */ + // Add number of lines + total += (vc - vpos) * Timings.H_Max_Master; + // If line 240 is in there and we're odd, subtract a dot + if (vpos <= 240 && vc > 240 && Timings.InterlaceField & !IPPU.Interlace) + total -= ONE_DOT_CYCLE; + } + else + { + if (vc == vpos && (hc > CPU.Cycles)) + { + return hc; + } + + total += (Timings.V_Max - vpos) * Timings.H_Max_Master; + if (vpos <= 240 && Timings.InterlaceField && !IPPU.Interlace) + total -= ONE_DOT_CYCLE; + + total += (vc) * Timings.H_Max_Master; + if (vc > 240 && !Timings.InterlaceField && !IPPU.Interlace) + total -= ONE_DOT_CYCLE; + } + + total += hc; + + return total; +} + +void S9xUpdateIRQPositions (bool initial) +{ + PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles; + PPU.HTimerPosition -= PPU.IRQHBeamPos ? 0 : ONE_DOT_CYCLE; + PPU.HTimerPosition += PPU.IRQHBeamPos > 322 ? (ONE_DOT_CYCLE / 2) : 0; + PPU.HTimerPosition += PPU.IRQHBeamPos > 326 ? (ONE_DOT_CYCLE / 2) : 0; + PPU.VTimerPosition = PPU.IRQVBeamPos; + + if (PPU.VTimerEnabled && (PPU.VTimerPosition >= (Timings.V_Max + (IPPU.Interlace ? 1 : 0)))) + { + Timings.NextIRQTimer = 0x0fffffff; + } + else if (!PPU.HTimerEnabled && !PPU.VTimerEnabled) + { + Timings.NextIRQTimer = 0x0fffffff; + } + else if (PPU.HTimerEnabled && !PPU.VTimerEnabled) + { + int v_pos = CPU.V_Counter; + + Timings.NextIRQTimer = PPU.HTimerPosition; + if (CPU.Cycles > Timings.NextIRQTimer - Timings.IRQTriggerCycles) + { + Timings.NextIRQTimer += Timings.H_Max; + v_pos++; + } + + // Check for short dot scanline + if (v_pos == 240 && Timings.InterlaceField && !IPPU.Interlace) + { + Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0; + Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0; + } + } + else if (!PPU.HTimerEnabled && PPU.VTimerEnabled) + { + if (CPU.V_Counter == PPU.VTimerPosition && initial) + Timings.NextIRQTimer = CPU.Cycles + Timings.IRQTriggerCycles - ONE_DOT_CYCLE; + else + Timings.NextIRQTimer = CyclesUntilNext (Timings.IRQTriggerCycles - ONE_DOT_CYCLE, PPU.VTimerPosition); + } + else + { + Timings.NextIRQTimer = CyclesUntilNext (PPU.HTimerPosition, PPU.VTimerPosition); + + // Check for short dot scanline + int field = Timings.InterlaceField; + + if (PPU.VTimerPosition < CPU.V_Counter || + (PPU.VTimerPosition == CPU.V_Counter && Timings.NextIRQTimer > Timings.H_Max)) + { + field = !field; + } + + if (PPU.VTimerPosition == 240 && field && !IPPU.Interlace) + { + Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0; + Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0; + } + } + +#ifdef DEBUGGER + S9xTraceFormattedMessage("--- IRQ Timer HC:%d VC:%d set %d cycles HTimer:%d Pos:%04d->%04d VTimer:%d Pos:%03d->%03d", CPU.Cycles, CPU.V_Counter, + Timings.NextIRQTimer, PPU.HTimerEnabled, PPU.IRQHBeamPos, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.IRQVBeamPos, PPU.VTimerPosition); +#endif +} + +void S9xFixColourBrightness (void) +{ + IPPU.XB = mul_brightness[PPU.Brightness]; + + for (int i = 0; i < 64; i++) + { + if (i > IPPU.XB[0x1f]) + brightness_cap[i] = IPPU.XB[0x1f]; + else + brightness_cap[i] = i; + } + + 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 (Settings.MSU1 && (Address & 0xfff8) == 0x2000) // MSU-1 + S9xMSU1WritePort(Address & 7, Byte); + else + 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; + PPU.Brightness = Byte & 0xf; + S9xFixColourBrightness(); + S9xBuildDirectColourMaps(); + 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 = 0; + 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); + if (PPU.BGMode == 6 || PPU.BGMode == 5 || PPU.BGMode == 7) + IPPU.Interlace = Memory.FillRAM[0x2133] & 1; + else + IPPU.Interlace = 0; + #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; + + S9xUpdateVRAMReadBuffer(); + + break; + + case 0x2117: // VMADDH + PPU.VMA.Address &= 0x00ff; + PPU.VMA.Address |= Byte << 8; + + S9xUpdateVRAMReadBuffer(); + + 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 (IPPU.DoubleHeightPixels) + IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; + else + IPPU.RenderedScreenHeight = PPU.ScreenHeight; + } + + 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 (Settings.MSU1 && (Address & 0xfff8) == 0x2000) + return (S9xMSU1ReadPort(Address & 7)); + else + 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 (PPU.OpenBus1); + + 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 = PPU.VRAMReadBuffer & 0xff; + if (!PPU.VMA.High) + { + S9xUpdateVRAMReadBuffer(); + + PPU.VMA.Address += PPU.VMA.Increment; + } + + #ifdef DEBUGGER + missing.vram_read = 1; + #endif + return (PPU.OpenBus1 = byte); + + case 0x213a: // VMDATAHREAD + byte = (PPU.VRAMReadBuffer >> 8) & 0xff; + if (PPU.VMA.High) + { + S9xUpdateVRAMReadBuffer(); + + 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 + #ifdef DEBUGGER + if (Settings.TraceHCEvent) + S9xTraceFormattedMessage("Write to 0x4200. Byte is %2x was %2x\n", Byte, Memory.FillRAM[Address]); + #endif + + if (Byte == Memory.FillRAM[0x4200]) + break; + + 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 (!(Byte & 0x10) && !(Byte & 0x20)) + { + CPU.IRQLine = FALSE; + CPU.IRQTransition = FALSE; + } + + if ((Byte & 0x30) != (Memory.FillRAM[0x4200] & 0x30)) + { + // Only allow instantaneous IRQ if turning it completely on or off + if ((Byte & 0x30) == 0 || (Memory.FillRAM[0x4200] & 0x30) == 0) + S9xUpdateIRQPositions(true); + else + S9xUpdateIRQPositions(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()? + Timings.IRQFlagChanging |= IRQ_TRIGGER_NMI; + + #ifdef DEBUGGER + if (Settings.TraceHCEvent) + S9xTraceFormattedMessage("NMI Triggered on low-to-high occurring at next HC=%d\n", Timings.NMITriggerPos); + #endif + } + + #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) + S9xUpdateIRQPositions(false); + #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) + S9xUpdateIRQPositions(false); + #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) + S9xUpdateIRQPositions(true); + #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) + S9xUpdateIRQPositions(true); + #ifdef DEBUGGER + missing.virq_pos = PPU.IRQVBeamPos; + #endif + break; + + case 0x420b: // MDMAEN + if (CPU.InDMAorHDMA) + return; + // XXX: Not quite right... + if (Byte) { + CPU.Cycles += Timings.DMACPUSync; + } + 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; + // we might currently be in FastROMSpeed region, S9xSetPCBase will update CPU.MemSpeed + S9xSetPCBase(Registers.PBPC); + } + + 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 = 0; + if (CPU.IRQLine) + { + byte = 0x80; + 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 S9xResetPPUFast (void) +{ + PPU.RecomputeClipWindows = TRUE; + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = 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); +} + +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; + 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); + PPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better? + GFX.InterlaceFrame = 0; + GFX.DoInterlace = 0; + 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(); + S9xBuildDirectColourMaps(); + + 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; + Memory.FillRAM[0x2126] = Memory.FillRAM[0x2128] = 1; +} diff --git a/snes9x/ppu.h b/snes9x/ppu.h new file mode 100644 index 0000000..f5b0e0a --- /dev/null +++ b/snes9x/ppu.h @@ -0,0 +1,593 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + uint8 *TileCache[7]; + uint8 *TileCached[7]; + 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; + uint8 CGSavedByte; + 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; + + uint16 VRAMReadBuffer; +}; + +extern uint16 SignExtend[2]; +extern struct SPPU PPU; +extern struct InternalPPU IPPU; + +void S9xResetPPU (void); +void S9xResetPPUFast (void); +void S9xSoftResetPPU (void); +void S9xSetPPU (uint8, uint16); +uint8 S9xGetPPU (uint16); +void S9xSetCPU (uint8, uint16); +uint8 S9xGetCPU (uint16); +void S9xUpdateIRQPositions (bool initial); +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 + +void S9xUpdateScreen (void); +static inline void FLUSH_REDRAW (void) +{ + if (IPPU.PreviousLine != IPPU.CurrentLine) + S9xUpdateScreen(); +} + +static inline void S9xUpdateVRAMReadBuffer() +{ + 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); + PPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((address << 1) & 0xffff)); + } + else + PPU.VRAMReadBuffer = READ_WORD(Memory.VRAM + ((PPU.VMA.Address << 1) & 0xffff)); +} + +static inline void REGISTER_2104 (uint8 Byte) +{ + if (!(PPU.OAMFlip & 1)) + { + PPU.OAMWriteRegister &= 0xff00; + PPU.OAMWriteRegister |= 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; + } + + } + else if (PPU.OAMFlip & 1) + { + 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; + 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; + } +} + +// 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) \ + { \ + PPU.VMA.Address += !PPU.VMA.High ? PPU.VMA.Increment : 0; \ + return; \ + } \ + } +#else +#define CHECK_INBLANK() \ + if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \ + { \ + PPU.VMA.Address += !PPU.VMA.High ? PPU.VMA.Increment : 0; \ + 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_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_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; +} + +#undef CHECK_INBLANK +#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) \ + { \ + PPU.VMA.Address += PPU.VMA.High ? PPU.VMA.Increment : 0; \ + return; \ + } \ + } +#else +#define CHECK_INBLANK() \ + if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \ + { \ + PPU.VMA.Address += PPU.VMA.High ? PPU.VMA.Increment : 0; \ + return; \ + } +#endif + + +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_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_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) || PPU.CGSavedByte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff)) + { + FLUSH_REDRAW(); + PPU.CGDATA[PPU.CGADD] = (Byte & 0x7f) << 8 | PPU.CGSavedByte; + IPPU.ColorsChanged = TRUE; + IPPU.Red[PPU.CGADD] = IPPU.XB[PPU.CGSavedByte & 0x1f]; + 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 + { + PPU.CGSavedByte = Byte; + } + + 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 diff --git a/snes9x/sa1.cpp b/snes9x/sa1.cpp new file mode 100644 index 0000000..e56bf6a --- /dev/null +++ b/snes9x/sa1.cpp @@ -0,0 +1,980 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 = 4; + 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 = ONE_CYCLE; + SA1.MemSpeedx2 = 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 & 0x1f) * 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] & 0x1f) * 0x2000; + S9xSA1SetBWRAMMemMap(Memory.FillRAM[0x2225]); +#if 0 + S9xSetSA1(Memory.FillRAM[0x2220], 0x2220); + S9xSetSA1(Memory.FillRAM[0x2221], 0x2221); + S9xSetSA1(Memory.FillRAM[0x2222], 0x2222); + S9xSetSA1(Memory.FillRAM[0x2223], 0x2223); +#endif +} + +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; + if (Multi.cartType != 5) + block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)]; + else + { + if ((map & 7) < 4) + block = Memory.ROM + Multi.cartOffsetA + ((map & 7) * 0x100000 + (c << 12)); + else + block = Memory.ROM + Multi.cartOffsetB + (((map & 7) - 4) * 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; + uint8 *block; + if (Multi.cartType != 5) + { + offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000; + block = &Memory.ROM[offset]; + } + else + { + if ((map & 7) < 4) + { + offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000; + block = Memory.ROM + Multi.cartOffsetA + offset; + } + else + { + offset = (((map & 0x80) ? (map - 4) : which1) & 7) * 0x100000 + (c << 11) - 0x8000; + block = Memory.ROM + Multi.cartOffsetB + 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 (0x23); + + 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 & 0x1f) * 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 dividend = (int16) SA1.op1; + uint16 divisor = (uint16) SA1.op2; + uint16 remainder = (dividend >= 0) ? dividend % divisor : (dividend % divisor) + divisor; + uint16 quotient = (dividend - remainder) / divisor; + 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) + { + SA1.Cycles += SA1.MemSpeed; + return (*(GetAddress + (address & 0xffff))); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_PPU: + SA1.Cycles += ONE_CYCLE; + return (S9xGetSA1(address & 0xffff)); + + case CMemory::MAP_LOROM_SRAM: + case CMemory::MAP_HIROM_SRAM: + case CMemory::MAP_SA1RAM: + SA1.Cycles += ONE_CYCLE * 2; + return (*(Memory.SRAM + (address & 0x3ffff))); + + case CMemory::MAP_BWRAM: + SA1.Cycles += ONE_CYCLE * 2; + return (*(SA1.BWRAM + (address & 0x1fff))); + + case CMemory::MAP_BWRAM_BITMAP: + SA1.Cycles += ONE_CYCLE * 2; + + address -= 0x600000; + if (SA1.VirtualBitmapFormat == 2) + return ((Memory.SRAM[(address >> 2) & 0x3ffff] >> ((address & 3) << 1)) & 3); + else + return ((Memory.SRAM[(address >> 1) & 0x3ffff] >> ((address & 1) << 2)) & 15); + + case CMemory::MAP_BWRAM_BITMAP2: + SA1.Cycles += ONE_CYCLE * 2; + + address = (address & 0xffff) - 0x6000; + if (SA1.VirtualBitmapFormat == 2) + return ((SA1.BWRAM[(address >> 2) & 0x3ffff] >> ((address & 3) << 1)) & 3); + else + return ((SA1.BWRAM[(address >> 1) & 0x3ffff] >> ((address & 1) << 2)) & 15); + + default: + SA1.Cycles += ONE_CYCLE; + 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_HIROM_SRAM: + case CMemory::MAP_SA1RAM: + *(Memory.SRAM + (address & 0x3ffff)) = byte; + return; + + case CMemory::MAP_BWRAM: + *(SA1.BWRAM + (address & 0x1fff)) = byte; + return; + + case CMemory::MAP_BWRAM_BITMAP: + address -= 0x600000; + if (SA1.VirtualBitmapFormat == 2) + { + uint8 *ptr = &Memory.SRAM[(address >> 2) & 0x3ffff]; + *ptr &= ~(3 << ((address & 3) << 1)); + *ptr |= (byte & 3) << ((address & 3) << 1); + } + else + { + uint8 *ptr = &Memory.SRAM[(address >> 1) & 0x3ffff]; + *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) & 0x3ffff]; + *ptr &= ~(3 << ((address & 3) << 1)); + *ptr |= (byte & 3) << ((address & 3) << 1); + } + else + { + uint8 *ptr = &SA1.BWRAM[(address >> 1) & 0x3ffff]; + *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 = ONE_CYCLE; + if ((address & 0xc00000) == 0x400000 || (address & 0x40e000) == 0x6000) + { + SA1.MemSpeed = TWO_CYCLES; + } + + 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; + } +} diff --git a/snes9x/sa1.h b/snes9x/sa1.h new file mode 100644 index 0000000..4a8ce72 --- /dev/null +++ b/snes9x/sa1.h @@ -0,0 +1,148 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/sa1cpu.cpp b/snes9x/sa1cpu.cpp new file mode 100644 index 0000000..c69480d --- /dev/null +++ b/snes9x/sa1cpu.cpp @@ -0,0 +1,230 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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(); + } + } + + #undef CPU + int cycles = CPU.Cycles * 3; + #define CPU SA1 + + for (; SA1.Cycles < cycles && !(Memory.FillRAM[0x2200] & 0x60);) + { + #ifdef DEBUGGER + if (SA1.Flags & TRACE_FLAG) + S9xSA1Trace(); + #endif + + uint8 Op; + struct SOpcodes *Opcodes; + + if (SA1.PCBase) + { + SA1OpenBus = Op = SA1.PCBase[Registers.PCw]; + Opcodes = SA1.S9xOpcodes; + SA1.Cycles += SA1.MemSpeed; + } + 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; + } + } + + 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; +} diff --git a/snes9x/sar.h b/snes9x/sar.h new file mode 100644 index 0000000..7e07b99 --- /dev/null +++ b/snes9x/sar.h @@ -0,0 +1,52 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/screenshot.cpp b/snes9x/screenshot.cpp new file mode 100644 index 0000000..90df100 --- /dev/null +++ b/snes9x/screenshot.cpp @@ -0,0 +1,144 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 +} diff --git a/snes9x/screenshot.h b/snes9x/screenshot.h new file mode 100644 index 0000000..91b5f33 --- /dev/null +++ b/snes9x/screenshot.h @@ -0,0 +1,12 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _SCREENSHOT_H_ +#define _SCREENSHOT_H_ + +bool8 S9xDoScreenshot (int, int); + +#endif diff --git a/snes9x/sdd1.cpp b/snes9x/sdd1.cpp new file mode 100644 index 0000000..e11f50a --- /dev/null +++ b/snes9x/sdd1.cpp @@ -0,0 +1,40 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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]); +} diff --git a/snes9x/sdd1.h b/snes9x/sdd1.h new file mode 100644 index 0000000..10dfeb7 --- /dev/null +++ b/snes9x/sdd1.h @@ -0,0 +1,14 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _SDD1_H_ +#define _SDD1_H_ + +void S9xSetSDD1MemoryMap (uint32, uint32); +void S9xResetSDD1 (void); +void S9xSDD1PostLoadState (void); + +#endif diff --git a/snes9x/sdd1emu.cpp b/snes9x/sdd1emu.cpp new file mode 100644 index 0000000..1e796b7 --- /dev/null +++ b/snes9x/sdd1emu.cpp @@ -0,0 +1,333 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +/* 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 diff --git a/snes9x/sdd1emu.h b/snes9x/sdd1emu.h new file mode 100644 index 0000000..b4d5163 --- /dev/null +++ b/snes9x/sdd1emu.h @@ -0,0 +1,12 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _SDD1EMU_H_ +#define _SDD1EMU_H_ + +void SDD1_decompress (uint8 *, uint8 *, int); + +#endif diff --git a/snes9x/server.cpp b/snes9x/server.cpp new file mode 100644 index 0000000..a56ed0d --- /dev/null +++ b/snes9x/server.cpp @@ -0,0 +1,1310 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifdef NETPLAY_SUPPORT + +#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 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) + { +#ifdef __WIN32__ + int Percent = (uint8) (((length - len) * 100) / length); + 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 *) (pint) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) (pint) 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 *) (pint) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) (pint) 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 *) (pint) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else +#ifdef __WIN32__ + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *)(UINT_PTR) 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 *) (pint) 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 S9xNPSendJoypadSwap() +{ +#ifdef NP_DEBUG + printf("SERVER: Swap Joypads - @%ld\n", S9xGetMilliTime() - START); +#endif + uint8 swap[7]; + uint8 *ptr = swap; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = 0; + *ptr++ = NP_SERV_JOYPAD_SWAP; + WRITE_LONG(ptr, 7); + S9xNPSendToAllClients(swap, 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) +{ +#ifdef __WIN32__ + static int p; + p = port; +#endif + +#ifdef NP_DEBUG + printf ("SERVER: Starting server on port %d @%ld\n", port, S9xGetMilliTime () - START); +#endif + + 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 (Memory.LoROM) + SRAMSize = SRAMSize < 0x70000 ? SRAMSize : 0x70000; + else if (Memory.HiROM) + SRAMSize = SRAMSize < 0x40000 ? SRAMSize : 0x40000; + + 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 diff --git a/snes9x/seta.cpp b/snes9x/seta.cpp new file mode 100644 index 0000000..7df06f2 --- /dev/null +++ b/snes9x/seta.cpp @@ -0,0 +1,22 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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); +} diff --git a/snes9x/seta.h b/snes9x/seta.h new file mode 100644 index 0000000..2fa4e56 --- /dev/null +++ b/snes9x/seta.h @@ -0,0 +1,67 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/seta010.cpp b/snes9x/seta010.cpp new file mode 100644 index 0000000..b57e43b --- /dev/null +++ b/snes9x/seta010.cpp @@ -0,0 +1,600 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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] = +{ + { 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 }, + { 0x40, 0x20, 0x13, 0x0D, 0x0A, 0x08, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01 }, + { 0x40, 0x2D, 0x20, 0x18, 0x13, 0x10, 0x0D, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x07, 0x06, 0x06, 0x05, + 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }, + { 0x40, 0x33, 0x28, 0x20, 0x1A, 0x16, 0x13, 0x10, 0x0F, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x09, 0x08, + 0x08, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04 }, + { 0x40, 0x36, 0x2D, 0x26, 0x20, 0x1B, 0x18, 0x15, 0x13, 0x11, 0x10, 0x0E, 0x0D, 0x0C, 0x0B, 0x0B, + 0x0A, 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05 }, + { 0x40, 0x38, 0x30, 0x2A, 0x25, 0x20, 0x1C, 0x19, 0x17, 0x15, 0x13, 0x11, 0x10, 0x0F, 0x0E, 0x0D, + 0x0C, 0x0C, 0x0B, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07 }, + { 0x40, 0x39, 0x33, 0x2D, 0x28, 0x24, 0x20, 0x1D, 0x1A, 0x18, 0x16, 0x14, 0x13, 0x12, 0x10, 0x10, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08 }, + { 0x40, 0x3A, 0x35, 0x30, 0x2B, 0x27, 0x23, 0x20, 0x1D, 0x1B, 0x19, 0x17, 0x16, 0x14, 0x13, 0x12, + 0x11, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0A, 0x0A, 0x0A, 0x09, 0x09 }, + { 0x40, 0x3B, 0x36, 0x31, 0x2D, 0x29, 0x26, 0x23, 0x20, 0x1E, 0x1B, 0x1A, 0x18, 0x16, 0x15, 0x14, + 0x13, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0B, 0x0A }, + { 0x40, 0x3B, 0x37, 0x33, 0x2F, 0x2B, 0x28, 0x25, 0x22, 0x20, 0x1E, 0x1C, 0x1A, 0x19, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0F, 0x0E, 0x0E, 0x0D, 0x0D, 0x0C, 0x0C, 0x0C }, + { 0x40, 0x3C, 0x38, 0x34, 0x30, 0x2D, 0x2A, 0x27, 0x25, 0x20, 0x20, 0x1E, 0x1C, 0x1B, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0F, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D }, + { 0x40, 0x3C, 0x39, 0x35, 0x32, 0x2F, 0x2C, 0x29, 0x26, 0x24, 0x22, 0x20, 0x1E, 0x1D, 0x1B, 0x1A, + 0x19, 0x17, 0x16, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0F, 0x0E, 0x0E }, + { 0x40, 0x3D, 0x39, 0x36, 0x33, 0x30, 0x2D, 0x2A, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1E, 0x1D, 0x1B, + 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x10, 0x10, 0x10, 0x0F }, + { 0x40, 0x3D, 0x3A, 0x37, 0x34, 0x31, 0x2E, 0x2C, 0x2A, 0x27, 0x25, 0x23, 0x22, 0x20, 0x1E, 0x1D, + 0x1C, 0x1B, 0x19, 0x18, 0x17, 0x17, 0x16, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10 }, + { 0x40, 0x3D, 0x3A, 0x37, 0x35, 0x32, 0x30, 0x2D, 0x2B, 0x29, 0x27, 0x25, 0x23, 0x22, 0x20, 0x1F, + 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x16, 0x15, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11 }, + { 0x40, 0x3D, 0x3B, 0x38, 0x35, 0x33, 0x30, 0x2E, 0x2C, 0x2A, 0x28, 0x26, 0x25, 0x23, 0x21, 0x20, + 0x1F, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16, 0x15, 0x15, 0x14, 0x13, 0x13, 0x12 }, + { 0x40, 0x3D, 0x3B, 0x38, 0x36, 0x34, 0x31, 0x2F, 0x2D, 0x2B, 0x29, 0x27, 0x26, 0x24, 0x23, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1B, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x13 }, + { 0x40, 0x3E, 0x3B, 0x39, 0x37, 0x34, 0x32, 0x30, 0x2E, 0x2C, 0x2A, 0x29, 0x27, 0x25, 0x24, 0x23, + 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x14 }, + { 0x40, 0x3E, 0x3B, 0x39, 0x37, 0x35, 0x33, 0x31, 0x2F, 0x2D, 0x2B, 0x2A, 0x28, 0x27, 0x25, 0x24, + 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x15 }, + { 0x40, 0x3E, 0x3C, 0x3A, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2E, 0x2C, 0x2B, 0x29, 0x28, 0x26, 0x25, + 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16 }, + { 0x40, 0x3E, 0x3C, 0x3A, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2F, 0x2D, 0x2C, 0x2A, 0x29, 0x27, 0x26, + 0x25, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1B, 0x1A, 0x19, 0x19, 0x18, 0x17 }, + { 0x40, 0x3E, 0x3C, 0x3A, 0x38, 0x36, 0x35, 0x33, 0x31, 0x30, 0x2E, 0x2C, 0x2B, 0x29, 0x28, 0x27, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1C, 0x1B, 0x1A, 0x1A, 0x19, 0x18 }, + { 0x40, 0x3E, 0x3C, 0x3A, 0x39, 0x37, 0x35, 0x33, 0x32, 0x30, 0x2F, 0x2D, 0x2C, 0x2A, 0x29, 0x28, + 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1D, 0x1C, 0x1B, 0x1A, 0x1A, 0x19 }, + { 0x40, 0x3E, 0x3C, 0x3B, 0x39, 0x37, 0x36, 0x34, 0x32, 0x31, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, 0x28, + 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C, 0x1B, 0x1B, 0x1A }, + { 0x40, 0x3E, 0x3D, 0x3B, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2E, 0x2D, 0x2C, 0x2A, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C, 0x1B, 0x1B }, + { 0x40, 0x3E, 0x3D, 0x3B, 0x3A, 0x38, 0x36, 0x35, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, + 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C, 0x1C }, + { 0x40, 0x3E, 0x3D, 0x3B, 0x3A, 0x38, 0x37, 0x35, 0x34, 0x32, 0x31, 0x30, 0x2E, 0x2D, 0x2C, 0x2B, + 0x2A, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1E, 0x1D, 0x1C }, + { 0x40, 0x3E, 0x3D, 0x3B, 0x3A, 0x39, 0x37, 0x36, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2D, 0x2B, + 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x1F, 0x1F, 0x1E, 0x1D }, + { 0x40, 0x3F, 0x3D, 0x3C, 0x3A, 0x39, 0x37, 0x36, 0x35, 0x33, 0x32, 0x31, 0x30, 0x2E, 0x2D, 0x2C, + 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x1F, 0x1F, 0x1E }, + { 0x40, 0x3F, 0x3D, 0x3C, 0x3A, 0x39, 0x38, 0x36, 0x35, 0x34, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, + 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1F, 0x1F }, + { 0x40, 0x3F, 0x3D, 0x3C, 0x3B, 0x39, 0x38, 0x37, 0x35, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2D, + 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x25, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1F }, + { 0x40, 0x3F, 0x3D, 0x3C, 0x3B, 0x39, 0x38, 0x37, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, + 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20 } +}; + +// 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] +#define ST010_DWORD(offset) (Memory.SRAM[offset + 3] << 24) | (Memory.SRAM[offset + 2] << 16) | (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]); +} + +void ST010_Compass(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; + } + + Theta = ST010_ArcTan[x1 & 0x1f][y1 & 0x1f] << 8; + Theta = (Theta | Quadrant) ^ 0x8000; + + if ((x0 == 0) && (y0 < 0)) Quadrant = 0x4000; +} + +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 ST010_Raster(int16 Theta) +{ + int16 data; + int offset = 0; + + for (int i = 0; i < 176; i++) + { + data = ST010_M7Scale[i] * ST010_Cos(Theta) >> 15; + + Memory.SRAM[0x00f0 + offset] = data; + Memory.SRAM[0x00f1 + offset] = data >> 8; + + Memory.SRAM[0x0510 + offset] = data; + Memory.SRAM[0x0511 + offset] = data >> 8; + + data = ST010_M7Scale[i] * ST010_Sin(Theta) >> 15; + + Memory.SRAM[0x0250 + offset] = data; + Memory.SRAM[0x0251 + offset] = data >> 8; + + if (data) data = ~data; + + Memory.SRAM[0x03b0 + offset] = data; + Memory.SRAM[0x03b1 + offset] = data >> 8; + + offset += 2; + } +} + +static void ST010_Distance(int16 x0, int16 y0, int16 &Distance) +{ + int32 Product; + + x0 = (x0 < 0) ? -x0 : x0; + y0 = (y0 < 0) ? -y0 : y0; + + if((uint16) x0 >= ((uint16) y0)) + Product = ((x0 * 0x3d78 << 1) + (y0 * 0x1976 << 1)) << 1; + else + Product = ((y0 * 0x3d78 << 1) + (x0 * 0x1976 << 1)) << 1; + + Distance = (Product + 0x8000) >> 16; +} + +static void ST010_Navigation(int16 &MaxX, int16 &MaxY, int32 &x0, int32 &y0, int16 &Theta0, int16 &Theta1, int16 &x1, int16 &y1, uint16 &Radius, uint16 Increment, uint16 MaxRadius, int16 &Compass, int16 &Flags, int16 NewMaxX, int16 NewMaxY) +{ + int16 dummy1,dummy2,dummy3; + uint16 utemp16; + int32 temp32; + + + x1 = MaxX - (x0 >> 16); + y1 = MaxY - (y0 >> 16); + + ST010_Compass(x1, y1, dummy1, dummy2, dummy3, Theta1); + Theta1 -= Theta0; + + if (Theta1 & 0xff00) + Theta0 += (Theta1 & 0x8000) ? 0xfd80 : 0x0280; + + // compiler notice: -0x8000 ==> +0x8000 + utemp16 = ((Theta1 < 0) ? (int16) -Theta1 : Theta1) >> 4; + + if (utemp16 < 0x0100) + { + temp32 = Radius + Increment; + Radius = (temp32 >= MaxRadius) ? MaxRadius : (uint16) temp32; + } + + else + { + temp32 = Radius - utemp16; + Radius = (temp32 <= 0) ? 0 : (uint16) temp32; + } + + x0 -= ((ST010_Sin(Theta0) >> 5) * (Radius >> 8)) << 1; + y0 -= ((ST010_Cos(Theta0) >> 5) * (Radius >> 8)) << 1; + + x0 &= 0x1fffffff; + y0 &= 0x1fffffff; + + + int16 MaxRadiusX, MaxRadiusY; + if (Compass & 0x8000) + { + MaxRadiusX = 0x0008; + MaxRadiusY = 0x0080; + } + else + { + MaxRadiusX = 0x0080; + MaxRadiusY = 0x0008; + } + + if ((abs(x1) < MaxRadiusX) && (abs(y1) < MaxRadiusY)) + { + MaxX = NewMaxX; + MaxY = NewMaxY & 0x0fff; + Compass = (NewMaxY & 0x8000) ? 0xffff : 0x0000; + Flags |= 0x0008; + } +} + +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) + { + // Heading + case 0x01: + { + Memory.SRAM[0x0006] = Memory.SRAM[0x0002]; + Memory.SRAM[0x0007] = Memory.SRAM[0x0003]; + + #ifdef FAST_LSB_WORD_ACCESS + ST010_Compass(*(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_Compass(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; + } + + // Sorts Driver Placements + 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 + 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; + } + + // calculate the vector length of (x, y) + case 0x04: + { + #ifdef FAST_LSB_WORD_ACCESS + ST010_Distance(*(int16 *) &Memory.SRAM[0x0000], *(int16 *) &Memory.SRAM[0x0002], (int16 &) Memory.SRAM[0x0010]); + #else + int16 square; + + ST010_Distance(ST010_WORD(0x0000), ST010_WORD(0x0002), square); + + Memory.SRAM[0x10] = (uint8) (square); + Memory.SRAM[0x11] = (uint8) (square >> 8); + #endif + break; + } + + // calculate AI orientation based on specific guidelines + case 0x05: + { + #ifdef FAST_LSB_WORD_ACCESS + ST010_Navigation((int16 &) Memory.SRAM[0x00c0], (int16 &) Memory.SRAM[0x00c2], (int32 &) Memory.SRAM[0x00c4], (int32 &) Memory.SRAM[0x00c8], (int16 &) Memory.SRAM[0x00cc], (int16 &) Memory.SRAM[0x00ce], (int16 &) Memory.SRAM[0x00d0], (int16 &) Memory.SRAM[0x00d2], (uint16 &) Memory.SRAM[0x00d4], *(uint16 *) &Memory.SRAM[0x00d6], *(uint16 *) &Memory.SRAM[0x00d8], (int16 &) Memory.SRAM[0x00da], (int16 &) Memory.SRAM[0x00dc], *(int16 *) &Memory.SRAM[0x00de], *(int16 *) &Memory.SRAM[0x00e0]); + #else + int32 x0,y0; + int16 MaxX,MaxY,Theta0,Theta1,x1,y1,Compass,Flags; + uint16 Radius; + + MaxX = ST010_WORD(0x00c0); + MaxY = ST010_WORD(0x00c2); + x0 = ST010_DWORD(0x00c4); + y0 = ST010_DWORD(0x00c8); + Theta0 = ST010_WORD(0x00cc); + Radius = ST010_WORD(0x00d4); + Compass = ST010_WORD(0x00da); + Flags = ST010_WORD(0x00dc); + + ST010_Navigation(MaxX, MaxY, x0, y0, Theta0, Theta1, x1, y1, Radius, ST010_WORD(0x00d6), ST010_WORD(0x00d8), Compass, Flags, ST010_WORD(0x00de), ST010_WORD(0x00e0)); + + Memory.SRAM[0x00c0] = (uint8) (MaxX); + Memory.SRAM[0x00c1] = (uint8) (MaxX >> 8); + Memory.SRAM[0x00c2] = (uint8) (MaxY); + Memory.SRAM[0x00c3] = (uint8) (MaxY >> 8); + Memory.SRAM[0x00c4] = (uint8) (x0); + Memory.SRAM[0x00c5] = (uint8) (x0 >> 8); + Memory.SRAM[0x00c6] = (uint8) (x0 >> 16); + Memory.SRAM[0x00c7] = (uint8) (x0 >> 24); + Memory.SRAM[0x00c8] = (uint8) (y0); + Memory.SRAM[0x00c9] = (uint8) (y0 >> 8); + Memory.SRAM[0x00ca] = (uint8) (y0 >> 16); + Memory.SRAM[0x00cb] = (uint8) (y0 >> 24); + Memory.SRAM[0x00cc] = (uint8) (Theta0); + Memory.SRAM[0x00cd] = (uint8) (Theta0 >> 8); + Memory.SRAM[0x00ce] = (uint8) (Theta1); + Memory.SRAM[0x00cf] = (uint8) (Theta1 >> 8); + Memory.SRAM[0x00d0] = (uint8) (x1); + Memory.SRAM[0x00d1] = (uint8) (x1 >> 8); + Memory.SRAM[0x00d2] = (uint8) (y1); + Memory.SRAM[0x00d3] = (uint8) (y1 >> 8); + Memory.SRAM[0x00d4] = (uint8) (Radius); + Memory.SRAM[0x00d5] = (uint8) (Radius >> 8); + Memory.SRAM[0x00da] = (uint8) (Compass); + Memory.SRAM[0x00db] = (uint8) (Compass >> 8); + Memory.SRAM[0x00dc] = (uint8) (Flags); + Memory.SRAM[0x00dd] = (uint8) (Flags >> 8); + #endif + break; + } + + // 16-bit Multiplication + 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 + case 0x07: + { + #ifdef FAST_LSB_WORD_ACCESS + ST010_Raster(*(int16 *) &Memory.SRAM[0x0000]); + #else + ST010_Raster(ST010_WORD(0x0000)); + #endif + + // Shift Angle for use with Lookup table + Memory.SRAM[0x00] = Memory.SRAM[0x01]; + Memory.SRAM[0x01] = 0x00; + + break; + } + + // Two dimensional Coordinate Rotation + 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; + } + + default: + #ifdef DEBUGGER + printf("Unknown Op\n"); + #endif + break; + } + + // lower signal: op processed + ST010.op_reg = 0; + ST010.execute = 0; + } +} diff --git a/snes9x/seta011.cpp b/snes9x/seta011.cpp new file mode 100644 index 0000000..32670b3 --- /dev/null +++ b/snes9x/seta011.cpp @@ -0,0 +1,138 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + } + } +} diff --git a/snes9x/seta018.cpp b/snes9x/seta018.cpp new file mode 100644 index 0000000..371a407 --- /dev/null +++ b/snes9x/seta018.cpp @@ -0,0 +1,182 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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; + } + } +} diff --git a/snes9x/sha256.cpp b/snes9x/sha256.cpp new file mode 100644 index 0000000..22691d7 --- /dev/null +++ b/snes9x/sha256.cpp @@ -0,0 +1,179 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) +#define SHA256_BLOCK_SIZE 32 /* SHA256 outputs a 32 byte digest */ + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; /* 8-bit byte */ +typedef unsigned int WORD; /* 32-bit word, change to "long" for 16-bit machines */ + +typedef struct { + BYTE data[64]; + WORD datalen; + uint64_t bitlen; + WORD state[8]; +} SHA256_CTX; + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(SHA256_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(SHA256_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + /* Append to the padding the total message's length in bits and transform. */ + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + /* Since this implementation uses little endian byte ordering and SHA uses big endian, + reverse all the bytes when copying the final state to the output hash. */ + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} + +void sha256sum(unsigned char *data, unsigned int length, unsigned char *hash) +{ + SHA256_CTX ctx; + + sha256_init(&ctx); + sha256_update(&ctx, data, length); + sha256_final(&ctx, hash); +} diff --git a/snes9x/sha256.h b/snes9x/sha256.h new file mode 100644 index 0000000..201364d --- /dev/null +++ b/snes9x/sha256.h @@ -0,0 +1,6 @@ +#ifndef __SHA256_H +#define __SHA256_H + +void sha256sum (unsigned char *data, unsigned int length, unsigned char *hash); + +#endif diff --git a/snes9x/snapshot.cpp b/snes9x/snapshot.cpp new file mode 100644 index 0000000..b2a845d --- /dev/null +++ b/snes9x/snapshot.cpp @@ -0,0 +1,2393 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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" +#include "gfx.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, NMIPending), + 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), + INT_ENTRY(11, CGSavedByte), + 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), + INT_ENTRY(11, VRAMReadBuffer) +}; + +#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), + ARRAY_ENTRY(10, internal_macs, 5, 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, IRQFlagChanging), + INT_ENTRY(6, APUSpeedup), + INT_ENTRY(7, IRQTriggerCycles), + INT_ENTRY(7, APUAllowTimeOverflow), + INT_ENTRY(11, NextIRQTimer) +}; + +#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 SMSU1 + +static FreezeData SnapMSU1[] = +{ + INT_ENTRY(9, MSU1_STATUS), + INT_ENTRY(9, MSU1_DATA_SEEK), + INT_ENTRY(9, MSU1_DATA_POS), + INT_ENTRY(9, MSU1_TRACK_SEEK), + INT_ENTRY(9, MSU1_CURRENT_TRACK), + INT_ENTRY(9, MSU1_RESUME_TRACK), + INT_ENTRY(9, MSU1_VOLUME), + INT_ENTRY(9, MSU1_CONTROL), + INT_ENTRY(9, MSU1_AUDIO_POS), + INT_ENTRY(9, MSU1_RESUME_POS) +}; + +#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); +static bool CheckBlockName(STREAM stream, const char *name, int &len); +static void SkipBlockWithName(STREAM stream, const char *name); + + +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); + snprintf(filename, PATH_MAX + 1, "%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; +} + +void S9xMessageFromResult(int result, const char* base) +{ + 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; + } +} + +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) + { + S9xMessageFromResult(result, base); + 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); +} + +bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &width, int &height) +{ + STREAM stream = NULL; + + const char *base = S9xBasename(filename); + + if(S9xOpenSnapshotFile(filename, TRUE, &stream)) + { + int result; + + result = S9xUnfreezeScreenshotFromStream(stream, image_buffer, width, height); + S9xCloseSnapshotFile(stream); + + if(result != SUCCESS) + { + S9xMessageFromResult(result, base); + return (FALSE); + } + + 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[8192]; + uint8 *soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE]; + + 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, 0x80000); + + 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.MSU1) + FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1)); + + 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; + } + } + + delete [] soundsnapshot; +} + +int S9xUnfreezeFromStream (STREAM stream) +{ + const bool8 fast = Settings.FastSavestates; + + int result = SUCCESS; + int version, len; + char buffer[PATH_MAX + 1]; + + len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; + if (READ_STREAM(buffer, len, stream) != (unsigned int ) 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_msu1_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; + + if (fast) + result = UnfreezeBlock(stream, "VRA", Memory.VRAM, 0x10000); + else + result = UnfreezeBlockCopy(stream, "VRA", &local_vram, 0x10000); + if (result != SUCCESS) + break; + + if (fast) + result = UnfreezeBlock(stream, "RAM", Memory.RAM, 0x20000); + else + result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000); + if (result != SUCCESS) + break; + + if (fast) + result = UnfreezeBlock(stream, "SRA", Memory.SRAM, 0x80000); + else + result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x80000); + if (result != SUCCESS) + break; + + if (fast) + result = UnfreezeBlock(stream, "FIL", Memory.FillRAM, 0x8000); + else + 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; + + if (Settings.C4) + { + if (fast) + result = UnfreezeBlock(stream, "CX4", Memory.C4RAM, 8192); + else + result = UnfreezeBlockCopy(stream, "CX4", &local_cx4_data, 8192); + if (result != SUCCESS) + break; + } + else + { + SkipBlockWithName(stream, "CX4"); + } + + 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; + + if (Settings.OBC1) + { + if (fast) + result = UnfreezeBlock(stream, "OBM", Memory.OBC1RAM, 8192); + else + result = UnfreezeBlockCopy(stream, "OBM", &local_obc1_data, 8192); + if (result != SUCCESS) + break; + } + else + { + SkipBlockWithName(stream, "OBM"); + } + + 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, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version); + if (result != SUCCESS && Settings.MSU1) + 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; + + if (fast) + { + S9xResetPPUFast(); + } + else + { + //Do not call this if you have written directly to "Memory." arrays + 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); + + if (local_vram) + memcpy(Memory.VRAM, local_vram, 0x10000); + + if (local_ram) + memcpy(Memory.RAM, local_ram, 0x20000); + + if (local_sram) + memcpy(Memory.SRAM, local_sram, 0x80000); + + if (local_fillram) + 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 (local_msu1_data) + UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version); + + if (version < SNAPSHOT_VERSION_IRQ) + { + printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION); + + CPU.NMIPending = (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 = ONE_CYCLE; + SA1.MemSpeedx2 = 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(); + if(version < SNAPSHOT_VERSION_IRQ_2018) + S9xUpdateIRQPositions(false); // calculate the new trigger pos from saved PPU data + S9xFixCycles(); + + for (int d = 0; d < 8; d++) + DMA[d] = dma_snap.dma[d]; + // TODO: these should already be correct since they are stored in the snapshot + CPU.InDMA = CPU.InHDMA = FALSE; + CPU.InDMAorHDMA = CPU.InWRAMDMAorHDMA = FALSE; + CPU.HDMARanInDMA = 0; + + S9xFixColourBrightness(); + S9xBuildDirectColourMaps(); + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = TRUE; + IPPU.RenderThisFrame = TRUE; + + GFX.InterlaceFrame = Timings.InterlaceField; + GFX.DoInterlace = 0; + + S9xGraphicsScreenResize(); + + if (Settings.FastSavestates == 0) + memset(GFX.Screen,0,GFX.Pitch * MAX_SNES_HEIGHT); + + // TODO: this seems to be a relic from 1.43 changes, completely remove if no issues in the future + /*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_msu1_data) + S9xMSU1PostLoadState(); + + 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; + } + } + + 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); +} + +// load screenshot from file, allocating memory for it +int S9xUnfreezeScreenshotFromStream(STREAM stream, uint16 **image_buffer, int &width, int &height) +{ + int result = SUCCESS; + int version, len; + char buffer[PATH_MAX + 1]; + + len = strlen(SNAPSHOT_MAGIC) + 1 + 4 + 1; + if(READ_STREAM(buffer, len, stream) != (unsigned int)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_screenshot = NULL; + + // skip all blocks until screenshot + SkipBlockWithName(stream, "CPU"); + SkipBlockWithName(stream, "REG"); + SkipBlockWithName(stream, "PPU"); + SkipBlockWithName(stream, "DMA"); + SkipBlockWithName(stream, "VRA"); + SkipBlockWithName(stream, "RAM"); + SkipBlockWithName(stream, "SRA"); + SkipBlockWithName(stream, "FIL"); + SkipBlockWithName(stream, "SND"); + SkipBlockWithName(stream, "CTL"); + SkipBlockWithName(stream, "TIM"); + SkipBlockWithName(stream, "SFX"); + SkipBlockWithName(stream, "SA1"); + SkipBlockWithName(stream, "SAR"); + SkipBlockWithName(stream, "DP1"); + SkipBlockWithName(stream, "DP2"); + SkipBlockWithName(stream, "DP4"); + SkipBlockWithName(stream, "CX4"); + SkipBlockWithName(stream, "ST0"); + SkipBlockWithName(stream, "OBC"); + SkipBlockWithName(stream, "OBM"); + SkipBlockWithName(stream, "S71"); + SkipBlockWithName(stream, "SRT"); + SkipBlockWithName(stream, "CLK"); + SkipBlockWithName(stream, "BSX"); + SkipBlockWithName(stream, "MSU"); + result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version); + + + if(result == SUCCESS && local_screenshot) + { + SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; + + UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version); + + width = min(ssi->Width, IMAGE_WIDTH); + height = min(ssi->Height, IMAGE_HEIGHT); + + *image_buffer = (uint16 *)malloc(width * height * sizeof(uint16)); + + uint8 *rowpix = ssi->Data; + uint16 *screen = (*image_buffer); + + for(int y = 0; y < height; y++, screen += width) + { + for(int x = 0; x < width; x++) + { + uint32 r, g, b; + + r = *(rowpix++); + g = *(rowpix++); + b = *(rowpix++); + + screen[x] = BUILD_PIXEL(r, g, b); + } + } + + delete ssi; + } + + if(local_screenshot) delete[] local_screenshot; + + 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 bool CheckBlockName(STREAM stream, const char *name, int &len) +{ + char buffer[16]; + len = 0; + + size_t l = READ_STREAM(buffer, 11, stream); + buffer[l] = 0; + REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0); + + 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 (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':') + { + return false; + } + + if (len <= 0) + { + return false; + } + + return true; +} + +static void SkipBlockWithName(STREAM stream, const char *name) +{ + int len; + bool matchesName = CheckBlockName(stream, name, len); + if (matchesName) + { + long rewind = FIND_STREAM(stream); + rewind += len + 11; + REVERT_STREAM(stream, rewind, 0); + } +} + +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; + } + + if (!Settings.FastSavestates) + { + memset(block, 0, size); + } + + if (READ_STREAM(block, len, stream) != (unsigned int) 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; + + //check name first to avoid memory allocation + int blockLength; + if (!CheckBlockName(stream, name, blockLength)) + { + return 0; + } + + *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); + } + } +} diff --git a/snes9x/snapshot.h b/snes9x/snapshot.h new file mode 100644 index 0000000..03e5985 --- /dev/null +++ b/snes9x/snapshot.h @@ -0,0 +1,37 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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_IRQ_2018 11 // irq changes were introduced earlier, since this we store NextIRQTimer directly +#define SNAPSHOT_VERSION 11 + +#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); +bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &width, int &height); +int S9xUnfreezeScreenshotFromStream(STREAM stream, uint16 **image_buffer, int &width, int &height); + +#endif diff --git a/snes9x/snes9x.cpp b/snes9x/snes9x.cpp new file mode 100644 index 0000000..9cb173c --- /dev/null +++ b/snes9x/snes9x.cpp @@ -0,0 +1,756 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 (!strcasecmp(arg, "macsrifle")) + S9xSetController(port, CTL_MACSRIFLE, 0, 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); + fStream fS(fp); + conf.LoadFile(&fS); + 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) + { + 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); + Cheat.enabled = false; + Settings.NoPatch = !conf.GetBool("ROM::Patch", true); + Settings.IgnorePatchChecksum = conf.GetBool("ROM::IgnorePatchChecksum", false); + + Settings.ForceLoROM = conf.GetBool("ROM::LoROM", false); + Settings.ForceHiROM = conf.GetBool("ROM::HiROM", false); + if (Settings.ForceLoROM) + Settings.ForceHiROM = false; + + 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); + Settings.InitialSnapshotFilename[0] = '\0'; + + // Sound + + Settings.SoundSync = conf.GetBool("Sound::Sync", false); + 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", 48000); + Settings.SoundInputRate = conf.GetUInt("Sound::InputRate", 31950); + Settings.Mute = conf.GetBool("Sound::Mute", false); + Settings.DynamicRateControl = conf.GetBool("Sound::DynamicRateControl", false); + Settings.DynamicRateLimit = conf.GetInt ("Sound::DynamicRateLimit", 5); + Settings.InterpolationMethod = conf.GetInt ("Sound::InterpolationMethod", 2); + + // Display + + Settings.SupportHiRes = conf.GetBool("Display::HiRes", true); + Settings.Transparency = conf.GetBool("Display::Transparency", true); + Settings.DisableGraphicWindows = !conf.GetBool("Display::GraphicWindows", true); + Settings.DisplayTime = conf.GetBool("Display::DisplayTime", false); + 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.BilinearFilter = conf.GetBool("Display::BilinearFilter", false); + + // 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.MacsRifleMaster = conf.GetBool("Controls::MacsRifleMaster", 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")); + if (conf.Exists("Controls::MacsRifleCrosshair")) + parse_crosshair_spec(X_MACSRIFLE, conf.GetString("Controls::MacsRifleCrosshair")); + + // Hack + Settings.SuperFXClockMultiplier = conf.GetUInt("Hack::SuperFXClockMultiplier", 100); + Settings.OverclockMode = conf.GetUInt("Hack::OverclockMode", 0); + Settings.SeparateEchoBuffer = conf.GetBool("Hack::SeparateEchoBuffer", false); + Settings.DisableGameSpecificHacks = !conf.GetBool("Hack::EnableGameSpecificHacks", true); + Settings.BlockInvalidVRAMAccessMaster = !conf.GetBool("Hack::AllowInvalidVRAMAccess", false); + Settings.HDMATimingHack = conf.GetInt ("Hack::HDMATiming", 100); + Settings.MaxSpriteTilesPerLine = conf.GetInt ("Hack::MaxSpriteTilesPerLine", 34); + + // 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; + } + Settings.TraceSMP = FALSE; +#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, "-displaytime Display the time"); + 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, "-nomacsrifle Disable emulation of the M.A.C.S. Rifle"); + 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, " macsrifle M.A.C.S. Rifle"); + 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, "-cheatcode Supply a cheat code in Game Genie,"); + S9xMessage(S9X_INFO, S9X_USAGE, " Pro-Action Replay, or Raw format (address=byte)"); + 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, ""); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + S9xMessage(S9X_INFO, S9X_USAGE, "ROM image can be compressed with zip, gzip, JMA, or compress."); + + exit(1); +} + +void S9xParseArgsForCheats (char **argv, int argc) +{ + for (int i = 1; i < argc; i++) + { + if (!strcasecmp(argv[i], "-gamegenie") || + !strcasecmp(argv[i], "-actionreplay") || + !strcasecmp(argv[i], "-cheatcode")) + { + if (i + 1 < argc) + { + if (S9xAddCheatGroup ("Unknown", argv[++i]) < 0) + { + S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, "Code format invalid"); + } + else + { + S9xEnableCheatGroup (Cheat.g.size() - 1); + } + } + else + S9xUsage(); + } + } +} + +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], "-dynamicratecontrol")) + { + Settings.DynamicRateControl = TRUE; + Settings.DynamicRateLimit = 5; + } + 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 < 31700) + Settings.SoundInputRate = 31700; + if (Settings.SoundInputRate > 32300) + Settings.SoundInputRate = 32300; + } + 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], "-displaytime")) + Settings.DisplayTime = TRUE; + else + 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], "-nomacsrifle")) + Settings.MacsRifleMaster = 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 + if (!strcasecmp(argv[i], "-snapshot")) + { + if (i + 1 < argc) + { + strncpy(Settings.InitialSnapshotFilename, argv[++i], PATH_MAX); + Settings.InitialSnapshotFilename[PATH_MAX] = 0; + } + else + S9xUsage(); + } + 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") || + !strcasecmp(argv[i], "-actionreplay") || + !strcasecmp(argv[i], "-cheatcode")) + { + if (i + 1 < argc) + { + if (S9xAddCheatGroup ("Unknown", argv[++i]) < 0) + { + S9xMessage(S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, "Code format invalid"); + } + else + { + S9xEnableCheatGroup (Cheat.g.size() - 1); + } + } + 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 + rom_filename = argv[i]; + } + + S9xVerifyControllers(); + + return (rom_filename); +} \ No newline at end of file diff --git a/snes9x/snes9x.h b/snes9x/snes9x.h new file mode 100644 index 0000000..4ff179e --- /dev/null +++ b/snes9x/snes9x.h @@ -0,0 +1,332 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _SNES9X_H_ +#define _SNES9X_H_ + +#ifndef VERSION +#define VERSION "1.60" +#endif + +#include "port.h" +#include "65c816.h" +#include "messages.h" + +#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) + +#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.727272 // 21477272 + 8/11 exact +#define PAL_MASTER_CLOCK 21281370.0 + +#define SNES_MAX_NTSC_VCOUNTER 262 +#define SNES_MAX_PAL_VCOUNTER 312 +#define SNES_HCOUNTER_MAX 341 + +#ifndef ALLOW_CPU_OVERCLOCK +#define ONE_CYCLE 6 +#define SLOW_ONE_CYCLE 8 +#define TWO_CYCLES 12 +#else +#define ONE_CYCLE (Settings.OneClockCycle) +#define SLOW_ONE_CYCLE (Settings.OneSlowClockCycle) +#define TWO_CYCLES (Settings.TwoClockCycles) +#endif +#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 (128 * 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 NMIPending; + 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 +}; + +enum +{ + IRQ_NONE = 0x0, + IRQ_SET_FLAG = 0x1, + IRQ_CLEAR_FLAG = 0x2, + IRQ_TRIGGER_NMI = 0x4 +}; + +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 NextIRQTimer; + 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 IRQFlagChanging; // 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 TraceSMP; + + 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 MSU1; + bool8 MouseMaster; + bool8 SuperScopeMaster; + bool8 JustifierMaster; + bool8 MultiPlayer5Master; + bool8 MacsRifleMaster; + + 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 DynamicRateControl; + int32 DynamicRateLimit; /* Multiplied by 1000 */ + int32 InterpolationMethod; + + bool8 SupportHiRes; + bool8 Transparency; + uint8 BG_Forced; + bool8 DisableGraphicWindows; + + bool8 DisplayTime; + bool8 DisplayFrameRate; + bool8 DisplayWatchedAddresses; + bool8 DisplayPressedKeys; + bool8 DisplayMovieFrame; + bool8 AutoDisplayMessages; + uint32 InitialInfoStringTimeout; + uint16 DisplayColor; + bool8 BilinearFilter; + + 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 Rewinding; + + 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; + char InitialSnapshotFilename[PATH_MAX + 1]; + bool8 FastSavestates; + + bool8 ApplyCheats; + bool8 NoPatch; + bool8 IgnorePatchChecksum; + bool8 IsPatched; + int32 AutoSaveDelay; + bool8 DontSaveOopsSnapshot; + bool8 UpAndDown; + + bool8 OpenGLEnable; + + bool8 SeparateEchoBuffer; + uint32 SuperFXClockMultiplier; + int OverclockMode; + int OneClockCycle; + int OneSlowClockCycle; + int TwoClockCycles; + int MaxSpriteTilesPerLine; +}; + +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 diff --git a/snes9x/spc7110.cpp b/snes9x/spc7110.cpp new file mode 100644 index 0000000..ef61415 --- /dev/null +++ b/snes9x/spc7110.cpp @@ -0,0 +1,313 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +/***** + * 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); +} diff --git a/snes9x/spc7110.h b/snes9x/spc7110.h new file mode 100644 index 0000000..5d082ac --- /dev/null +++ b/snes9x/spc7110.h @@ -0,0 +1,104 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/spc7110dec.cpp b/snes9x/spc7110dec.cpp new file mode 100644 index 0000000..5d8cde3 --- /dev/null +++ b/snes9x/spc7110dec.cpp @@ -0,0 +1,529 @@ +/***** + * 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() > 0x500000 ? memory_cartrom_size() - 0x200000 : 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]; } +uint8 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[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 diff --git a/snes9x/spc7110dec.h b/snes9x/spc7110dec.h new file mode 100644 index 0000000..85f1d9c --- /dev/null +++ b/snes9x/spc7110dec.h @@ -0,0 +1,67 @@ +/***** + * 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); + uint8 toggle_invert(unsigned n); + + unsigned morton16[2][256]; + unsigned morton32[4][256]; + unsigned morton_2x8(unsigned data); + unsigned morton_4x8(unsigned data); +}; + +#endif diff --git a/snes9x/spc7110emu.cpp b/snes9x/spc7110emu.cpp new file mode 100644 index 0000000..304e5d0 --- /dev/null +++ b/snes9x/spc7110emu.cpp @@ -0,0 +1,645 @@ +/***** + * 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() > 0x500000 ? memory_cartrom_size() - 0x200000 : 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() { +} diff --git a/snes9x/spc7110emu.h b/snes9x/spc7110emu.h new file mode 100644 index 0000000..5f66fec --- /dev/null +++ b/snes9x/spc7110emu.h @@ -0,0 +1,136 @@ +/***** + * 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 diff --git a/snes9x/srtc.cpp b/snes9x/srtc.cpp new file mode 100644 index 0000000..4b8cb29 --- /dev/null +++ b/snes9x/srtc.cpp @@ -0,0 +1,73 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +/***** + * 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(); +} diff --git a/snes9x/srtc.h b/snes9x/srtc.h new file mode 100644 index 0000000..7152d0a --- /dev/null +++ b/snes9x/srtc.h @@ -0,0 +1,32 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 diff --git a/snes9x/srtcemu.cpp b/snes9x/srtcemu.cpp new file mode 100644 index 0000000..c535843 --- /dev/null +++ b/snes9x/srtcemu.cpp @@ -0,0 +1,223 @@ +/***** + * 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() { +} diff --git a/snes9x/srtcemu.h b/snes9x/srtcemu.h new file mode 100644 index 0000000..fc1af24 --- /dev/null +++ b/snes9x/srtcemu.h @@ -0,0 +1,30 @@ +/***** + * 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 diff --git a/snes9x/statemanager.cpp b/snes9x/statemanager.cpp new file mode 100644 index 0000000..7280ec8 --- /dev/null +++ b/snes9x/statemanager.cpp @@ -0,0 +1,191 @@ +#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; +} diff --git a/snes9x/statemanager.h b/snes9x/statemanager.h new file mode 100644 index 0000000..38f3c0d --- /dev/null +++ b/snes9x/statemanager.h @@ -0,0 +1,35 @@ +#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 diff --git a/snes9x/stream.cpp b/snes9x/stream.cpp new file mode 100644 index 0000000..d6e1c1c --- /dev/null +++ b/snes9x/stream.cpp @@ -0,0 +1,471 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +// Abstract the details of reading from zip files versus FILE *'s. + +#include +#ifdef UNZIP_SUPPORT +# ifdef SYSTEM_ZIP +# include +# else +# include "unzip.h" +# endif +#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); +} + +size_t Stream::pos_from_origin_offset(uint8 origin, int32 offset) +{ + size_t position = 0; + switch (origin) + { + case SEEK_SET: + position = offset; + break; + case SEEK_END: + position = size() + offset; + break; + case SEEK_CUR: + position = pos() + offset; + break; + } + return position; +} + +// 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 (uint8 origin, int32 offset) +{ + return (REVERT_FSTREAM(fp, offset, origin)); +} + +void fStream::closeStream() +{ + CLOSE_FSTREAM(fp); + delete this; +} + +// unzip Stream + +#ifdef UNZIP_SUPPORT + +unzStream::unzStream (unzFile &v) +{ + file = v; + pos_in_buf = 0; + buf_pos_in_unzipped = unztell(file); + bytes_in_buf = 0; + + // remember start pos for seeks + unzGetFilePos(file, &unz_file_start_pos); +} + +unzStream::~unzStream (void) +{ + return; +} + +size_t unzStream::buffer_remaining() +{ + return bytes_in_buf - pos_in_buf; +} + +void unzStream::fill_buffer() +{ + buf_pos_in_unzipped = unztell(file); + bytes_in_buf = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); + pos_in_buf = 0; +} + +int unzStream::get_char (void) +{ + unsigned char c; + + if (buffer_remaining() <= 0) + { + fill_buffer(); + if (bytes_in_buf <= 0) + return (EOF); + } + + c = *(buffer + pos_in_buf); + pos_in_buf++; + + 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); + + size_t to_read = len; + uint8 *read_to = (uint8 * )buf; + do + { + size_t in_buffer = buffer_remaining(); + if (to_read <= in_buffer) + { + memcpy(read_to, buffer + pos_in_buf, to_read); + pos_in_buf += to_read; + to_read = 0; + break; + } + + memcpy(read_to, buffer + pos_in_buf, in_buffer); + to_read -= in_buffer; + fill_buffer(); + } while (bytes_in_buf); + + return (len - to_read); +} + +// not supported +size_t unzStream::write (void *buf, size_t len) +{ + return (0); +} + +size_t unzStream::pos (void) +{ + return buf_pos_in_unzipped + pos_in_buf; +} + +size_t unzStream::size (void) +{ + unz_file_info info; + unzGetCurrentFileInfo(file,&info,NULL,0,NULL,0,NULL,0); + return info.uncompressed_size; +} + +int unzStream::revert (uint8 origin, int32 offset) +{ + size_t target_pos = pos_from_origin_offset(origin, offset); + + // new pos inside buffered data + if (target_pos >= buf_pos_in_unzipped && target_pos < buf_pos_in_unzipped + bytes_in_buf) + { + pos_in_buf = target_pos - buf_pos_in_unzipped; + } + else // outside of buffer, reset file and read until pos + { + unzGoToFilePos(file, &unz_file_start_pos); + unzOpenCurrentFile(file); // necessary to reopen after seek + int times_to_read = target_pos / unz_BUFFSIZ + 1; + for( int i = 0; i < times_to_read; i++) + { + fill_buffer(); + } + pos_in_buf = target_pos % unz_BUFFSIZ; + } + return 0; +} + +void unzStream::closeStream() +{ + unzClose(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 (uint8 origin, int32 offset) +{ + size_t pos = pos_from_origin_offset(origin, 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 (uint8 origin, int32 offset) +{ + size_t target_pos = pos_from_origin_offset(origin, offset); + bytes_written = target_pos; + 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); +} diff --git a/snes9x/stream.h b/snes9x/stream.h new file mode 100644 index 0000000..07e8410 --- /dev/null +++ b/snes9x/stream.h @@ -0,0 +1,135 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#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 (uint8 origin, int32 offset) = 0; + virtual void closeStream() = 0; + + protected: + size_t pos_from_origin_offset(uint8 origin, int32 offset); +}; + +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 (uint8 origin, int32 offset); + virtual void closeStream(); + + private: + FSTREAM fp; +}; + +#ifdef UNZIP_SUPPORT +# ifdef SYSTEM_ZIP +# include +# else +# include "unzip.h" +# endif + +#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 (uint8 origin, int32 offset); + virtual void closeStream(); + + private: + void fill_buffer(); + size_t buffer_remaining(); + + unzFile file; + char buffer[unz_BUFFSIZ]; + size_t pos_in_buf; + size_t buf_pos_in_unzipped; + size_t bytes_in_buf; + unz_file_pos unz_file_start_pos; +}; + +#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 (uint8 origin, int32 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 (uint8 origin, int32 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 diff --git a/snes9x/tile.cpp b/snes9x/tile.cpp new file mode 100644 index 0000000..35d9b15 --- /dev/null +++ b/snes9x/tile.cpp @@ -0,0 +1,531 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#include "tileimpl.h" + +using namespace TileImpl; + +namespace { + + uint32 pixbit[8][16]; + uint8 hrbit_odd[256]; + uint8 hrbit_even[256]; + + // 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]; \ + } + + uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32) + { + 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; + uint8 pix; + + DOBIT( 0, 0); + DOBIT( 1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + + return (non_zero ? TRUE : BLANK_TILE); + } + + uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32) + { + 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; + 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); + } + + uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32) + { + 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; + 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]; + + uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) + { + 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; + uint8 pix; + + DOBIT( 0, 0); + DOBIT( 1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + + return (non_zero ? TRUE : BLANK_TILE); + } + + uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) + { + 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; + 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]; + + uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) + { + 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; + uint8 pix; + + DOBIT( 0, 0); + DOBIT( 1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + + return (non_zero ? TRUE : BLANK_TILE); + } + + uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) + { + 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; + 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 + +} // anonymous namespace + +void S9xInitTileRenderer (void) +{ + int i; + + for (i = 0; i < 16; i++) + { + 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++) + { + uint8 m = 0; + 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; + } +} + +// Functions to select which converter and renderer to use. +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; + +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; + +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; +extern template struct TileImpl::Renderers; + +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::Functions; + DCT = Renderers::Functions; + DMP = Renderers::Functions; + DB = Renderers::Functions; + DM7BG1 = M7M1 ? Renderers::Functions : Renderers::Functions; + DM7BG2 = M7M2 ? Renderers::Functions : Renderers::Functions; + GFX.LinesPerTile = 8; + } + else if(hires) // hires double width + { + if (interlace) + { + DT = Renderers::Functions; + DCT = Renderers::Functions; + DMP = Renderers::Functions; + DB = Renderers::Functions; + DM7BG1 = M7M1 ? Renderers::Functions : Renderers::Functions; + DM7BG2 = M7M2 ? Renderers::Functions : Renderers::Functions; + GFX.LinesPerTile = 4; + } + else + { + DT = Renderers::Functions; + DCT = Renderers::Functions; + DMP = Renderers::Functions; + DB = Renderers::Functions; + DM7BG1 = M7M1 ? Renderers::Functions : Renderers::Functions; + DM7BG2 = M7M2 ? Renderers::Functions : Renderers::Functions; + GFX.LinesPerTile = 8; + } + } + else // normal double width + { + if (interlace) + { + DT = Renderers::Functions; + DCT = Renderers::Functions; + DMP = Renderers::Functions; + DB = Renderers::Functions; + DM7BG1 = M7M1 ? Renderers::Functions : Renderers::Functions; + DM7BG2 = M7M2 ? Renderers::Functions : Renderers::Functions; + GFX.LinesPerTile = 4; + } + else + { + DT = Renderers::Functions; + DCT = Renderers::Functions; + DMP = Renderers::Functions; + DB = Renderers::Functions; + DM7BG1 = M7M1 ? Renderers::Functions : Renderers::Functions; + DM7BG2 = M7M2 ? Renderers::Functions : Renderers::Functions; + 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++; + } + if (IPPU.MaxBrightness != 0xf) + { + if (i == 1) + i = 7; + else if (i == 3) + i = 8; + } + + } + + 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; + } +} diff --git a/snes9x/tile.h b/snes9x/tile.h new file mode 100644 index 0000000..1a07a40 --- /dev/null +++ b/snes9x/tile.h @@ -0,0 +1,14 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _TILE_H_ +#define _TILE_H_ + +void S9xInitTileRenderer (void); +void S9xSelectTileRenderers (int, bool8, bool8); +void S9xSelectTileConverter (int, bool8, bool8, bool8); + +#endif diff --git a/snes9x/tileimpl-h2x1.cpp b/snes9x/tileimpl-h2x1.cpp new file mode 100644 index 0000000..37143ad --- /dev/null +++ b/snes9x/tileimpl-h2x1.cpp @@ -0,0 +1,47 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#define _TILEIMPL_CPP_ +#include "tileimpl.h" + +namespace TileImpl { + + template + void HiresBase::Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2) + { + if (Z1 > GFX.DB[Offset + 2 * N] && (M)) + { + GFX.S[Offset + 2 * N + 1] = MATH::Calc(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); + if ((OffsetInLine + 2 * N ) != (SNES_WIDTH - 1) << 1) + GFX.S[Offset + 2 * N + 2] = MATH::Calc((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); + if ((OffsetInLine + 2 * N) == 0 || (OffsetInLine + 2 * N) == GFX.RealPPL) + GFX.S[Offset + 2 * N] = MATH::Calc((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; + } + } + + + // hires double width + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + + // hires double width interlace + template struct Renderers; + template struct Renderers; + template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + +} // namespace TileImpl diff --git a/snes9x/tileimpl-n1x1.cpp b/snes9x/tileimpl-n1x1.cpp new file mode 100644 index 0000000..1c37c60 --- /dev/null +++ b/snes9x/tileimpl-n1x1.cpp @@ -0,0 +1,34 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#define _TILEIMPL_CPP_ +#include "tileimpl.h" + +namespace TileImpl { + + template + void Normal1x1Base::Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2) + { + (void) OffsetInLine; + if (Z1 > GFX.DB[Offset + N] && (M)) + { + GFX.S[Offset + N] = MATH::Calc(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + N], GFX.SubZBuffer[Offset + N]); + GFX.DB[Offset + N] = Z2; + } + } + + + // normal width + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + +} // namespace TileImpl diff --git a/snes9x/tileimpl-n2x1.cpp b/snes9x/tileimpl-n2x1.cpp new file mode 100644 index 0000000..4025c69 --- /dev/null +++ b/snes9x/tileimpl-n2x1.cpp @@ -0,0 +1,44 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#define _TILEIMPL_CPP_ +#include "tileimpl.h" + +namespace TileImpl { + + template + void Normal2x1Base::Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2) + { + (void) OffsetInLine; + if (Z1 > GFX.DB[Offset + 2 * N] && (M)) + { + GFX.S[Offset + 2 * N] = GFX.S[Offset + 2 * N + 1] = MATH::Calc(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; + } + } + + + // normal double width + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + template struct Renderers; + + // normal double width interlace + template struct Renderers; + template struct Renderers; + template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + //template struct Renderers; + +} // namespace TileImpl diff --git a/snes9x/tileimpl.h b/snes9x/tileimpl.h new file mode 100644 index 0000000..9ea546e --- /dev/null +++ b/snes9x/tileimpl.h @@ -0,0 +1,800 @@ +/*****************************************************************************\ + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + This file is licensed under the Snes9x License. + For further information, consult the LICENSE file in the root directory. +\*****************************************************************************/ + +#ifndef _TILEIMPL_H_ +#define _TILEIMPL_H_ + +#include "snes9x.h" +#include "ppu.h" +#include "tile.h" + +extern struct SLineMatrixData LineMatrixData[240]; + + +namespace TileImpl { + + struct BPProgressive + { + enum { Pitch = 1 }; + static alwaysinline uint32 Get(uint32 StartLine) { return StartLine; } + }; + + // Interlace: Only draw every other line, so we'll redefine bpstart_t and Pitch to do so. + // Otherwise, it's the same as Normal2x1/Hires2x1. + struct BPInterlace + { + enum { Pitch = 2 }; + static alwaysinline uint32 Get(uint32 StartLine) { return StartLine * 2 + BG.InterlaceLine; } + }; + + + // The 1x1 pixel plotter, for speedhacking modes. + template + struct Normal1x1Base + { + enum { Pitch = BPSTART::Pitch }; + typedef BPSTART bpstart_t; + + static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); + }; + + template + struct Normal1x1 : public Normal1x1Base {}; + + + // The 2x1 pixel plotter, for normal rendering when we've used hires/interlace already this frame. + template + struct Normal2x1Base + { + enum { Pitch = BPSTART::Pitch }; + typedef BPSTART bpstart_t; + + static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); + }; + + template + struct Normal2x1 : public Normal2x1Base {}; + template + struct Interlace : public Normal2x1Base {}; + + + // 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. + template + struct HiresBase + { + enum { Pitch = BPSTART::Pitch }; + typedef BPSTART bpstart_t; + + static void Draw(int N, int M, uint32 Offset, uint32 OffsetInLine, uint8 Pix, uint8 Z1, uint8 Z2); + }; + + template + struct Hires : public HiresBase {}; + template + struct HiresInterlace : public HiresBase {}; + + + class CachedTile + { + public: + CachedTile(uint32 tile) : Tile(tile) {} + + alwaysinline void GetCachedTile() + { + 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); + } + } + + alwaysinline bool IsBlankTile() const + { + return ((Tile & H_FLIP) ? BG.BufferedFlip[TileNumber] : BG.Buffered[TileNumber]) == BLANK_TILE; + } + + alwaysinline void SelectPalette() const + { + if (BG.DirectColourMode) + { + 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; + } + + alwaysinline uint8* Ptr() const + { + return pCache; + } + + private: + uint8 *pCache; + uint32 Tile; + uint32 TileNumber; + uint32 TileAddr; + }; + + + struct NOMATH + { + static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) + { + return Main; + } + }; + typedef NOMATH Blend_None; + + template + struct REGMATH + { + static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) + { + return Op::fn(Main, (SD & 0x20) ? Sub : GFX.FixedColour); + } + }; + typedef REGMATH Blend_Add; + typedef REGMATH Blend_Sub; + typedef REGMATH Blend_AddBrightness; + + template + struct MATHF1_2 + { + static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) + { + return GFX.ClipColors ? Op::fn(Main, GFX.FixedColour) : Op::fn1_2(Main, GFX.FixedColour); + } + }; + typedef MATHF1_2 Blend_AddF1_2; + typedef MATHF1_2 Blend_SubF1_2; + + template + struct MATHS1_2 + { + static alwaysinline uint16 Calc(uint16 Main, uint16 Sub, uint8 SD) + { + return GFX.ClipColors ? REGMATH::Calc(Main, Sub, SD) : (SD & 0x20) ? Op::fn1_2(Main, Sub) : Op::fn(Main, GFX.FixedColour); + } + }; + typedef MATHS1_2 Blend_AddS1_2; + typedef MATHS1_2 Blend_SubS1_2; + typedef MATHS1_2 Blend_AddS1_2Brightness; + + template< + template class TILE, + template class PIXEL + > + struct Renderers + { + enum { Pitch = PIXEL::Pitch }; + typedef typename TILE< PIXEL >::call_t call_t; + + static call_t Functions[9]; + }; + + #ifdef _TILEIMPL_CPP_ + template< + template class TILE, + template class PIXEL + > + typename Renderers::call_t Renderers::Functions[9] = + { + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + TILE< PIXEL >::Draw, + }; + #endif + + // Basic routine to render an unclipped tile. + // Input parameters: + // bpstart_t = 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 OFFSET_IN_LINE \ + uint32 OffsetInLine = Offset % GFX.RealPPL; + #define DRAW_PIXEL(N, M) PIXEL::Draw(N, M, Offset, OffsetInLine, Pix, Z1, Z2) + #define Z1 GFX.Z1 + #define Z2 GFX.Z2 + + template + struct DrawTile16 + { + typedef void (*call_t)(uint32, uint32, uint32, uint32); + + enum { Pitch = PIXEL::Pitch }; + typedef typename PIXEL::bpstart_t bpstart_t; + + static void Draw(uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount) + { + CachedTile cache(Tile); + int32 l; + uint8 *bp, Pix; + + cache.GetCachedTile(); + if (cache.IsBlankTile()) + return; + cache.SelectPalette(); + + if (!(Tile & (V_FLIP | H_FLIP))) + { + bp = cache.Ptr() + bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) + { + for (int x = 0; x < 8; x++) { + Pix = bp[x]; DRAW_PIXEL(x, Pix); + } + } + } + else + if (!(Tile & V_FLIP)) + { + bp = cache.Ptr() + bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) + { + for (int x = 0; x < 8; x++) { + Pix = bp[7 - x]; DRAW_PIXEL(x, Pix); + } + } + } + else + if (!(Tile & H_FLIP)) + { + bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) + { + for (int x = 0; x < 8; x++) { + Pix = bp[x]; DRAW_PIXEL(x, Pix); + } + } + } + else + { + bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) + { + for (int x = 0; x < 8; x++) { + Pix = bp[7 - x]; DRAW_PIXEL(x, Pix); + } + } + } + } + }; + + #undef Z1 + #undef Z2 + + // Basic routine to render a clipped tile. Inputs same as above. + + #define Z1 GFX.Z1 + #define Z2 GFX.Z2 + + template + struct DrawClippedTile16 + { + typedef void (*call_t)(uint32, uint32, uint32, uint32, uint32, uint32); + + enum { Pitch = PIXEL::Pitch }; + typedef typename PIXEL::bpstart_t bpstart_t; + + static void Draw(uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount) + { + CachedTile cache(Tile); + int32 l; + uint8 *bp, Pix, w; + + cache.GetCachedTile(); + if (cache.IsBlankTile()) + return; + cache.SelectPalette(); + + if (!(Tile & (V_FLIP | H_FLIP))) + { + bp = cache.Ptr() + bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) + { + w = Width; + switch (StartPixel) + { + case 0: Pix = bp[0]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ + case 1: Pix = bp[1]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ + case 2: Pix = bp[2]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ + case 3: Pix = bp[3]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ + case 4: Pix = bp[4]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ + case 5: Pix = bp[5]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ + case 6: Pix = bp[6]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ + case 7: Pix = bp[7]; DRAW_PIXEL(7, Pix); break; + } + } + } + else + if (!(Tile & V_FLIP)) + { + bp = cache.Ptr() + bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp += 8 * Pitch, Offset += GFX.PPL) + { + w = Width; + switch (StartPixel) + { + case 0: Pix = bp[7]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ + case 1: Pix = bp[6]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ + case 2: Pix = bp[5]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ + case 3: Pix = bp[4]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ + case 4: Pix = bp[3]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ + case 5: Pix = bp[2]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ + case 6: Pix = bp[1]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ + case 7: Pix = bp[0]; DRAW_PIXEL(7, Pix); break; + } + } + } + else + if (!(Tile & H_FLIP)) + { + bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) + { + w = Width; + switch (StartPixel) + { + case 0: Pix = bp[0]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ + case 1: Pix = bp[1]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ + case 2: Pix = bp[2]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ + case 3: Pix = bp[3]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ + case 4: Pix = bp[4]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ + case 5: Pix = bp[5]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ + case 6: Pix = bp[6]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ + case 7: Pix = bp[7]; DRAW_PIXEL(7, Pix); break; + } + } + } + else + { + bp = cache.Ptr() + 56 - bpstart_t::Get(StartLine); + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, bp -= 8 * Pitch, Offset += GFX.PPL) + { + w = Width; + switch (StartPixel) + { + case 0: Pix = bp[7]; DRAW_PIXEL(0, Pix); if (!--w) break; /* Fall through */ + case 1: Pix = bp[6]; DRAW_PIXEL(1, Pix); if (!--w) break; /* Fall through */ + case 2: Pix = bp[5]; DRAW_PIXEL(2, Pix); if (!--w) break; /* Fall through */ + case 3: Pix = bp[4]; DRAW_PIXEL(3, Pix); if (!--w) break; /* Fall through */ + case 4: Pix = bp[3]; DRAW_PIXEL(4, Pix); if (!--w) break; /* Fall through */ + case 5: Pix = bp[2]; DRAW_PIXEL(5, Pix); if (!--w) break; /* Fall through */ + case 6: Pix = bp[1]; DRAW_PIXEL(6, Pix); if (!--w) break; /* Fall through */ + case 7: Pix = bp[0]; DRAW_PIXEL(7, Pix); break; + } + } + } + } + }; + + #undef Z1 + #undef Z2 + + // Basic routine to render a single mosaic pixel. + // DRAW_PIXEL, bpstart_t, Z1, Z2 and Pix are the same as above, but Pitch is not used. + + #define Z1 GFX.Z1 + #define Z2 GFX.Z2 + + template + struct DrawMosaicPixel16 + { + typedef void (*call_t)(uint32, uint32, uint32, uint32, uint32, uint32); + + typedef typename PIXEL::bpstart_t bpstart_t; + + static void Draw(uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount) + { + CachedTile cache(Tile); + int32 l, w; + uint8 Pix; + + cache.GetCachedTile(); + if (cache.IsBlankTile()) + return; + cache.SelectPalette(); + + if (Tile & H_FLIP) + StartPixel = 7 - StartPixel; + + if (Tile & V_FLIP) + Pix = cache.Ptr()[56 - bpstart_t::Get(StartLine) + StartPixel]; + else + Pix = cache.Ptr()[bpstart_t::Get(StartLine) + StartPixel]; + + if (Pix) + { + OFFSET_IN_LINE; + for (l = LineCount; l > 0; l--, Offset += GFX.PPL) + { + for (w = Width - 1; w >= 0; w--) + DRAW_PIXEL(w, 1); + } + } + } + }; + + #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_t + // (or interlace at all, really). + // The backdrop is always depth = 1, so Z1 = Z2 = 1. And backdrop is always color 0. + + #define Z1 1 + #define Z2 1 + #define Pix 0 + + template + struct DrawBackdrop16 + { + typedef void (*call_t)(uint32 Offset, uint32 Left, uint32 Right); + + static void Draw(uint32 Offset, uint32 Left, uint32 Right) + { + uint32 l, x; + + GFX.RealScreenColors = IPPU.ScreenColors; + GFX.ScreenColors = GFX.ClipColors ? BlackColourMap : GFX.RealScreenColors; + + OFFSET_IN_LINE; + for (l = GFX.StartY; l <= GFX.EndY; l++, Offset += GFX.PPL) + { + for (x = Left; x < Right; x++) + DRAW_PIXEL(x, 1); + } + } + }; + + #undef Pix + #undef Z1 + #undef Z2 + #undef DRAW_PIXEL + + // Basic routine to render a chunk of a Mode 7 BG. + // Mode 7 has no interlace, so bpstart_t 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)) + + #define DRAW_PIXEL(N, M) PIXEL::Draw(N, M, Offset, OffsetInLine, Pix, OP::Z1(D, b), OP::Z2(D, b)) + + struct DrawMode7BG1_OP + { + enum { + MASK = 0xff, + BG = 0 + }; + static uint8 Z1(int D, uint8 b) { return D + 7; } + static uint8 Z2(int D, uint8 b) { return D + 7; } + static uint8 DCMODE() { return Memory.FillRAM[0x2130] & 1; } + }; + struct DrawMode7BG2_OP + { + enum { + MASK = 0x7f, + BG = 1 + }; + static uint8 Z1(int D, uint8 b) { return D + ((b & 0x80) ? 11 : 3); } + static uint8 Z2(int D, uint8 b) { return D + ((b & 0x80) ? 11 : 3); } + static uint8 DCMODE() { return 0; } + }; + + template + struct DrawTileNormal + { + typedef void (*call_t)(uint32 Left, uint32 Right, int D); + + static void Draw(uint32 Left, uint32 Right, int D) + { + uint8 *VRAM1 = Memory.VRAM + 1; + + if (OP::DCMODE()) + { + 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]; + + OFFSET_IN_LINE; + 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)); + + Pix = b & OP::MASK; DRAW_PIXEL(x, Pix); + } + } + 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; + + Pix = b & OP::MASK; DRAW_PIXEL(x, Pix); + } + } + } + } + }; + + template + struct DrawMode7BG1 : public DrawTileNormal {}; + template + struct DrawMode7BG2 : public DrawTileNormal {}; + + template + struct DrawTileMosaic + { + typedef void (*call_t)(uint32 Left, uint32 Right, int D); + + static void Draw(uint32 Left, uint32 Right, int D) + { + uint8 *VRAM1 = Memory.VRAM + 1; + + if (OP::DCMODE()) + { + 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[OP::BG]) + { + HMosaic = PPU.Mosaic; + MLeft -= MLeft % HMosaic; + MRight += HMosaic - 1; + MRight -= MRight % HMosaic; + } + + uint32 Offset = StartY * GFX.PPL; + struct SLineMatrixData *l = &LineMatrixData[StartY]; + + OFFSET_IN_LINE; + 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 & OP::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 & OP::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; + } + } + }; + + template + struct DrawMode7MosaicBG1 : public DrawTileMosaic {}; + template + struct DrawMode7MosaicBG2 : public DrawTileMosaic {}; + + #undef DRAW_PIXEL + +} // namespace TileImpl + +#endif diff --git a/snes9x/unix/Makefile b/snes9x/unix/Makefile new file mode 100644 index 0000000..55cd7a5 --- /dev/null +++ b/snes9x/unix/Makefile @@ -0,0 +1,93 @@ +#S9XDEBUGGER=1 +#S9XNETPLAY=1 +#S9XZIP=1 +S9XJMA=1 +#SYSTEM_ZIP=1 + +OS = `Hi3521A` +BUILDDIR = . + +OBJECTS = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../msu1.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../tileimpl-n1x1.o ../tileimpl-n2x1.o ../tileimpl-h2x1.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o ../statemanager.o ../sha256.o ../bml.o ../compat.o sample_comm_vo.o sample_comm_sys.o hifb.o main.o +DEFS = -DMITSHM + +ifdef S9XDEBUGGER +OBJECTS += ../debug.o ../fxdbg.o +endif + +ifdef S9XNETPLAY +OBJECTS += ../netplay.o ../server.o +endif + +ifdef S9XZIP +OBJECTS += ../loadzip.o +ifndef SYSTEM_ZIP +OBJECTS += ../unzip/ioapi.o ../unzip/unzip.o +INCLUDES = -I../unzip/ +endif +endif + +ifdef S9XJMA +OBJECTS += ../jma/7zlzma.o ../jma/crc32.o ../jma/iiostrm.o ../jma/inbyte.o ../jma/jma.o ../jma/lzma.o ../jma/lzmadec.o ../jma/s9x-jma.o ../jma/winout.o +endif + +CCC = arm-hisiv400-linux-gnueabi-g++ +CC = arm-hisiv400-linux-gnueabi-gcc +GASM = arm-hisiv400-linux-gnueabi-g++ +INCLUDES += -I. -I.. -I../apu/ -I../apu/bapu -I../jma/ -I../filter/ + +CCFLAGS = -g -O2 -O3 -fomit-frame-pointer -fno-exceptions -fno-rtti -pedantic -Wall -W -Wno-unused-parameter -DJOYSTICK_SUPPORT -DJMA_SUPPORT -DHAVE_MKSTEMP -DHAVE_STRINGS_H -DHAVE_SYS_IOCTL_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR -DNOSOUND $(DEFS) +CFLAGS = $(CCFLAGS) + +.SUFFIXES: .o .cpp .c .cc .h .m .i .s .obj + +all: snes9x + +snes9x: $(OBJECTS) + $(CCC) $(LDFLAGS) $(INCLUDES) -o $@ $(OBJECTS) -lm -ldl -lpthread libs/libmpi.a libs/libmd.a libs/libive.a libs/libupvqe.a libs/libdnvqe.a libs/libhdmi.a libs/libtde.a libs/libjpeg.a libs/libVoiceEngine.a + +../jma/s9x-jma.o: ../jma/s9x-jma.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/7zlzma.o: ../jma/7zlzma.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/crc32.o: ../jma/crc32.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/iiostrm.o: ../jma/iiostrm.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/inbyte.o: ../jma/inbyte.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/jma.o: ../jma/jma.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/lzma.o: ../jma/lzma.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/lzmadec.o: ../jma/lzmadec.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ +../jma/winout.o: ../jma/winout.cpp + $(CCC) $(INCLUDES) -c $(CCFLAGS) -fexceptions $*.cpp -o $@ + +.cpp.o: + $(CCC) $(INCLUDES) -c $(CCFLAGS) $*.cpp -o $@ + +.c.o: + $(CC) $(INCLUDES) -c $(CCFLAGS) $*.c -o $@ + +.cpp.S: + $(GASM) $(INCLUDES) -S $(CCFLAGS) $*.cpp -o $@ + +.cpp.i: + $(GASM) $(INCLUDES) -E $(CCFLAGS) $*.cpp -o $@ + +.S.o: + $(GASM) $(INCLUDES) -c $(CCFLAGS) $*.S -o $@ + +.S.i: + $(GASM) $(INCLUDES) -c -E $(CCFLAGS) $*.S -o $@ + +.s.o: + @echo Compiling $*.s + sh-elf-as -little $*.s -o $@ + +.obj.o: + cp $*.obj $*.o + +clean: + rm -f $(OBJECTS) diff --git a/snes9x/unix/hifb.cpp b/snes9x/unix/hifb.cpp new file mode 100644 index 0000000..689086a --- /dev/null +++ b/snes9x/unix/hifb.cpp @@ -0,0 +1,194 @@ + +#include "hifb.hpp" + +HI_S32 g_hFrameBuffer; +HIFB_BUFFER_S g_stCanvasBuf; +void* g_BackBuffer; + +static struct fb_bitfield s_r16 = {10, 5, 0}; +static struct fb_bitfield s_g16 = {5, 5, 0}; +static struct fb_bitfield s_b16 = {0, 5, 0}; +static struct fb_bitfield s_a16 = {15, 1, 0}; + +HI_BOOL HiInitDisplay() { + HI_S32 s32Ret = HI_SUCCESS; + HI_U32 u32PicWidth = SCREEN_WIDTH; + HI_U32 u32PicHeight = SCREEN_HEIGHT; + SIZE_S stSize; + + VO_LAYER VoLayer = 0; + VO_PUB_ATTR_S stPubAttr; + VO_VIDEO_LAYER_ATTR_S stLayerAttr; + HI_U32 u32VoFrmRate; + + HI_BOOL bShow = HI_TRUE; + HIFB_LAYER_INFO_S stLayerInfo = {}; + HIFB_POINT_S stPoint = {}; + struct fb_var_screeninfo stVarInfo; + HIFB_COLORKEY_S stColorKey; + VB_CONF_S stVbConf; + HI_U32 u32BlkSize; + + /****************************************** + step 1: init variable + ******************************************/ + memset(&stVbConf, 0, sizeof(VB_CONF_S)); + + u32BlkSize = CEILING_2_POWER(u32PicWidth, SAMPLE_SYS_ALIGN_WIDTH) * + CEILING_2_POWER(u32PicHeight, SAMPLE_SYS_ALIGN_WIDTH) * 2; + + stVbConf.u32MaxPoolCnt = 128; + stVbConf.astCommPool[0].u32BlkSize = u32BlkSize; + stVbConf.astCommPool[0].u32BlkCnt = 6; + + /****************************************** + step 2: mpp system init. + ******************************************/ + s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("system init failed with %d!\n", s32Ret); + return HI_FALSE; + } + + /****************************************** + step 3: start vo hd0. + *****************************************/ + s32Ret = HI_MPI_VO_UnBindGraphicLayer(GRAPHICS_LAYER_HC0, SAMPLE_VO_DEV_DHD0); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("UnBindGraphicLayer failed with %d!\n", s32Ret); + return HI_FALSE; + } + + s32Ret = HI_MPI_VO_BindGraphicLayer(GRAPHICS_LAYER_HC0, SAMPLE_VO_DEV_DHD0); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("BindGraphicLayer failed with %d!\n", s32Ret); + return HI_FALSE; + } + + stPubAttr.enIntfSync = VO_OUTPUT_640x480_60; + stPubAttr.enIntfType = VO_INTF_HDMI; + stPubAttr.u32BgColor = 0x000000; + + stLayerAttr.bClusterMode = HI_FALSE; + stLayerAttr.bDoubleFrame = HI_FALSE; + stLayerAttr.enPixFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420; + + u32VoFrmRate = 60; + stSize.u32Width = SCREEN_WIDTH; + stSize.u32Height = SCREEN_HEIGHT; + + memcpy(&stLayerAttr.stImageSize, &stSize, sizeof(stSize)); + + stLayerAttr.u32DispFrmRt = 60; + stLayerAttr.stDispRect.s32X = 0; + stLayerAttr.stDispRect.s32Y = 0; + stLayerAttr.stDispRect.u32Width = stSize.u32Width; + stLayerAttr.stDispRect.u32Height = stSize.u32Height; + + s32Ret = SAMPLE_COMM_VO_StartDev(SAMPLE_VO_DEV_DHD0, &stPubAttr); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("start vo dev failed with %d!\n", s32Ret); + return HI_FALSE; + } + + s32Ret = SAMPLE_COMM_VO_StartLayer(VoLayer, &stLayerAttr); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("start vo layer failed with %d!\n", s32Ret); + return HI_FALSE; + } + + if (stPubAttr.enIntfType & VO_INTF_HDMI) { + s32Ret = SAMPLE_COMM_VO_HdmiStart(stPubAttr.enIntfSync); + if (HI_SUCCESS != s32Ret) { + SAMPLE_PRT("start HDMI failed with %d!\n", s32Ret); + return HI_FALSE; + } + } + + if ((g_hFrameBuffer = open("/dev/fb0", O_RDWR, NULL)) < 0) { + SAMPLE_PRT("failed to open /dev/fb0...\n"); + return HI_FALSE; + } + + /*all layer surport colorkey*/ + stColorKey.bKeyEnable = HI_TRUE; + stColorKey.u32Key = 0x0; + if (ioctl(g_hFrameBuffer, FBIOPUT_COLORKEY_HIFB, &stColorKey) < 0) { + SAMPLE_PRT("FBIOPUT_COLORKEY_HIFB!\n"); + return HI_FALSE; + } + + s32Ret = ioctl(g_hFrameBuffer, FBIOGET_VSCREENINFO, &stVarInfo); + if (s32Ret < 0) { + SAMPLE_PRT("GET_VSCREENINFO failed!\n"); + return HI_FALSE; + } + + if (ioctl(g_hFrameBuffer, FBIOPUT_SCREEN_ORIGIN_HIFB, &stPoint) < 0) { + SAMPLE_PRT("set screen original show position failed!\n"); + return HI_FALSE; + } + + stVarInfo.transp = s_a16; + stVarInfo.red = s_r16; + stVarInfo.green = s_g16; + stVarInfo.blue = s_b16; + stVarInfo.bits_per_pixel = 16; + stVarInfo.activate = FB_ACTIVATE_NOW; + stVarInfo.xres = stVarInfo.xres_virtual = SCREEN_WIDTH; + stVarInfo.yres = stVarInfo.yres_virtual = SCREEN_HEIGHT; + + if (ioctl(g_hFrameBuffer, FBIOPUT_VSCREENINFO, &stVarInfo) < 0) { + SAMPLE_PRT("PUT_VSCREENINFO failed!\n"); + return HI_FALSE; + } + + stLayerInfo.BufMode = HIFB_LAYER_BUF_ONE; + stLayerInfo.u32Mask = HIFB_LAYERMASK_BUFMODE; + + if (ioctl(g_hFrameBuffer, FBIOPUT_LAYER_INFO, &stLayerInfo) < 0) { + SAMPLE_PRT("PUT_LAYER_INFO failed!\n"); + return HI_FALSE; + } + + if (ioctl(g_hFrameBuffer, FBIOPUT_SHOW_HIFB, &bShow) < 0) { + SAMPLE_PRT("FBIOPUT_SHOW_HIFB failed!\n"); + return HI_FALSE; + } + + /* allocate mmz memory for back buffer... */ + if (HI_FAILURE == HI_MPI_SYS_MmzAlloc(&g_stCanvasBuf.stCanvas.u32PhyAddr, + &g_BackBuffer, NULL, NULL, + SCREEN_WIDTH * SCREEN_HEIGHT * 2)) { + SAMPLE_PRT("allocate memory (640*480*2 bytes) failed\n"); + return HI_FALSE; + } + + /* when we call RefreshScreen we will re-draw the entire screen... */ + g_stCanvasBuf.UpdateRect.x = 0; + g_stCanvasBuf.UpdateRect.y = 0; + g_stCanvasBuf.UpdateRect.w = SCREEN_WIDTH; + g_stCanvasBuf.UpdateRect.h = SCREEN_HEIGHT; + + /* meta data about the back buffer... */ + g_stCanvasBuf.stCanvas.u32Height = SCREEN_HEIGHT; + g_stCanvasBuf.stCanvas.u32Width = SCREEN_WIDTH; + g_stCanvasBuf.stCanvas.u32Pitch = SCREEN_WIDTH * 2; + g_stCanvasBuf.stCanvas.enFmt = HIFB_FMT_ARGB1555; + + memset(g_BackBuffer, 0x00, + g_stCanvasBuf.stCanvas.u32Pitch * g_stCanvasBuf.stCanvas.u32Height); + + /* finally open TDE so we can do hardware accelerated color conversions... */ + s32Ret = HI_TDE2_Open(); + if (s32Ret < 0) { + SAMPLE_PRT("HI_TDE2_Open failed :%d!\n", s32Ret); + return HI_FALSE; + } + + return HI_TRUE; +} + +void RefreshScreen() { + ioctl(g_hFrameBuffer, FBIO_REFRESH, &g_stCanvasBuf); +} \ No newline at end of file diff --git a/snes9x/unix/hifb.hpp b/snes9x/unix/hifb.hpp new file mode 100644 index 0000000..5cee0be --- /dev/null +++ b/snes9x/unix/hifb.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpp/hi_comm_vo.h" +#include "mpp/hi_tde_api.h" +#include "mpp/hi_tde_type.h" +#include "mpp/hifb.h" +#include "sample_comm.h" + +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 480 + +#define SCALE_WIDTH 504 +#define SCALE_HEIGHT 480 + +extern HI_S32 g_hFrameBuffer; +extern HIFB_BUFFER_S g_stCanvasBuf; +extern void* g_BackBuffer; + +extern HI_U32 g_pSnesBackBufferPhys; +extern void* g_pSnesBackBufferVirt; + +extern HI_U32 g_pScaleBufferPhys; +extern void* g_pScaleBufferVirt; + +HI_BOOL HiInitDisplay(); +void RefreshScreen(); \ No newline at end of file diff --git a/snes9x/unix/main.cpp b/snes9x/unix/main.cpp new file mode 100644 index 0000000..02b4d73 --- /dev/null +++ b/snes9x/unix/main.cpp @@ -0,0 +1,478 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "apu/apu.h" +#include "blit.h" +#include "conffile.h" +#include "controls.h" +#include "display.h" +#include "gfx.h" +#include "hifb.hpp" +#include "hq2x.h" +#include "memmap.h" +#include "snes9x.h" + +#define MAP_KEY(x, y) \ + { \ + s9xcommand_t cmd; \ + \ + cmd = S9xGetCommandT(y); \ + S9xMapInput(x, &cmd); \ + } + +HI_U32 g_pSnesBackBufferPhys; +void* g_pSnesBackBufferVirt; + +HI_U32 g_pScaleBufferPhys; +void* g_pScaleBufferVirt; + +uint8 js_mod[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +int js_fd[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; +const char* js_device[8] = {"/dev/js0", "/dev/js1", "/dev/js2", "/dev/js3", + "/dev/js4", "/dev/js5", "/dev/js6", "/dev/js7"}; +bool8 js_unplugged[8] = {FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE}; + +void S9xCloseSnapshotFile(STREAM file) {} +void S9xExit(void) {} +void S9xAutoSaveSRAM(void) {} +void S9xToggleSoundChannel(int c) {} +void S9xSyncSpeed(void) {} +void S9xMessage(int type, int number, const char* message) {} +void S9xParsePortConfig(ConfigFile& conf, int pass) {} + +bool8 S9xMapInput(const char* n, s9xcommand_t* cmd) { + int i, j, d; + char* c; + char buf[4] = "M1+"; + + if (!strncmp(n, "PseudoPointer", 13) && n[13] >= '1' && n[13] <= '8' && + n[14] == '\0') + return (S9xMapPointer(PseudoPointerBase + (n[13] - '1'), *cmd, false)); + + if (!strncmp(n, "PseudoButton", 12) && isdigit(n[12]) && + (j = strtol(n + 12, &c, 10)) < 256 && (c == NULL || *c == '\0')) + return (S9xMapButton(PseudoButtonBase + j, *cmd, false)); + + if (n[0] != 'J' || !isdigit(n[1]) || !isdigit(n[2]) || n[3] != ':') + return false; + + d = ((n[1] - '0') * 10 + (n[2] - '0')) << 24; + d |= 0x80000000; + i = 4; + if (!strncmp(n + i, "X+", 2)) { + d |= 0x4000; + i += 2; + } else { + for (buf[1] = '1'; buf[1] <= '8'; buf[1]++) { + if (!strncmp(n + i, buf, 3)) { + d |= 1 << (buf[1] - '1' + 16); + i += 3; + } + } + } + + if (!strncmp(n + i, "Axis", 4)) { + d |= 0x8000; + i += 4; + } else if (n[i] == 'B') + i++; + else + return false; + + d |= j = strtol(n + i, &c, 10); + if ((c != NULL && *c != '\0') || j > 0x3fff) + return false; + + if (d & 0x8000) + return (S9xMapAxis(d, *cmd, false)); + + return (S9xMapButton(d, *cmd, false)); +} + +void InitJoysticks(void) { + int version; + unsigned char axes, buttons; + + if ((js_fd[0] = open(js_device[0], O_RDONLY | O_NONBLOCK)) == -1) { + fprintf(stderr, "joystick: No joystick found.\n"); + return; + } + + if (ioctl(js_fd[0], JSIOCGVERSION, &version) == -1) { + fprintf(stderr, + "joystick: You need at least driver version 1.0 for joystick " + "support.\n"); + close(js_fd[0]); + return; + } + + for (int i = 1; i < 8; i++) + js_fd[i] = open(js_device[i], O_RDONLY | O_NONBLOCK); + + char name[130]; + bzero(name, 128); + + if (ioctl(js_fd[0], JSIOCGNAME(128), name) > 0) { + printf("Using %s (%s) as joystick1\n", name, js_device[0]); + + for (int i = 1; i < 8; i++) { + if (js_fd[i] > 0) { + ioctl(js_fd[i], JSIOCGNAME(128), name); + printf(" and %s (%s) as joystick%d\n", name, js_device[i], i + 1); + } + } + } else { + ioctl(js_fd[0], JSIOCGAXES, &axes); + ioctl(js_fd[0], JSIOCGBUTTONS, &buttons); + printf("Using %d-axis %d-button joystick (%s) as joystick1\n", axes, + buttons, js_device[0]); + + for (int i = 1; i < 8; i++) { + if (js_fd[i] > 0) { + ioctl(js_fd[i], JSIOCGAXES, &axes); + ioctl(js_fd[i], JSIOCGBUTTONS, &buttons); + printf(" and %d-axis %d-button joystick (%s) as joystick%d\n", axes, + buttons, js_device[i], i + 1); + } + } + } +} + +bool8 ReadJoysticks(void) { + // track if ANY joystick event happened this frame + int js_latch = FALSE; + struct js_event js_ev; + + for (int i = 0; i < 8; i++) { + // Try to reopen unplugged sticks + if (js_unplugged[i]) { + js_fd[i] = open(js_device[i], O_RDONLY | O_NONBLOCK); + if (js_fd[i] >= 0) { + fprintf(stderr, "Joystick %d reconnected.\n", i); + js_unplugged[i] = FALSE; + js_latch = TRUE; + } + } + + // skip sticks without valid file desc + if (js_fd[i] < 0) + continue; + + while (read(js_fd[i], &js_ev, sizeof(struct js_event)) == + sizeof(struct js_event)) { + switch (js_ev.type) { + case JS_EVENT_AXIS: + S9xReportAxis(0x8000c000 | (i << 24) | js_ev.number, js_ev.value); + S9xReportAxis( + 0x80008000 | (i << 24) | (js_mod[i] << 16) | js_ev.number, + js_ev.value); + js_latch = TRUE; + break; + + case JS_EVENT_BUTTON: + case JS_EVENT_BUTTON | JS_EVENT_INIT: + S9xReportButton(0x80004000 | (i << 24) | js_ev.number, js_ev.value); + S9xReportButton( + 0x80000000 | (i << 24) | (js_mod[i] << 16) | js_ev.number, + js_ev.value); + js_latch = TRUE; + break; + } + } + + /* EAGAIN is returned when the queue is empty */ + if (errno != EAGAIN) { + // Error reading joystick. + fprintf(stderr, "Error reading joystick %d!\n", i); + + // Mark for reconnect attempt. + js_unplugged[i] = TRUE; + + for (unsigned int j = 0; j < 16; j++) { + // Center all axis + S9xReportAxis(0x8000c000 | (i << 24) | j, 0); + S9xReportAxis(0x80008000 | (i << 24) | (js_mod[i] << 16) | j, 0); + // Unpress all buttons. + S9xReportButton(0x80004000 | (i << 24) | j, 0); + S9xReportButton(0x80000000 | (i << 24) | (js_mod[i] << 16) | j, 0); + } + + js_latch = TRUE; + } + } + return js_latch; +} + +const char* S9xStringInput(const char* message) { + static char buffer[256]; + + printf("%s: ", message); + fflush(stdout); + + if (fgets(buffer, sizeof(buffer) - 2, stdin)) + return (buffer); + + return (NULL); +} + +bool8 S9xContinueUpdate(int width, int height) { + return true; +} + +bool S9xPollButton(uint32 id, bool* pressed) { + return false; +} + +bool S9xPollAxis(uint32 id, int16* value) { + return false; +} + +bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM* file) { + return true; +} + +bool8 S9xInitUpdate(void) { + return true; +} + +bool8 S9xDeinitUpdate(int width, int height) { + TDE2_RECT_S stSrcRect, stDstRect, stScaleRect; + TDE2_SURFACE_S stSrc, stDst, stScale; + TDE2_OPT_S stOpt = {TDE2_ALUCMD_NONE}; + TDE_HANDLE s32Handle; + HI_S32 s32Ret; + + /* 1. start job */ + s32Handle = HI_TDE2_BeginJob(); + if (HI_ERR_TDE_INVALID_HANDLE == s32Handle) { + SAMPLE_PRT("start job failed!\n"); + return false; + } + + /* copy (scale and pixel convert) from snes buffer to scale buffer... */ + + stSrcRect.s32Xpos = 0; + stSrcRect.s32Ypos = 0; + stSrcRect.u32Height = SNES_HEIGHT; + stSrcRect.u32Width = SNES_WIDTH; + + stSrc.enColorFmt = TDE2_COLOR_FMT_RGB565; + stSrc.u32Width = SNES_WIDTH; + stSrc.u32Height = SNES_HEIGHT; + stSrc.u32Stride = 2 * SNES_WIDTH; + stSrc.u32PhyAddr = g_pSnesBackBufferPhys; + + stScaleRect.s32Xpos = 0; + stScaleRect.s32Ypos = 0; + stScaleRect.u32Height = SCALE_HEIGHT; + stScaleRect.u32Width = SCALE_WIDTH; + + stScale.enColorFmt = TDE2_COLOR_FMT_ARGB1555; + stScale.u32Width = SCALE_WIDTH; + stScale.u32Height = SCALE_HEIGHT; + stScale.u32Stride = SCALE_WIDTH * 2; + stScale.u32PhyAddr = g_pScaleBufferPhys; + + stDstRect.s32Xpos = (SCREEN_WIDTH - SCALE_WIDTH) / 2; + stDstRect.s32Ypos = 0; + stDstRect.u32Height = SCREEN_HEIGHT; + stDstRect.u32Width = SCREEN_WIDTH; + + stDst.enColorFmt = TDE2_COLOR_FMT_ARGB1555; + stDst.u32Width = SCREEN_WIDTH; + stDst.u32Height = SCREEN_HEIGHT; + stDst.u32Stride = SCREEN_WIDTH * 2; + stDst.u32PhyAddr = g_stCanvasBuf.stCanvas.u32PhyAddr; + stOpt.bResize = HI_TRUE; + + s32Ret = HI_TDE2_Bitblit(s32Handle, &stScale, &stScaleRect, &stSrc, + &stSrcRect, &stScale, &stScaleRect, &stOpt); + + if (s32Ret < 0) { + SAMPLE_PRT("HI_TDE2_Bitblit:%d failed,ret=0x%x!\n", __LINE__, s32Ret); + HI_TDE2_CancelJob(s32Handle); + return false; + } + + s32Ret = + HI_TDE2_QuickCopy(s32Handle, &stScale, &stScaleRect, &stDst, &stDstRect); + + if (s32Ret < 0) { + SAMPLE_PRT("HI_TDE2_QuickCopy:%d failed,ret=0x%x!\n", __LINE__, s32Ret); + HI_TDE2_CancelJob(s32Handle); + return false; + } + + /* 3. submit job */ + s32Ret = HI_TDE2_EndJob(s32Handle, HI_FALSE, HI_TRUE, 10); + if (s32Ret < 0) { + SAMPLE_PRT("Line:%d,HI_TDE2_EndJob failed,ret=0x%x!\n", __LINE__, s32Ret); + HI_TDE2_CancelJob(s32Handle); + return false; + } + + RefreshScreen(); + return true; +} + +bool8 S9xOpenSoundDevice(void) { + return false; +} + +const char* S9xGetFilename(const char* ex, s9x_getdirtype dirtype) { + static char s[PATH_MAX + 1]; + char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], + ext[_MAX_EXT + 1]; + + _splitpath(Memory.ROMFilename, drive, dir, fname, ext); + snprintf(s, PATH_MAX + 1, "%s%s%s%s", S9xGetDirectory(dirtype), SLASH_STR, + fname, ex); + + return (s); +} + +const char* S9xGetFilenameInc(const char* ex, enum s9x_getdirtype dirtype) { + static char s[PATH_MAX + 1]; + char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], + ext[_MAX_EXT + 1]; + + unsigned int i = 0; + const char* d; + struct stat buf; + + _splitpath(Memory.ROMFilename, drive, dir, fname, ext); + d = S9xGetDirectory(dirtype); + + do + snprintf(s, PATH_MAX + 1, "%s%s%s.%03d%s", d, SLASH_STR, fname, i++, ex); + while (stat(s, &buf) == 0 && i < 1000); + return (s); +} + +const char* S9xGetDirectory(enum s9x_getdirtype dirtype) { + static char s[PATH_MAX + 1]; + switch (dirtype) { + case DEFAULT_DIR: + strncpy(s, getenv("HOME"), PATH_MAX + 1); + s[PATH_MAX] = 0; + break; + + case HOME_DIR: + strncpy(s, getenv("HOME"), PATH_MAX + 1); + s[PATH_MAX] = 0; + break; + + case ROMFILENAME_DIR: + strncpy(s, Memory.ROMFilename, PATH_MAX + 1); + s[PATH_MAX] = 0; + + for (int i = strlen(s); i >= 0; i--) { + if (s[i] == SLASH_CHAR) { + s[i] = 0; + break; + } + } + + break; + + default: + s[0] = 0; + break; + } + return (s); +} + +const char* S9xBasename(const char* path) { + const char* p; + + if ((p = strrchr(path, '/')) != NULL || (p = strrchr(path, '\\')) != NULL) + return (p + 1); + + return (path); +} + +int main(int argc, char* argv[]) { + /* default settings to get snes emulation working... */ + 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 = 48000; + Settings.SoundInputRate = 31950; + Settings.SupportHiRes = FALSE; + Settings.Transparency = TRUE; + Settings.AutoDisplayMessages = TRUE; + Settings.InitialInfoStringTimeout = 120; + Settings.HDMATimingHack = 100; + Settings.BlockInvalidVRAMAccessMaster = TRUE; + Settings.SkipFrames = AUTO_FRAMERATE; + Settings.TurboSkipFrames = 15; + + HI_MPI_SYS_MmzAlloc(&g_pScaleBufferPhys, &g_pScaleBufferVirt, NULL, NULL, + 2 * SCALE_WIDTH * SCALE_HEIGHT); + + HI_MPI_SYS_MmzAlloc(&g_pSnesBackBufferPhys, &g_pSnesBackBufferVirt, NULL, + NULL, 2 * SNES_WIDTH * SNES_HEIGHT); + + GFX.Screen = (uint16_t*)g_pSnesBackBufferVirt; + GFX.Pitch = 2 * SNES_WIDTH; + std::printf("[+] init back buffer and scale buffer...\n"); + + S9xLoadConfigFiles(argv, argc); + Memory.Init(); + S9xInitAPU(); + S9xInitSound(0); + S9xSetSoundMute(TRUE); + S9xGraphicsInit(); + S9xBlitFilterInit(); + S9xBlit2xSaIFilterInit(); + S9xBlitHQ2xFilterInit(); + HiInitDisplay(); + std::printf("[+] init snes emulator...\n"); + + Memory.LoadROM("super_mario.smc"); + InitJoysticks(); + + S9xSetController(0, CTL_JOYPAD, 0, 0, 0, 0); + S9xSetController(1, CTL_JOYPAD, 1, 0, 0, 0); + + S9xUnmapAllControls(); + MAP_KEY("J00:Axis0", "Joypad1 Axis Left/Right T=50%"); + MAP_KEY("J00:Axis1", "Joypad1 Axis Up/Down T=50%"); + MAP_KEY("J00:B0", "Joypad1 X"); + MAP_KEY("J00:B1", "Joypad1 A"); + MAP_KEY("J00:B2", "Joypad1 B"); + MAP_KEY("J00:B3", "Joypad1 Y"); + MAP_KEY("J00:B6", "Joypad1 L"); + MAP_KEY("J00:B7", "Joypad1 R"); + MAP_KEY("J00:B8", "Joypad1 Select"); + MAP_KEY("J00:B11", "Joypad1 Start"); + + std::printf("[+] setup joystick... emulating...\n"); + while (true) { + ReadJoysticks(); + S9xMainLoop(); + } +} \ No newline at end of file diff --git a/snes9x/unix/mpp/hi_comm_adec.h b/snes9x/unix/mpp/hi_comm_adec.h new file mode 100644 index 0000000..3b36fb8 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_adec.h @@ -0,0 +1,146 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_adec.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2006/12/15 + Last Modified : + Description : + Function List : + History : + 1.Date : 2006/12/15 + Author : z50825 + Modification : Created file + 2.Date : 2007/5/10 + Author : z50825 + Modification : add err code +******************************************************************************/ + + +#ifndef __HI_COMM_ADEC_H__ +#define __HI_COMM_ADEC_H__ + + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_aio.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +typedef struct hiADEC_ATTR_G711_S +{ + HI_U32 resv; +}ADEC_ATTR_G711_S; + +typedef struct hiADEC_ATTR_G726_S +{ + G726_BPS_E enG726bps; +}ADEC_ATTR_G726_S; + +typedef struct hiADEC_ATTR_ADPCM_S +{ + ADPCM_TYPE_E enADPCMType; +}ADEC_ATTR_ADPCM_S; + +typedef struct hiADEC_ATTR_LPCM_S +{ + HI_U32 resv; +}ADEC_ATTR_LPCM_S; + +typedef enum hiADEC_MODE_E +{ + ADEC_MODE_PACK = 0,/*require input is valid dec pack(a + complete frame encode result), + e.g.the stream get from AENC is a + valid dec pack, the stream know actually + pack len from file is also a dec pack. + this mode is high-performative*/ + ADEC_MODE_STREAM ,/*input is stream,low-performative, + if you couldn't find out whether a stream is + vaild dec pack,you could use + this mode*/ + ADEC_MODE_BUTT +}ADEC_MODE_E; + +typedef struct hiADEC_CH_ATTR_S +{ + PAYLOAD_TYPE_E enType; + HI_U32 u32BufSize; /*buf size[2~MAX_AUDIO_FRAME_NUM]*/ + ADEC_MODE_E enMode; /*decode mode*/ + HI_VOID *pValue; +}ADEC_CHN_ATTR_S; + +typedef struct hiADEC_DECODER_S +{ + PAYLOAD_TYPE_E enType; + HI_CHAR aszName[16]; + HI_S32 (*pfnOpenDecoder)(HI_VOID *pDecoderAttr, HI_VOID **ppDecoder); /*struct ppDecoder is packed by user,user malloc and free memory for this struct */ + HI_S32 (*pfnDecodeFrm)(HI_VOID *pDecoder, HI_U8 **pu8Inbuf,HI_S32 *ps32LeftByte, + HI_U16 *pu16Outbuf,HI_U32 *pu32OutLen,HI_U32 *pu32Chns); + HI_S32 (*pfnGetFrmInfo)(HI_VOID *pDecoder, HI_VOID *pInfo); + HI_S32 (*pfnCloseDecoder)(HI_VOID *pDecoder); + HI_S32 (*pfnResetDecoder)(HI_VOID *pDecoder); +} ADEC_DECODER_S; + +typedef enum hiEN_ADEC_ERR_CODE_E +{ + ADEC_ERR_DECODER_ERR = 64, + ADEC_ERR_BUF_LACK, + +} EN_ADEC_ERR_CODE_E; + + +/* invlalid device ID */ +#define HI_ERR_ADEC_INVALID_DEVID HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_ADEC_INVALID_CHNID HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_ADEC_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_ADEC_EXIST HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/* channel unexists */ +#define HI_ERR_ADEC_UNEXIST HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_ADEC_NULL_PTR HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_ADEC_NOT_CONFIG HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_ADEC_NOT_SUPPORT HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_ADEC_NOT_PERM HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_ADEC_NOMEM HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_ADEC_NOBUF HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_ADEC_BUF_EMPTY HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_ADEC_BUF_FULL HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_ADEC_SYS_NOTREADY HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/* decoder internal err */ +#define HI_ERR_ADEC_DECODER_ERR HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, ADEC_ERR_DECODER_ERR) +/* input buffer not enough to decode one frame */ +#define HI_ERR_ADEC_BUF_LACK HI_DEF_ERR(HI_ID_ADEC, EN_ERR_LEVEL_ERROR, ADEC_ERR_BUF_LACK) + + + + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif/* End of #ifndef __HI_COMM_ADEC_H__*/ + diff --git a/snes9x/unix/mpp/hi_comm_aenc.h b/snes9x/unix/mpp/hi_comm_aenc.h new file mode 100644 index 0000000..8a7a3b4 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_aenc.h @@ -0,0 +1,126 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_aenc.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2006/12/15 + Last Modified : + Description : + Function List : + History : + 1.Date : 2006/12/15 + Author : z50825 + Modification : Created file + 2.Date : 2007/5/10 + Author : z50825 + Modification : add err code +******************************************************************************/ + + +#ifndef __HI_COMM_AENC_H__ +#define __HI_COMM_AENC_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_aio.h" + + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +typedef struct hiAENC_ATTR_G711_S +{ + HI_U32 resv; /*reserve item*/ +}AENC_ATTR_G711_S; + +typedef struct hiAENC_ATTR_G726_S +{ + G726_BPS_E enG726bps; +}AENC_ATTR_G726_S; + +typedef struct hiAENC_ATTR_ADPCM_S +{ + ADPCM_TYPE_E enADPCMType; +}AENC_ATTR_ADPCM_S; + +typedef struct hiAENC_ATTR_LPCM_S +{ + HI_U32 resv; /*reserve item*/ +}AENC_ATTR_LPCM_S; + +typedef struct hiAENC_ENCODER_S +{ + PAYLOAD_TYPE_E enType; + HI_U32 u32MaxFrmLen; + HI_CHAR aszName[16]; /* encoder type,be used to print proc information */ + HI_S32 (*pfnOpenEncoder)(HI_VOID *pEncoderAttr, HI_VOID **ppEncoder); /* pEncoder is the handle to control the encoder */ + HI_S32 (*pfnEncodeFrm)(HI_VOID *pEncoder, const AUDIO_FRAME_S *pstData, + HI_U8 *pu8Outbuf,HI_U32 *pu32OutLen); + HI_S32 (*pfnCloseEncoder)(HI_VOID *pEncoder); +} AENC_ENCODER_S; + +typedef struct hiAENC_CHN_ATTR_S +{ + PAYLOAD_TYPE_E enType; /*payload type ()*/ + HI_U32 u32PtNumPerFrm; + HI_U32 u32BufSize; /*buf size [2~MAX_AUDIO_FRAME_NUM]*/ + HI_VOID *pValue; /*point to attribute of definite audio encoder*/ +}AENC_CHN_ATTR_S; + +typedef enum hiEN_AENC_ERR_CODE_E +{ + AENC_ERR_ENCODER_ERR = 64 , + AENC_ERR_VQE_ERR = 65 , + +} EN_AENC_ERR_CODE_E; + + +/* invlalid device ID */ +#define HI_ERR_AENC_INVALID_DEVID HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_AENC_INVALID_CHNID HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_AENC_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_AENC_EXIST HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/* channel unexists */ +#define HI_ERR_AENC_UNEXIST HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_AENC_NULL_PTR HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_AENC_NOT_CONFIG HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_AENC_NOT_SUPPORT HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change static attribute */ +#define HI_ERR_AENC_NOT_PERM HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_AENC_NOMEM HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_AENC_NOBUF HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_AENC_BUF_EMPTY HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_AENC_BUF_FULL HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_AENC_SYS_NOTREADY HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/* encoder internal err */ +#define HI_ERR_AENC_ENCODER_ERR HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, AENC_ERR_ENCODER_ERR) +/* vqe internal err */ +#define HI_ERR_AENC_VQE_ERR HI_DEF_ERR(HI_ID_AENC, EN_ERR_LEVEL_ERROR, AENC_ERR_VQE_ERR) + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif/* End of #ifndef __HI_COMM_AENC_H__*/ + diff --git a/snes9x/unix/mpp/hi_comm_ai.h b/snes9x/unix/mpp/hi_comm_ai.h new file mode 100644 index 0000000..d11ed3b --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_ai.h @@ -0,0 +1,36 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_ai.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/5/5 + Description : + History : + 1.Date : 2009/5/5 + Author : p00123320 + Modification: Created file +******************************************************************************/ + + +#ifndef __HI_COMM_AI_H__ +#define __HI_COMM_AI_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_AI_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_aio.h b/snes9x/unix/mpp/hi_comm_aio.h new file mode 100644 index 0000000..a035411 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_aio.h @@ -0,0 +1,533 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_aio.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/5/5 + Description : + History : + 1.Date : 2009/5/5 + Author : p00123320 + Modification: Created file +******************************************************************************/ + + +#ifndef __HI_COMM_AIO_H__ +#define __HI_COMM_AIO_H__ + +#include "hi_common.h" +#include "hi_errno.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + +#define MAX_AUDIO_FRAME_NUM 50 /*max count of audio frame in Buffer */ +#define MAX_AUDIO_POINT_BYTES 4 /*max bytes of one sample point(now 32bit max)*/ + +#define MAX_VOICE_POINT_NUM 480 /*max sample per frame for voice encode */ + +#define MAX_AUDIO_POINT_NUM 2048 /*max sample per frame for all encoder(aacplus:2048)*/ +#define MAX_AO_POINT_NUM 4096 /* from h3£»support 4096 framelen*/ +#define MIN_AUDIO_POINT_NUM 80 /*min sample per frame*/ +#define MAX_AI_POINT_NUM 2048 /*max sample per frame for all encoder(aacplus:2048)*/ + +/*max length of audio frame by bytes, one frame contain many sample point */ +#define MAX_AUDIO_FRAME_LEN (MAX_AUDIO_POINT_BYTES*MAX_AO_POINT_NUM) + +/*max length of audio stream by bytes */ +#define MAX_AUDIO_STREAM_LEN MAX_AUDIO_FRAME_LEN + +#define MAX_AI_USRFRM_DEPTH 30 /*max depth of user frame buf */ + +/*The VQE EQ Band num.*/ +#define VQE_EQ_BAND_NUM 10 + + +typedef enum hiAUDIO_SAMPLE_RATE_E +{ + AUDIO_SAMPLE_RATE_8000 = 8000, /* 8K samplerate*/ + AUDIO_SAMPLE_RATE_12000 = 12000, /* 12K samplerate*/ + AUDIO_SAMPLE_RATE_11025 = 11025, /* 11.025K samplerate*/ + AUDIO_SAMPLE_RATE_16000 = 16000, /* 16K samplerate*/ + AUDIO_SAMPLE_RATE_22050 = 22050, /* 22.050K samplerate*/ + AUDIO_SAMPLE_RATE_24000 = 24000, /* 24K samplerate*/ + AUDIO_SAMPLE_RATE_32000 = 32000, /* 32K samplerate*/ + AUDIO_SAMPLE_RATE_44100 = 44100, /* 44.1K samplerate*/ + AUDIO_SAMPLE_RATE_48000 = 48000, /* 48K samplerate*/ + AUDIO_SAMPLE_RATE_BUTT, +} AUDIO_SAMPLE_RATE_E; + +typedef enum hiAUDIO_BIT_WIDTH_E +{ + AUDIO_BIT_WIDTH_8 = 0, /* 8bit width */ + AUDIO_BIT_WIDTH_16 = 1, /* 16bit width*/ + AUDIO_BIT_WIDTH_24 = 2, /* 24bit width*/ + AUDIO_BIT_WIDTH_BUTT, +} AUDIO_BIT_WIDTH_E; + +typedef enum hiAIO_MODE_E +{ + AIO_MODE_I2S_MASTER = 0, /* AIO I2S master mode */ + AIO_MODE_I2S_SLAVE, /* AIO I2S slave mode */ + AIO_MODE_PCM_SLAVE_STD, /* AIO PCM slave standard mode */ + AIO_MODE_PCM_SLAVE_NSTD, /* AIO PCM slave non-standard mode */ + AIO_MODE_PCM_MASTER_STD, /* AIO PCM master standard mode */ + AIO_MODE_PCM_MASTER_NSTD, /* AIO PCM master non-standard mode */ + AIO_MODE_BUTT +} AIO_MODE_E; + +typedef enum hiAIO_SOUND_MODE_E +{ + AUDIO_SOUND_MODE_MONO =0,/*mono*/ + AUDIO_SOUND_MODE_STEREO =1,/*stereo*/ + AUDIO_SOUND_MODE_BUTT +} AUDIO_SOUND_MODE_E; + +/* +An example of the packing scheme for G726-32 codewords is as shown, and bit A3 is the least significant bit of the first codeword: +RTP G726-32: +0 1 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +|B B B B|A A A A|D D D D|C C C C| ... +|0 1 2 3|0 1 2 3|0 1 2 3|0 1 2 3| ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- + +MEDIA G726-32: +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +|A A A A|B B B B|C C C C|D D D D| ... +|3 2 1 0|3 2 1 0|3 2 1 0|3 2 1 0| ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +*/ +typedef enum hiG726_BPS_E +{ + G726_16K = 0, /* G726 16kbps, see RFC3551.txt 4.5.4 G726-16 */ + G726_24K, /* G726 24kbps, see RFC3551.txt 4.5.4 G726-24 */ + G726_32K, /* G726 32kbps, see RFC3551.txt 4.5.4 G726-32 */ + G726_40K, /* G726 40kbps, see RFC3551.txt 4.5.4 G726-40 */ + MEDIA_G726_16K, /* G726 16kbps for ASF ... */ + MEDIA_G726_24K, /* G726 24kbps for ASF ... */ + MEDIA_G726_32K, /* G726 32kbps for ASF ... */ + MEDIA_G726_40K, /* G726 40kbps for ASF ... */ + G726_BUTT, +} G726_BPS_E; + +typedef enum hiADPCM_TYPE_E +{ + /* see DVI4 diiffers in three respects from the IMA ADPCM at RFC3551.txt 4.5.1 DVI4 */ + + ADPCM_TYPE_DVI4 = 0, /* 32kbps ADPCM(DVI4) for RTP */ + ADPCM_TYPE_IMA, /* 32kbps ADPCM(IMA),NOTICE:point num must be 161/241/321/481 */ + ADPCM_TYPE_ORG_DVI4, + ADPCM_TYPE_BUTT, +} ADPCM_TYPE_E; + +#define AI_EXPAND 0x01 +#define AI_CUT 0x02 + +typedef struct hiAIO_ATTR_S +{ + AUDIO_SAMPLE_RATE_E enSamplerate; /* sample rate */ + AUDIO_BIT_WIDTH_E enBitwidth; /* bitwidth */ + AIO_MODE_E enWorkmode; /* master or slave mode */ + AUDIO_SOUND_MODE_E enSoundmode; /* momo or steror */ + HI_U32 u32EXFlag; /* expand 8bit to 16bit,use AI_EXPAND(only valid for AI 8bit) */ + HI_U32 u32FrmNum; /* frame num in buf[2,MAX_AUDIO_FRAME_NUM] */ + HI_U32 u32PtNumPerFrm; /* point num per frame (80/160/240/320/480/1024/2048) + (ADPCM IMA should add 1 point, AMR only support 160) */ + HI_U32 u32ChnCnt; /* channel number, valid value:1/2/4/8 */ + HI_U32 u32ClkChnCnt; /* channel number on FS, valid value:1/2/4/8/16*/ + HI_U32 u32ClkSel; /* 0: AI and AO clock is separate + 1: AI and AO clock is inseparate, AI use AO's clock + */ +} AIO_ATTR_S; + +typedef struct hiAI_CHN_PARAM_S +{ + HI_U32 u32UsrFrmDepth; +} AI_CHN_PARAM_S; + +typedef struct hiAUDIO_FRAME_S +{ + AUDIO_BIT_WIDTH_E enBitwidth; /*audio frame bitwidth*/ + AUDIO_SOUND_MODE_E enSoundmode; /*audio frame momo or stereo mode*/ + HI_VOID *pVirAddr[2]; + HI_U32 u32PhyAddr[2]; + HI_U64 u64TimeStamp; /*audio frame timestamp*/ + HI_U32 u32Seq; /*audio frame seq*/ + HI_U32 u32Len; /*data lenth per channel in frame*/ + HI_U32 u32PoolId[2]; +} AUDIO_FRAME_S; + +typedef struct hiAEC_FRAME_S +{ + AUDIO_FRAME_S stRefFrame; /* AEC reference audio frame */ + HI_BOOL bValid; /* whether frame is valid */ + HI_BOOL bSysBind; /* whether is sysbind */ +} AEC_FRAME_S; + +typedef struct hiAUDIO_FRAME_INFO_S +{ + AUDIO_FRAME_S *pstFrame;/*frame ptr*/ + HI_U32 u32Id; /*frame id*/ +} AUDIO_FRAME_INFO_S; + +typedef struct hiAUDIO_STREAM_S +{ + HI_U8 *pStream; /* the virtual address of stream */ + HI_U32 u32PhyAddr; /* the physics address of stream */ + HI_U32 u32Len; /* stream lenth, by bytes */ + HI_U64 u64TimeStamp; /* frame time stamp*/ + HI_U32 u32Seq; /* frame seq,if stream is not a valid frame,u32Seq is 0*/ +} AUDIO_STREAM_S; + + +typedef struct hiAO_CHN_STATE_S +{ + HI_U32 u32ChnTotalNum; /* total number of channel buffer */ + HI_U32 u32ChnFreeNum; /* free number of channel buffer */ + HI_U32 u32ChnBusyNum; /* busy number of channel buffer */ +} AO_CHN_STATE_S; + + +typedef enum hiAUDIO_TRACK_MODE_E +{ + AUDIO_TRACK_NORMAL = 0, + AUDIO_TRACK_BOTH_LEFT = 1, + AUDIO_TRACK_BOTH_RIGHT = 2, + AUDIO_TRACK_EXCHANGE = 3, + AUDIO_TRACK_MIX = 4, + AUDIO_TRACK_LEFT_MUTE = 5, + AUDIO_TRACK_RIGHT_MUTE = 6, + AUDIO_TRACK_BOTH_MUTE = 7, + + AUDIO_TRACK_BUTT +} AUDIO_TRACK_MODE_E; + +typedef enum hiAUDIO_FADE_RATE_E +{ + AUDIO_FADE_RATE_1 = 0, + AUDIO_FADE_RATE_2 = 1, + AUDIO_FADE_RATE_4 = 2, + AUDIO_FADE_RATE_8 = 3, + AUDIO_FADE_RATE_16 = 4, + AUDIO_FADE_RATE_32 = 5, + AUDIO_FADE_RATE_64 = 6, + AUDIO_FADE_RATE_128 = 7, + + AUDIO_FADE_RATE_BUTT +} AUDIO_FADE_RATE_E; + +typedef struct hiAUDIO_FADE_S +{ + HI_BOOL bFade; + AUDIO_FADE_RATE_E enFadeInRate; + AUDIO_FADE_RATE_E enFadeOutRate; +} AUDIO_FADE_S; + +/**Defines the configure parameters of AGC.*/ +typedef struct hiAUDIO_AGC_CONFIG_S +{ + HI_BOOL bUsrMode; /* mode 0: auto£¬mode 1: manual.*/ + + HI_S8 s8TargetLevel; /* target voltage level, range: [-40, -1]dB */ + HI_S8 s8NoiseFloor; /* noise floor, range: [-65, -20]dB */ + HI_S8 s8MaxGain; /* max gain, range: [0, 30]dB */ + HI_S8 s8AdjustSpeed; /* adjustable speed, range: [0, 10]dB/s */ + + HI_S8 s8ImproveSNR; /* switch for improving SNR, range: [0:close, 1:upper limit 3dB, 2:upper limit 6dB] */ + HI_S8 s8UseHighPassFilt; /* switch for using high pass filt, range: [0:close, 1:80Hz, 2:120Hz, 3:150:Hz, 4:300Hz: 5:500Hz] */ + HI_S8 s8OutputMode; /* output mode, mute when lower than noise floor, range: [0:close, 1:open] */ + HI_S16 s16NoiseSupSwitch; /* switch for noise suppression, range: [0:close, 1:open] */ + + + HI_S32 s32Reserved; +} AUDIO_AGC_CONFIG_S; + +/**Defines the configure parameters of AEC.*/ +typedef struct hiAI_AEC_CONFIG_S +{ + HI_BOOL bUsrMode; /* mode 0: auto mode 1: mannual.*/ + HI_S8 s8CngMode; /* cozy noisy mode: 0 close, 1 open, recommend 1*/ + HI_S8 s8NearAllPassEnergy; /* the far-end energy threshold for judging whether unvarnished transmission: 0 -59dBm0, 1 -49dBm0, 2 -39dBm0, recommend 1 */ + HI_S8 s8NearCleanSupEnergy; /* the energy threshold for compelling reset of near-end signal: 0 12dB, 1 15dB, 2 18dB, recommend 2 */ + + HI_S16 s16DTHnlSortQTh; /* the threshold of judging single or double talk, recommend 16384, [0, 32767] */ + + HI_S16 s16EchoBandLow; /* voice processing band1, low frequency parameter, [1, 63] for 8k, [1, 127] for 16k, recommend 10 */ + HI_S16 s16EchoBandHigh; /* voice processing band1, high frequency parameter, (s16EchoBandLow, 63] for 8k, (s16EchoBandLow, 127] for 16k, recommend 41 */ + /* s16EchoBandHigh must be greater than s16EchoBandLow */ + HI_S16 s16EchoBandLow2; /* voice processing band2, low frequency parameter, [1, 63] for 8k, [1, 127] for 16k, recommend 47 */ + HI_S16 s16EchoBandHigh2; /* voice processing band2, high frequency parameter, (s16EchoBandLow2, 63] for 8k, (s16EchoBandLow2, 127] for 16k, recommend 72 */ + /* s16EchoBandHigh2 must be greater than s16EchoBandLow2 */ + + HI_S16 s16ERLBand[6]; /* ERL protect area, [1, 63] for 8k, [1, 127] for 16k, frequency band calculated by s16ERLBand * 62.5 */ + /* besides, s16ERLBand[n+1] should be greater than s16ERLBand[n] */ + HI_S16 s16ERL[7]; /* ERL protect value of ERL protect area, the smaller its value, the more strength its protect ability£¬[0, 18]*/ + HI_S16 s16VioceProtectFreqL; /* protect area of near-end low frequency, [1, 63] for 8k, [1, 127] for 16k, recommend 3 */ + HI_S16 s16VioceProtectFreqL1; /* protect area of near-end low frequency1, [s16VioceProtectFreqL, 63] for 8k, [s16VioceProtectFreqL, 127] for 16k, recommend 6 */ + HI_S32 s32Reserved; /* s16VioceProtectFreqL1 must be greater than s16VioceProtectFreqL */ +} AI_AEC_CONFIG_S; + +/**Defines the configure parameters of ANR.*/ +typedef struct hiAUDIO_ANR_CONFIG_S +{ + HI_BOOL bUsrMode; /* mode 0: auto£¬mode 1: manual.*/ + + HI_S16 s16NrIntensity; /* noise reduce intensity, range: [0, 25] */ + HI_S16 s16NoiseDbThr; /* noise threshold, range: [30, 60] */ + HI_S8 s8SpProSwitch; /* switch for music probe, range: [0:close, 1:open] */ + + HI_S32 s32Reserved; +} AUDIO_ANR_CONFIG_S; + +/**Defines the configure parameters of HPF.*/ +typedef enum hiAUDIO_HPF_FREQ_E +{ + AUDIO_HPF_FREQ_80 = 80, /* 80Hz */ + AUDIO_HPF_FREQ_120 = 120, /* 120Hz */ + AUDIO_HPF_FREQ_150 = 150, /* 150Hz */ + AUDIO_HPF_FREQ_BUTT, +} AUDIO_HPF_FREQ_E; + +typedef struct hiAUDIO_HPF_CONFIG_S +{ + HI_BOOL bUsrMode; /* mode 0: auto mode 1: mannual.*/ + AUDIO_HPF_FREQ_E enHpfFreq; /*freq to be processed*/ +} AUDIO_HPF_CONFIG_S; + +typedef struct hiAI_RNR_CONFIG_S +{ + HI_BOOL bUsrMode; /* mode 0: auto£¬mode 1: mannual.*/ + + HI_S32 s32NrMode; /*mode 0: floor noise; 1:ambient noise */ + + HI_S32 s32MaxNrLevel; /*max NR level range:[2,20]dB*/ + + HI_S32 s32NoiseThresh; /*noise threshold, range:[-80, -20]*/ +} AI_RNR_CONFIG_S; + +typedef struct hiAUDIO_EQ_CONFIG_S +{ + HI_S8 s8GaindB[VQE_EQ_BAND_NUM]; /*EQ band, include 100,200,250,350,500,800,1.2k,2.5k,4k,8k in turn, range:[-100, 20]*/ + HI_S32 s32Reserved; +} AUDIO_EQ_CONFIG_S; + + +/**Defines the configure parameters of UPVQE work state.*/ +typedef enum hiVQE_WORKSTATE_E +{ + VQE_WORKSTATE_COMMON = 0, /* common environment, Applicable to the family of voice calls. */ + VQE_WORKSTATE_MUSIC = 1, /* music environment , Applicable to the family of music environment. */ + VQE_WORKSTATE_NOISY = 2, /* noisy environment , Applicable to the noisy voice calls. */ +} VQE_WORKSTATE_E; + +/* HDR Set CODEC GAIN Function Handle type */ +typedef HI_S32 (*pFuncGainCallBack)(HI_S32 s32SetGain); + +typedef struct hiAI_HDR_CONFIG_S +{ + /*not support for now!*/ + HI_BOOL bUsrMode; /* mode 0: auto mode 1: mannual.*/ + + HI_S32 s32MinGaindB; /* the minimum of MIC(AI) CODEC gain, [0, 120]*/ + HI_S32 s32MaxGaindB; /* the maximum of MIC(AI) CODEC gain, [0, 120]*/ + + HI_S32 s32MicGaindB; /* the current gain of MIC(AI) CODEC£¬[s32MinGaindB, s32MaxGaindB]*/ + HI_S32 s32MicGainStepdB; /* the step size of gain adjustment, [1, 3], recommemd 2 */ + pFuncGainCallBack pcallback; /* the callback function pointer of CODEC gain adjustment */ +} AI_HDR_CONFIG_S; + + +/**Defines the configure parameters of VQE.*/ +typedef struct hiAI_VQE_CONFIG_S +{ + HI_S32 bHpfOpen; + HI_S32 bAecOpen; + HI_S32 bAnrOpen; + HI_S32 bRnrOpen; + HI_S32 bAgcOpen; + HI_S32 bEqOpen; + HI_S32 bHdrOpen; + + HI_S32 s32WorkSampleRate; /* Sample Rate£º8KHz/16KHz/48KHz¡£default: 8KHz*/ + HI_S32 s32FrameSample; /* VQE frame length£º 80-4096 */ + VQE_WORKSTATE_E enWorkstate; + + + AUDIO_HPF_CONFIG_S stHpfCfg; + AI_AEC_CONFIG_S stAecCfg; + AUDIO_ANR_CONFIG_S stAnrCfg; + AI_RNR_CONFIG_S stRnrCfg; + AUDIO_AGC_CONFIG_S stAgcCfg; + AUDIO_EQ_CONFIG_S stEqCfg; + AI_HDR_CONFIG_S stHdrCfg; +} AI_VQE_CONFIG_S; + +typedef struct hiAO_VQE_CONFIG_S +{ + HI_S32 bHpfOpen; + HI_S32 bAnrOpen; + HI_S32 bAgcOpen; + HI_S32 bEqOpen; + + HI_S32 s32WorkSampleRate; /* Sample Rate£º8KHz/16KHz/48KHz¡£default: 8KHz*/ + HI_S32 s32FrameSample; /* VQE frame length£º 80-4096 */ + VQE_WORKSTATE_E enWorkstate; + + AUDIO_HPF_CONFIG_S stHpfCfg; + AUDIO_ANR_CONFIG_S stAnrCfg; + AUDIO_AGC_CONFIG_S stAgcCfg; + AUDIO_EQ_CONFIG_S stEqCfg; +} AO_VQE_CONFIG_S; + + +/*Defines the configure parameters of AI saving file.*/ +typedef struct hiAUDIO_SAVE_FILE_INFO_S +{ + HI_BOOL bCfg; + HI_CHAR aFilePath[256]; + HI_CHAR aFileName[256]; + HI_U32 u32FileSize; /*in KB*/ +} AUDIO_SAVE_FILE_INFO_S; + +typedef enum hiEN_AIO_ERR_CODE_E +{ + AIO_ERR_VQE_ERR = 65 , /*vqe error*/ + +} EN_AIO_ERR_CODE_E; + +/* obsolete */ +typedef enum hiAUDIO_CLKDIR_E +{ + AUDIO_CLKDIR_RISE = 0, + AUDIO_CLKDIR_FALL = 1, + + AUDIO_CLKDIR_BUTT +} AUDIO_CLKDIR_E; + +/* obsolete */ +typedef struct hiAUDIO_FRAME_COMBINE_S +{ + AUDIO_FRAME_S stFrm; /* audio frame */ + AEC_FRAME_S stRefFrm; /* AEC reference audio frame */ + HI_BOOL bEnableVqe; /* whether is enable vqe */ +} AUDIO_FRAME_COMBINE_S; + +/* obsolete */ +typedef struct hiAUDIO_RESAMPLE_ATTR_S +{ + HI_U32 u32InPointNum; /* input point number of frame */ + AUDIO_SAMPLE_RATE_E enInSampleRate; /* input sample rate */ + AUDIO_SAMPLE_RATE_E enOutSampleRate; /* output sample rate */ +} AUDIO_RESAMPLE_ATTR_S; + +typedef struct hiAIO_RESMP_INFO_S +{ + HI_BOOL bReSmpEnable; /* resample enable or disable */ + AUDIO_RESAMPLE_ATTR_S stResmpAttr; +} AIO_RESMP_INFO_S; + +/* obsolete */ +typedef struct hiAI_VQE_INFO_S +{ + HI_BOOL bVqeEnable; /* vqe enable or disable */ + AI_VQE_CONFIG_S stAiVqeCfg; +} AI_VQE_INFO_S; + +/* obsolete */ +typedef struct hiAO_VQE_INFO_S +{ + HI_BOOL bVqeEnable; /* vqe enable or disable */ + AO_VQE_CONFIG_S stAoVqeCfg; +} AO_VQE_INFO_S; + +/* obsolete */ +typedef enum hiAUDIO_AEC_MODE_E +{ + AUDIO_AEC_MODE_CLOSE = 0, + AUDIO_AEC_MODE_OPEN = 1, + + AUDIO_AEC_MODE_BUTT +} AUDIO_AEC_MODE_E; + + +/* invlalid device ID */ +#define HI_ERR_AI_INVALID_DEVID HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_AI_INVALID_CHNID HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_AI_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* using a NULL point */ +#define HI_ERR_AI_NULL_PTR HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_AI_NOT_CONFIG HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_AI_NOT_SUPPORT HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_AI_NOT_PERM HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* the devide is not enabled */ +#define HI_ERR_AI_NOT_ENABLED HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* failure caused by malloc memory */ +#define HI_ERR_AI_NOMEM HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_AI_NOBUF HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_AI_BUF_EMPTY HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_AI_BUF_FULL HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_AI_SYS_NOTREADY HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) + +#define HI_ERR_AI_BUSY HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +/* vqe err */ +#define HI_ERR_AI_VQE_ERR HI_DEF_ERR(HI_ID_AI, EN_ERR_LEVEL_ERROR, AIO_ERR_VQE_ERR) + +/* invlalid device ID */ +#define HI_ERR_AO_INVALID_DEVID HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_AO_INVALID_CHNID HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_AO_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* using a NULL point */ +#define HI_ERR_AO_NULL_PTR HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_AO_NOT_CONFIG HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_AO_NOT_SUPPORT HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_AO_NOT_PERM HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* the devide is not enabled */ +#define HI_ERR_AO_NOT_ENABLED HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* failure caused by malloc memory */ +#define HI_ERR_AO_NOMEM HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_AO_NOBUF HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_AO_BUF_EMPTY HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_AO_BUF_FULL HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_AO_SYS_NOTREADY HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) + +#define HI_ERR_AO_BUSY HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + +/* vqe err */ +#define HI_ERR_AO_VQE_ERR HI_DEF_ERR(HI_ID_AO, EN_ERR_LEVEL_ERROR, AIO_ERR_VQE_ERR) + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_AI_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_ao.h b/snes9x/unix/mpp/hi_comm_ao.h new file mode 100644 index 0000000..78fd51b --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_ao.h @@ -0,0 +1,37 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_ao.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/5/5 + Description : + History : + 1.Date : 2009/5/5 + Author : p00123320 + Modification: Created file +******************************************************************************/ + + +#ifndef __HI_COMM_AO_H__ +#define __HI_COMM_AO_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_AO_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_hdmi.h b/snes9x/unix/mpp/hi_comm_hdmi.h new file mode 100644 index 0000000..79cf55d --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_hdmi.h @@ -0,0 +1,773 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_hdmi.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2011/12/21 + Description : + History : + 1.Date : 2011/12/21 + Author : n00168968 + Modification: Created file + +******************************************************************************/ + +#ifndef __HI_COMM_HDMI_H__ +#define __HI_COMM_HDMI_H__ + +#include "hi_type.h" +#include "hi_errno.h" +#include "hi_common.h" +#include "hi_comm_video.h" + +#define HI_HDMI_MAX_AUDIO_CAP_COUNT 15 + +#define HI_HDMI_MAX_AUDIO_SMPRATE_COUNT 10 + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +typedef enum hiHDMI_VIDEO_FMT_E +{ + HI_HDMI_VIDEO_FMT_1080P_60 = 0, + HI_HDMI_VIDEO_FMT_1080P_50, + HI_HDMI_VIDEO_FMT_1080P_30, + HI_HDMI_VIDEO_FMT_1080P_25, + HI_HDMI_VIDEO_FMT_1080P_24, + + HI_HDMI_VIDEO_FMT_1080i_60, + HI_HDMI_VIDEO_FMT_1080i_50, + + HI_HDMI_VIDEO_FMT_720P_60, + HI_HDMI_VIDEO_FMT_720P_50, + + HI_HDMI_VIDEO_FMT_576P_50, + HI_HDMI_VIDEO_FMT_480P_60, + + HI_HDMI_VIDEO_FMT_PAL, /* B D G H I PAL */ + HI_HDMI_VIDEO_FMT_PAL_N, /* (N)PAL */ + HI_HDMI_VIDEO_FMT_PAL_Nc, /* (Nc)PAL */ + + HI_HDMI_VIDEO_FMT_NTSC, /* (M)NTSC */ + HI_HDMI_VIDEO_FMT_NTSC_J, /* NTSC-J */ + HI_HDMI_VIDEO_FMT_NTSC_PAL_M, /* (M)PAL */ + + HI_HDMI_VIDEO_FMT_SECAM_SIN, /**< SECAM_SIN*/ + HI_HDMI_VIDEO_FMT_SECAM_COS, /**< SECAM_COS*/ + + HI_HDMI_VIDEO_FMT_861D_640X480_60, + HI_HDMI_VIDEO_FMT_VESA_800X600_60, + HI_HDMI_VIDEO_FMT_VESA_1024X768_60, + HI_HDMI_VIDEO_FMT_VESA_1280X720_60, + HI_HDMI_VIDEO_FMT_VESA_1280X800_60, + HI_HDMI_VIDEO_FMT_VESA_1280X1024_60, + HI_HDMI_VIDEO_FMT_VESA_1366X768_60, + HI_HDMI_VIDEO_FMT_VESA_1440X900_60, + HI_HDMI_VIDEO_FMT_VESA_1440X900_60_RB, + HI_HDMI_VIDEO_FMT_VESA_1600X900_60_RB, + HI_HDMI_VIDEO_FMT_VESA_1600X1200_60, + HI_HDMI_VIDEO_FMT_VESA_1680X1050_60, + HI_HDMI_VIDEO_FMT_VESA_1920X1080_60, + HI_HDMI_VIDEO_FMT_VESA_1920X1200_60, + HI_HDMI_VIDEO_FMT_VESA_2048X1152_60, /* Currently, not support */ + + + HI_HDMI_VIDEO_FMT_2560x1440_30, + HI_HDMI_VIDEO_FMT_2560x1600_60, + HI_HDMI_VIDEO_FMT_1920x2160_30, + + HI_HDMI_VIDEO_FMT_3840X2160P_24, /** 93:3840x2160p @ 24Hz No Repetition */ + HI_HDMI_VIDEO_FMT_3840X2160P_25, /** 94:3840x2160p @ 25Hz No Repetition */ + HI_HDMI_VIDEO_FMT_3840X2160P_30, /** 95:3840x2160p @ 30Hz No Repetition */ + HI_HDMI_VIDEO_FMT_3840X2160P_50, /** 96:3840x2160p @ 50Hz No Repetition */ + HI_HDMI_VIDEO_FMT_3840X2160P_60, /** 97:3840x2160p @ 60Hz No Repetition */ + + HI_HDMI_VIDEO_FMT_4096X2160P_24, /** 98:4096x2160p @ 24Hz No Repetition */ + HI_HDMI_VIDEO_FMT_4096X2160P_25, /** 99:4096x2160p @ 25Hz No Repetition */ + HI_HDMI_VIDEO_FMT_4096X2160P_30, /** 100:4096x2160p @ 30Hz No Repetition */ + HI_HDMI_VIDEO_FMT_4096X2160P_50, /** 101:4096x2160p @ 50Hz No Repetition */ + HI_HDMI_VIDEO_FMT_4096X2160P_60, /** 102:4096x2160p @ 60Hz No Repetition */ + + + HI_HDMI_VIDEO_FMT_VESA_CUSTOMER_DEFINE, /* Currently, not support */ + + HI_HDMI_VIDEO_FMT_BUTT +}HI_HDMI_VIDEO_FMT_E; + +typedef enum hiHDMI_VIDEO_SAMPLE_TYPE_E +{ + HI_HDMI_VIDEO_SAMPLE_TYPE_UNKNOWN, + HI_HDMI_VIDEO_SAMPLE_TYPE_PROGRESSIVE, + HI_HDMI_VIDEO_SAMPLE_TYPE_INTERLACE, + HI_HDMI_VIDEO_SAMPLE_TYPE_INFERED_PROGRESSIVE, + HI_HDMI_VIDEO_SAMPLE_TYPE_INFERED_INTERLACE, + + HI_HDMI_VIDEO_SAMPLE_TYPE_BUTT +}HI_HDMI_VIDEO_SAMPLE_TYPE_E; + +typedef enum hiHDMI_ASPECT_RATIO_E +{ + HI_HDMI_ASPECT_RATIO_UNKNOWN, /**< unknown aspect ratio */ + HI_HDMI_ASPECT_RATIO_4TO3, /**< 4:3 */ + HI_HDMI_ASPECT_RATIO_16TO9, /**< 16:9 */ + HI_HDMI_ASPECT_RATIO_SQUARE, /**< square */ + HI_HDMI_ASPECT_RATIO_14TO9, /**< 14:9 */ + HI_HDMI_ASPECT_RATIO_221TO1, /**< 221:100 */ + HI_HDMI_ASPECT_RATIO_ZOME, /**< default not support, use source's aspect ratio to display */ + HI_HDMI_ASPECT_RATIO_FULL, /**< default not support, full screen display */ + + HI_HDMI_ASPECT_RATIO_BUTT +}HI_HDMI_ASPECT_RATIO_E; + +typedef enum hiHDMI_SAMPLE_RATE_E +{ + HI_HDMI_SAMPLE_RATE_UNKNOWN=0, /**< unknown sample rate */ + HI_HDMI_SAMPLE_RATE_8K = 8000, /**< 8K sample rate */ + HI_HDMI_SAMPLE_RATE_11K = 11025, /**< 11.025K sample rate */ + HI_HDMI_SAMPLE_RATE_12K = 12000, /**< 12K sample rate */ + HI_HDMI_SAMPLE_RATE_16K = 16000, /**< 16K sample rate */ + HI_HDMI_SAMPLE_RATE_22K = 22050, /**< 22.050K sample rate */ + HI_HDMI_SAMPLE_RATE_24K = 24000, /**< 24K sample rate */ + HI_HDMI_SAMPLE_RATE_32K = 32000, /**< 32K sample rate */ + HI_HDMI_SAMPLE_RATE_44K = 44100, /**< 44.1K sample rate */ + HI_HDMI_SAMPLE_RATE_48K = 48000, /**< 48K sample rate */ + HI_HDMI_SAMPLE_RATE_88K = 88200, /**< 88.2K sample rate */ + HI_HDMI_SAMPLE_RATE_96K = 96000, /**< 96K sample rate */ + HI_HDMI_SAMPLE_RATE_176K = 176400, /**< 176K sample rate */ + HI_HDMI_SAMPLE_RATE_192K = 192000, /**< 192K sample rate */ + + HI_HDMI_SAMPLE_RATE_BUTT +}HI_HDMI_SAMPLE_RATE_E; + +typedef enum hiHDMI_BIT_DEPTH_E +{ + HI_HDMI_BIT_DEPTH_UNKNOWN =0, /**< unknown bit width */ + HI_HDMI_BIT_DEPTH_8 = 8, /**< 8 bits width */ + HI_HDMI_BIT_DEPTH_16 = 16, /**< 16 bits width */ + HI_HDMI_BIT_DEPTH_18 = 18, /**< 18 bits width */ + HI_HDMI_BIT_DEPTH_20 = 20, /**< 20 bits width */ + HI_HDMI_BIT_DEPTH_24 = 24, /**< 24 bits width */ + HI_HDMI_BIT_DEPTH_32 = 32, /**< 32 bits width */ + + HI_HDMI_BIT_DEPTH_BUTT +}HI_HDMI_BIT_DEPTH_E; + +typedef enum hiHDMI_SND_INTERFACE_E +{ + HI_HDMI_SND_INTERFACE_I2S, /** Used as a response to indicate that the device does not support the requested message type, or that it cannot execute it at the present time. */ +#define CEC_OPCODE_ABORT_MESSAGE 0XFF /**< Message This message is reserved for testing purposes. */ +/**< One Touch Play Feature*/ +#define CEC_OPCODE_ACTIVE_SOURCE 0X82 /**< Used by a new source to indicate that it has started to transmit a stream OR used in response to a */ +#define CEC_OPCODE_IMAGE_VIEW_ON 0X04 /**< Sent by a source device to the TV whenever it enters the active state (alternatively it may send ). */ +#define CEC_OPCODE_TEXT_VIEW_ON 0X0D /**< As , but should also remove any text, menus and PIP windows from the TV¡¯s display. */ +/**< Routing Control Feature*/ +#define CEC_OPCODE_INACTIVE_SOURCE 0X9D /**< Used by the currently active source to inform the TV that it has no video to be presented to the user, or is going into standby as the result of a local user command on the device. */ +#define CEC_OPCODE_REQUEST_ACTIVE_SOURCE 0X85 /**< Used by a new device to discover the status of the system. */ +#define CEC_OPCODE_ROUTING_CHANGE 0X80 /**< Sent by a CEC Switch when it is manually switched to inform all other devices on the network that the active route below the switch has changed. */ +#define CEC_OPCODE_ROUTING_INFORMATION 0X81 /**< Sent by a CEC Switch to indicate the active route below the switch. */ +#define CEC_OPCODE_SET_STREAM_PATH 0X86 /**< Used by the TV to request a streaming path from the specified physical address. */ +/**< Standby Feature*/ +#define CEC_OPCODE_STANDBY 0X36 /**< Switches one or all devices into standby mode. Can be used as a broadcast message or be addressed to a specific device. See section CEC 13.3 for important notes on the use of this message */ +/**< One Touch Record Feature*/ +#define CEC_OPCODE_RECORD_OFF 0X0B /**< Requests a device to stop a recording. */ +#define CEC_OPCODE_RECORD_ON 0X09 /**< Attempt to record the specified source. */ +#define CEC_OPCODE_RECORD_STATUS 0X0A /**< Used by a Recording Device to inform the initiator of the message about its status. */ +#define CEC_OPCODE_RECORD_TV_SCREEN 0X0F /**< Request by the Recording Device to record the presently displayed source. */ +/**< Timer Programming Feature*/ +#define CEC_OPCODE_CLEAR_ANALOGUE_TIMER 0X33 /**< Used to clear an Analogue timer block of a device. */ +#define CEC_OPCODE_CLEAR_DIGITAL_TIMER 0X99 /**< Used to clear a Digital timer block of a device. */ +#define CEC_OPCODE_CLEAR_EXTERNAL_TIMER 0XA1 /**< Used to clear an External timer block of a device. */ +#define CEC_OPCODE_SET_ANALOGUE_TIMER 0X34 /**< Used to set a single timer block on an Analogue Recording Device. */ +#define CEC_OPCODE_SET_DIGITAL_TIMER 0X97 /**< Used to set a single timer block on a Digital Recording Device. */ +#define CEC_OPCODE_SET_EXTERNAL_TIMER 0XA2 /**< Used to set a single timer block to record from an external device. */ +#define CEC_OPCODE_SET_TIMER_PROGRAM_TITLE 0X67 /**< Used to set the name of a program associated with a timer block. Sent directly after sending a or message. The name is then associated with that timer block. */ +#define CEC_OPCODE_TIMER_CLEARED_STATUS 0X43 /**< Used to give the status of a , or message. */ +#define CEC_OPCODE_TIMER_STATUS 0X35 /**< Used to send timer status to the initiator of a message. */ +/**< System Information Feature*/ +#define CEC_OPCODE_CEC_VERSION 0X9E /**< Used to indicate the supported CEC version, in response to a */ +#define CEC_OPCODE_GET_CEC_VERSION 0X9F /**< Used by a device to enquire which version of CEC the target supports */ +#define CEC_OPCODE_GIVE_PHYSICAL_ADDRESS 0X83 /**< A request to a device to return its physical address. */ +#define CEC_OPCODE_REPORT_PHYSICAL_ADDRESS 0X84 /**< Used to inform all other devices of the mapping between physical and logical address of the initiator. */ +#define CEC_OPCODE_GET_MENU_LANGUAGE 0X91 /**< Sent by a device capable of character generation (for OSD and Menus) to a TV in order to discover the currently selected Menu language. Also used by a TV during installation to discover the currently set menu language of other devices. */ +#define CEC_OPCODE_SET_MENU_LANGUAGE 0X32 /**< Used by a TV or another device to indicate the menu language. */ +/**< Deck Control Feature*/ +#define CEC_OPCODE_DECK_CONTROL 0X42 /**< Used to control a device¡¯s media functions. */ +#define CEC_OPCODE_DECK_STATUS 0X1B /**< Used to provide a deck¡¯s status to the initiator of the message. */ +#define CEC_OPCODE_GIVE_DECK_STATUS 0X1A /**< Used to request the status of a device, regardless of whether or not it is the current active source. */ +#define CEC_OPCODE_PLAY 0X41 /**< Used to control the playback behaviour of a source device. */ +/**< Tuner Control Feature*/ +#define CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS 0X08 /**< Used to request the status of a tuner device. */ +#define CEC_OPCODE_SELECT_ANALOGUE_SERVICE 0X92 /**< Directly selects a Digital TV, Radio or Data Broadcast Service */ +#define CEC_OPCODE_TUNER_DEVICE_STATUS 0X07 /**< Use by a tuner device to provide its status to the initiator of the message. */ +#define CEC_OPCODE_TUNER_STEP_DECREMENT 0X06 /**< Used to tune to next lowest service in a tuner¡¯s service list. Can be used for PIP. */ +#define CEC_OPCODE_TUNER_STEP_INCREMENT 0X05 /**< Used to tune to next highest service in a tuner¡¯s service list. Can be used for PIP. */ +/**< Vendor Specific Command*/ +#define CEC_OPCODE_DEVICE_VENDOR_ID 0X87 /**< Reports the vendor ID of this device. */ +#define CEC_OPCODE_GIVE_DEVICE_VENDOR_ID 0X8C /**< Requests the Vendor ID from a device. */ +#define CEC_OPCODE_VENDOR_COMMAND 0X89 /**< Allows vendor specific commands to be sent between two devices. */ +#define CEC_OPCODE_VENDOR_COMMAND_WITH_ID 0XA0 /**< Allows vendor specific commands to be sent between two devices or broadcast. */ +#define CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN 0X8A /**< Indicates that a remote control button has been depressed. */ +#define CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP 0X8B /**< Indicates that a remote control button (the last button pressed indicated by the Vendor Remote Button Down message) has been released. */ +/**< OSD Display Feature*/ +#define CEC_OPCODE_SET_OSD_STRING 0X64 /**< Used to send a text message to output on a TV. */ +#define CEC_OPCODE_GIVE_OSD_NAME 0X46 /**< Used to request the preferred OSD name of a device for use in menus associated with that device. */ +#define CEC_OPCODE_SET_OSD_NAME 0X47 /**< Used to set the preferred OSD name of a device for use in menus associated with that device. */ +/**< Device Menu Control Feature*/ +#define CEC_OPCODE_MENU_REQUEST 0X8D /**< A request from the TV for a device to show/remove a menu or to query if a device is currently showing a menu. */ +#define CEC_OPCODE_MENU_STATUS 0X8E /**< Used to indicate to the TV that the device is showing/has removed a menu and requests the remote control keys to be passed though. */ +#define CEC_OPCODE_USER_CONTROL_PRESSED 0X44 /**< Used to indicate that the user pressed a remote control button or switched from one remote control button to another. */ +#define CEC_OPCODE_USER_CONTROL_RELEASED 0X45 /**< Indicates that user released a remote control button (the last one indicated by the message) */ +/**< Power Status Feature*/ +#define CEC_OPCODE_GIVE_DEVICE_POWER_STATUS 0X8F /**< Used to determine the current power status of a target device */ +#define CEC_OPCODE_REPORT_POWER_STATUS 0X90 /**< Used to inform a requesting device of the current power status */ +/**< System Audio Control Feature*/ +#define CEC_OPCODE_GIVE_AUDIO_STATUS 0X71 /**< Requests an amplifier to send its volume and mute status */ +#define CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7D /**< Requests the status of the System Audio Mode */ +#define CEC_OPCODE_REPORT_AUDIO_STATUS 0X7A /**< Reports an amplifier¡¯s volume and mute status */ +#define CEC_OPCODE_SET_SYSTEM_AUDIO_MODE 0X72 /**< Turns the System Audio Mode On or Off. */ +#define CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST 0X70 /**< A device implementing System Audio Control and which has volume control RC buttons (eg TV or STB) requests to use System Audio Mode to the amplifier */ +#define CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS 0X7E /**< Reports the current status of the System Audio Mode */ +/**< Audio Rate Control Feature*/ +#define CEC_OPCODE_SET_AUDIO_RATE 0X9A /**< Used to control audio rate from Source Device. */ + +#define CEC_OPCODE_POLLING_MESSAGE 0XFE/**< POLL message have no opcode, So, we just use this value */ + +typedef enum hiUNF_CEC_LOGICALADD_S +{ + HI_CEC_LOGICALADD_TV = 0X00, + HI_CEC_LOGICALADD_RECORDDEV_1 = 0X01, + HI_CEC_LOGICALADD_RECORDDEV_2 = 0X02, + HI_CEC_LOGICALADD_TUNER_1 = 0X03, + HI_CEC_LOGICALADD_PLAYDEV_1 = 0X04, + HI_CEC_LOGICALADD_AUDIOSYSTEM = 0X05, + HI_CEC_LOGICALADD_TUNER_2 = 0X06, + HI_CEC_LOGICALADD_TUNER_3 = 0X07, + HI_CEC_LOGICALADD_PLAYDEV_2 = 0X08, + HI_CEC_LOGICALADD_RECORDDEV_3 = 0X09, + HI_CEC_LOGICALADD_TUNER_4 = 0X0A, + HI_CEC_LOGICALADD_PLAYDEV_3 = 0X0B, + HI_CEC_LOGICALADD_RESERVED_1 = 0X0C, + HI_CEC_LOGICALADD_RESERVED_2 = 0X0D, + HI_CEC_LOGICALADD_SPECIALUSE = 0X0E, + HI_CEC_LOGICALADD_BROADCAST = 0X0F, + HI_CEC_LOGICALADD_BUTT +}HI_CEC_LOGICALADD_S; + +typedef enum hiUNF_CEC_CMDTYPE_E +{ + HI_CEC_STRUCTCOMMAND, + HI_CEC_RAWCOMMAND, + HI_CEC_BUTT +}HI_CEC_CMDTYPE_E; + +typedef struct hiUNF_CEC_RAWDATA_S +{ + HI_U8 u8Length; + HI_U8 u8Data[15]; +}HI_CEC_RAWDATA_S; + +typedef enum hiUNF_CEC_UICMD_E /**< User Interface Command Opcode */ +{ + HI_CEC_UICMD_SELECT = 0x00, + HI_CEC_UICMD_UP = 0x01, + HI_CEC_UICMD_DOWN = 0x02, + HI_CEC_UICMD_LEFT = 0x03, + HI_CEC_UICMD_RIGHT = 0x04, + HI_CEC_UICMD_RIGHT_UP = 0x05, + HI_CEC_UICMD_RIGHT_DOWN = 0x06, + HI_CEC_UICMD_LEFT_UP = 0x07, + HI_CEC_UICMD_LEFT_DOWN = 0x08, + HI_CEC_UICMD_ROOT_MENU = 0x09, + HI_CEC_UICMD_SETUP_MENU = 0x0A, + HI_CEC_UICMD_CONTENTS_MENU = 0x0B, + HI_CEC_UICMD_FAVORITE_MENU = 0x0C, + HI_CEC_UICMD_EXIT = 0x0D, + HI_CEC_UICMD_NUM_0 = 0x20, + HI_CEC_UICMD_NUM_1 = 0x21, + HI_CEC_UICMD_NUM_2 = 0x22, + HI_CEC_UICMD_NUM_3 = 0x23, + HI_CEC_UICMD_NUM_4 = 0x24, + HI_CEC_UICMD_NUM_5 = 0x25, + HI_CEC_UICMD_NUM_6 = 0x26, + HI_CEC_UICMD_NUM_7 = 0x27, + HI_CEC_UICMD_NUM_8 = 0x28, + HI_CEC_UICMD_NUM_9 = 0x29, + HI_CEC_UICMD_DOT = 0x2A, + HI_CEC_UICMD_ENTER = 0x2B, + HI_CEC_UICMD_CLEAR = 0x2C, + HI_CEC_UICMD_NEXT_FAVORITE = 0x2F, + HI_CEC_UICMD_CHANNEL_UP = 0x30, + HI_CEC_UICMD_CHANNEL_DOWN = 0x31, + HI_CEC_UICMD_PREVIOUS_CHANNEL = 0x32, + HI_CEC_UICMD_SOUND_SELECT = 0x33, + HI_CEC_UICMD_INPUT_SELECT = 0x34, + HI_CEC_UICMD_DISPLAY_INFORMATION = 0x35, + HI_CEC_UICMD_HELP = 0x36, + HI_CEC_UICMD_PAGE_UP = 0x37, + HI_CEC_UICMD_PAGE_DOWN = 0x38, + HI_CEC_UICMD_POWER = 0x40, + HI_CEC_UICMD_VOLUME_UP = 0x41, + HI_CEC_UICMD_VOLUME_DOWN = 0x42, + HI_CEC_UICMD_MUTE = 0x43, + HI_CEC_UICMD_PLAY = 0x44, + HI_CEC_UICMD_STOP = 0x45, + HI_CEC_UICMD_PAUSE = 0x46, + HI_CEC_UICMD_RECORD = 0x47, + HI_CEC_UICMD_REWIND = 0x48, + HI_CEC_UICMD_FAST_FORWARD = 0x49, + HI_CEC_UICMD_EJECT = 0x4A, + HI_CEC_UICMD_FORWARD = 0x4B, + HI_CEC_UICMD_BACKWARD = 0x4C, + HI_CEC_UICMD_STOP_RECORD = 0x4D, + HI_CEC_UICMD_PAUSE_RECORD = 0x4E, + HI_CEC_UICMD_ANGLE = 0x50, + HI_CEC_UICMD_SUBPICTURE = 0x51, + HI_CEC_UICMD_VIDEO_ON_DEMAND = 0x52, + HI_CEC_UICMD_ELECTRONIC_PROGRAM_GUIDE = 0x53, + HI_CEC_UICMD_TIMER_PROGRAMMING = 0x54, + HI_CEC_UICMD_INITIAL_CONFIGURATION = 0x55, + HI_CEC_UICMD_PLAY_FUNCTION = 0x60, + HI_CEC_UICMD_PAUSE_PLAY_FUNCTION = 0x61, + HI_CEC_UICMD_RECORD_FUNCTION = 0x62, + HI_CEC_UICMD_PAUSE_RECORD_FUNCTION = 0x63, + HI_CEC_UICMD_STOP_FUNCTION = 0x64, + HI_CEC_UICMD_MUTE_FUNCTION = 0x65, + HI_CEC_UICMD_RESTORE_VOLUME_FUNCTION = 0x66, + HI_CEC_UICMD_TUNE_FUNCTION = 0x67, + HI_CEC_UICMD_SELECT_MEDIA_FUNCTION = 0x68, + HI_CEC_UICMD_SELECT_AV_INPUT_FUNCTION = 0x69, + HI_CEC_UICMD_SELECT_AUDIO_INPUT_FUNCTION = 0x6A, + HI_CEC_UICMD_POWER_TOGGLE_FUNCTION = 0x6B, + HI_CEC_UICMD_POWER_OFF_FUNCTION = 0x6C, + HI_CEC_UICMD_POWER_ON_FUNCTION = 0x6D, + HI_CEC_UICMD_F1_BLUE = 0x71, + HI_CEC_UICMD_F2_RED = 0x72, + HI_CEC_UICMD_F3_GREEN = 0x73, + HI_CEC_UICMD_F4_YELLOW = 0x74, + HI_CEC_UICMD_F5 = 0x75, + HI_CEC_UICMD_DATA = 0x76 +}HI_CEC_UICMD_E; /* User Control Code */ + +typedef union hiUNF_CEC_Operand_t +{ + HI_CEC_RAWDATA_S stRawData; + HI_CEC_UICMD_E stUIOpcode; +}HI_CEC_Operand_t; + +typedef struct hiUNF_HDMI_CEC_CMD_S +{ + HI_CEC_LOGICALADD_S enSrcAdd; + HI_CEC_LOGICALADD_S enDstAdd; + HI_U8 u8Opcode; + HI_CEC_Operand_t unOperand; +}HI_HDMI_CEC_CMD_S; + +typedef struct hiUNF_HDMI_CEC_STATUS_S +{ + HI_BOOL bEnable; + HI_U8 u8PhysicalAddr[4]; /**< CEC physic addr */ + HI_U8 u8LogicalAddr; /**< CEC logic addr, default:0x03. */ + HI_U8 u8Network[HI_CEC_LOGICALADD_BUTT]; /**< CEC's net work£¬1:this device can answer cec command */ +}HI_HDMI_CEC_STATUS_S; + + +typedef enum hiERR_HDMI_CODE_E +{ + ERR_HDMI_NOT_INIT = 1, + ERR_HDMI_INVALID_PARA = 2, + ERR_HDMI_NUL_PTR = 3, + ERR_HDMI_DEV_NOT_OPEN = 4, + ERR_HDMI_DEV_NOT_CONNECT = 5, + ERR_HDMI_READ_SINK_FAILED = 6, + ERR_HDMI_INIT_ALREADY = 7, + ERR_HDMI_CALLBACK_ALREADY = 8, + ERR_HDMI_INVALID_CALLBACK = 9, + ERR_HDMI_FEATURE_NO_SUPPORT = 10, + ERR_HDMI_BUS_BUSY = 11, + ERR_HDMI_READ_EVENT_FAILED = 12, + ERR_HDMI_NOT_START = 13, + ERR_HDMI_READ_EDID_FAILED = 14, + + ERR_HDMI_BUTT, +} ERR_HDMI_CODE_E; + +#define HI_ERR_HDMI_NOT_INIT HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_NOT_INIT) +#define HI_ERR_HDMI_INVALID_PARA HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_INVALID_PARA) +#define HI_ERR_HDMI_NUL_PTR HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_NUL_PTR) +#define HI_ERR_HDMI_DEV_NOT_OPEN HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_DEV_NOT_OPEN) +#define HI_ERR_HDMI_DEV_NOT_CONNECT HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_DEV_NOT_CONNECT) +#define HI_ERR_HDMI_READ_SINK_FAILED HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_READ_SINK_FAILED) +#define HI_ERR_HDMI_INIT_ALREADY HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_INIT_ALREADY) +#define HI_ERR_HDMI_CALLBACK_ALREADY HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_CALLBACK_ALREADY) +#define HI_ERR_HDMI_INVALID_CALLBACK HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_INVALID_CALLBACK) +#define HI_ERR_HDMI_FEATURE_NO_SUPPORT HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_FEATURE_NO_SUPPORT) +#define HI_ERR_HDMI_BUS_BUSY HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_BUS_BUSY) +#define HI_ERR_HDMI_READ_EVENT_FAILED HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_READ_EVENT_FAILED) +#define HI_ERR_HDMI_NOT_START HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_NOT_START) +#define HI_ERR_HDMI_READ_EDID_FAILED HI_DEF_ERR(HI_ID_HDMI, EN_ERR_LEVEL_ERROR, ERR_HDMI_READ_EDID_FAILED) + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_VO_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_ive.h b/snes9x/unix/mpp/hi_comm_ive.h new file mode 100644 index 0000000..801c627 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_ive.h @@ -0,0 +1,340 @@ +/****************************************************************************** + + Copyright (C), 2001-2014, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_ive.h + Version : Initial Draft + Author : Hisilicon multimedia software (IVE) group + Created : 2011/05/16 + Description : + History : + 1.Date : 2011/05/16 + Author : + Modification: Created file + + 2.Date : 2013/07/01~2014/08/08 + Author : + Modification: Add MPI function +******************************************************************************/ +#ifndef _HI_COMM_IVE_H_ +#define _HI_COMM_IVE_H_ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif + +#include "hi_type.h" +#include "hi_errno.h" + +/*-----------------------------------------------* + * The fixed-point data type, will be used to * + * represent float data in hardware calculations.* + *-----------------------------------------------*/ + +/*--u8bit----------------------------------------*/ +typedef unsigned char HI_U0Q8; +typedef unsigned char HI_U1Q7; +typedef unsigned char HI_U5Q3; + +/*--u16bit---------------------------------------*/ +typedef unsigned short HI_U0Q16; +typedef unsigned short HI_U4Q12; +typedef unsigned short HI_U6Q10; +typedef unsigned short HI_U8Q8; +typedef unsigned short HI_U12Q4; +typedef unsigned short HI_U14Q2; + +/*--s16bit---------------------------------------*/ +typedef short HI_S9Q7; +typedef short HI_S14Q2; +typedef short HI_S1Q15; + +/*--u32bit---------------------------------------*/ +typedef unsigned int HI_U22Q10; +typedef unsigned int HI_U25Q7; + +/*--s32bit---------------------------------------*/ +typedef int HI_S25Q7; +typedef int HI_S16Q16; + +/*-----------------------------------------------* + * The fixed-point data type combine with flag_bits.* + *-----------------------------------------------*/ + +/*8bits unsigned integer,4bits decimal fraction,4bits flag_bits*/ +typedef unsigned short HI_U8Q4F4; + +/*float*/ +typedef float HI_FLOAT; +/*double*/ +typedef double HI_DOUBLE; + +/* +* Type of the IVE_IMAGE_S data. +* Aded by tanbing 2013-7-22 +*/ +typedef enum hiIVE_IMAGE_TYPE_E +{ + IVE_IMAGE_TYPE_U8C1 = 0x0, + IVE_IMAGE_TYPE_S8C1 = 0x1, + + IVE_IMAGE_TYPE_YUV420SP = 0x2, /*YUV420 SemiPlanar*/ + IVE_IMAGE_TYPE_YUV422SP = 0x3, /*YUV422 SemiPlanar*/ + IVE_IMAGE_TYPE_YUV420P = 0x4, /*YUV420 Planar */ + IVE_IMAGE_TYPE_YUV422P = 0x5, /*YUV422 planar */ + + IVE_IMAGE_TYPE_S8C2_PACKAGE = 0x6, + IVE_IMAGE_TYPE_S8C2_PLANAR = 0x7, + + IVE_IMAGE_TYPE_S16C1 = 0x8, + IVE_IMAGE_TYPE_U16C1 = 0x9, + + IVE_IMAGE_TYPE_U8C3_PACKAGE = 0xa, + IVE_IMAGE_TYPE_U8C3_PLANAR = 0xb, + + IVE_IMAGE_TYPE_S32C1 = 0xc, + IVE_IMAGE_TYPE_U32C1 = 0xd, + + IVE_IMAGE_TYPE_S64C1 = 0xe, + IVE_IMAGE_TYPE_U64C1 = 0xf, + + IVE_IMAGE_TYPE_BUTT + +}IVE_IMAGE_TYPE_E; + +/* +* Definition of the IVE_IMAGE_S. +* Added by Tan Bing, 2013-7-22. +*/ +typedef struct hiIVE_IMAGE_S +{ + IVE_IMAGE_TYPE_E enType; + + HI_U32 u32PhyAddr[3]; + HI_U8 *pu8VirAddr[3]; + + HI_U16 u16Stride[3]; + HI_U16 u16Width; + HI_U16 u16Height; + + HI_U16 u16Reserved; /*Can be used such as elemSize*/ +}IVE_IMAGE_S; + +typedef IVE_IMAGE_S IVE_SRC_IMAGE_S; +typedef IVE_IMAGE_S IVE_DST_IMAGE_S; + +/* +* Definition of the IVE_MEM_INFO_S.This struct special purpose for input or ouput, such as Hist, CCL, ShiTomasi. +* Added by Chen Quanfu, 2013-7-23. +*/ +typedef struct hiIVE_MEM_INFO_S +{ + HI_U32 u32PhyAddr; + HI_U8 *pu8VirAddr; + HI_U32 u32Size; +}IVE_MEM_INFO_S; +typedef IVE_MEM_INFO_S IVE_SRC_MEM_INFO_S; +typedef IVE_MEM_INFO_S IVE_DST_MEM_INFO_S; + +/* +*Data struct ,created by Chen Quanfu 2013-07-19 +*/ +typedef struct hiIVE_DATA_S +{ + HI_U32 u32PhyAddr; /*Physical address of the data*/ + HI_U8 *pu8VirAddr; + + HI_U16 u16Stride; /*2D data stride by byte*/ + HI_U16 u16Width; /*2D data width by byte*/ + HI_U16 u16Height; /*2D data height*/ + + HI_U16 u16Reserved; +}IVE_DATA_S; +typedef IVE_DATA_S IVE_SRC_DATA_S; +typedef IVE_DATA_S IVE_DST_DATA_S; + +/* +* Definition of the union of IVE_8BIT_U. +* Added by Tan Bing, 2013-7-22. +*/ +typedef union hiIVE_8BIT_U +{ + HI_S8 s8Val; + HI_U8 u8Val; +}IVE_8BIT_U; + +/* +* Definition of u16 point +*/ +typedef struct hiIVE_POINT_U16_S +{ + HI_U16 u16X; + HI_U16 u16Y; +}IVE_POINT_U16_S; + +/* +*Float point represented by Fixed-point SQ25.7 +*/ +typedef struct hiIVE_POINT_S25Q7_S +{ + HI_S25Q7 s25q7X; /*X coordinate*/ + HI_S25Q7 s25q7Y; /*Y coordinate*/ +}IVE_POINT_S25Q7_S; + +/* +* Definition of rect +*/ +typedef struct hiIVE_RECT_U16_S +{ + HI_U16 u16X; + HI_U16 u16Y; + HI_U16 u16Width; + HI_U16 u16Height; +}IVE_RECT_U16_S; + +typedef struct hiIVE_LOOK_UP_TABLE_S +{ + IVE_MEM_INFO_S stTable; + HI_U16 u16ElemNum; /*LUT's elements number*/ + + HI_U8 u8TabInPreci; + HI_U8 u8TabOutNorm; + + HI_S32 s32TabInLower; /*LUT's original input lower limit*/ + HI_S32 s32TabInUpper; /*LUT's original input upper limit*/ +}IVE_LOOK_UP_TABLE_S; + + +typedef enum hiEN_IVE_ERR_CODE_E +{ + ERR_IVE_SYS_TIMEOUT = 0x40, /* IVE process timeout */ + ERR_IVE_QUERY_TIMEOUT = 0x41, /* IVE query timeout */ + ERR_IVE_OPEN_FILE = 0x42, /* IVE open file error */ + ERR_IVE_READ_FILE = 0x43, /* IVE read file error */ + ERR_IVE_WRITE_FILE = 0x44, /* IVE write file error */ + + ERR_IVE_BUTT +}EN_IVE_ERR_CODE_E; + +typedef enum hiEN_FD_ERR_CODE_E +{ + ERR_FD_SYS_TIMEOUT = 0x40, /* FD process timeout */ + ERR_FD_CFG = 0x41, /* FD configuration error */ + ERR_FD_FACE_NUM_OVER = 0x42, /* FD candidate face number over*/ + ERR_FD_OPEN_FILE = 0x43, /* FD open file error */ + ERR_FD_READ_FILE = 0x44, /* FD read file error */ + ERR_FD_WRITE_FILE = 0x45, /* FD write file error */ + + ERR_FD_BUTT +}EN_FD_ERR_CODE_E; + +/************************************************IVE error code ***********************************/ +/*Invalid device ID*/ +#define HI_ERR_IVE_INVALID_DEVID HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/*Invalid channel ID*/ +#define HI_ERR_IVE_INVALID_CHNID HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/*At least one parameter is illegal. For example, an illegal enumeration value exists.*/ +#define HI_ERR_IVE_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/*The channel exists.*/ +#define HI_ERR_IVE_EXIST HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/*The UN exists.*/ +#define HI_ERR_IVE_UNEXIST HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/*A null point is used.*/ +#define HI_ERR_IVE_NULL_PTR HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/*Try to enable or initialize the system, device, or channel before configuring attributes.*/ +#define HI_ERR_IVE_NOT_CONFIG HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/*The operation is not supported currently.*/ +#define HI_ERR_IVE_NOT_SURPPORT HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/*The operation, changing static attributes for example, is not permitted.*/ +#define HI_ERR_IVE_NOT_PERM HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/*A failure caused by the malloc memory occurs.*/ +#define HI_ERR_IVE_NOMEM HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/*A failure caused by the malloc buffer occurs.*/ +#define HI_ERR_IVE_NOBUF HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/*The buffer is empty.*/ +#define HI_ERR_IVE_BUF_EMPTY HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/*No buffer is provided for storing new data.*/ +#define HI_ERR_IVE_BUF_FULL HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/*The system is not ready because it may be not initialized or loaded. + *The error code is returned when a device file fails to be opened. */ +#define HI_ERR_IVE_NOTREADY HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) + +/*The source address or target address is incorrect during the operations such as calling copy_from_user or copy_to_user.*/ +#define HI_ERR_IVE_BADADDR HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_BADADDR) +/*The resource is busy during the operations such as destroying a VENC channel without deregistering it.*/ +#define HI_ERR_IVE_BUSY HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + +/*IVE process timeout: 0xA01D8040*/ +#define HI_ERR_IVE_SYS_TIMEOUT HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, ERR_IVE_SYS_TIMEOUT) +/*IVE query timeout: 0xA01D8041*/ +#define HI_ERR_IVE_QUERY_TIMEOUT HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, ERR_IVE_QUERY_TIMEOUT) +/*IVE open file error: 0xA01D8042*/ +#define HI_ERR_IVE_OPEN_FILE HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, ERR_IVE_OPEN_FILE) +/*IVE read file error: 0xA01D8043*/ +#define HI_ERR_IVE_READ_FILE HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, ERR_IVE_READ_FILE) +/*IVE read file error: 0xA01D8044*/ +#define HI_ERR_IVE_WRITE_FILE HI_DEF_ERR(HI_ID_IVE, EN_ERR_LEVEL_ERROR, ERR_IVE_WRITE_FILE) + +/************************************************FD error code ***********************************/ +/*Invalid device ID*/ +#define HI_ERR_FD_INVALID_DEVID HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/*Invalid channel ID*/ +#define HI_ERR_FD_INVALID_CHNID HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/*At least one parameter is illegal. For example, an illegal enumeration value exists.*/ +#define HI_ERR_FD_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/*The channel exists.*/ +#define HI_ERR_FD_EXIST HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/*The UN exists.*/ +#define HI_ERR_FD_UNEXIST HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/*A null point is used.*/ +#define HI_ERR_FD_NULL_PTR HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/*Try to enable or initialize the system, device, or channel before configuring attributes.*/ +#define HI_ERR_FD_NOT_CONFIG HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/*The operation is not supported currently.*/ +#define HI_ERR_FD_NOT_SURPPORT HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/*The operation, changing static attributes for example, is not permitted.*/ +#define HI_ERR_FD_NOT_PERM HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/*A failure caused by the malloc memory occurs.*/ +#define HI_ERR_FD_NOMEM HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/*A failure caused by the malloc buffer occurs.*/ +#define HI_ERR_FD_NOBUF HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/*The buffer is empty.*/ +#define HI_ERR_FD_BUF_EMPTY HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/*No buffer is provided for storing new data.*/ +#define HI_ERR_FD_BUF_FULL HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/*The system is not ready because it may be not initialized or loaded. + *The error code is returned when a device file fails to be opened. */ +#define HI_ERR_FD_NOTREADY HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/*The source address or target address is incorrect during the operations such as calling copy_from_user or copy_to_user.*/ +#define HI_ERR_FD_BADADDR HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_BADADDR) +/*The resource is busy during the operations such as destroying a VENC channel without deregistering it.*/ +#define HI_ERR_FD_BUSY HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +/*FD process timeout: 0xA02F8040*/ +#define HI_ERR_FD_SYS_TIMEOUT HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_SYS_TIMEOUT) +/*FD configuration error: 0xA02F8041*/ +#define HI_ERR_FD_CFG HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_CFG) +/*FD candidate face number over: 0xA02F8042*/ +#define HI_ERR_FD_FACE_NUM_OVER HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_FACE_NUM_OVER) +/*FD open file error: 0xA02F8043*/ +#define HI_ERR_FD_OPEN_FILE HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_OPEN_FILE) +/*FD read file error: 0xA02F8044*/ +#define HI_ERR_FD_READ_FILE HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_READ_FILE) +/*FD read file error: 0xA02F8045*/ +#define HI_ERR_FD_WRITE_FILE HI_DEF_ERR(HI_ID_FD, EN_ERR_LEVEL_ERROR, ERR_FD_WRITE_FILE) + +/************************************************ODT error code ***********************************/ +/*ODT exist: 0xA0308004*/ +#define HI_ERR_ODT_EXIST HI_DEF_ERR(HI_ID_ODT, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/*ODT the system is not ready because it may be not initialized: 0xA0308010*/ +#define HI_ERR_ODT_NOTREADY HI_DEF_ERR(HI_ID_ODT, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/*ODT busy: 0xA0308012*/ +#define HI_ERR_ODT_BUSY HI_DEF_ERR(HI_ID_ODT, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif/*__HI_COMM_IVE_H__*/ diff --git a/snes9x/unix/mpp/hi_comm_pciv.h b/snes9x/unix/mpp/hi_comm_pciv.h new file mode 100644 index 0000000..6153fbf --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_pciv.h @@ -0,0 +1,286 @@ + +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_pciv.h + Version : Initial Draft + Author : Hisilicon multimedia software pciv + Created : 2008/06/04 + Last Modified : + Description : common struct definition for PCIV + Function List : + History : + +******************************************************************************/ + +#ifndef __HI_COMM_PCIV_H__ +#define __HI_COMM_PCIV_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" +#include "hi_comm_vdec.h" +#include "hi_comm_vpss.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +typedef HI_S32 PCIV_CHN; + +#define PCIV_MAX_BUF_NUM 16 /* pciv channel max buffer number */ +#define PCIV_MAX_CHIPNUM 32 /* max pciv device number which can join in the system */ +#define PCIV_TIMER_EXPIRES 10 + +#define MAKE_DWORD(high,low) (((low)&0x0000ffff)|((high)<<16)) +#define HIGH_WORD(x) (((x)&0xffff0000)>>16) +#define LOW_WORD(x) ((x)&0x0000ffff) + +/* vi object struct */ +typedef struct hiPCIV_VIDEVICE_S +{ + VI_DEV viDev; /* vi device number */ + VI_CHN viChn; /* vi channel number */ +} PCIV_VIDEVICE_S; + +/* vo object struct */ +typedef struct hiPCIV_VODEVICE_S +{ + VO_DEV voDev; /* vo device number */ + VO_CHN voChn; /* vo channel number */ +} PCIV_VODEVICE_S; + +/* vdec object struct */ +typedef struct hiPCIV_VDECDEVICE_S +{ + VDEC_CHN vdecChn; /* vedc channel number */ +} PCIV_VDECDEVICE_S; + +/* vpss object struct */ +typedef struct hiPCIV_VPSSDEVICE_S +{ + VPSS_GRP vpssGrp; /* vpss group number */ + VPSS_CHN vpssChn; /* vpss channel number */ +} PCIV_VPSSDEVICE_S; + +/* venc object struct */ +typedef struct hiPCIV_VENCDEVICE_S +{ + VENC_CHN vencChn; /* venc channel number */ +} PCIV_VENCDEVICE_S; + +/* bind type for pciv */ +typedef enum hiPCIV_BIND_TYPE_E +{ + PCIV_BIND_VI = 0, + PCIV_BIND_VO = 1, + PCIV_BIND_VDEC = 2, + PCIV_BIND_VPSS = 3, + PCIV_BIND_VENC = 4, + PCIV_BIND_BUTT +} PCIV_BIND_TYPE_E; + +/* bind object struct for pciv */ +typedef struct hiPCI_BIND_OBJ_S +{ + HI_BOOL bVpssSend; + PCIV_BIND_TYPE_E enType; /* bind type for pciv */ + union + { + PCIV_VIDEVICE_S viDevice; + PCIV_VODEVICE_S voDevice; + PCIV_VDECDEVICE_S vdecDevice; + PCIV_VPSSDEVICE_S vpssDevice; + PCIV_VENCDEVICE_S vencDevice; + } unAttachObj; +} PCIV_BIND_OBJ_S; + +/* remote pciv object */ +typedef struct hiPCIV_REMOTE_OBJ_S +{ + HI_S32 s32ChipId; /* remote pciv device Id number */ + PCIV_CHN pcivChn; /* pciv channel number of remote pciv device */ +} PCIV_REMOTE_OBJ_S; + +/* attribution of target picture */ +typedef struct hiPCIV_PIC_ATTR_S +{ + HI_U32 u32Width; /* pciture width of pciv channel */ + HI_U32 u32Height; /* picture height of pciv channel */ + HI_U32 u32Stride[3]; /* pciture stride of pciv channel */ + VIDEO_FIELD_E u32Field; /* video frame field type of pciv channel */ + PIXEL_FORMAT_E enPixelFormat; /* pixel format of pciture of pciv channel */ +} PCIV_PIC_ATTR_S; + + +/* attribution of pciv chn */ +typedef struct hiPCIV_ATTR_S +{ + PCIV_PIC_ATTR_S stPicAttr; /* picture attibute */ + HI_S32 s32BufChip; /* The chip id which buffer is belong to */ + HI_U32 u32BlkSize; /* vb size of receiver for preview */ + HI_U32 u32Count; /* lenght of address list */ + HI_U32 u32PhyAddr[PCIV_MAX_BUF_NUM]; /* address list for picture move */ + PCIV_REMOTE_OBJ_S stRemoteObj; /* remote pciv object */ +} PCIV_ATTR_S; + +/* max count of video buffer block for pci window */ +#define PCIV_MAX_VBCOUNT 8 + +/* mpp video buffer config for pci window */ +typedef struct hiPCIV_WINVBCFG_S +{ + HI_U32 u32PoolCount; /* total number of video buffer pool */ + HI_U32 u32BlkSize[PCIV_MAX_VBCOUNT]; /* size of video buffer pool */ + HI_U32 u32BlkCount[PCIV_MAX_VBCOUNT]; /* number of video buffer pool */ +} PCIV_WINVBCFG_S; + +typedef struct hiPCIV_BASEWINDOW_S +{ + HI_S32 s32ChipId; /* pciv device number */ + HI_U32 u32NpWinBase; /* non-prefetch window pcie base address */ + HI_U32 u32PfWinBase; /* prefetch window pcie base address */ + HI_U32 u32CfgWinBase; /* config window pcie base address */ + HI_U32 u32PfAHBAddr; /* prefetch window AHB base address */ +} PCIV_BASEWINDOW_S; + +#define PCIV_MAX_DMABLK 128 +typedef struct hiPCIV_DMA_BLOCK_S +{ + HI_U32 u32SrcAddr; /* source address of dma task */ + HI_U32 u32DstAddr; /* destination address of dma task */ + HI_U32 u32BlkSize; /* data block size of dma task */ +} PCIV_DMA_BLOCK_S; + +typedef struct hiPCIV_DMA_TASK_S +{ + HI_U32 u32Count; /* total dma task number */ + HI_BOOL bRead; /* dam task is read or write data */ + PCIV_DMA_BLOCK_S *pBlock; +} PCIV_DMA_TASK_S; + + +/* + * Message port used in pciv_drvadp, you can't use it in your application. + */ +#define PCIV_MSGPORT_KERNEL 80 + + +/* + * You should not use follow mocros, they will be deleted ! + */ +#define PCIV_MSGPORT_MAXPORT 100 +#define PCIV_MSGPORT_TIME 79 +#define PCIV_MSGPORT_USERCMD 81 +#define PCIV_MSGPORT_USERNOTIFY2HOST 82 +#define PCIV_MSGPORT_USERNOTIFY2SLAVE 83 +#define PCIV_MSGPORT_USERNOTIFY2HOST_VDEC 84 +#define PCIV_MSGPORT_USERNOTIFY2SLAVE_VDEC 85 +#define PCIV_MAXVO_BIND 4 +/*----------------------------------------*/ + +typedef enum hiPCIV_FILTER_TYPE_E +{ + PCIV_FILTER_TYPE_NORM, + PCIV_FILTER_TYPE_EX, + PCIV_FILTER_TYPE_EX2, + + PCIV_FILTER_TYPE_BUTT +} PCIV_FILTER_TYPE_E; + +typedef enum hiPCIV_PIC_FIELD_E +{ + PCIV_FIELD_TOP, + PCIV_FIELD_BOTTOM, + PCIV_FIELD_BOTH, + + PCIV_FIELD_BUTT +} PCIV_PIC_FIELD_E; + +/* + * configuration of pre-process before sending source picture whth PCI + * item in this structrue have default value when sys init + */ +typedef struct hiPCIV_PREPROC_CFG_S +{ + PCIV_PIC_FIELD_E enFieldSel; /* pictrue field select */ + PCIV_FILTER_TYPE_E enFilterType; /* filter group type */ +} PCIV_PREPROC_CFG_S; + + +#if 0 +/* Synchronize the time and PTS. The host is base. */ +typedef struct hiPCIV_TIME_SYNC_S +{ + struct timeval stSysTime; /* The current system time */ + HI_U64 u64PtsBase; /* The media PTS */ + HI_U32 u32ReqTagId; +} PCIV_TIME_SYNC_S; +#endif + +/* invlalid channel ID */ +#define HI_ERR_PCIV_INVALID_CHNID HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_PCIV_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_PCIV_EXIST HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/* channel exists */ +#define HI_ERR_PCIV_UNEXIST HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_PCIV_NULL_PTR HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_PCIV_NOT_CONFIG HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_PCIV_NOT_SUPPORT HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_PCIV_NOT_PERM HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_PCIV_NOMEM HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_PCIV_NOBUF HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_PCIV_BUF_EMPTY HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_PCIV_BUF_FULL HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_PCIV_SYS_NOTREADY HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/* One DMA task is working, wait a minute */ +#define HI_ERR_PCIV_BUSY HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_PCIV_TIMEOUT HI_DEF_ERR(HI_ID_PCIV, EN_ERR_LEVEL_ERROR, EN_ERR_BUTT+1) + +#define PCIV_TRACE(level, fmt...)\ +do{ \ + HI_TRACE(level, HI_ID_PCIV,"[Func]:%s [Line]:%d [Info]:", __FUNCTION__, __LINE__);\ + HI_TRACE(level,HI_ID_PCIV,##fmt);\ +}while(0) + +#define PCIV_CHECK_CHNID(ChnID)\ +do{\ + if(((ChnID) < 0) || ((ChnID) >= PCIV_MAX_CHN_NUM))\ + {\ + PCIV_TRACE(HI_DBG_ERR, "invalid chn id:%d \n", ChnID);\ + return HI_ERR_PCIV_INVALID_CHNID;\ + }\ +}while(0) + +#define PCIV_CHECK_PTR(ptr)\ +do{\ + if(NULL == (ptr))\ + {\ + return HI_ERR_PCIV_NULL_PTR;\ + }\ +}while(0) + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ +#endif /* __HI_COMM_PCIV_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_rc.h b/snes9x/unix/mpp/hi_comm_rc.h new file mode 100644 index 0000000..7239e68 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_rc.h @@ -0,0 +1,324 @@ +/****************************************************************************** + + Copyright (C), 2001-2012, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_rc.h + Version : + Author : Hisilicon Hi35xx MPP Team + Created : 2006/11/24 + Last Modified : + Description : common struct definition for Rate control + Function List : + History : +******************************************************************************/ +#ifndef __HI_COMM_RC_H__ +#define __HI_COMM_RC_H__ + +#include "hi_defines.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +typedef HI_U32 HI_FR32; + +typedef enum hiVENC_RC_MODE_E +{ + VENC_RC_MODE_H264CBR = 1, + VENC_RC_MODE_H264VBR, + VENC_RC_MODE_H264ABR, + VENC_RC_MODE_H264FIXQP, + + VENC_RC_MODE_MJPEGCBR, + VENC_RC_MODE_MJPEGVBR, + VENC_RC_MODE_MJPEGABR, + VENC_RC_MODE_MJPEGFIXQP, + + VENC_RC_MODE_MPEG4CBR, + VENC_RC_MODE_MPEG4VBR, + VENC_RC_MODE_MPEG4ABR, + VENC_RC_MODE_MPEG4FIXQP, + + VENC_RC_MODE_H265CBR, + VENC_RC_MODE_H265VBR, + VENC_RC_MODE_H265FIXQP, + + VENC_RC_MODE_BUTT, + +}VENC_RC_MODE_E; + + +typedef struct hiVENC_ATTR_H264_FIXQP_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32IQp; /* qp of the i frame */ + HI_U32 u32PQp; /* qp of the p frame */ +} VENC_ATTR_H264_FIXQP_S; + +typedef struct hiVENC_ATTR_H264_CBR_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32BitRate; /* average bitrate */ + HI_U32 u32FluctuateLevel; /* level [0..5].scope of bitrate fluctuate. 1-5: 10%-50%. 0: SDK optimized, recommended; */ +} VENC_ATTR_H264_CBR_S; + +typedef struct hiVENC_ATTR_H264_VBR_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32MaxBitRate; /* the max bitrate */ + HI_U32 u32MaxQp; /* the max qp */ + HI_U32 u32MinQp; /* the min qp */ +}VENC_ATTR_H264_VBR_S; + +typedef struct hiVENC_ATTR_H264_ABR_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32AvgBitRate; /* average bitrate */ + HI_U32 u32MaxBitRate; /* the max bitrate */ +}VENC_ATTR_H264_ABR_S; + +typedef struct hiVENC_ATTR_H264_CBR_S VENC_ATTR_H265_CBR_S; +typedef struct hiVENC_ATTR_H264_VBR_S VENC_ATTR_H265_VBR_S; +typedef struct hiVENC_ATTR_H264_FIXQP_S VENC_ATTR_H265_FIXQP_S; + + + +typedef struct hiVENC_ATTR_MPEG4_FIXQP_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32IQp; /* qp of the i frame */ + HI_U32 u32PQp; /* qp of the p frame */ +}VENC_ATTR_MPEG4_FIXQP_S; + +typedef struct hiVENC_ATTR_MPEG4_CBR_S +{ + HI_U32 u32Gop; /*the interval of ISLICE. */ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32BitRate; /* average bitrate */ + HI_U32 u32FluctuateLevel; /* level [0..5].scope of bitrate fluctuate. 1-5: 10%-50%. 0: SDK optimized, recommended; */ +}VENC_ATTR_MPEG4_CBR_S; + +typedef struct hiVENC_ATTR_MPEG4_VBR_S +{ + HI_U32 u32Gop; /* the interval of ISLICE. */ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32MaxBitRate; /* the max bitrate */ + HI_U32 u32MaxQp; /* the max qp */ + HI_U32 u32MinQp; /* the min qp */ +}VENC_ATTR_MPEG4_VBR_S; + +typedef struct hiVENC_ATTR_MJPEG_FIXQP_S +{ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate; /* the target frame rate of the venc chnnel */ + HI_U32 u32Qfactor; /* image quality :[1,99]*/ +}VENC_ATTR_MJPEG_FIXQP_S; + +typedef struct hiVENC_ATTR_MJPEG_CBR_S +{ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate ; /* the target frame rate of the venc chnnel */ + HI_U32 u32BitRate; /* average bitrate */ + HI_U32 u32FluctuateLevel; /* level [0..5].scope of bitrate fluctuate. 1-5: 10%-50%. 0: SDK optimized, recommended; */ +} VENC_ATTR_MJPEG_CBR_S; + +typedef struct hiVENC_ATTR_MJPEG_VBR_S +{ + HI_U32 u32StatTime; /* the rate statistic time, the unit is senconds(s) */ + HI_U32 u32SrcFrmRate; /* the input frame rate of the venc chnnel */ + HI_FR32 fr32DstFrmRate; /* the target frame rate of the venc chnnel */ + HI_U32 u32MaxBitRate; /* max bitrate */ + HI_U32 u32MaxQfactor; /* max image quailty allowed */ + HI_U32 u32MinQfactor; /* min image quality allowed */ + }VENC_ATTR_MJPEG_VBR_S; + +typedef struct hiVENC_RC_ATTR_S +{ + VENC_RC_MODE_E enRcMode; /*the type of rc*/ + union + { + VENC_ATTR_H264_CBR_S stAttrH264Cbr; + VENC_ATTR_H264_VBR_S stAttrH264Vbr; + VENC_ATTR_H264_FIXQP_S stAttrH264FixQp; + VENC_ATTR_H264_ABR_S stAttrH264Abr; + + VENC_ATTR_MPEG4_CBR_S stAttrMpeg4Cbr; + VENC_ATTR_MPEG4_FIXQP_S stAttrMpeg4FixQp; + VENC_ATTR_MPEG4_VBR_S stAttrMpeg4Vbr; + + VENC_ATTR_MJPEG_CBR_S stAttrMjpegeCbr; + VENC_ATTR_MJPEG_FIXQP_S stAttrMjpegeFixQp; + VENC_ATTR_MJPEG_VBR_S stAttrMjpegeVbr; + + VENC_ATTR_H265_CBR_S stAttrH265Cbr; + VENC_ATTR_H265_VBR_S stAttrH265Vbr; + VENC_ATTR_H265_FIXQP_S stAttrH265FixQp; + }; + HI_VOID* pRcAttr ; /*the rc attribute which could be specified by user*/ + +}VENC_RC_ATTR_S; + +typedef enum hiRC_SUPERFRM_MODE_E +{ + SUPERFRM_NONE, /* sdk don't care super frame */ + SUPERFRM_DISCARD, /* the super frame is discarded */ + SUPERFRM_REENCODE, /* the super frame is re-encode */ + SUPERFRM_BUTT +}VENC_SUPERFRM_MODE_E; + +typedef struct hiVENC_PARAM_H264_CBR_S +{ + HI_U32 u32MinIprop; /* the min ratio of i frame and p frame */ + HI_U32 u32MaxIprop; /* the max ratio of i frame and p frame */ + HI_U32 u32MaxQp; /* the max QP value */ + HI_U32 u32MinQp; /* the min QP value */ + HI_S32 s32IPQPDelta; /* the qp difference between the i frame and the before gop avarage qp; == Qp(P) - Qp(I) */ + HI_S32 s32QualityLevel; /* quality of picture [1, 5] */ + HI_S32 s32MaxReEncodeTimes; /* max number of re-encode times [0, 3]*/ + HI_U32 u32MinIQp; /* min qp for i frame */ +}VENC_PARAM_H264_CBR_S; + +typedef struct hiVENC_PARAM_H264_VBR_S +{ + HI_S32 s32IPQPDelta; /* the qp difference between the i frame and the before gop avarage qp; == Qp(P) - Qp(I) */ + HI_S32 s32ChangePos; /* Indicates the ratio of the current bit rate to the maximum + bit rate when the QP value starts to be adjusted */ + HI_U32 u32MinIprop; /* the min ratio of i frame and p frame */ + HI_U32 u32MaxIprop; /* the max ratio of i frame and p frame */ + HI_U32 u32MinIQP; /* min qp for i frame */ +}VENC_PARAM_H264_VBR_S; + + + +typedef struct hiVENC_PARAM_MJPEG_CBR_S +{ + HI_U32 u32MaxQfactor; /* the max Qfactor value*/ + HI_U32 u32MinQfactor; /* the min Qfactor value */ + HI_U32 u32RQRatio[RC_RQRATIO_SIZE]; /* the rate stabilization weight, + 100-u32RQRatio[i] is the sequence quality stabilization weight */ + +}VENC_PARAM_MJPEG_CBR_S; + +typedef struct hiVENC_PARAM_MJPEG_VBR_S +{ + HI_S32 s32DeltaQfactor; /* Indicates the maximum change of Qfactor values of frames + when the picture quality changes */ + HI_S32 s32ChangePos; /* Indicates the ratio of the current bit rate to the maximum + bit rate when the Qfactor value starts to be adjusted */ +}VENC_PARAM_MJPEG_VBR_S; + +typedef struct hiVENC_PARAM_MPEG4_CBR_S +{ + HI_U32 u32MinIprop; /* the min ratio of i frame and p frame*/ + HI_U32 u32MaxIprop; /* the max ratio of i frame and p frame */ + + HI_U32 u32MaxQp; /* the max QP value*/ + HI_U32 u32MinQp; /* the min QP value */ + HI_U32 u32MaxPPDeltaQp; /* the max qp value difference between two successive P frame */ + HI_U32 u32MaxIPDeltaQp; /* the max qp value difference between p frame and the next i frame */ + HI_S32 s32IPQPDelta; /* the qp difference between the i frame and the before gop avarage qp*/ + + HI_U32 u32RQRatio[RC_RQRATIO_SIZE]; /* the rate stabilization weight, + 100-u32RQRatio[i] is the sequence quality stabilization weight */ +}VENC_PARAM_MPEG4_CBR_S; + +typedef struct hiVENC_PARAM_MPEG4_VBR_S +{ + HI_S32 s32IPQPDelta; /* the qp difference between the i frame and the before gop avarage qp*/ + + HI_S32 s32ChangePos; /* Indicates the ratio of the current bit rate to the maximum + bit rate when the QP value starts to be adjusted */ + + HI_U32 u32MinIprop; /* the min ratio of i frame and p frame */ + HI_U32 u32MaxIprop; /* the max ratio of i frame and p frame */ +}VENC_PARAM_MPEG4_VBR_S; + +typedef struct hiVENC_PARAM_H264_CBR_S VENC_PARAM_H265_CBR_S; +typedef struct hiVENC_PARAM_H264_VBR_S VENC_PARAM_H265_VBR_S; + + +typedef struct hiVENC_RC_PARAM_S +{ + HI_U32 u32ThrdI[RC_TEXTURE_THR_SIZE]; /* just useful for h264/h265 and mpeg4 for now */ + HI_U32 u32ThrdP[RC_TEXTURE_THR_SIZE]; + HI_U32 u32RowQpDelta; + union + { + VENC_PARAM_H264_CBR_S stParamH264Cbr; + VENC_PARAM_H264_VBR_S stParamH264VBR; + VENC_PARAM_MJPEG_CBR_S stParamMjpegCbr; + VENC_PARAM_MJPEG_VBR_S stParamMjpegVbr; + VENC_PARAM_MPEG4_CBR_S stParamMpeg4Cbr; + VENC_PARAM_MPEG4_VBR_S stParamMpeg4Vbr; + VENC_PARAM_H265_CBR_S stParamH265Cbr; + VENC_PARAM_H265_VBR_S stParamH265Vbr; + }; + + HI_VOID* pRcParam; /*RC parameter which could be specified by usrer*/ +}VENC_RC_PARAM_S; + + + +typedef enum hiVENC_FRAMELOST_MODE_E +{ + FRMLOST_NORMAL, /*normal mode*/ + FRMLOST_PSKIP, /*pskip mode*/ + FRMLOST_BUTT, +}VENC_FRAMELOST_MODE_E; + +typedef struct hiVENC_PARAM_FRAMELOST_S +{ + HI_BOOL bFrmLostOpen; /* Indicates whether to discard frames to ensure + stable bit rate when the instant bit rate is exceeded */ + HI_U32 u32FrmLostBpsThr; /* the instant bit rate threshold */ + VENC_FRAMELOST_MODE_E enFrmLostMode; /*frame lost strategy*/ + HI_U32 u32EncFrmGaps; /*the gap of frame lost*/ +}VENC_PARAM_FRAMELOST_S; + + +typedef struct hiVENC_SUPERFRAME_CFG_S +{ + VENC_SUPERFRM_MODE_E enSuperFrmMode; /* Indicates the mode of processing the super frame,[SUPERFRM_NONE,SUPERFRM_DISCARD,SUPERFRM_REENCODE]*/ + HI_U32 u32SuperIFrmBitsThr; /* Indicate the threshold of the super I frame + for enabling the super frame processing mode */ + HI_U32 u32SuperPFrmBitsThr; /* Indicate the threshold of the super P frame */ + HI_U32 u32SuperBFrmBitsThr; /* Indicate the threshold of the super B frame */ +}VENC_SUPERFRAME_CFG_S; + +typedef enum hiVENC_RC_PRIORITY_E +{ + VENC_RC_PRIORITY_BITRATE_FIRST = 1, /* BitRate is prior to super frame */ + VENC_RC_PRIORITY_FRAMEBITS_FIRST, /* Super frame is prior to bitRate */ + + VENC_RC_PRIORITY_BUTT, +} VENC_RC_PRIORITY_E; + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_COMM_RC_H__ */ diff --git a/snes9x/unix/mpp/hi_comm_region.h b/snes9x/unix/mpp/hi_comm_region.h new file mode 100644 index 0000000..b3f1104 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_region.h @@ -0,0 +1,305 @@ +/****************************************************************************** +* +* Copyright (C), 2001-2011, Huawei Tech. Co., Ltd. +* +******************************************************************************* +* File Name : hi_comm_region.h +* Version : Initial Draft +* Author : j00169368 +* Created : 2010/12/13 +* Last Modified : +* Description : include RGN struct , Marco and Error information +* Function List : +* +* +* History: +* +* 1. Date : 2010/12/13 +* Author : j00169368 +* Modification : Created file +* +******************************************************************************/ + + +#ifndef __HI_COMM_REGION_H__ +#define __HI_COMM_REGION_H__ + +#include "hi_common.h" +#include "hi_comm_video.h" +#include "hi_errno.h" +#include "hi_defines.h" + + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + +typedef HI_U32 RGN_HANDLE; + +/* type of video regions */ +typedef enum hiRGN_TYPE_E +{ + OVERLAY_RGN = 0, /* video overlay region */ + COVER_RGN, + COVEREX_RGN, + OVERLAYEX_RGN, + LINE_RGN, + MOSAIC_RGN, + RGN_BUTT +} RGN_TYPE_E; + +typedef enum hiINVERT_COLOR_MODE_E +{ + LESSTHAN_LUM_THRESH = 0, /* the lum of the video is less than the lum threshold which is set by u32LumThresh */ + MORETHAN_LUM_THRESH, /* the lum of the video is more than the lum threshold which is set by u32LumThresh */ + INVERT_COLOR_BUTT +}INVERT_COLOR_MODE_E; + +typedef struct hiOVERLAY_QP_INFO_S +{ + HI_BOOL bQpDisable; + HI_BOOL bAbsQp; + HI_S32 s32Qp; +}OVERLAY_QP_INFO_S; + +typedef struct hiOVERLAY_INVERT_COLOR_S +{ + SIZE_S stInvColArea; //it must be multipe of 16 but not more than 64. + HI_U32 u32LumThresh; //the threshold to decide whether invert the OSD's color or not. + INVERT_COLOR_MODE_E enChgMod; + HI_BOOL bInvColEn; //the switch of inverting color. +}OVERLAY_INVERT_COLOR_S; + +typedef struct hiOVERLAY_ATTR_S +{ + /* bitmap pixel format*/ + PIXEL_FORMAT_E enPixelFmt; + + /* background color, pixel format depends on "enPixelFmt" */ + HI_U32 u32BgColor; + + /* region size */ + SIZE_S stSize; +}OVERLAY_ATTR_S; + +typedef struct hiOVERLAY_CHN_ATTR_S +{ + /* start point */ + POINT_S stPoint; + + /* foreground transparence */ + + HI_U32 u32FgAlpha; + + /* background transparence */ + HI_U32 u32BgAlpha; + + /* OVERLAY region layer*/ + HI_U32 u32Layer; + + /* QP infomation when venc*/ + OVERLAY_QP_INFO_S stQpInfo; + + /* invertColor infomation*/ + OVERLAY_INVERT_COLOR_S stInvertColor; +}OVERLAY_CHN_ATTR_S; + +typedef enum hiRGN_AREA_TYPE_E +{ + AREA_RECT = 0, + AREA_QUAD_RANGLE, + AREA_BUTT +} RGN_AREA_TYPE_E; + +typedef struct hiRGN_QUADRANGLE_S +{ + HI_BOOL bSolid; /* whether solid or dashed framework */ + HI_U32 u32LineWidth; /* Line Width of framework, valid when dashed framework */ + POINT_S stPoint[4]; /* points of quadrilateral*/ +} RGN_QUADRANGLE_S; + +typedef struct hiCOVER_CHN_ATTR_S +{ + RGN_AREA_TYPE_E enCoverType; /* rect or arbitary quadrilateral COVER */ + union + { + RECT_S stRect; /* config of rect*/ + RGN_QUADRANGLE_S stQuadRangle; /* config of arbitary quadrilateral COVER */ + }; + HI_U32 u32Color; + HI_U32 u32Layer; /* COVER region layer range:[0,3] */ +}COVER_CHN_ATTR_S; + +typedef struct hiCOVEREX_CHN_ATTR_S +{ + RGN_AREA_TYPE_E enCoverType; /* rect or arbitary quadrilateral COVER */ + union + { + RECT_S stRect; /* config of rect */ + RGN_QUADRANGLE_S stQuadRangle; /* config of arbitary quadrilateral COVER */ + }; + HI_U32 u32Color; + HI_U32 u32Layer; /* COVEREX region layer range:[0,7] */ +}COVEREX_CHN_ATTR_S; + +typedef enum hiMOSAIC_BLK_SIZE_E +{ + MOSAIC_BLK_SIZE_8 = 0, /*block size 8*8 of MOSAIC*/ + MOSAIC_BLK_SIZE_16, /*block size 16*16 of MOSAIC*/ + MOSAIC_BLK_SIZE_32, /*block size 32*32 of MOSAIC*/ + MOSAIC_BLK_SIZE_64, /*block size 64*64 of MOSAIC*/ + MOSAIC_BLK_SIZE_BUTT +} MOSAIC_BLK_SIZE_E; + +typedef struct hiMOSAIC_CHN_ATTR_S +{ + RECT_S stRect; /*location of MOSAIC*/ + MOSAIC_BLK_SIZE_E enBlkSize; /*block size of MOSAIC*/ + HI_U32 u32Layer; /*MOSAIC region layer range:[0,3] */ +}MOSAIC_CHN_ATTR_S; + +typedef struct hiOVERLAYEX_ATTR_S +{ + PIXEL_FORMAT_E enPixelFmt; + + /* background color, pixel format depends on "enPixelFmt" */ + HI_U32 u32BgColor; + + /* region size */ + SIZE_S stSize; +}OVERLAYEX_ATTR_S; + +typedef struct hiOVERLAYEX_CHN_ATTR_S +{ + /* start point */ + POINT_S stPoint; + + /* foreground transparence */ + HI_U32 u32FgAlpha; + + /* background transparence */ + HI_U32 u32BgAlpha; + + /* OVERLAYEX region layer */ + HI_U32 u32Layer; + +}OVERLAYEX_CHN_ATTR_S; + + +typedef struct hiLINE_CHN_ATTR_S +{ + HI_U32 u32LineWidth; /* width of line */ + HI_U32 u32LineColor; /* color of line */ + POINT_S stLinePoints[2]; /* startpoint and endpoint of line */ +}LINE_CHN_ATTR_S; + +typedef union hiRGN_ATTR_U +{ + OVERLAY_ATTR_S stOverlay; /* attribute of overlay region */ + OVERLAYEX_ATTR_S stOverlayEx; /* attribute of overlayex region */ +} RGN_ATTR_U; + +typedef union hiRGN_CHN_ATTR_U +{ + OVERLAY_CHN_ATTR_S stOverlayChn; /* attribute of overlay region */ + COVER_CHN_ATTR_S stCoverChn; /* attribute of cover region */ + COVEREX_CHN_ATTR_S stCoverExChn; /* attribute of coverex region */ + OVERLAYEX_CHN_ATTR_S stOverlayExChn; /* attribute of overlayex region */ + LINE_CHN_ATTR_S stLineChn; /* attribute of drawline region */ + MOSAIC_CHN_ATTR_S stMosaicChn; /* attribute of mosic region */ +} RGN_CHN_ATTR_U; + +/* attribute of a region */ +typedef struct hiRGN_ATTR_S +{ + RGN_TYPE_E enType; /* region type */ + RGN_ATTR_U unAttr; /* region attribute */ +} RGN_ATTR_S; + +/* attribute of a region */ +typedef struct hiRGN_CHN_ATTR_S +{ + HI_BOOL bShow; + RGN_TYPE_E enType; /* region type */ + RGN_CHN_ATTR_U unChnAttr; /* region attribute */ +} RGN_CHN_ATTR_S; + + +#define RGN_MAX_BMP_UPDATE_NUM 16 + +typedef struct hiRGN_BMP_UPDATE_S +{ + POINT_S stPoint; + BITMAP_S stBmp; + HI_U32 u32Stride; +} RGN_BMP_UPDATE_S; + +typedef struct hiRGN_BMP_UPDATE_CFG_S +{ + HI_U32 u32BmpCnt; + RGN_BMP_UPDATE_S astBmpUpdate[RGN_MAX_BMP_UPDATE_NUM]; +} RGN_BMP_UPDATE_CFG_S; + +typedef struct hiRGN_CANVAS_INFO_S +{ + HI_U32 u32PhyAddr; + HI_U32 u32VirtAddr; + SIZE_S stSize; + HI_U32 u32Stride; + PIXEL_FORMAT_E enPixelFmt; +} RGN_CANVAS_INFO_S; + +/* PingPong buffer change when set attr, it needs to remap memory in mpi interface */ +#define HI_NOTICE_RGN_BUFFER_CHANGE HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_NOTICE, HI_SUCCESS) + +/* invlalid device ID */ +#define HI_ERR_RGN_INVALID_DEVID HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_RGN_INVALID_CHNID HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_RGN_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_RGN_EXIST HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/*UN exist*/ +#define HI_ERR_RGN_UNEXIST HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_RGN_NULL_PTR HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_RGN_NOT_CONFIG HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_RGN_NOT_SUPPORT HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_RGN_NOT_PERM HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_RGN_NOMEM HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_RGN_NOBUF HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_RGN_BUF_EMPTY HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_RGN_BUF_FULL HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* bad address, eg. used for copy_from_user & copy_to_user */ +#define HI_ERR_RGN_BADADDR HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_BADADDR) +/* resource is busy, eg. destroy a venc chn without unregistering it */ +#define HI_ERR_RGN_BUSY HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + +/* System is not ready,maybe not initialed or loaded. + * Returning the error code when opening a device file failed. + */ +#define HI_ERR_RGN_NOTREADY HI_DEF_ERR(HI_ID_RGN, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + + +#endif /* __HI_COMM_REGION_H__ */ + + + diff --git a/snes9x/unix/mpp/hi_comm_sys.h b/snes9x/unix/mpp/hi_comm_sys.h new file mode 100644 index 0000000..803d6f4 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_sys.h @@ -0,0 +1,77 @@ +/****************************************************************************** +Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi3511_sys.h +Version : Initial Draft +Author : Hi3511 MPP Team +Created : 2007/1/30 +Last Modified : +Description : Hi3511 chip specific configure data structure +Function List : +History : + 1.Date : 2007/1/30 + Author : c42025 + Modification: Created file + + 2.Date : 2007/11/30 + Author : c42025 + Modification: modify according review comments + + 3.Date : 2008/03/03 + Author : c42025 + Modification: modify HI_TRACE_SYS + + 4.Date : 2008/03/05 + Author : c42025 + Modification: modify 'HI_LOG_LEVEL_ERROR' to 'EN_ERR_LEVEL_ERROR' + +******************************************************************************/ +#ifndef __HI_COMM_SYS_H__ +#define __HI_COMM_SYS_H__ + +#include "hi_type.h" +#include "hi_errno.h" +#include "hi_debug.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#define HI_TRACE_SYS(level, fmt...) HI_TRACE(level, HI_ID_SYS,##fmt) +typedef struct hiMPP_SYS_CONF_S +{ + /* stride of picture buffer must be aligned with this value. + * you can choose a value from 1 to 1024, and it must be multiple of 16. + */ + HI_U32 u32AlignWidth; + +}MPP_SYS_CONF_S; + +typedef enum hiEN_SYS_ERR_CODE_E +{ + ERR_SYS_NOHEARTBEAT = 0x40, + + ERR_SYS_BUTT +}EN_SYS_ERR_CODE_E; + + +#define HI_ERR_SYS_NULL_PTR HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_SYS_NOTREADY HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_SYS_NOT_PERM HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +#define HI_ERR_SYS_NOMEM HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +#define HI_ERR_SYS_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_SYS_BUSY HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_SYS_NOT_SUPPORT HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +#define HI_ERR_SYS_NOHEARTBEAT HI_DEF_ERR(HI_ID_SYS, EN_ERR_LEVEL_ERROR, ERR_SYS_NOHEARTBEAT) + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_COMM_SYS_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_vb.h b/snes9x/unix/mpp/hi_comm_vb.h new file mode 100644 index 0000000..3d498c5 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vb.h @@ -0,0 +1,149 @@ +/****************************************************************************** +Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi_common.h +Version : Initial Draft +Author : Hi3511 MPP Team +Created : 2006/11/09 +Last Modified : +Description : The common data type defination for VB module. +Function List : +History : + 1.Date : 2006/11/03 + Author : c42025 + Modification: Created file + + 2.Date : 2007/11/30 + Author : c42025 + Modification: modify according review comments + + 3.Date : 2008/06/18 + Author : c42025 + Modification: add VB_UID_PCIV + + 4.Date : 2008/10/31 + Author : z44949 + Modification : Translate the chinese comment + + 5.Date : 2008/10/31 + Author : p00123320 + Modification : change commentary of u32MaxPoolCnt in VB_CONF_S +******************************************************************************/ +#ifndef __HI_COMM_VB_H__ +#define __HI_COMM_VB_H__ + +#include "hi_type.h" +#include "hi_errno.h" +#include "hi_debug.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#define VB_MAX_POOLS 256 +#define VB_MAX_COMM_POOLS 16 +#define VB_MAX_MOD_COMM_POOLS 16 + + +/* user ID for VB */ +#define VB_MAX_USER 22 + +typedef enum hiVB_UID_E +{ + VB_UID_VIU = 0, + VB_UID_VOU = 1, + VB_UID_VGS = 2, + VB_UID_VENC = 3, + VB_UID_VDEC = 4, + VB_UID_VDA = 5, + VB_UID_H264E = 6, + VB_UID_JPEGE = 7, + VB_UID_MPEG4E = 8, + VB_UID_H264D = 9, + VB_UID_JPEGD = 10, + VB_UID_MPEG4D = 11, + VB_UID_VPSS = 12, + VB_UID_GRP = 13, + VB_UID_MPI = 14, + VB_UID_PCIV = 15, + VB_UID_AI = 16, + VB_UID_AENC = 17, + VB_UID_RC = 18, + VB_UID_VFMW = 19, + VB_UID_USER = 20, + VB_UID_H265E = 21, + VB_UID_BUTT + +} VB_UID_E; + +#define VB_INVALID_POOLID (-1UL) +#define VB_INVALID_HANDLE (-1UL) + +/* Generall common pool use this owner id, module common pool use VB_UID as owner id */ +#define POOL_OWNER_COMMON -1 + +/* Private pool use this owner id */ +#define POOL_OWNER_PRIVATE -2 + +typedef enum hiPOOL_TYPE_E +{ + POOL_TYPE_COMMON = 0, + POOL_TYPE_PRIVATE = 1, + POOL_TYPE_MODULE_COMMON = 2, + POOL_TYPE_BUTT +} POOL_TYPE_E; + +typedef HI_U32 VB_POOL; +typedef HI_U32 VB_BLK; + +#define RESERVE_MMZ_NAME "window" + +typedef struct hiVB_CONF_S +{ + HI_U32 u32MaxPoolCnt; /* max count of pools, (0,VB_MAX_POOLS] */ + struct hiVB_CPOOL_S + { + HI_U32 u32BlkSize; + HI_U32 u32BlkCnt; + HI_CHAR acMmzName[MAX_MMZ_NAME_LEN]; + }astCommPool[VB_MAX_COMM_POOLS]; +} VB_CONF_S; + +typedef struct hiVB_POOL_STATUS_S +{ + HI_U32 bIsCommPool; + HI_U32 u32BlkCnt; + HI_U32 u32FreeBlkCnt; +}VB_POOL_STATUS_S; + +#define VB_SUPPLEMENT_JPEG_MASK 0x1 + +typedef struct hiVB_SUPPLEMENT_CONF_S +{ + HI_U32 u32SupplementConf; +}VB_SUPPLEMENT_CONF_S; + + +#define HI_ERR_VB_NULL_PTR HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_VB_NOMEM HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +#define HI_ERR_VB_NOBUF HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +#define HI_ERR_VB_UNEXIST HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +#define HI_ERR_VB_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_VB_NOTREADY HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_VB_BUSY HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_VB_NOT_PERM HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) + +#define HI_ERR_VB_2MPOOLS HI_DEF_ERR(HI_ID_VB, EN_ERR_LEVEL_ERROR, EN_ERR_BUTT + 1) + +#define HI_TRACE_VB(level,fmt...) HI_TRACE(level, HI_ID_VB,##fmt) + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_COMM_VB_H_ */ + diff --git a/snes9x/unix/mpp/hi_comm_vda.h b/snes9x/unix/mpp/hi_comm_vda.h new file mode 100644 index 0000000..b983345 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vda.h @@ -0,0 +1,288 @@ +/****************************************************************************** +* +* Copyright (C), 2001-2011, Huawei Tech. Co., Ltd. +* +******************************************************************************* +* File Name : hi_comm_vda.h +* Version : Initial Draft +* Author : j00169368,l64467 +* Created : 2011/1/7 +* Last Modified : +* Description : include VDA struct , Marco and Error information +* Function List : +* +* +* History: +* +* 1. Date : 2011/1/7 +* Author : j00169368,l64467 +* Modification : Created file +* +******************************************************************************/ + +#ifndef __HI_COMM_VDA_H__ +#define __HI_COMM_VDA_H__ + +#include "hi_type.h" +#include "hi_debug.h" +#include "hi_comm_video.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_defines.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + +/*Motion Region Data*/ +typedef struct hiVDA_OBJ_S +{ + HI_U16 u16Left; + HI_U16 u16Top; + HI_U16 u16Right; + HI_U16 u16Bottom; +}VDA_OBJ_S; + +/*reference pictrue mode*/ +typedef enum hiVDA_REF_MODE_E +{ + VDA_REF_MODE_DYNAMIC = 0, /*reference pictrue dynamic*/ + VDA_REF_MODE_STATIC, /*reference pictrue static*/ + VDA_REF_MODE_USER, /*reference pictrue user*/ + VDA_REF_MODE_BUTT /*reserve*/ +}VDA_REF_MODE_E; + +/*VDA algorithm*/ +typedef enum hiVDA_ALG_E +{ + VDA_ALG_BG = 0, /*base on background pictrue*/ + VDA_ALG_REF, /*base on reference pictrue*/ + VDA_ALG_BUTT +}VDA_ALG_E; + +/*MB size*/ +typedef enum hiVDA_MB_SIZE_E +{ + VDA_MB_8PIXEL, /* 8*8 */ + VDA_MB_16PIXEL, /* 16*16 */ + VDA_MB_BUTT +}VDA_MB_SIZE_E; + +/*SAD bits*/ +typedef enum hiVDA_MB_SADBITS_E +{ + VDA_MB_SAD_8BIT = 0, /*SAD precision 8bits*/ + VDA_MB_SAD_16BIT, /*SAD precision 16bits*/ + VDA_MB_SAD_BUTT /*reserve*/ +} VDA_MB_SADBITS_E; + + +/*OD region attribute*/ +typedef struct hiVDA_OD_RGN_ATTR_S +{ + /*static attribute*/ + RECT_S stRect; /*region rect + *X:[0,VDA_MAX_WIDTH),align:16 + *Y:[0,VDA_MAX_HEIGHT) + *W:[16,VDA_MAX_WIDTH],align:16 + *H:[16,VDA_MAX_HEIGHT],align:16 + *X+W <= chunnel wight + *Y+H <= chunnel height + */ + + /*dynamic attribute*/ + HI_U32 u32SadTh; /*SAD threshold,range:[0,4080]*/ + HI_U32 u32AreaTh; /*alarm area threshold,range:[0,100]*/ + HI_U32 u32OccCntTh; /*alarm frame count threshold,range:[1,256]*/ + HI_U32 u32UnOccCntTh; /*The max uncover count,range:[0,256]*/ +}VDA_OD_RGN_ATTR_S; + +/*MD attribute*/ +typedef struct hiVDA_MD_ATTR_S +{ + /*static attribute*/ + VDA_ALG_E enVdaAlg; /*arithmetic*/ + VDA_MB_SIZE_E enMbSize; /*MB size*/ + VDA_MB_SADBITS_E enMbSadBits; /*MB SAD size*/ + VDA_REF_MODE_E enRefMode; /*reference picture mode*/ + HI_U32 u32MdBufNum; /*Result buffer number,range:[1,16]*/ + + /*dynamic attribute*/ + HI_U32 u32VdaIntvl; /*VDA interval,range:[0,256]*/ + + HI_U32 u32BgUpSrcWgt; /*the source picture weight, + *back ground updata totle weight 256, + *range:[1,255],recommendatory value:128 + */ + + HI_U32 u32SadTh; /*SAD threshold,range:[0,4080],recommendatory value:100*/ + HI_U32 u32ObjNumMax; /*max OBJ number,range:[1,128]*/ +}VDA_MD_ATTR_S; + + +#define VDA_OD_RGN_NUM_MAX 4 + +/*OD attribute*/ +typedef struct hiVDA_OD_ATTR_S +{ + HI_U32 u32RgnNum; /*region number*/ + VDA_OD_RGN_ATTR_S astOdRgnAttr[VDA_OD_RGN_NUM_MAX]; /*region attribute*/ + + /*static attribute*/ + VDA_ALG_E enVdaAlg; /*arithmetic*/ + VDA_MB_SIZE_E enMbSize; /*MB size*/ + VDA_MB_SADBITS_E enMbSadBits; /*MB SAD size*/ + VDA_REF_MODE_E enRefMode; /*reference picture mode*/ + + /*dynamic attribute*/ + HI_U32 u32VdaIntvl; /*VDA interval,[0,256]*/ + HI_U32 u32BgUpSrcWgt; /*back ground updata totle weight 256,the source picture weight,[1,255]*/ + + +}VDA_OD_ATTR_S; + + +/*work mode*/ +typedef enum hiVDA_WORK_MODE_E +{ + VDA_WORK_MODE_MD = 0, /*motion detection*/ + VDA_WORK_MODE_OD, /*Occlusion detection*/ + VDA_WORK_MODE_BUTT +}VDA_WORK_MODE_E; + + +/*work mode attribute*/ +typedef union hiVDA_WORK_MODE_ATTR_U +{ + VDA_MD_ATTR_S stMdAttr; /*MD attribute*/ + VDA_OD_ATTR_S stOdAttr; /*OD attribute*/ +}VDA_WORK_MODE_ATTR_U; + + +/*VDA CHN attribute*/ +typedef struct hiVDA_CHN_ATTR_S +{ + VDA_WORK_MODE_E enWorkMode; /*work mode*/ + VDA_WORK_MODE_ATTR_U unAttr; /*work mode attribute*/ + HI_U32 u32Width; /*the width of CHNL,[16,VDA_MAX_WIDTH]*/ + HI_U32 u32Height; /*the height of CHNL,[16,VDA_MAX_HEIGHT]*/ +}VDA_CHN_ATTR_S; + + +/*MB SAD data*/ +typedef struct hiVDA_MB_SAD_DATA_S +{ + HI_VOID *pAddr; /*address*/ + HI_U32 u32Stride; /*stride*/ + VDA_MB_SADBITS_E enMbSadBits; /*the MB SAD size*/ +}VDA_MB_SAD_DATA_S; + +/*OBJ data*/ +typedef struct hiVDA_OBJ_DATA_S +{ + HI_U32 u32ObjNum; /*OBJ number*/ + VDA_OBJ_S *pstAddr; /*OBJ data address*/ + + HI_U32 u32IndexOfMaxObj; /*index of max OBJ*/ + HI_U32 u32SizeOfMaxObj; /*size of max OBJ*/ + HI_U32 u32SizeOfTotalObj; /*total size of all OBJ*/ +}VDA_OBJ_DATA_S; + + +/*MD data*/ +typedef struct hiVDA_MD_DATA_S +{ + HI_BOOL bMbSadValid; /*SAD data is valid?*/ + VDA_MB_SAD_DATA_S stMbSadData; /*MB SAD data*/ + + HI_BOOL bObjValid; /*OBJ data is valid?*/ + VDA_OBJ_DATA_S stObjData; /*OBJ data*/ + + HI_BOOL bPelsNumValid; /*alarm pixel number data is valid?*/ + HI_U32 u32AlarmPixCnt;/*motion pix of picture*/ +}VDA_MD_DATA_S; + + +/*OD data*/ +typedef struct hiVDA_OD_DATA_S +{ + HI_U32 u32RgnNum; /*region number*/ + HI_BOOL abRgnAlarm[VDA_OD_RGN_NUM_MAX]; /*HI_TRUE:alarm*/ +}VDA_OD_DATA_S; + + + +typedef union hiVDA_DATA_U +{ + VDA_MD_DATA_S stMdData; /*MD data*/ + VDA_OD_DATA_S stOdData; /*OD data*/ +}VDA_DATA_U; + + +/*VDA data*/ +typedef struct hiVDA_DATA_S +{ + VDA_WORK_MODE_E enWorkMode; /*work mode*/ + VDA_DATA_U unData; /*VDA data*/ + VDA_MB_SIZE_E enMbSize; /*MB size*/ + HI_U32 u32MbWidth; /*VDA channle width in MB*/ + HI_U32 u32MbHeight; /*VDA channle height in MB*/ + HI_U64 u64Pts; /*time*/ +}VDA_DATA_S; + + +/*chnnel state*/ +typedef struct hiVDA_CHN_STAT_S +{ + HI_BOOL bStartRecvPic; /*start receive picture*/ + HI_U32 u32LeftPic; /*left picture*/ + HI_U32 u32LeftRst; /*left data*/ +}VDA_CHN_STAT_S; + +/* invlalid device ID */ +#define HI_ERR_VDA_INVALID_DEVID HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +/* invlalid channel ID */ +#define HI_ERR_VDA_INVALID_CHNID HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_VDA_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_VDA_EXIST HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/*UN exist*/ +#define HI_ERR_VDA_UNEXIST HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_VDA_NULL_PTR HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_VDA_NOT_CONFIG HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_VDA_NOT_SUPPORT HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_VDA_NOT_PERM HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_VDA_NOMEM HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_VDA_NOBUF HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_VDA_BUF_EMPTY HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_VDA_BUF_FULL HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* bad address, eg. used for copy_from_user & copy_to_user */ +#define HI_ERR_VDA_BADADDR HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_BADADDR) +/* resource is busy, eg. destroy a venc chn without unregistering it */ +#define HI_ERR_VDA_BUSY HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + +/* System is not ready,maybe not initialed or loaded. + * Returning the error code when opening a device file failed. + */ +#define HI_ERR_VDA_NOTREADY HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + + +#endif /* End of #ifndef __HI_COMM_VDA_H__ */ diff --git a/snes9x/unix/mpp/hi_comm_vdec.h b/snes9x/unix/mpp/hi_comm_vdec.h new file mode 100644 index 0000000..72f720b --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vdec.h @@ -0,0 +1,249 @@ +/****************************************************************************** + + Copyright (C), 2013, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_vdec.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2013/05/08 + Description : Common Def Of video decode + History : + 1.Date : 2013/05/08 + Author : l00226816 + Modification: Created file +******************************************************************************/ + + +#ifndef __HI_COMM_VDEC_H__ +#define __HI_COMM_VDEC_H__ +#include "hi_type.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" +#include "hi_comm_vb.h" +#include "hi_defines.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +/*vdec channel attr(user interface)*/ + +#define HI_IO_BLOCK HI_TRUE +#define HI_IO_NOBLOCK HI_FALSE + + +typedef struct hiVDEC_CHN_LUM_S +{ + HI_U64 u64LumPixSum; /* Luma sum of current frame */ + HI_U32 u32LumPixAverage; /* Luma average of current frame */ + HI_U64 u64Pts; /* PTS of current frame ?? */ +} VDEC_CHN_LUM_S; + + +typedef enum hiVIDEO_MODE_E +{ + VIDEO_MODE_STREAM = 0, /*send by stream*/ + VIDEO_MODE_FRAME , /*send by frame*/ + VIDEO_MODE_BUTT +}VIDEO_MODE_E; + +typedef enum hiVDEC_JPG_COLOR_FMT_E +{ + JPG_COLOR_FMT_YCBCR400, /*YUV400*/ + JPG_COLOR_FMT_YCBCR420, /*YUV420*/ + JPG_COLOR_FMT_YCBCR422BHP, /*YUV 422 2x1*/ + JPG_COLOR_FMT_YCBCR422BVP, /*YUV 422 1x2*/ + JPG_COLOR_FMT_YCBCR444, /*YUV 444*/ + JPG_COLOR_FMT_BUTT +} VDEC_JPG_COLOR_FMT_E; + +typedef struct hiVDEC_ATTR_JPEG_S +{ + VIDEO_MODE_E enMode; /* video stream mode select */ + VDEC_JPG_COLOR_FMT_E enJpegFormat; /* jpeg format select ,may be YUV420,YUV400,YUV422,YUV444*/ +}VDEC_ATTR_JPEG_S,*PTR_VDEC_ATTR_JPEG_S; + + +typedef struct hiVDEC_ATTR_VIDEO_S +{ + HI_U32 u32RefFrameNum; /*ref pic num [1,16]*/ + VIDEO_MODE_E enMode; /*send by stream or by frame*/ + HI_BOOL bTemporalMvpEnable; /* specifies whether temporal motion vector predictors can be used for inter prediction*/ +}VDEC_ATTR_VIDEO_S,*PTR_VDEC_ATTR_VIDEO_S; + + +typedef struct hiVDEC_CHN_ATTR_S +{ + PAYLOAD_TYPE_E enType; /* video type to be decoded */ + HI_U32 u32BufSize ; /* stream buf size(Byte) */ + HI_U32 u32Priority ; /* priority */ + HI_U32 u32PicWidth ; /* max pic width */ + HI_U32 u32PicHeight ; /* max pic height */ + union + { + VDEC_ATTR_JPEG_S stVdecJpegAttr; /* structure with jpeg or mjpeg type */ + VDEC_ATTR_VIDEO_S stVdecVideoAttr; /* structure with video ( h264/mpeg4) */ + }; +}VDEC_CHN_ATTR_S; + + +typedef struct hiVDEC_STREAM_S +{ + HI_U8* pu8Addr; /* stream address */ + HI_U32 u32Len; /* stream len */ + HI_U64 u64PTS; /* time stamp */ + HI_BOOL bEndOfFrame; /* is the end of a frame */ + HI_BOOL bEndOfStream; /* is the end of all stream */ +}VDEC_STREAM_S; + +typedef struct hiVDEC_USERDATA_S{ + HI_U8* pu8Addr; /* userdata data vir address */ + HI_U32 u32PhyAddr; /* userdata data phy address */ + HI_U32 u32Len; /* userdata data len */ + HI_BOOL bValid; /* is valid? */ +}VDEC_USERDATA_S; + + +typedef struct hi_VDEC_DECODE_ERROR_S +{ + HI_S32 s32FormatErr; /* format error. eg: do not support filed */ + HI_S32 s32PicSizeErrSet; /* picture width or height is larger than chnnel width or height*/ + HI_S32 s32StreamUnsprt; /* unsupport the stream specification */ + HI_S32 s32PackErr; /* stream package error */ + HI_S32 s32PrtclNumErrSet; /* protocol num is not enough. eg: slice, pps, sps */ + HI_S32 s32RefErrSet; /* refrence num is not enough */ + HI_S32 s32PicBufSizeErrSet; /* the buffer size of picture is not enough */ + HI_S32 s32VdecStreamNotRelease; /* the stream not released for too long time */ +}VDEC_DECODE_ERROR_S; + + +typedef struct hiVDEC_CHN_STAT_S +{ + PAYLOAD_TYPE_E enType; /* video type to be decoded */ + HI_U32 u32LeftStreamBytes; /* left stream bytes waiting for decode */ + HI_U32 u32LeftStreamFrames; /* left frames waiting for decode,only valid for H264D_MODE_FRAME */ + HI_U32 u32LeftPics; /* pics waiting for output */ + HI_BOOL bStartRecvStream; /* had started recv stream? */ + HI_U32 u32RecvStreamFrames; /* how many frames of stream has been received. valid when send by frame. */ + HI_U32 u32DecodeStreamFrames; /* how many frames of stream has been decoded. valid when send by frame. */ + VDEC_DECODE_ERROR_S stVdecDecErr; /* information about decode error */ +}VDEC_CHN_STAT_S; + +/* + * static parameter: must set after stop sending stream and all stream is decoded. + * dynamic parameter: can be set at any time. + */ +typedef struct hiVDEC_CHN_PARAM_S +{ + HI_S32 s32DisplayFrameNum; /* display frame num */ + HI_S32 s32ChanErrThr; /* threshold for stream error process, 0: discard with any error, 100 : keep data with any error */ + HI_S32 s32ChanStrmOFThr; /* threshold for stream overflow, 0~ , 0: nothing to do when stream is overflow */ + HI_S32 s32DecMode; /* decode mode , 0: deocde IPB frames, 1: only decode I frame & P frame , 2: only decode I frame */ + HI_S32 s32DecOrderOutput; /* frames output order ,0: the same with display order , 1: the same width decoder order */ + VIDEO_FORMAT_E enVideoFormat; + COMPRESS_MODE_E enCompressMode; +}VDEC_CHN_PARAM_S; + + +typedef struct hiH264_PRTCL_PARAM_S +{ + HI_S32 s32MaxSliceNum; /* max slice num support */ + HI_S32 s32MaxSpsNum; /* max sps num support */ + HI_S32 s32MaxPpsNum; /* max pps num support */ +}H264_PRTCL_PARAM_S; + +typedef struct hiH265_PRTCL_PARAM_S +{ + HI_S32 s32MaxSliceSegmentNum; /* max slice segmnet num support */ + HI_S32 s32MaxVpsNum; /* max vps num support */ + HI_S32 s32MaxSpsNum; /* max sps num support */ + HI_S32 s32MaxPpsNum; /* max pps num support */ +}H265_PRTCL_PARAM_S; + +typedef struct hiVDEC_PRTCL_PARAM_S +{ + PAYLOAD_TYPE_E enType; /* video type to be decoded ,only h264 and HEVC supported*/ + union + { + H264_PRTCL_PARAM_S stH264PrtclParam; /* protocol param structure for h264*/ + H265_PRTCL_PARAM_S stH265PrtclParam; /* protocol param structure for HEVC*/ + }; +}VDEC_PRTCL_PARAM_S; + + +typedef struct hiVDEC_CHN_POOL_S +{ + VB_POOL hPicVbPool; + VB_POOL hPmvVbPool; +}VDEC_CHN_POOL_S; + + +typedef enum hiVDEC_EVNT_E +{ + VDEC_EVNT_STREAM_ERR = 1, + VDEC_EVNT_UNSUPPORT, + VDEC_EVNT_OVER_REFTHR, + VDEC_EVNT_REF_NUM_OVER, + VDEC_EVNT_SLICE_NUM_OVER, + VDEC_EVNT_SPS_NUM_OVER, + VDEC_EVNT_PPS_NUM_OVER, + VDEC_EVNT_PICBUF_SIZE_ERR, + VDEC_EVNT_SIZE_OVER, + VDEC_EVNT_IMG_SIZE_CHANGE, + VDEC_EVNT_VPS_NUM_OVER, + VDEC_EVNT_BUTT +} VDEC_EVNT_E; + +typedef struct hiVDEC_MOD_PARAM_S +{ + HI_U32 u32MiniBufMode; + HI_U32 u32VBSource; +} VDEC_MOD_PARAM_S; + +/************************************************************************************************************************/ + +/* invlalid channel ID */ +#define HI_ERR_VDEC_INVALID_CHNID HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_VDEC_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_VDEC_EXIST HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/* using a NULL point */ +#define HI_ERR_VDEC_NULL_PTR HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_VDEC_NOT_CONFIG HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_VDEC_NOT_SURPPORT HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_VDEC_NOT_PERM HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* the channle is not existed */ +#define HI_ERR_VDEC_UNEXIST HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* failure caused by malloc memory */ +#define HI_ERR_VDEC_NOMEM HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_VDEC_NOBUF HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_VDEC_BUF_EMPTY HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_VDEC_BUF_FULL HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_VDEC_SYS_NOTREADY HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/*system busy*/ +#define HI_ERR_VDEC_BUSY HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + +/* bad address, eg. used for copy_from_user & copy_to_user */ +#define HI_ERR_VDEC_BADADDR HI_DEF_ERR(HI_ID_VDEC, EN_ERR_LEVEL_ERROR, EN_ERR_BADADDR) + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_VDEC_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_venc.h b/snes9x/unix/mpp/hi_comm_venc.h new file mode 100644 index 0000000..02ec130 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_venc.h @@ -0,0 +1,589 @@ +/****************************************************************************** + + Copyright (C), 2001-2012, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_venc.h + Version : + Author : Hisilicon Hi35xx MPP Team + Created : 2006/11/24 + Last Modified : + Description : common struct definition for VENC + Function List : + History : +******************************************************************************/ +#ifndef __HI_COMM_VENC_H__ +#define __HI_COMM_VENC_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" +#include "hi_comm_rc.h" + + + +/* invlalid channel ID */ +#define HI_ERR_VENC_INVALID_CHNID HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +/* at lease one parameter is illagal ,eg, an illegal enumeration value */ +#define HI_ERR_VENC_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +/* channel exists */ +#define HI_ERR_VENC_EXIST HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +/* channel exists */ +#define HI_ERR_VENC_UNEXIST HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +/* using a NULL point */ +#define HI_ERR_VENC_NULL_PTR HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +/* try to enable or initialize system,device or channel, before configing attribute */ +#define HI_ERR_VENC_NOT_CONFIG HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +/* operation is not supported by NOW */ +#define HI_ERR_VENC_NOT_SUPPORT HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +/* operation is not permitted ,eg, try to change stati attribute */ +#define HI_ERR_VENC_NOT_PERM HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +/* failure caused by malloc memory */ +#define HI_ERR_VENC_NOMEM HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +/* failure caused by malloc buffer */ +#define HI_ERR_VENC_NOBUF HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +/* no data in buffer */ +#define HI_ERR_VENC_BUF_EMPTY HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +/* no buffer for new data */ +#define HI_ERR_VENC_BUF_FULL HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +/* system is not ready,had not initialed or loaded*/ +#define HI_ERR_VENC_SYS_NOTREADY HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +/* system is busy*/ +#define HI_ERR_VENC_BUSY HI_DEF_ERR(HI_ID_VENC, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) + + +/*the nalu type of H264E*/ +typedef enum hiH264E_NALU_TYPE_E +{ + H264E_NALU_PSLICE = 1, /*PSLICE types*/ + H264E_NALU_ISLICE = 5, /*ISLICE types*/ + H264E_NALU_SEI = 6, /*SEI types*/ + H264E_NALU_SPS = 7, /*SPS types*/ + H264E_NALU_PPS = 8, /*PPS types*/ + H264E_NALU_IPSLICE = 9, + H264E_NALU_BUTT +} H264E_NALU_TYPE_E; + +/*the nalu type of H265E*/ +typedef enum hiH265E_NALU_TYPE_E +{ + H265E_NALU_PSLICE = 1, /*P SLICE types*/ + H265E_NALU_ISLICE = 19, /*I SLICE types*/ + H265E_NALU_VPS = 32, /*VPS types*/ + H265E_NALU_SPS = 33, /*SPS types*/ + H265E_NALU_PPS = 34, /*PPS types*/ + H265E_NALU_SEI = 39, /*SEI types*/ + + H265E_NALU_BUTT +} H265E_NALU_TYPE_E; + +/*the reference type of H264E slice*/ +typedef enum hiH264E_REFSLICE_TYPE_E +{ + H264E_REFSLICE_FOR_1X = 1, /*Reference slice for H264E_REF_MODE_1X*/ + H264E_REFSLICE_FOR_2X = 2, /*Reference slice for H264E_REF_MODE_2X*/ + H264E_REFSLICE_FOR_4X = 5, /*Reference slice for H264E_REF_MODE_4X*/ + H264E_REFSLICE_FOR_BUTT /* slice not for reference*/ +} H264E_REFSLICE_TYPE_E; + +/*the pack type of JPEGE*/ +typedef enum hiJPEGE_PACK_TYPE_E +{ + JPEGE_PACK_ECS = 5, /*ECS types*/ + JPEGE_PACK_APP = 6, /*APP types*/ + JPEGE_PACK_VDO = 7, /*VDO types*/ + JPEGE_PACK_PIC = 8, /*PIC types*/ + JPEGE_PACK_BUTT +} JPEGE_PACK_TYPE_E; + +/*the pack type of MPEG4*/ +typedef enum hiMPEG4E_PACK_TYPE_E +{ + MPEG4E_PACK_VOP_P = 1, /*P VOP packet types*/ + MPEG4E_PACK_VOP_I = 5, /*I VOP packet types*/ + MPEG4E_PACK_VOS = 6, /*VOS types*/ + MPEG4E_PACK_VO = 7, /*VO types*/ + MPEG4E_PACK_VOL = 8, /*VOL types*/ + MPEG4E_PACK_GVOP = 9 /*GROUP of vop types */ +} MPEG4E_PACK_TYPE_E; + +/*the data type of VENC*/ +typedef union hiVENC_DATA_TYPE_U +{ + H264E_NALU_TYPE_E enH264EType; /*H264E NALU types*/ + JPEGE_PACK_TYPE_E enJPEGEType; /*JPEGE pack types*/ + MPEG4E_PACK_TYPE_E enMPEG4EType; /*MPEG4E pack types*/ + H265E_NALU_TYPE_E enH265EType; /*H264E NALU types*/ +}VENC_DATA_TYPE_U; + +typedef struct hiVENC_PACK_INFO_S +{ + VENC_DATA_TYPE_U u32PackType; + HI_U32 u32PackOffset; + HI_U32 u32PackLength; +}VENC_PACK_INFO_S; + + +typedef struct hiVENC_PACK_S +{ + HI_U32 u32PhyAddr; /*the physics address of stream*/ + HI_U8 *pu8Addr; /*the virtual address of stream*/ + HI_U32 u32Len; /*the length of stream*/ + + HI_U64 u64PTS; /*PTS*/ + HI_BOOL bFrameEnd; /*frame end*/ + + VENC_DATA_TYPE_U DataType; /*the type of stream*/ + HI_U32 u32Offset; + + HI_U32 u32DataNum; + VENC_PACK_INFO_S stPackInfo[8]; +}VENC_PACK_S; + +typedef enum hiH264E_REF_TYPE_E +{ + BASE_IDRSLICE = 0, /*the Idr frame at Base layer*/ + BASE_PSLICE_REFBYBASE, /*the P frame at Base layer, referenced by other frames at Base layer*/ + BASE_PSLICE_REFBYENHANCE, /*the P frame at Base layer, referenced by other frames at Enhance layer*/ + ENHANCE_PSLICE_REFBYENHANCE, /*the P frame at Enhance layer, referenced by other frames at Enhance layer*/ + ENHANCE_PSLICE_NOTFORREF, /*the P frame at Enhance layer ,not referenced*/ + ENHANCE_PSLICE_BUTT +} H264E_REF_TYPE_E; + +typedef enum hiH264E_REF_TYPE_E H265E_REF_TYPE_E; + +typedef struct hiVENC_STREAM_INFO_H264_S +{ + HI_U32 u32PicBytesNum; /* the coded picture stream byte number */ + HI_U32 u32PSkipMbNum; /* the skip macroblock num */ + HI_U32 u32IpcmMbNum; /* the ipcm macroblock num */ + HI_U32 u32Inter16x8MbNum; /* the inter16x8 macroblock num */ + HI_U32 u32Inter16x16MbNum; /* the inter16x16 macroblock num */ + HI_U32 u32Inter8x16MbNum; /* the inter8x16 macroblock num */ + HI_U32 u32Inter8x8MbNum; /* the inter8x8 macroblock num */ + HI_U32 u32Intra16MbNum; /* the intra16x16 macroblock num */ + HI_U32 u32Intra8MbNum; /* the intra8x8 macroblock num */ + HI_U32 u32Intra4MbNum; /* the inter4x4 macroblock num */ + + H264E_REFSLICE_TYPE_E enRefSliceType; /*the reference type of H264E slice*/ + H264E_REF_TYPE_E enRefType; /*Type of encoded frames in advanced frame skipping reference mode*/ + HI_U32 u32UpdateAttrCnt; /*Number of times that channel attributes or parameters (including RC parameters) are set*/ + HI_U32 u32StartQp; /*StartQP Value*/ +}VENC_STREAM_INFO_H264_S; + +typedef struct hiVENC_STREAM_INFO_H265_S +{ + HI_U32 u32PicBytesNum; /* the coded picture stream byte number */ + HI_U32 u32Inter64x64CuNum; /* the Inter64x64 Cu num */ + HI_U32 u32Inter32x32CuNum; /* the Inter32x32 Cu num */ + HI_U32 u32Inter16x16CuNum; /* the Inter16x16 Cu num */ + HI_U32 u32Inter8x8CuNum; /* the Inter8x8 Cu num */ + HI_U32 u32Intra32x32CuNum; /* the Intra32x32 Cu num */ + HI_U32 u32Intra16x16CuNum; /* the Intra16x16 Cu num */ + HI_U32 u32Intra8x8CuNum; /* the Intra8x8 Cu num */ + HI_U32 u32Intra4x4CuNum; /* the Intra4x4 Cu num */ + + H265E_REF_TYPE_E enRefType; /*Type of encoded frames in advanced frame skipping reference mode*/ + HI_U32 u32UpdateAttrCnt; /*Number of times that channel attributes or parameters (including RC parameters) are set*/ + HI_U32 u32StartQp; /*StartQP Value*/ +}VENC_STREAM_INFO_H265_S; + +typedef struct hiVENC_STREAM_INFO_JPEG_S +{ + HI_U32 u32PicBytesNum; /* the coded picture stream byte number */ + HI_U32 u32UpdateAttrCnt; /*Number of times that channel attributes or parameters (including RC parameters) are set*/ + HI_U32 u32Qfactor; /* image quality */ +}VENC_STREAM_INFO_JPEG_S; + +typedef struct hiVENC_STREAM_INFO_MPEG4_S +{ + HI_U32 u32PicBytesNum; /* the coded picture stream byte number */ + HI_U32 u32UpdateAttrCnt; /*Number of times that channel attributes or parameters (including RC parameters) are set*/ +}VENC_STREAM_INFO_MPEG4_S; + +typedef struct hiVENC_STREAM_S +{ + VENC_PACK_S *pstPack; /*stream pack attribute*/ + HI_U32 u32PackCount; /*the pack number of one frame stream*/ + HI_U32 u32Seq; /*the list number of stream*/ + + union + { + VENC_STREAM_INFO_H264_S stH264Info; /*the stream info of h264*/ + VENC_STREAM_INFO_JPEG_S stJpegInfo; /*the stream info of jpeg*/ + VENC_STREAM_INFO_MPEG4_S stMpeg4Info; /*the stream info of mpeg4*/ + VENC_STREAM_INFO_H265_S stH265Info; /*the stream info of h265*/ + }; +}VENC_STREAM_S; + +typedef struct hiVENC_ATTR_H264_S +{ + HI_U32 u32MaxPicWidth; /*maximum width of a picture to be encoded, in pixel*/ + HI_U32 u32MaxPicHeight; /*maximum height of a picture to be encoded, in pixel*/ + + HI_U32 u32BufSize; /*stream buffer size*/ + HI_U32 u32Profile; /*0: baseline; 1:MP; 2:HP; 3: SVC-T [0,3]; */ + HI_BOOL bByFrame; /*get stream mode is slice mode or frame mode*/ + + + HI_U32 u32PicWidth; /*width of a picture to be encoded, in pixel*/ + HI_U32 u32PicHeight; /*height of a picture to be encoded, in pixel*/ + + HI_U32 u32BFrameNum; /* 0: not support B frame; >=1: number of B frames */ + HI_U32 u32RefNum; /* 0: default; number of refrence frame*/ + +}VENC_ATTR_H264_S; + +typedef struct hiVENC_ATTR_H265_S +{ + HI_U32 u32MaxPicWidth; /*maximum width of a picture to be encoded, in pixel*/ + HI_U32 u32MaxPicHeight; /*maximum height of a picture to be encoded, in pixel*/ + + HI_U32 u32BufSize; /*stream buffer size*/ + HI_U32 u32Profile; /*0: MP */ + HI_BOOL bByFrame; /*get stream mode is slice mode or frame mode*/ + + + HI_U32 u32PicWidth; /*width of a picture to be encoded, in pixel*/ + HI_U32 u32PicHeight; /*height of a picture to be encoded, in pixel*/ + + HI_U32 u32BFrameNum; /* 0: not support B frame; >=1: number of B frames */ + HI_U32 u32RefNum; /* 0: default; number of refrence frame*/ +}VENC_ATTR_H265_S; + +typedef struct hiVENC_ATTR_MJPEG_S +{ + HI_U32 u32MaxPicWidth; /*maximum width of a picture to be encoded, in pixel*/ + HI_U32 u32MaxPicHeight; /*maximum height of a picture to be encoded, in pixel*/ + HI_U32 u32BufSize; /*stream buffer size*/ + HI_BOOL bByFrame; /*get stream mode is field mode or frame mode*/ + + + HI_U32 u32PicWidth; /*width of a picture to be encoded, in pixel*/ + HI_U32 u32PicHeight; /*height of a picture to be encoded, in pixel*/ + +}VENC_ATTR_MJPEG_S; + +typedef struct hiVENC_ATTR_JPEG_S +{ + HI_U32 u32MaxPicWidth; /*maximum width of a picture to be encoded, in pixel*/ + HI_U32 u32MaxPicHeight; /*maximum height of a picture to be encoded, in pixel*/ + HI_U32 u32BufSize; /*stream buffer size*/ + HI_BOOL bByFrame; /*get stream mode is field mode or frame mode*/ + + + HI_U32 u32PicWidth; /*width of a picture to be encoded, in pixel*/ + HI_U32 u32PicHeight; /*height of a picture to be encoded, in pixel*/ + HI_BOOL bSupportDCF; /*support dcf*/ + +}VENC_ATTR_JPEG_S; + +/* attribute of MPEG4*/ +typedef struct hiVENC_ATTR_MPEG4_S +{ + HI_U32 u32MaxPicWidth; /*maximum width of a picture to be encoded, in pixel*/ + HI_U32 u32MaxPicHeight; /*maximum height of a picture to be encoded, in pixel*/ + + HI_U32 u32BufSize; /*buffer size*/ + HI_BOOL bByFrame; /*get stream mode is pack or frame*/ + + + HI_U32 u32PicWidth; /*width of a picture to be encoded, in pixel*/ + HI_U32 u32PicHeight; /*height of a picture to be encoded, in pixel*/ +}VENC_ATTR_MPEG4_S; + +typedef struct hiVENC_ATTR_S +{ + PAYLOAD_TYPE_E enType; /*the type of payload*/ + union + { + VENC_ATTR_H264_S stAttrH264e; /*attributes of h264*/ + VENC_ATTR_MJPEG_S stAttrMjpeg; /*attributes of mjpeg*/ + VENC_ATTR_JPEG_S stAttrJpeg; /*attributes of jpeg*/ + VENC_ATTR_MPEG4_S stAttrMpeg4; /*attributes of mpeg4*/ + VENC_ATTR_H265_S stAttrH265e; /*attributes of h265*/ + }; +}VENC_ATTR_S; + +typedef struct hiVENC_CHN_ATTR_S +{ + VENC_ATTR_S stVeAttr; /*the attribute of video encoder*/ + VENC_RC_ATTR_S stRcAttr; /*the attribute of rate ctrl*/ +}VENC_CHN_ATTR_S; + +typedef struct hiVENC_CHN_STAT_S +{ + HI_U32 u32LeftPics; /*left picture number */ + HI_U32 u32LeftStreamBytes; /*left stream bytes*/ + HI_U32 u32LeftStreamFrames; /*left stream frames*/ + HI_U32 u32CurPacks; /*pack number of current frame*/ + HI_U32 u32LeftRecvPics; /*Number of frames to be received. This member is valid after HI_MPI_VENC_StartRecvPicEx is called.*/ + HI_U32 u32LeftEncPics; /*Number of frames to be encoded. This member is valid after HI_MPI_VENC_StartRecvPicEx is called.*/ +}VENC_CHN_STAT_S; + + + +typedef struct hiVENC_PARAM_H264_SLICE_SPLIT_S +{ + HI_BOOL bSplitEnable; /*slice split enable, HI_TRUE:enable, HI_FALSE:diable, default value:HI_FALSE*/ + HI_U32 u32SplitMode; /*0:bit number, 1:mb line number, >=2:no meaning*/ + HI_U32 u32SliceSize; /*when the splitmode is 0, this value presents the bitsnum of one slice average, + when the splitmode is 1, this value presents the mb num of one slice*/ +} VENC_PARAM_H264_SLICE_SPLIT_S; + +typedef struct hiVENC_PARAM_H264_INTER_PRED_S +{ + /* search window */ + HI_U32 u32HWSize; /* size of horizontal search window. + default value: differ with the picture size */ + HI_U32 u32VWSize; /* size of vertical search window. + default value: differ with the picture size */ + + /* inter pred, one of the following 4 kinds of inter prediction mode must be enable */ + HI_BOOL bInter16x16PredEn; /*default: HI_TRUE, enable 16x16 prediction*/ + HI_BOOL bInter16x8PredEn; /*default: HI_TRUE*/ + HI_BOOL bInter8x16PredEn; /*default: HI_TRUE*/ + HI_BOOL bInter8x8PredEn; /*default: HI_TRUE*/ + HI_BOOL bExtedgeEn; /*default: HI_TRUE*/ +} VENC_PARAM_H264_INTER_PRED_S; + +typedef struct hiVENC_PARAM_H264_INTRA_PRED_S +{ + /* intra pred, one of following 2 kinds of intra pred mode must be enable */ + HI_BOOL bIntra16x16PredEn; /*default: HI_TRUE, enable 16x16 intra prediction*/ + HI_BOOL bIntraNxNPredEn; /*default: HI_TRUE, enable 4x4 and/or 8x8 prediction + Notes: this value must work with IntraTransMode*/ + HI_U32 constrained_intra_pred_flag; /*default: HI_FALSE, see the H.264 protocol*/ + HI_BOOL bIpcmEn; /*default: HI_TRUE, enable ipcm*/ +}VENC_PARAM_H264_INTRA_PRED_S; + +typedef struct hiVENC_PARAM_H264_TRANS_S +{ + HI_U32 u32IntraTransMode; /* 0: trans4x4, trans8x8; 1: trans4x4, 2: trans8x8 */ + HI_U32 u32InterTransMode; /* 0: trans4x4, trans8x8; 1: trans4x4, 2: trans8x8 */ + + HI_BOOL bScalingListValid; /* default: HI_FALSE */ + /* Notes: Enable IntraScalingList8X8 and InterScalingList8X8 while bScalingListValid is HI_TRUE */ + HI_U8 InterScalingList8X8[64]; + HI_U8 IntraScalingList8X8[64]; + + HI_S32 chroma_qp_index_offset; /* [-12,12],default value: 0*/ +}VENC_PARAM_H264_TRANS_S; + +typedef struct hiVENC_PARAM_H264_ENTROPY_S +{ + HI_U32 u32EntropyEncModeI; /* 0:cavlc, 1:cabac */ + HI_U32 u32EntropyEncModeP; /* 0:cavlc, 1:cabac */ + HI_U32 cabac_stuff_en; /* default: 0*/ + HI_U32 Cabac_init_idc; /* 0~2 */ +}VENC_PARAM_H264_ENTROPY_S; + +typedef struct hiVENC_PARAM_H264_POC_S +{ + HI_U32 pic_order_cnt_type; /* default value: 2. {0,1,2} */ + +}VENC_PARAM_H264_POC_S; + +typedef struct hiVENC_PARAM_H264_DBLK_S +{ + HI_U32 disable_deblocking_filter_idc; /* default value: 0. {0,1,2} */ + HI_S32 slice_alpha_c0_offset_div2; /* default value: 5. [-6,+6] */ + HI_S32 slice_beta_offset_div2; /* default value: 5. [-6,+6] */ +}VENC_PARAM_H264_DBLK_S; + + +typedef struct hiVENC_PARAM_H264_VUI_TIME_INFO_S +{ + HI_U8 timing_info_present_flag; /* default value: 0. If 1, timing info belows will be encoded into vui. {0,1} */ + HI_U8 fixed_frame_rate_flag; /* default value: n/a. {0,1} */ + HI_U32 num_units_in_tick; /* default value: n/a. > 0. */ + HI_U32 time_scale; /* default value: n/a. > 0. */ + +}VENC_PARAM_VUI_H264_TIME_INFO_S; + +typedef struct hiVENC_PARAM_VUI_ASPECT_RATIO_S +{ + HI_U8 aspect_ratio_info_present_flag; /* default value: 0. If 1, aspectratio info belows will be encoded into vui. {0,1} */ + HI_U8 aspect_ratio_idc; /* default value: n/a. [0,255],17~254 is reserved. */ + HI_U8 overscan_info_present_flag; /* default value: 0,just be 0.If 1, oversacan info belows will be encoded into vui. {0,1} */ + HI_U8 overscan_appropriate_flag; /* default value: n/a. */ + HI_U16 sar_width; /* default value: n/a. sar_width and sar_height shall be relatively prime. */ + HI_U16 sar_height ; /* default value: n/a. */ +}VENC_PARAM_VUI_ASPECT_RATIO_S; + + +typedef struct hiVENC_PARAM_VUI_VIDEO_SIGNAL_S +{ + HI_U8 video_signal_type_present_flag ; /* default value: 0. If 1, video singnal info will be encoded into vui. {0,1} */ + HI_U8 video_format ; /* default value: n/a. >= 0. */ + HI_U8 video_full_range_flag; /* default value: n/a. {0,1}. */ + HI_U8 colour_description_present_flag ; /* default value: n/a. {0,1} */ + HI_U8 colour_primaries ; /* default value: n/a. [0,255],0/9~255 is reserved */ + HI_U8 transfer_characteristics; /* default value: n/a. [0,255],0/13~255 is reserved */ + HI_U8 matrix_coefficients; /* default value: n/a. [0,255],9~255 is reserved */ +}VENC_PARAM_VUI_VIDEO_SIGNAL_S; + + + +typedef struct hiVENC_PARAM_H264_VUI_S +{ + VENC_PARAM_VUI_ASPECT_RATIO_S stVuiAspectRatio; /* the param of aspect ratio */ + VENC_PARAM_VUI_H264_TIME_INFO_S stVuiTimeInfo; /* the param of time info */ + VENC_PARAM_VUI_VIDEO_SIGNAL_S stVuiVideoSignal; /* the param of video signal */ +}VENC_PARAM_H264_VUI_S; + + +typedef struct hiVENC_PARAM_JPEG_S +{ + HI_U32 u32Qfactor; /*image quality :[1,99]*/ + + HI_U8 u8YQt[64]; /* y qt value */ + HI_U8 u8CbQt[64]; /* cb qt value */ + HI_U8 u8CrQt[64]; /* cr qt value */ + + HI_U32 u32MCUPerECS; /*default value: 0, MCU number of one ECS*/ +} VENC_PARAM_JPEG_S; + +typedef struct hiVENC_PARAM_MJPEG_S +{ + HI_U8 u8YQt[64]; /* y qt value */ + HI_U8 u8CbQt[64]; /* cb qt value */ + HI_U8 u8CrQt[64]; /* cr qt value */ + + HI_U32 u32MCUPerECS; /*default value: 0, MCU number of one ECS*/ +} VENC_PARAM_MJPEG_S; + + + + +/* ROI struct */ +typedef struct hiVENC_ROI_CFG_S +{ + HI_U32 u32Index; /* Index of an ROI. The system supports indexes ranging from 0 to 7 */ + HI_BOOL bEnable; /* Whether to enable this ROI */ + HI_BOOL bAbsQp; /* QP mode of an ROI.HI_FALSE: relative QP.HI_TURE: absolute QP.*/ + HI_S32 s32Qp; /* QP value. */ + RECT_S stRect; /* Region of an ROI*/ +}VENC_ROI_CFG_S; + + +typedef struct hiVENC_ROIBG_FRAME_RATE_S +{ + HI_S32 s32SrcFrmRate; /* Input frame rate of Roi backgroud*/ + HI_S32 s32DstFrmRate; /* Output frame rate of Roi backgroud */ +}VENC_ROIBG_FRAME_RATE_S; + + +typedef struct hiVENC_COLOR2GREY_S +{ + HI_BOOL bColor2Grey; /* Whether to enable Color2Grey.*/ +}VENC_COLOR2GREY_S; + +typedef struct hiVENC_CROP_CFG_S +{ + HI_BOOL bEnable; /* Crop region enable */ + RECT_S stRect; /* Crop region, note: s32X must be multi of 16 */ +}VENC_CROP_CFG_S; + + +typedef struct hiVENC_FRAME_RATE_S +{ + HI_S32 s32SrcFrmRate; /* Input frame rate of a channel*/ + HI_S32 s32DstFrmRate; /* Output frame rate of a channel*/ +} VENC_FRAME_RATE_S; + +typedef struct hiVENC_PARAM_REF_S +{ + HI_U32 u32Base; /*Base layer period*/ + HI_U32 u32Enhance; /*Enhance layer period*/ + HI_BOOL bEnablePred; /*Whether some frames at the base layer are referenced by other frames at the base layer. When bEnablePred is HI_FALSE, all frames at the base layer reference IDR frames.*/ +} VENC_PARAM_REF_S; + + +typedef enum hiH264E_IDR_PIC_ID_MODE_E +{ + H264E_IDR_PIC_ID_MODE_AUTO = 0, /*auto mode */ + H264E_IDR_PIC_ID_MODE_USR, /*user mode */ + H264E_IDR_PIC_ID_MODE_BUTT, +}H264E_IDR_PIC_ID_MODE_E; + +typedef struct hiVENC_H264_IDRPICID_CFG_S +{ + H264E_IDR_PIC_ID_MODE_E enH264eIdrPicIdMode; /*the mode of idr_pic_id that is set*/ + HI_U32 u32H264eIdrPicId; /*idr_pic_id value*/ +} VENC_H264_IDRPICID_CFG_S; + +typedef struct hiVENC_RECV_PIC_PARAM_S +{ + HI_S32 s32RecvPicNum; /*Number of frames received and encoded by the encoding channel*/ +} VENC_RECV_PIC_PARAM_S; + +typedef struct hiVENC_STREAM_BUF_INFO_S +{ + HI_U32 u32PhyAddr; + HI_VOID *pUserAddr; + HI_U32 u32BufSize; +} VENC_STREAM_BUF_INFO_S; + +typedef enum hiVENC_MODTYPE_E +{ + MODTYPE_VENC = 1, + MODTYPE_H264E, + MODTYPE_H265E, + MODTYPE_JPEGE, + MODTYPE_BUTT +} VENC_MODTYPE_E; + +typedef struct hiVENC_PARAM_MOD_H264E_S +{ + HI_U32 u32OneStreamBuffer; + HI_U32 u32H264eVBSource; + HI_U32 u32H264eRcnEqualRef; + HI_U32 u32H264eMiniBufMode; +} VENC_PARAM_MOD_H264E_S; + +typedef struct hiVENC_PARAM_MOD_H265E_S +{ + HI_U32 u32OneStreamBuffer; + HI_U32 u32H265eMiniBufMode; +} VENC_PARAM_MOD_H265E_S; + +typedef struct hiVENC_PARAM_MOD_JPEGE_S +{ + HI_U32 u32OneStreamBuffer; + HI_U32 u32JpegeMiniBufMode; + +} VENC_PARAM_MOD_JPEGE_S; + + +typedef struct hiVENC_PARAM_MOD_VENC_S +{ + HI_U32 u32VencBufferCache; +} VENC_PARAM_MOD_VENC_S; + + +typedef struct hiVENC_MODPARAM_S +{ + VENC_MODTYPE_E enVencModType; + union + { + VENC_PARAM_MOD_VENC_S stVencModParam; + VENC_PARAM_MOD_H264E_S stH264eModParam; + VENC_PARAM_MOD_H265E_S stH265eModParam; + VENC_PARAM_MOD_JPEGE_S stJpegeModParam; + }; +} VENC_PARAM_MOD_S; +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_COMM_VENC_H__ */ diff --git a/snes9x/unix/mpp/hi_comm_vgs.h b/snes9x/unix/mpp/hi_comm_vgs.h new file mode 100644 index 0000000..c0bd3f4 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vgs.h @@ -0,0 +1,141 @@ +/****************************************************************************** + + Copyright (C), 2013-2033, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_vgs.h + Version : + Author : Hisilicon Hi35xx MPP Team + Created : 2013/07/24 + Last Modified : + Description : common struct definition for VGS + Function List : + History : +******************************************************************************/ +#ifndef __HI_COMM_VGS_H__ +#define __HI_COMM_VGS_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" + +/* failure caused by malloc buffer */ +#define HI_ERR_VGS_NOBUF HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +#define HI_ERR_VGS_BUF_EMPTY HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +#define HI_ERR_VGS_NULL_PTR HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_VGS_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_VGS_BUF_FULL HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +#define HI_ERR_VGS_SYS_NOTREADY HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_VGS_NOT_SUPPORT HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +#define HI_ERR_VGS_NOT_PERMITTED HI_DEF_ERR(HI_ID_VGS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) + +typedef HI_S32 VGS_HANDLE; + +typedef struct hiVGS_TASK_ATTR_S +{ + VIDEO_FRAME_INFO_S stImgIn; /* input picture */ + VIDEO_FRAME_INFO_S stImgOut; /* output picture */ + HI_U32 au32privateData[4]; /* task's private data */ + HI_U32 reserved; /* save current picture's state while debug */ +}VGS_TASK_ATTR_S; + +typedef struct hiVGS_LINE_S +{ + POINT_S stStartPoint; /* line start point [-8191, 8191] */ + POINT_S stEndPoint; /* line end point [-8191, 8191] */ + + HI_U32 u32Thick; /* width of line [0, 14] */ + HI_U32 u32Color; /* color of line */ +}VGS_LINE_S; + +typedef enum hiVGS_COVER_TYPE_E +{ + COVER_RECT = 0, + COVER_QUAD_RANGLE, + COVER_BUTT +} VGS_COVER_TYPE_E; + +typedef struct hiVGS_QUADRANGLE_COVER_S +{ + HI_BOOL bSolid; /* solid or hollow cover */ + HI_U32 u32Thick; /* width of hollow cover */ + POINT_S stPoint[4]; /* four coordinate of quadrangle */ +} VGS_QUADRANGLE_COVER_S; + +typedef struct hiVGS_COVER_S +{ + VGS_COVER_TYPE_E enCoverType; + union + { + RECT_S stDstRect; /* config of rectrangle */ + VGS_QUADRANGLE_COVER_S stQuadRangle; /* config of quadrangle */ + }; + + HI_U32 u32Color; /* color of cover */ +}VGS_COVER_S; + +typedef struct hiVGS_OSD_S +{ + RECT_S stRect; /* start point, width and height of osd [0, 8192] */ + HI_U32 u32BgColor; /* background color of osd */ + PIXEL_FORMAT_E enPixelFmt; /* pixel format of osd */ + HI_U32 u32PhyAddr; + HI_U32 u32Stride; + HI_U32 u32BgAlpha; + HI_U32 u32FgAlpha; +}VGS_OSD_S; + +typedef enum hiVGS_ROTATE_E +{ + VGS_ROTATE_NONE = 0, /* no rotate */ + VGS_ROTATE_90 = 1, /* 90 degrees clockwise */ + VGS_ROTATE_180 = 2, /* 180 degrees clockwise */ + VGS_ROTATE_270 = 3, /* 270 degrees clockwise */ + VGS_ROTATE_BUTT +} VGS_ROTATE_E; + +typedef struct HI_VGS_BORDER_S +{ + HI_U32 u32Width[4]; /* width of 4 frames,0:L,1:R,2:B,3:T */ + HI_U32 u32Color; /* color of 4 frames,R/G/B */ +}VGS_BORDER_S; + +typedef struct hiVGS_ASPECTRATIO_S +{ + RECT_S stVideoRect; + HI_U32 u32CoverData; + }VGS_ASPECTRATIO_S; + + +typedef struct hiVGS_ONLINE_S +{ + HI_BOOL bCrop; /* if enable crop */ + RECT_S stCropRect; + HI_BOOL bHSharpen; /* if enable sharpen */ + HI_U32 u32LumaGain; + HI_BOOL bBorder; /* if enable Border */ + VGS_BORDER_S stBorderOpt; + HI_BOOL bAspectRatio; /* if enable aspect ratio */ + VGS_ASPECTRATIO_S stAspectRatioOpt; + + HI_BOOL bForceHFilt; /* if enable horizontal filter */ + HI_BOOL bForceVFilt; /* if enable vertical filter */ + HI_BOOL bDeflicker; /* if enable deflicker */ +}VGS_ONLINE_S; + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_COMM_VGS_H__ */ diff --git a/snes9x/unix/mpp/hi_comm_vi.h b/snes9x/unix/mpp/hi_comm_vi.h new file mode 100644 index 0000000..5eb2ff5 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vi.h @@ -0,0 +1,459 @@ +/****************************************************************************** + +Copyright (C), 2004-2020, Hisilicon Tech. Co., Ltd. + +****************************************************************************** +File Name : hi_comm_vi.h +Version : Initial Draft +Author : Hisilicon multimedia software group +Created : 2009/3/9 +Last Modified : +Description : +Function List : +History : +1.Date : 2010/11/16 + Author : p00123320/w54723/n168968 + Modification: Created file + +2.Date : 2011/06/16 + Author : w54723/l00181524/c00186004 + Modification: Created file + + +******************************************************************************/ + +#ifndef __HI_COMM_VI_H__ +#define __HI_COMM_VI_H__ + +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" + + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +#define VI_INVALID_FRMRATE (-1UL) +#define VIU_MAX_USER_FRAME_DEPTH 8 + +typedef enum hiEN_VIU_ERR_CODE_E +{ + ERR_VI_FAILED_NOTENABLE = 64, /* device or channel not enable*/ + ERR_VI_FAILED_NOTDISABLE, /* device not disable*/ + ERR_VI_FAILED_CHNOTDISABLE, /* channel not disable*/ + ERR_VI_CFG_TIMEOUT, /* config timeout*/ + ERR_VI_NORM_UNMATCH, /* video norm of ADC and VIU is unmatch*/ + ERR_VI_INVALID_WAYID, /* invlalid way ID */ + ERR_VI_INVALID_PHYCHNID, /* invalid phychn id*/ + ERR_VI_FAILED_NOTBIND, /* device or channel not bind */ + ERR_VI_FAILED_BINDED, /* device or channel not unbind */ +} EN_VIU_ERR_CODE_E; + +#define HI_ERR_VI_INVALID_PARA HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_VI_INVALID_DEVID HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +#define HI_ERR_VI_INVALID_CHNID HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +#define HI_ERR_VI_INVALID_NULL_PTR HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_VI_FAILED_NOTCONFIG HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_CONFIG) +#define HI_ERR_VI_SYS_NOTREADY HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_VI_BUF_EMPTY HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) +#define HI_ERR_VI_BUF_FULL HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_FULL) +#define HI_ERR_VI_NOMEM HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +#define HI_ERR_VI_NOT_SUPPORT HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +#define HI_ERR_VI_BUSY HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_VI_NOT_PERM HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) + +#define HI_ERR_VI_FAILED_NOTENABLE HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_FAILED_NOTENABLE)/* 0xA0108040*/ +#define HI_ERR_VI_FAILED_NOTDISABLE HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_FAILED_NOTDISABLE)/* 0xA0108041*/ +#define HI_ERR_VI_FAILED_CHNOTDISABLE HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_FAILED_CHNOTDISABLE)/* 0xA0108042*/ +#define HI_ERR_VI_CFG_TIMEOUT HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_CFG_TIMEOUT)/* 0xA0108043*/ +#define HI_ERR_VI_NORM_UNMATCH HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_NORM_UNMATCH)/* 0xA0108044*/ +#define HI_ERR_VI_INVALID_WAYID HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_INVALID_WAYID)/* 0xA0108045*/ +#define HI_ERR_VI_INVALID_PHYCHNID HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_INVALID_PHYCHNID)/* 0xA0108046*/ +#define HI_ERR_VI_FAILED_NOTBIND HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_FAILED_NOTBIND)/* 0xA0108047*/ +#define HI_ERR_VI_FAILED_BINDED HI_DEF_ERR(HI_ID_VIU, EN_ERR_LEVEL_ERROR, ERR_VI_FAILED_BINDED)/* 0xA0108048*/ + +/* interface mode of video input */ +typedef enum hiVI_INTF_MODE_E +{ + VI_MODE_BT656 = 0, /* ITU-R BT.656 YUV4:2:2 */ + VI_MODE_BT601, /* ITU-R BT.601 YUV4:2:2 */ + VI_MODE_DIGITAL_CAMERA, /* digatal camera mode */ + VI_MODE_BT1120_STANDARD, /* BT.1120 progressive mode */ + VI_MODE_BT1120_INTERLEAVED, /* BT.1120 interstage mode */ + + VI_MODE_BUTT +} VI_INTF_MODE_E; + + +/* Input mode */ +typedef enum hiVI_INPUT_MODE_E +{ + VI_INPUT_MODE_BT656 = 0, /* ITU-R BT.656 YUV4:2:2 */ + VI_INPUT_MODE_BT601, /* ITU-R BT.601 YUV4:2:2 */ + VI_INPUT_MODE_DIGITAL_CAMERA, /* digatal camera mode */ + VI_INPUT_MODE_INTERLEAVED, + + VI_INPUT_MODE_BUTT +} VI_INPUT_MODE_E; + +typedef enum hiVI_WORK_MODE_E +{ + VI_WORK_MODE_1Multiplex = 0, /* 1 Multiplex mode */ + VI_WORK_MODE_2Multiplex, /* 2 Multiplex mode */ + VI_WORK_MODE_4Multiplex, /* 4 Multiplex mode */ + + + VI_WORK_MODE_BUTT +} VI_WORK_MODE_E; + + + +/* whether an input picture is interlaced or progressive */ +typedef enum hiVI_SCAN_MODE_E +{ + VI_SCAN_INTERLACED = 0, + VI_SCAN_PROGRESSIVE, + + VI_SCAN_BUTT, +} VI_SCAN_MODE_E; + +typedef enum hiVI_DATA_YUV_SEQ_E +{ + /*The input sequence of the second component(only contains u and v) in BT.1120 mode */ + VI_INPUT_DATA_VUVU = 0, + VI_INPUT_DATA_UVUV, + + /* The input sequence for yuv */ + VI_INPUT_DATA_UYVY = 0, + VI_INPUT_DATA_VYUY, + VI_INPUT_DATA_YUYV, + VI_INPUT_DATA_YVYU, + + VI_DATA_YUV_BUTT +} VI_DATA_YUV_SEQ_E; + +typedef enum hiVI_CLK_EDGE_E +{ + VI_CLK_EDGE_SINGLE_UP = 0, /* single-edge mode and in rising edge */ + VI_CLK_EDGE_SINGLE_DOWN, /* single-edge mode and in falling edge */ + VI_CLK_EDGE_DOUBLE , /* Double edge mode */ + + VI_CLK_EDGE_BUTT +} VI_CLK_EDGE_E; + +typedef enum hiVI_COMP_MODE_E +{ + VI_COMP_MODE_SINGLE = 0, /* in single component mode */ + VI_COMP_MODE_DOUBLE = 1, /* in double component mode */ + VI_COMP_MODE_BUTT, +}VI_COMP_MODE_E; + +/* Y/C composite or separation mode */ +typedef enum hiVI_COMBINE_MODE_E +{ + VI_COMBINE_COMPOSITE = 0, /* Composite mode */ + VI_COMBINE_SEPARATE, /* Separate mode */ + VI_COMBINE_BUTT, +} VI_COMBINE_MODE_E; + +/* Attribute of the vertical synchronization signal */ +typedef enum hiVI_VSYNC_E +{ + VI_VSYNC_FIELD = 0, /* Field/toggle mode:a signal reversal means a new frame or a field */ + VI_VSYNC_PULSE, /* Pusle/effective mode:a pusle or an effective signal means a new frame or a field */ +} VI_VSYNC_E; + +/* Polarity of the vertical synchronization signal */ +typedef enum hiVI_VSYNC_NEG_E +{ + VI_VSYNC_NEG_HIGH = 0, /*if VIU_VSYNC_E = VIU_VSYNC_FIELD,then the vertical synchronization signal of even field is high-level, + if VIU_VSYNC_E = VIU_VSYNC_PULSE,then the vertical synchronization pulse is positive pulse.*/ + VI_VSYNC_NEG_LOW /*if VIU_VSYNC_E = VIU_VSYNC_FIELD,then the vertical synchronization signal of even field is low-level, + if VIU_VSYNC_E = VIU_VSYNC_PULSE,then the vertical synchronization pulse is negative pulse.*/ +} VI_VSYNC_NEG_E; + +/* Attribute of the horizontal synchronization signal */ +typedef enum hiVI_HSYNC_E +{ + VI_HSYNC_VALID_SINGNAL = 0, /* the horizontal synchronization is valid signal mode */ + VI_HSYNC_PULSE, /* the horizontal synchronization is pulse mode, a new pulse means the beginning of a new line */ +} VI_HSYNC_E; + +/* Polarity of the horizontal synchronization signal */ +typedef enum hiVI_HSYNC_NEG_E +{ + VI_HSYNC_NEG_HIGH = 0, /*if VI_HSYNC_E = VI_HSYNC_VALID_SINGNAL,then the valid horizontal synchronization signal is high-level; + if VI_HSYNC_E = VI_HSYNC_PULSE,then the horizontal synchronization pulse is positive pulse */ + VI_HSYNC_NEG_LOW /*if VI_HSYNC_E = VI_HSYNC_VALID_SINGNAL,then the valid horizontal synchronization signal is low-level; + if VI_HSYNC_E = VI_HSYNC_PULSE,then the horizontal synchronization pulse is negative pulse */ +} VI_HSYNC_NEG_E; + +/* Attribute of the valid vertical synchronization signal */ +typedef enum hiVI_VSYNC_VALID_E +{ + VI_VSYNC_NORM_PULSE = 0, /* the vertical synchronization is pusle mode, a pusle means a new frame or field */ + VI_VSYNC_VALID_SINGAL, /* the vertical synchronization is effective mode, a effective signal means a new frame or field */ +} VI_VSYNC_VALID_E; + +/* Polarity of the valid vertical synchronization signal */ +typedef enum hiVI_VSYNC_VALID_NEG_E +{ + VI_VSYNC_VALID_NEG_HIGH = 0, /*if VI_VSYNC_VALID_E = VI_VSYNC_NORM_PULSE,a positive pulse means vertical synchronization pulse; + if VI_VSYNC_VALID_E = VI_VSYNC_VALID_SINGAL,the valid vertical synchronization signal is high-level */ + VI_VSYNC_VALID_NEG_LOW /*if VI_VSYNC_VALID_E = VI_VSYNC_NORM_PULSE,a negative pulse means vertical synchronization pulse; + if VI_VSYNC_VALID_E = VI_VSYNC_VALID_SINGAL,the valid vertical synchronization signal is low-level */ +} VI_VSYNC_VALID_NEG_E; + + + +/* Blank information of the input timing */ +typedef struct hiVI_TIMING_BLANK_S +{ + HI_U32 u32HsyncHfb ; /* Horizontal front blanking width */ + HI_U32 u32HsyncAct ; /* Horizontal effetive width */ + HI_U32 u32HsyncHbb ; /* Horizontal back blanking width */ + HI_U32 u32VsyncVfb ; /* Vertical front blanking height of one frame or odd-field frame picture */ + HI_U32 u32VsyncVact ; /* Vertical effetive width of one frame or odd-field frame picture */ + HI_U32 u32VsyncVbb ; /* Vertical back blanking height of one frame or odd-field frame picture */ + HI_U32 u32VsyncVbfb ; /* Even-field vertical front blanking height when input mode is interlace (invalid when progressive input mode) */ + HI_U32 u32VsyncVbact ; /* Even-field vertical effetive width when input mode is interlace (invalid when progressive input mode) */ + HI_U32 u32VsyncVbbb ; /* Even-field vertical back blanking height when input mode is interlace (invalid when progressive input mode) */ +}VI_TIMING_BLANK_S; + +/* synchronization information about the BT.601 or DC timing */ +typedef struct hiVI_SYNC_CFG_S +{ + VI_VSYNC_E enVsync; + VI_VSYNC_NEG_E enVsyncNeg; + VI_HSYNC_E enHsync; + VI_HSYNC_NEG_E enHsyncNeg; + VI_VSYNC_VALID_E enVsyncValid; + VI_VSYNC_VALID_NEG_E enVsyncValidNeg; + VI_TIMING_BLANK_S stTimingBlank; +} VI_SYNC_CFG_S; + +/* the highest bit of the BT.656 timing reference code*/ +typedef enum hiBT656_FIXCODE_E +{ + BT656_FIXCODE_1 = 0, /* The highest bit of the EAV/SAV data over the BT.656 protocol is always 1.*/ + BT656_FIXCODE_0 /* The highest bit of the EAV/SAV data over the BT.656 protocol is always 0.*/ +}BT656_FIXCODE_E; + +/* Polarity of the field indicator bit (F) of the BT.656 timing reference code */ +typedef enum hiBT656_FIELD_POLAR_E +{ + BT656_FIELD_POLAR_STD = 0, /* the standard BT.656 mode,the first filed F=0,the second filed F=1*/ + BT656_FIELD_POLAR_NSTD /* the non-standard BT.656 mode,the first filed F=1,the second filed F=0*/ +}BT656_FIELD_POLAR_E; + +typedef struct hiVI_BT656_SYNC_CFG_S +{ + BT656_FIXCODE_E enFixCode; + BT656_FIELD_POLAR_E enFieldPolar; +}VI_BT656_SYNC_CFG_S; + +typedef enum hiVI_VBI_LOCAL_E +{ + VI_VBI_LOCAL_ODD_FRONT = 0, + VI_VBI_LOCAL_ODD_END, + VI_VBI_LOCAL_EVEN_FRONT, + VI_VBI_LOCAL_EVEN_END, + VI_VBI_LOCAL_BUTT +} VI_VBI_LOCAL_E; + +typedef struct hiVI_VBI_ATTR_S +{ + VI_VBI_LOCAL_E enLocal; /* location of VBI */ + HI_S32 s32X; /* horizontal original position of the VBI data */ + HI_S32 s32Y; /* vertical original position of the VBI data */ + HI_U32 u32Len; /* length of VBI data, by word(4 Bytes) */ +} VI_VBI_ATTR_S; + +typedef struct hiVI_VBI_ARG_S +{ + VI_VBI_ATTR_S stVbiAttr[2]; +}VI_VBI_ARG_S; + +typedef enum hiVI_DATA_TYPE_E +{ + VI_DATA_TYPE_YUV = 0, + VI_DATA_TYPE_RGB = 1, + VI_DATA_TYPE_BUTT +} VI_DATA_TYPE_E; + +typedef enum hiVI_DATA_PATH_E +{ + VI_PATH_BYPASS = 0, /* ISP bypass */ + VI_PATH_ISP = 1, /* ISP enable */ + VI_PATH_RAW = 2, /* Capture raw data, for debug */ + VI_PATH_BUTT +}VI_DATA_PATH_E; + +/* the extended attributes of VI device */ +typedef struct hiVI_DEV_ATTR_EX_S +{ + VI_INPUT_MODE_E enInputMode; /* Input mode */ + VI_WORK_MODE_E enWorkMode; /*1-, 2-, or 4-channel multiplexed work mode */ + + VI_COMBINE_MODE_E enCombineMode; /* Y/C composite or separation mode */ + VI_COMP_MODE_E enCompMode; /* Component mode (single-component or dual-component) */ + VI_CLK_EDGE_E enClkEdge; /* Clock edge mode (sampling on the rising or falling edge) */ + + HI_U32 au32CompMask[2]; /* Component mask */ + + HI_S32 s32AdChnId[4]; /* AD channel ID. Typically, the default value -1 is recommended */ + + VI_DATA_YUV_SEQ_E enDataSeq; /* Input data sequence (only the YUV format is supported) */ + VI_SYNC_CFG_S stSynCfg; /* Sync timing. This member must be configured in BT.601 mode or DC mode */ + + VI_BT656_SYNC_CFG_S stBT656SynCfg; /* Sync timing. This member must be configured in BT.656 mode */ + + VI_DATA_PATH_E enDataPath; /* ISP enable or bypass */ + VI_DATA_TYPE_E enInputDataType; /* RGB: CSC-709 or CSC-601, PT YUV444 disable; YUV: default yuv CSC coef PT YUV444 enable. */ + + HI_BOOL bDataRev; /* Data reverse */ +} VI_DEV_ATTR_EX_S; + +/* the attributes of a VI device */ +typedef struct hiVI_DEV_ATTR_S +{ + VI_INTF_MODE_E enIntfMode; /* Interface mode */ + VI_WORK_MODE_E enWorkMode; /*1-, 2-, or 4-channel multiplexed work mode */ + + HI_U32 au32CompMask[2]; /* Component mask */ + + VI_CLK_EDGE_E enClkEdge; /* Clock edge mode (sampling on the rising or falling,double edge) */ + HI_S32 s32AdChnId[4]; /* AD channel ID. Typically, the default value -1 is recommended */ + + /* The below members must be configured in BT.601 mode or DC mode and are invalid in other modes */ + VI_DATA_YUV_SEQ_E enDataSeq; /* Input data sequence (only the YUV format is supported) */ + VI_SYNC_CFG_S stSynCfg; /* Sync timing. This member must be configured in BT.601 mode or DC mode */ + + VI_DATA_PATH_E enDataPath; /* ISP enable or bypass */ + VI_DATA_TYPE_E enInputDataType; /* RGB: CSC-709 or CSC-601, PT YUV444 disable; YUV: default yuv CSC coef PT YUV444 enable. */ + + HI_BOOL bDataRev; /* Data reverse */ +} VI_DEV_ATTR_S; + + +typedef struct hiVI_CHN_BIND_ATTR_S +{ + VI_DEV ViDev; + VI_WAY ViWay; +} VI_CHN_BIND_ATTR_S; + +/* the attributes of a VI way */ +typedef struct hiVI_WAY_ATTR_S +{ + HI_S32 s32AdChnId; +} VI_WAY_ATTR_S; + +/* captrue selection of video input */ +typedef enum hiVI_CAPSEL_E +{ + VI_CAPSEL_TOP = 0, /* top field */ + VI_CAPSEL_BOTTOM, /* bottom field */ + VI_CAPSEL_BOTH, /* top and bottom field */ + VI_CAPSEL_BUTT +} VI_CAPSEL_E; + +/* the attributes of a VI channel */ +typedef struct hiVI_CHN_ATTR_S +{ + RECT_S stCapRect; /* the capture rect (corresponding to the size of the picture captured by a VI device). + For primary channels, the stCapRect's u32Width and u32Height are static attributes. That is, + the value of them can be changed only after primary and secondary channels are disabled. + For secondary channels, stCapRect is an invalid attribute */ + SIZE_S stDestSize; /* Target picture size. + For primary channels, stDestSize must be equal to stCapRect's u32Width and u32Height, + because primary channel doesn't have scale capability. Additionally, it is a static + attribute, That is, the value of stDestSize can be changed only after primary and + secondary channels are disabled. + For secondary channels, stDestSize is a dynamic attribute */ + + VI_CAPSEL_E enCapSel; /* Frame/field select. It is used only in interlaced mode. + For primary channels, enCapSel is a static attribute */ + VI_SCAN_MODE_E enScanMode; /* Input scanning mode (progressive or interlaced) */ + PIXEL_FORMAT_E enPixFormat; /* Pixel storage format. Only the formats semi-planar420 and semi-planar422 are supported */ + HI_BOOL bMirror; /* Whether to mirror */ + HI_BOOL bFlip; /* Whether to flip */ + HI_S32 s32SrcFrameRate; /* Source frame rate. The value -1 indicates that the frame rate is not controlled */ + HI_S32 s32DstFrameRate; /* Target frame rate. The value -1 indicates that the frame rate is not controlled */ +} VI_CHN_ATTR_S; + +typedef struct hiVI_CHN_STAT_S +{ + HI_BOOL bEnable; /* Whether this channel is enabled */ + HI_U32 u32IntCnt; /* The video frame interrupt count */ + HI_U32 u32FrmRate; /* current frame rate */ + HI_U32 u32LostInt; /* The interrupt is received but nobody care */ + HI_U32 u32VbFail; /* Video buffer malloc failure */ + HI_U32 u32PicWidth; /* curren pic width */ + HI_U32 u32PicHeight; /* current pic height */ + HI_U32 u32AutoDisInt; /* auto disable interrupt count, when VIU detected too many interrupts */ +} VI_CHN_STAT_S; + +typedef enum hi_VI_USERPIC_MODE_E +{ + VI_USERPIC_MODE_PIC = 0, /* YUV picture */ + VI_USERPIC_MODE_BGC, /* Background picture only with a color */ + VI_USERPIC_MODE_BUTT, +} VI_USERPIC_MODE_E; + +typedef struct hiVI_USERPIC_BGC_S +{ + HI_U32 u32BgColor; +} VI_USERPIC_BGC_S; + +typedef struct hiVI_USERPIC_ATTR_S +{ + HI_BOOL bPub; /* Whether the user picture information is shared by all VI devices and channels*/ + VI_USERPIC_MODE_E enUsrPicMode; /* User picture mode */ + union + { + VIDEO_FRAME_INFO_S stUsrPicFrm; /* Information about a YUV picture */ + VI_USERPIC_BGC_S stUsrPicBg; /* Information about a background picture only with a color */ + }unUsrPic; +} VI_USERPIC_ATTR_S; + +typedef struct hiVI_USR_GET_FRM_TIMEOUT_S +{ + VIDEO_FRAME_INFO_S stVFrame; + HI_S32 s32MilliSec; +} VI_USR_GET_FRM_TIMEOUT_S; + +typedef struct hiVI_EXT_CHN_ATTR_S +{ + VI_CHN s32BindChn; /* The channel num which extend channel will bind to*/ + SIZE_S stDestSize; /* Target size*/ + + HI_S32 s32SrcFrameRate; /* Source frame rate. The value -1 indicates that the frame rate is not controlled */ + HI_S32 s32DstFrameRate; /* Target frame rate. The value -1 indicates that the frame rate is not controlled */ + PIXEL_FORMAT_E enPixFormat; /* Pixel storage format. Only the formats semi-planar420 and semi-planar422 are supported */ +}VI_EXT_CHN_ATTR_S; + +typedef struct hiVI_CHN_LUM_S +{ + HI_U32 u32Lum; /* Luma sum of current frame */ + HI_U64 u64Pts; /* PTS of current frame */ +} VI_CHN_LUM_S; + +typedef enum hiVI_SKIP_MODE_E +{ + VI_SKIP_NONE = 0, /*default mode, no skip*/ + VI_SKIP_YES, + VI_SKIP_BUTT, +}VI_SKIP_MODE_E; +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* End of #ifndef__HI_COMM_VIDEO_IN_H__ */ + + diff --git a/snes9x/unix/mpp/hi_comm_video.h b/snes9x/unix/mpp/hi_comm_video.h new file mode 100644 index 0000000..e62a78b --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_video.h @@ -0,0 +1,339 @@ +/******************************************************************************* + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_video.h + Version : Initial Draft + Author : c42025 + Created : 2006/11/09 + Description : + History : + 1.Date : 2006/11/03 + Author : c42025 + Modification: Created file + + 2.Date : 2007/12/11 + Author : c42025 + Modification: delelte all about digital watermark + + 3.Date : 2008/10/31 + Author : z44949 + Modification: Translate the chinese comment +******************************************************************************/ + +#ifndef __HI_COMM_VIDEO_H__ +#define __HI_COMM_VIDEO_H__ + +#include "hi_type.h" +#include "hi_common.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#define FISHEYE_MAX_REGION_NUM 4 +#define FISHEYE_MAX_OFFSET 127 + +typedef enum hiPIC_SIZE_E +{ + PIC_QCIF = 0, + PIC_CIF, + PIC_2CIF, + PIC_HD1, + PIC_D1, + PIC_960H, + PIC_1280H, + PIC_1440H, + + PIC_QVGA, /* 320 * 240 */ + PIC_VGA, /* 640 * 480 */ + PIC_XGA, /* 1024 * 768 */ + PIC_SXGA, /* 1400 * 1050 */ + PIC_UXGA, /* 1600 * 1200 */ + PIC_QXGA, /* 2048 * 1536 */ + + PIC_WVGA, /* 854 * 480 */ + PIC_WSXGA, /* 1680 * 1050 */ + PIC_WUXGA, /* 1920 * 1200 */ + PIC_WQXGA, /* 2560 * 1600 */ + + PIC_HD720, /* 1280 * 720 */ + PIC_HD1080, /* 1920 * 1080 */ + PIC_qHD, /*960 * 540*/ + + PIC_UHD4K, /* 3840*2160 */ + + PIC_BUTT +}PIC_SIZE_E; + +typedef enum hiVIDEO_NORM_E +{ + VIDEO_ENCODING_MODE_PAL=0, + VIDEO_ENCODING_MODE_NTSC, + VIDEO_ENCODING_MODE_AUTO, + VIDEO_ENCODING_MODE_BUTT +} VIDEO_NORM_E; + +typedef enum hiVIDEO_CONTROL_MODE_E +{ + VIDEO_CONTROL_MODE_SLAVER=0, + VIDEO_CONTROL_MODE_MASTER, + VIDEO_CONTROL_MODE_BUTT +}VIDEO_CONTROL_MODE_E; + +/* we ONLY define picture format used, all unused will be deleted!*/ +typedef enum hiPIXEL_FORMAT_E +{ + PIXEL_FORMAT_RGB_1BPP = 0, + PIXEL_FORMAT_RGB_2BPP, + PIXEL_FORMAT_RGB_4BPP, + PIXEL_FORMAT_RGB_8BPP, + PIXEL_FORMAT_RGB_444, + + PIXEL_FORMAT_RGB_4444, + PIXEL_FORMAT_RGB_555, + PIXEL_FORMAT_RGB_565, + PIXEL_FORMAT_RGB_1555, + + /* 9 reserved */ + PIXEL_FORMAT_RGB_888, + PIXEL_FORMAT_RGB_8888, + + PIXEL_FORMAT_RGB_PLANAR_888, + PIXEL_FORMAT_RGB_BAYER_8BPP, + PIXEL_FORMAT_RGB_BAYER_10BPP, + PIXEL_FORMAT_RGB_BAYER_12BPP, + PIXEL_FORMAT_RGB_BAYER_14BPP, + + PIXEL_FORMAT_RGB_BAYER, /* 16 bpp */ + + PIXEL_FORMAT_YUV_A422, + PIXEL_FORMAT_YUV_A444, + + PIXEL_FORMAT_YUV_PLANAR_422, + PIXEL_FORMAT_YUV_PLANAR_420, + + PIXEL_FORMAT_YUV_PLANAR_444, + + PIXEL_FORMAT_YUV_SEMIPLANAR_422, + PIXEL_FORMAT_YUV_SEMIPLANAR_420, + PIXEL_FORMAT_YUV_SEMIPLANAR_444, + + PIXEL_FORMAT_UYVY_PACKAGE_422, + PIXEL_FORMAT_YUYV_PACKAGE_422, + PIXEL_FORMAT_VYUY_PACKAGE_422, + PIXEL_FORMAT_YCbCr_PLANAR, + + PIXEL_FORMAT_YUV_400, + + PIXEL_FORMAT_BUTT +} PIXEL_FORMAT_E; + +typedef struct hiVIDEO_VBI_INFO_S +{ + HI_U32 au32Data[VIU_MAX_VBI_LEN]; + HI_U32 u32Len; +}VIDEO_VBI_INFO_S; + +typedef enum hiVIDEO_FIELD_E +{ + VIDEO_FIELD_TOP = 0x1, /* even field */ + VIDEO_FIELD_BOTTOM = 0x2, /* odd field */ + VIDEO_FIELD_INTERLACED = 0x3, /* two interlaced fields */ + VIDEO_FIELD_FRAME = 0x4, /* frame */ + + VIDEO_FIELD_BUTT +} VIDEO_FIELD_E; + +typedef enum hiVIDEO_FORMAT_E +{ + VIDEO_FORMAT_LINEAR = 0x0, /* nature video line */ + VIDEO_FORMAT_TILE = 0x1, /* tile cell: 256pixel x 16line, default tile mode */ + VIDEO_FORMAT_TILE64 = 0x2, /* tile cell: 64pixel x 16line */ + + VIDEO_FORMAT_BUTT +} VIDEO_FORMAT_E; + +typedef enum hiCOMPRESS_MODE_E +{ + COMPRESS_MODE_NONE = 0x0, /* no compress */ + COMPRESS_MODE_SEG = 0x1, /* compress unit is 256 bytes as a segment, default seg mode */ + COMPRESS_MODE_SEG128 = 0x2, /* compress unit is 128 bytes as a segment */ + COMPRESS_MODE_LINE = 0x3, /* compress unit is the whole line */ + COMPRESS_MODE_FRAME = 0x4, /* compress unit is the whole frame */ + + COMPRESS_MODE_BUTT +} COMPRESS_MODE_E; + +typedef enum hiVIDEO_DISPLAY_MODE_E +{ + VIDEO_DISPLAY_MODE_PREVIEW = 0x0, + VIDEO_DISPLAY_MODE_PLAYBACK = 0x1, + + VIDEO_DISPLAY_MODE_BUTT +} VIDEO_DISPLAY_MODE_E; + +typedef enum hiFRAME_FLASH_TYPE_E +{ + FRAME_FLASH_OFF = 0, + FRAME_FLASH_ON = 1, + FRAME_FLASH_BUTT, +}FRAME_FLASH_TYPE_E; + +typedef struct hiVIDEO_SUPPLEMENT_S +{ + HI_U32 u32JpegDcfPhyAddr; + HI_VOID *pJpegDcfVirAddr; + + FRAME_FLASH_TYPE_E enFlashType; +}VIDEO_SUPPLEMENT_S; + +typedef struct hiVIDEO_FRAME_S +{ + HI_U32 u32Width; + HI_U32 u32Height; + VIDEO_FIELD_E u32Field; + PIXEL_FORMAT_E enPixelFormat; + + VIDEO_FORMAT_E enVideoFormat; + COMPRESS_MODE_E enCompressMode; + + HI_U32 u32PhyAddr[3]; + HI_VOID *pVirAddr[3]; + HI_U32 u32Stride[3]; + + HI_U32 u32HeaderPhyAddr[3]; + HI_VOID *pHeaderVirAddr[3]; + HI_U32 u32HeaderStride[3]; + + HI_S16 s16OffsetTop; /* top offset of show area */ + HI_S16 s16OffsetBottom; /* bottom offset of show area */ + HI_S16 s16OffsetLeft; /* left offset of show area */ + HI_S16 s16OffsetRight; /* right offset of show area */ + + HI_U64 u64pts; + HI_U32 u32TimeRef; + + HI_U32 u32PrivateData; + VIDEO_SUPPLEMENT_S stSupplement; +}VIDEO_FRAME_S; + +typedef struct hiVIDEO_FRAME_INFO_S +{ + VIDEO_FRAME_S stVFrame; + HI_U32 u32PoolId; +} VIDEO_FRAME_INFO_S; + +/* VI Mix-Capture info. */ +typedef struct hiVI_MIXCAP_STAT_S +{ + HI_BOOL bMixCapMode; /* In mix-capture mode or not. */ + HI_BOOL bHasDownScale; /* VI Frame is downscaled or not. */ +} VI_MIXCAP_STAT_S; + +/* VI output frame info. */ +typedef struct hiVI_FRAME_INFO_S +{ + VI_MIXCAP_STAT_S stMixCapState; /* VI Mix-Capture info. */ + VIDEO_FRAME_INFO_S stViFrmInfo; /* Video frame info. */ + HI_BOOL bFlashed; /* Flashed Video frame or not. */ +}VI_FRAME_INFO_S; + + +typedef struct hiBITMAP_S +{ + PIXEL_FORMAT_E enPixelFormat; /* Bitmap's pixel format */ + HI_U32 u32Width; /* Bitmap's width */ + HI_U32 u32Height; /* Bitmap's height */ + HI_VOID *pData; /* Address of Bitmap's data */ +} BITMAP_S; + + +typedef enum hiFISHEYE_MOUNT_MODE_E +{ + + FISHEYE_DESKTOP_MOUNT = 0, /* desktop mount mode */ + FISHEYE_CEILING_MOUNT = 1, /* ceiling mount mode */ + FISHEYE_WALL_MOUNT = 2, /* wall mount mode */ + + FISHEYE_MOUNT_MODE_BUTT +}FISHEYE_MOUNT_MODE_E; + + +typedef enum hiFISHEYE_VIEW_MODE_E +{ + FISHEYE_VIEW_360_PANORAMA = 0, /* 360 panorama mode of fisheye correction */ + FISHEYE_VIEW_180_PANORAMA = 1, /* 180 panorama mode of fisheye correction */ + FISHEYE_VIEW_NORMAL = 2, /* normal mode of fisheye correction */ + FISHEYE_NO_TRANSFORMATION = 3, /* no fisheye correction */ + + FISHEYE_VIEW_MODE_BUTT +}FISHEYE_VIEW_MODE_E; + +typedef enum hiFISHEYE_FILTER_MODE_E +{ + FISHEYE_FILTER_BILINEAR = 0, /* bilinear filter */ + FISHEYE_FILTER_LINEAR = 1, /* linear filter */ + FISHEYE_FILTER_NEAREST = 2, /* nearest filter */ + FISHEYE_FILTER_MODE_BUTT +}FISHEYE_FILTER_MODE_E; + +typedef struct hiFISHEYE_GPU_PRI_S +{ + FISHEYE_FILTER_MODE_E enYFilter; /* Fiter mode for Luma */ + FISHEYE_FILTER_MODE_E enCbCrFilter; /* Fiter mode for chroma */ + HI_U32 u32CCMPhyAddr; /* Physical address of correction coordinate memory , the size is region's width x height x sizeof(float) x 2. */ +}FISHEYE_GPU_PRI_S; + + +typedef struct hiFISHEYE_REGION_ATTR_S +{ + FISHEYE_VIEW_MODE_E enViewMode; /* fisheye view mode */ + HI_U32 u32InRadius; /* inner radius of fisheye correction region [0, u32OutRadius) */ + HI_U32 u32OutRadius; /* out radius of fisheye correction region [1, max(width/2 of input picture, height/2 of input picture)] */ + HI_U32 u32Pan; /* [0, 360] */ + HI_U32 u32Tilt; /* [0, 360] */ + HI_U32 u32HorZoom; /* [1, 4095] */ + HI_U32 u32VerZoom; /* [1, 4095] */ + RECT_S stOutRect; /* output image info after fisheye correction range of width [960, 4608], + rang of height [360, 3456], rang of x [0, 4608), rang of y [0, 3456) */ + FISHEYE_GPU_PRI_S stGPUPrivate; /* GPU related attribute. Only for GPU use */ +}FISHEYE_REGION_ATTR_S; + + +typedef struct hiFISHEYE_ATTR_S +{ + HI_BOOL bEnable; /* whether enable fisheye correction or not */ + HI_BOOL bLMF; /* whether fisheye len's LMF coefficient is from user config + or from default linear config */ + HI_BOOL bBgColor; /* whether use background color or not */ + HI_U32 u32BgColor; /* the background color ARGB8888 */ + + HI_S32 s32HorOffset; /* the horizontal offset between image center and physical center of len */ + HI_S32 s32VerOffset; /* the vertical offset between image center and physical center of len */ + + HI_U32 u32TrapezoidCoef; /* strength coefficient of trapezoid correction */ + + FISHEYE_MOUNT_MODE_E enMountMode; /* fisheye mount mode */ + + HI_U32 u32RegionNum; /* fisheye correction region number */ + FISHEYE_REGION_ATTR_S astFisheyeRegionAttr[FISHEYE_MAX_REGION_NUM];/* attribution of fisheye correction region */ +}FISHEYE_ATTR_S; + + +typedef struct hiFISHEYE_CONFIG_S +{ + HI_U16 au16LMFCoef[128]; /* LMF coefficient of fisheye len */ +}FISHEYE_CONFIG_S; + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* _HI_COMM_VIDEO_H_ */ + diff --git a/snes9x/unix/mpp/hi_comm_vo.h b/snes9x/unix/mpp/hi_comm_vo.h new file mode 100644 index 0000000..b3fd3b1 --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vo.h @@ -0,0 +1,486 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_vo.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/03/18 + Description : + History : + 1.Date : 2009/03/18 + Author : x00100808 + Modification: Created file + +******************************************************************************/ + +#ifndef __HI_COMM_VO_H__ +#define __HI_COMM_VO_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_video.h" + +#define VO_DEF_CHN_BUF_LEN 8 +#define VO_DEF_DISP_BUF_LEN 5 +#define VO_DEF_VIRT_BUF_LEN 3 +#define VO_DEF_WBC_DEPTH_LEN 8 + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +typedef enum hiEN_VOU_ERR_CODE_E +{ + EN_ERR_VO_DEV_NOT_CONFIG = 0x40, + EN_ERR_VO_DEV_NOT_ENABLE = 0x41, + EN_ERR_VO_DEV_HAS_ENABLED = 0x42, + EN_ERR_VO_DEV_HAS_BINDED = 0x43, + EN_ERR_VO_DEV_NOT_BINDED = 0x44, + + ERR_VO_NOT_ENABLE = 0x45, + ERR_VO_NOT_DISABLE = 0x46, + ERR_VO_NOT_CONFIG = 0x47, + + ERR_VO_CHN_NOT_DISABLE = 0x48, + ERR_VO_CHN_NOT_ENABLE = 0x49, + ERR_VO_CHN_NOT_CONFIG = 0x4a, + ERR_VO_CHN_NOT_ALLOC = 0x4b, + + ERR_VO_CCD_INVALID_PAT = 0x4c, + ERR_VO_CCD_INVALID_POS = 0x4d, + + ERR_VO_WAIT_TIMEOUT = 0x4e, + ERR_VO_INVALID_VFRAME = 0x4f, + ERR_VO_INVALID_RECT_PARA = 0x50, + ERR_VO_SETBEGIN_ALREADY = 0x51, + ERR_VO_SETBEGIN_NOTYET = 0x52, + ERR_VO_SETEND_ALREADY = 0x53, + ERR_VO_SETEND_NOTYET = 0x54, + + ERR_VO_GRP_INVALID_ID = 0x55, + ERR_VO_GRP_NOT_CREATE = 0x56, + ERR_VO_GRP_HAS_CREATED = 0x57, + ERR_VO_GRP_NOT_DESTROY = 0x58, + ERR_VO_GRP_CHN_FULL = 0x59, + ERR_VO_GRP_CHN_EMPTY = 0x5a, + ERR_VO_GRP_CHN_NOT_EMPTY = 0x5b, + ERR_VO_GRP_INVALID_SYN_MODE = 0x5c, + ERR_VO_GRP_INVALID_BASE_PTS = 0x5d, + ERR_VO_GRP_NOT_START = 0x5e, + ERR_VO_GRP_NOT_STOP = 0x5f, + ERR_VO_GRP_INVALID_FRMRATE = 0x60, + ERR_VO_GRP_CHN_HAS_REG = 0x61, + ERR_VO_GRP_CHN_NOT_REG = 0x62, + ERR_VO_GRP_CHN_NOT_UNREG = 0x63, + ERR_VO_GRP_BASE_NOT_CFG = 0x64, + + ERR_GFX_NOT_DISABLE = 0x65, + ERR_GFX_NOT_BIND = 0x66, + ERR_GFX_NOT_UNBIND = 0x67, + ERR_GFX_INVALID_ID = 0x68, + + ERR_VO_WBC_NOT_DISABLE = 0x69, + ERR_VO_WBC_NOT_CONFIG = 0x6a, + + ERR_VO_CHN_AREA_OVERLAP = 0x6b, + + EN_ERR_INVALID_WBCID = 0x6c, + EN_ERR_INVALID_LAYERID = 0x6d, + EN_ERR_VO_VIDEO_HAS_BINDED = 0x6e, + EN_ERR_VO_VIDEO_NOT_BINDED = 0x6f, + ERR_VO_WBC_HAS_BIND = 0x70, + ERR_VO_WBC_HAS_CONFIG = 0x71, + ERR_VO_WBC_NOT_BIND = 0x72, + + /* new added */ + ERR_VO_BUTT + +}EN_VOU_ERR_CODE_E; + +/* System define error code */ +#define HI_ERR_VO_BUSY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_VO_NO_MEM HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +#define HI_ERR_VO_NULL_PTR HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_VO_SYS_NOTREADY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_VO_INVALID_DEVID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +#define HI_ERR_VO_INVALID_CHNID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +#define HI_ERR_VO_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_VO_NOT_SUPPORT HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +#define HI_ERR_VO_NOT_PERMIT HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +#define HI_ERR_VO_INVALID_WBCID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_WBCID) +#define HI_ERR_VO_INVALID_LAYERID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_LAYERID) + + +/* device relative error code */ +#define HI_ERR_VO_DEV_NOT_CONFIG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_DEV_NOT_CONFIG) +#define HI_ERR_VO_DEV_NOT_ENABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_DEV_NOT_ENABLE) +#define HI_ERR_VO_DEV_HAS_ENABLED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_DEV_HAS_ENABLED) +#define HI_ERR_VO_DEV_HAS_BINDED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_DEV_HAS_BINDED) +#define HI_ERR_VO_DEV_NOT_BINDED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_DEV_NOT_BINDED) + +/* video relative error code */ +#define HI_ERR_VO_VIDEO_NOT_ENABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_NOT_ENABLE) +#define HI_ERR_VO_VIDEO_NOT_DISABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_NOT_DISABLE) +#define HI_ERR_VO_VIDEO_NOT_CONFIG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_NOT_CONFIG) +#define HI_ERR_VO_VIDEO_HAS_BINDED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_VIDEO_HAS_BINDED) +#define HI_ERR_VO_VIDEO_NOT_BINDED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, EN_ERR_VO_VIDEO_NOT_BINDED) + +/*wbc error code*/ +#define HI_ERR_VO_WBC_NOT_DISABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WBC_NOT_DISABLE) +#define HI_ERR_VO_WBC_NOT_CONFIG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WBC_NOT_CONFIG) +#define HI_ERR_VO_WBC_HAS_CONFIG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WBC_HAS_CONFIG) +#define HI_ERR_VO_WBC_NOT_BIND HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WBC_NOT_BIND) +#define HI_ERR_VO_WBC_HAS_BIND HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WBC_HAS_BIND) + +/* channel relative error code */ +#define HI_ERR_VO_CHN_NOT_DISABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CHN_NOT_DISABLE) +#define HI_ERR_VO_CHN_NOT_ENABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CHN_NOT_ENABLE) +#define HI_ERR_VO_CHN_NOT_CONFIG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CHN_NOT_CONFIG) +#define HI_ERR_VO_CHN_NOT_ALLOC HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CHN_NOT_ALLOC) +#define HI_ERR_VO_CHN_AREA_OVERLAP HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CHN_AREA_OVERLAP) + + +/* cascade relatvie error code */ +#define HI_ERR_VO_INVALID_PATTERN HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CCD_INVALID_PAT) +#define HI_ERR_VO_INVALID_POSITION HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_CCD_INVALID_POS) + +/* misc */ +#define HI_ERR_VO_WAIT_TIMEOUT HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_WAIT_TIMEOUT) +#define HI_ERR_VO_INVALID_VFRAME HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_INVALID_VFRAME) +#define HI_ERR_VO_INVALID_RECT_PARA HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_INVALID_RECT_PARA) +#define HI_ERR_VO_SETBEGIN_ALREADY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_SETBEGIN_ALREADY) +#define HI_ERR_VO_SETBEGIN_NOTYET HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_SETBEGIN_NOTYET) +#define HI_ERR_VO_SETEND_ALREADY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_SETEND_ALREADY) +#define HI_ERR_VO_SETEND_NOTYET HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_SETEND_NOTYET) + +/* sync group relative error code */ +#define HI_ERR_VO_GRP_INVALID_ID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_INVALID_ID) +#define HI_ERR_VO_GRP_NOT_CREATE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_NOT_CREATE) +#define HI_ERR_VO_GRP_HAS_CREATED HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_HAS_CREATED) +#define HI_ERR_VO_GRP_NOT_DESTROY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_NOT_DESTROY) +#define HI_ERR_VO_GRP_CHN_FULL HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_FULL) +#define HI_ERR_VO_GRP_CHN_EMPTY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_EMPTY) +#define HI_ERR_VO_GRP_CHN_NOT_EMPTY HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_NOT_EMPTY) +#define HI_ERR_VO_GRP_INVALID_SYN_MODE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_INVALID_SYN_MODE) +#define HI_ERR_VO_GRP_INVALID_BASE_PTS HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_INVALID_BASE_PTS) +#define HI_ERR_VO_GRP_NOT_START HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_NOT_START) +#define HI_ERR_VO_GRP_NOT_STOP HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_NOT_STOP) +#define HI_ERR_VO_GRP_INVALID_FRMRATE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_INVALID_FRMRATE) +#define HI_ERR_VO_GRP_CHN_HAS_REG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_HAS_REG) +#define HI_ERR_VO_GRP_CHN_NOT_REG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_NOT_REG) +#define HI_ERR_VO_GRP_CHN_NOT_UNREG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_CHN_NOT_UNREG) +#define HI_ERR_VO_GRP_BASE_NOT_CFG HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_VO_GRP_BASE_NOT_CFG) + + +/* graphics relative error code */ +#define HI_ERR_VO_GFX_NOT_DISABLE HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_GFX_NOT_DISABLE) +#define HI_ERR_VO_GFX_NOT_BIND HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_GFX_NOT_BIND) +#define HI_ERR_VO_GFX_NOT_UNBIND HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_GFX_NOT_UNBIND) +#define HI_ERR_VO_GFX_INVALID_ID HI_DEF_ERR(HI_ID_VOU, EN_ERR_LEVEL_ERROR, ERR_GFX_INVALID_ID) + +/* vo inteface type */ +#define VO_INTF_CVBS (0x01L<<0) +#define VO_INTF_YPBPR (0x01L<<1) +#define VO_INTF_VGA (0x01L<<2) +#define VO_INTF_BT656 (0x01L<<3) +#define VO_INTF_BT1120 (0x01L<<4) +#define VO_INTF_HDMI (0x01L<<5) +#define VO_INTF_LCD (0x01L<<6) +#define VO_INTF_BT656_H (0x01L<<7) +#define VO_INTF_BT656_L (0x01L<<8) + + +/* WBC channel id*/ +#define VO_WBC_CHN_ID (VO_MAX_CHN_NUM + 1) + +#define VO_DEFAULT_CHN -1 /* use vo buffer as pip buffer */ + +/***************************************************************************** + * 3520 ADDed + *****************************************************************************/ +typedef HI_S32 VO_INTF_TYPE_E; + +//typedef HI_S32 VO_WBC_CHN; + +typedef enum hiVO_INTF_SYNC_E +{ + VO_OUTPUT_PAL = 0, + VO_OUTPUT_NTSC, + VO_OUTPUT_960H_PAL, /* ITU-R BT.1302 960 x 576 at 50 Hz (interlaced)*/ + VO_OUTPUT_960H_NTSC, /* ITU-R BT.1302 960 x 480 at 60 Hz (interlaced)*/ + + VO_OUTPUT_1080P24, + VO_OUTPUT_1080P25, + VO_OUTPUT_1080P30, + + VO_OUTPUT_720P50, + VO_OUTPUT_720P60, + VO_OUTPUT_1080I50, + VO_OUTPUT_1080I60, + VO_OUTPUT_1080P50, + VO_OUTPUT_1080P60, + + VO_OUTPUT_576P50, + VO_OUTPUT_480P60, + + VO_OUTPUT_640x480_60, /* VESA 640 x 480 at 60 Hz (non-interlaced) CVT */ + VO_OUTPUT_800x600_60, /* VESA 800 x 600 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1024x768_60, /* VESA 1024 x 768 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1280x1024_60, /* VESA 1280 x 1024 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1366x768_60, /* VESA 1366 x 768 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1440x900_60, /* VESA 1440 x 900 at 60 Hz (non-interlaced) CVT Compliant */ + VO_OUTPUT_1280x800_60, /* 1280*800@60Hz VGA@60Hz*/ + VO_OUTPUT_1680x1050_60, /* VESA 1680 x 1050 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1920x2160_30, /* 1920x2160_30 */ + VO_OUTPUT_1600x1200_60, /* VESA 1600 x 1200 at 60 Hz (non-interlaced) */ + VO_OUTPUT_1920x1200_60, /* VESA 1920 x 1600 at 60 Hz (non-interlaced) CVT (Reduced Blanking)*/ + VO_OUTPUT_2560x1440_30, /* 2560x1440_30 */ + VO_OUTPUT_2560x1600_60, /* 2560x1600_60 */ + VO_OUTPUT_3840x2160_30, /* 3840x2160_30 */ + VO_OUTPUT_3840x2160_60, /* 3840x2160_60 */ + VO_OUTPUT_USER, + VO_OUTPUT_BUTT + +} VO_INTF_SYNC_E; + +typedef enum hiVO_DISPLAY_FIELD_E +{ + VO_FIELD_TOP, /* top field*/ + VO_FIELD_BOTTOM, /* bottom field*/ + VO_FIELD_BOTH, /* top and bottom field*/ + VO_FIELD_BUTT +} VO_DISPLAY_FIELD_E; + +typedef enum hiVOU_ZOOM_IN_E +{ + VOU_ZOOM_IN_RECT = 0, /* zoom in by rect */ + VOU_ZOOM_IN_RATIO, /* zoom in by ratio */ + VOU_ZOOM_IN_BUTT +} VOU_ZOOM_IN_E; + +typedef enum hiVO_CSC_MATRIX_E +{ + VO_CSC_MATRIX_IDENTITY = 0, /* do not change color space */ + + VO_CSC_MATRIX_BT601_TO_BT709, /* change color space from BT.601 to BT.709 */ + VO_CSC_MATRIX_BT709_TO_BT601, /* change color space from BT.709 to BT.601 */ + + VO_CSC_MATRIX_BT601_TO_RGB_PC, /* change color space from BT.601 to RGB */ + VO_CSC_MATRIX_BT709_TO_RGB_PC, /* change color space from BT.709 to RGB */ + + VO_CSC_MATRIX_RGB_TO_BT601_PC, /* change color space from RGB to BT.601 */ + VO_CSC_MATRIX_RGB_TO_BT709_PC, /* change color space from RGB to BT.709 */ + + VO_CSC_MATRIX_BUTT +} VO_CSC_MATRIX_E; + +typedef struct hiVO_CHN_ATTR_S +{ + HI_U32 u32Priority; /* video out overlay pri sd */ + RECT_S stRect; /* rect of video out chn */ + HI_BOOL bDeflicker; /* deflicker or not sd */ +}VO_CHN_ATTR_S; + +typedef struct hiVO_CHN_PARAM_S +{ + ASPECT_RATIO_S stAspectRatio; /* aspect ratio */ +}VO_CHN_PARAM_S; + +typedef struct hiVO_BORDER_S +{ + HI_BOOL bBorderEn; /*do Frame or not*/ + BORDER_S stBorder; +}VO_BORDER_S; + +typedef struct hiVO_QUERY_STATUS_S +{ + HI_U32 u32ChnBufUsed; /* channel buffer that been occupied */ +} VO_QUERY_STATUS_S; + +typedef struct tagVO_SYNC_INFO_S +{ + HI_BOOL bSynm; /* sync mode(0:timing,as BT.656; 1:signal,as LCD) */ + HI_BOOL bIop; /* interlaced or progressive display(0:i; 1:p) */ + HI_U8 u8Intfb; /* interlace bit width while output */ + + HI_U16 u16Vact ; /* vertical active area */ + HI_U16 u16Vbb; /* vertical back blank porch */ + HI_U16 u16Vfb; /* vertical front blank porch */ + + HI_U16 u16Hact; /* herizontal active area */ + HI_U16 u16Hbb; /* herizontal back blank porch */ + HI_U16 u16Hfb; /* herizontal front blank porch */ + HI_U16 u16Hmid; /* bottom herizontal active area */ + + HI_U16 u16Bvact; /* bottom vertical active area */ + HI_U16 u16Bvbb; /* bottom vertical back blank porch */ + HI_U16 u16Bvfb; /* bottom vertical front blank porch */ + + HI_U16 u16Hpw; /* horizontal pulse width */ + HI_U16 u16Vpw; /* vertical pulse width */ + + HI_BOOL bIdv; /* inverse data valid of output */ + HI_BOOL bIhs; /* inverse horizontal synch signal */ + HI_BOOL bIvs; /* inverse vertical synch signal */ + +} VO_SYNC_INFO_S; + +typedef struct hiVO_PUB_ATTR_S +{ + HI_U32 u32BgColor; /* Background color of a device, in RGB format. */ + VO_INTF_TYPE_E enIntfType; /* Type of a VO interface */ + VO_INTF_SYNC_E enIntfSync; /* Type of a VO interface timing */ + VO_SYNC_INFO_S stSyncInfo; /* Information about VO interface timings */ +} VO_PUB_ATTR_S; + +typedef struct hiVO_WBC_ATTR_S +{ + SIZE_S stTargetSize; /* WBC Zoom target size */ + PIXEL_FORMAT_E enPixelFormat; /* the pixel format of WBC output */ + HI_U32 u32FrameRate; /* frame rate control */ +} VO_WBC_ATTR_S; + +typedef enum hiVO_WBC_MODE_E +{ + VO_WBC_MODE_NOMAL = 0, /* In this mode, wbc will capture frames according to dev frame rate + and wbc frame rate */ + VO_WBC_MODE_DROP_REPEAT, /* In this mode, wbc will drop dev repeat frame, and capture the real frame + according to video layer's display rate and wbc frame rate */ + VO_WBC_MODE_PROG_TO_INTL, /* In this mode, wbc will drop dev repeat frame which repeats more than 3 times, + and change two progressive frames to one interlace frame */ + + VO_WBC_MODE_BUTT, +} VO_WBC_MODE_E; + + +typedef enum hiVO_WBC_SOURCE_TYPE_E +{ + VO_WBC_SOURCE_DEV = 0x0, /* WBC source is device */ + VO_WBC_SOURCE_VIDEO = 0x1, /* WBC source is video layer */ + VO_WBC_SOURCE_GRAPHIC = 0x2, /* WBC source is graphic layer, not support */ + + VO_WBC_SOURCE_BUTT +} VO_WBC_SOURCE_TYPE_E; + +typedef struct hiVO_WBC_SOURCE_S +{ + VO_WBC_SOURCE_TYPE_E enSourceType; /* the type of WBC source */ + HI_U32 u32SourceId; /* the device, video layer or graphic layer */ +} VO_WBC_SOURCE_S; + +typedef enum hiVO_CAS_MODE_E +{ + VO_CAS_MODE_SINGLE = 0, /* cascade mode is single */ + VO_CAS_MODE_DUAL, /* cascade mode is dual */ + VO_CAS_MODE_BUTT, +} VO_CAS_MODE_E; + +typedef enum hiVO_CAS_DATA_TRAN_MODE_E +{ + VO_CAS_DATA_SINGLE_TRAN_MODE = 0, /* single transition,clock rising edge or clock falling edge tigger transition */ + VO_CAS_DATA_DOUBLE_TRAN_MODE, /* double transition,clock rising edge and clock falling edge tigger transition */ + VO_CAS_DATA_MODE_BUTT, +} VO_CAS_DATA_TRAN_MODE_E; + +typedef enum hiVO_CAS_RGN_E +{ + VO_CAS_64_RGN = 0, + VO_CAS_32_RGN, + VO_CAS_RGN_BUTT, +} VO_CAS_RGN_E; /* cascade region number */ + +typedef struct hiVO_CAS_ATTR_S +{ + HI_BOOL bSlave; /* HI_TRUE: slave mode, HI_FALSE: master mode */ + VO_CAS_RGN_E enCasRgn; /* cascade region number */ + VO_CAS_MODE_E enCasMode; /* cascade mode */ + VO_CAS_DATA_TRAN_MODE_E enCasDataTranMode; /* cascade data transition mode */ +} VO_CAS_ATTR_S; + +typedef enum hiVO_PART_MODE_E +{ + VO_PART_MODE_SINGLE = 0, /* single partition, which use software to make multi-picture in one hardware cell */ + VO_PART_MODE_MULTI = 1, /* muliti partition, each partition is a hardware cell */ + VO_PART_MODE_BUTT + +} VO_PART_MODE_E; + +typedef struct hiVO_COMPRESS_ATTR_S +{ + HI_BOOL bSupportCompress; /* Whether to support compress */ +}VO_COMPRESS_ATTR_S; + +typedef struct hiVO_VIDEO_LAYER_ATTR_S +{ + RECT_S stDispRect; /* Display resolution */ + SIZE_S stImageSize; /* Canvas size of the video layer */ + HI_U32 u32DispFrmRt; /* Display frame rate */ + PIXEL_FORMAT_E enPixFormat; /* Pixel format of the video layer */ + HI_BOOL bDoubleFrame; /* Whether to double frames */ + HI_BOOL bClusterMode; /* Whether to take Cluster way to use memory*/ +} VO_VIDEO_LAYER_ATTR_S; + +typedef enum hiVOU_LAYER_DDR_E +{ + VOU_LAYER_DDR0 = 0, + VOU_LAYER_DDR1 = 1, + VOU_LAYER_DDR_BUTT +}VOU_LAYER_DDR_E; + +typedef struct hiVO_ZOOM_RATIO_S +{ + HI_U32 u32XRatio; + HI_U32 u32YRatio; + HI_U32 u32WRatio; + HI_U32 u32HRatio; +} VO_ZOOM_RATIO_S; + +typedef struct hiVO_ZOOM_ATTR_S +{ + VOU_ZOOM_IN_E enZoomType; /* choose the type of zoom in */ + union + { + RECT_S stZoomRect; /* zoom in by rect */ + VO_ZOOM_RATIO_S stZoomRatio; /* zoom in by ratio */ + }; +} VO_ZOOM_ATTR_S; + +typedef struct hiVO_CSC_S +{ + VO_CSC_MATRIX_E enCscMatrix; + HI_U32 u32Luma; /* luminance: 0 ~ 100 default: 50 */ + HI_U32 u32Contrast; /* contrast : 0 ~ 100 default: 50 */ + HI_U32 u32Hue; /* hue : 0 ~ 100 default: 50 */ + HI_U32 u32Saturation; /* saturation: 0 ~ 100 default: 50 */ +} VO_CSC_S; + +typedef struct hiVO_VGA_PARAM_S +{ + VO_CSC_S stCSC; /* color space */ + HI_U32 u32Gain; /* current gain of VGA signals. [0, 64). default:0x30 */ + HI_S32 s32SharpenStrength; /* current sharpen strength of VGA signals. [0, 255]. default:0x80 */ +} VO_VGA_PARAM_S; + +typedef struct hiVO_HDMI_PARAM_S +{ + VO_CSC_S stCSC; /* color space */ +} VO_HDMI_PARAM_S; + +typedef struct hiVO_REGION_INFO_S +{ + RECT_S *pstRegion; /*region attribute*/ + HI_U32 u32RegionNum; /*count of the region*/ +}VO_REGION_INFO_S; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __HI_COMM_VO_H__ */ + diff --git a/snes9x/unix/mpp/hi_comm_vpss.h b/snes9x/unix/mpp/hi_comm_vpss.h new file mode 100644 index 0000000..57b46ea --- /dev/null +++ b/snes9x/unix/mpp/hi_comm_vpss.h @@ -0,0 +1,233 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_vpss.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : + Last Modified : + Description : common struct definition for vpss + Function List : + History : + 1.Date : 20130508 + Author : l00183122 + Modification: Create + + +******************************************************************************/ + +#ifndef __HI_COMM_VPSS_H__ +#define __HI_COMM_VPSS_H__ + + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_errno.h" +#include "hi_comm_video.h" + +#define HI_ERR_VPSS_NULL_PTR HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_NULL_PTR) +#define HI_ERR_VPSS_NOTREADY HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_SYS_NOTREADY) +#define HI_ERR_VPSS_INVALID_DEVID HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_DEVID) +#define HI_ERR_VPSS_INVALID_CHNID HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +#define HI_ERR_VPSS_EXIST HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_EXIST) +#define HI_ERR_VPSS_UNEXIST HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_UNEXIST) +#define HI_ERR_VPSS_NOT_SUPPORT HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_SUPPORT) +#define HI_ERR_VPSS_NOT_PERM HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_NOT_PERM) +#define HI_ERR_VPSS_NOMEM HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_NOMEM) +#define HI_ERR_VPSS_NOBUF HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_NOBUF) +#define HI_ERR_VPSS_ILLEGAL_PARAM HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_ILLEGAL_PARAM) +#define HI_ERR_VPSS_BUSY HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_BUSY) +#define HI_ERR_VPSS_BUF_EMPTY HI_DEF_ERR(HI_ID_VPSS, EN_ERR_LEVEL_ERROR, EN_ERR_BUF_EMPTY) + + +typedef HI_S32 VPSS_GRP; /* [0, 128] */ +typedef HI_S32 VPSS_CHN; /* [0, 3] */ + +/*Define 4 video frame*/ +typedef enum hiVPSS_FRAME_WORK_E +{ + VPSS_FRAME_WORK_LEFT = 0, + VPSS_FRAME_WORK_RIGHT = 1, + VPSS_FRAME_WORK_BOTTOM = 2, + VPSS_FRAME_WORK_TOP = 3, + VPSS_FRAME_WORK_BUTT +}VPSS_FRAME_WORK_E; + +/*Define de-interlace mode*/ +typedef enum hiVPSS_DIE_MODE_E +{ + VPSS_DIE_MODE_NODIE = 0, + VPSS_DIE_MODE_AUTO = 1, + VPSS_DIE_MODE_DIE = 2, + VPSS_DIE_MODE_BUTT +}VPSS_DIE_MODE_E; + +/*Define attributes of vpss channel*/ +typedef struct hiVPSS_CHN_ATTR_S +{ + HI_BOOL bSpEn; /*Sharpen enable*/ + HI_BOOL bUVInvert; /* UV Invert enable*/ + HI_BOOL bBorderEn; /*Frame enable*/ + BORDER_S stBorder; +}VPSS_CHN_ATTR_S; + +typedef struct hiVPSS_GRP_PARAM_S +{ + HI_U32 u32Contrast; /*strength of dymanic contrast improve*/ + HI_U32 u32DieStrength; /*strength of de-interlace,not used now*/ + HI_U32 u32IeStrength; /*strength of image enhance*/ + HI_U32 u32SfStrength; /*strength of y space filter*/ + HI_U32 u32TfStrength; /*strength of y time filter*/ + HI_U32 u32CfStrength; /*strength of c space filter*/ + HI_U32 u32CTfStrength; /*strength of c time filter*/ + HI_U32 u32CvbsStrength; /*strength of cvbs*/ + HI_U32 u32DeMotionBlurring; /*strength of de motion blurring,not used now*/ +}VPSS_GRP_PARAM_S; + +/*Define detailed NR params for grp image process*/ +typedef struct hiVPSS_NR_ADVANCED_PARAM_S +{ + HI_U32 u32Mdz; + HI_U32 u32HTfRelaStrength; /*relation strength of hard NR chn */ + + /*only for weak nr chn*/ + HI_U32 u32Edz; + HI_U32 u32WTfRelaStrength; /*relation strength of weak NR chn */ +}VPSS_NR_ADVANCED_PARAM_S; + + +/* Define image feild select mode */ +typedef enum hiVPSS_CAPSEL_E +{ + VPSS_CAPSEL_BOTH = 0, /* top and bottom field */ + VPSS_CAPSEL_TOP, /* top field */ + VPSS_CAPSEL_BOTTOM, /* bottom field */ + + VPSS_CAPSEL_BUTT +} VPSS_CAPSEL_E; + +/*Define coordinate mode*/ +typedef enum hiVPSS_CROP_COORDINATE_E +{ + VPSS_CROP_RATIO_COOR = 0, /*Ratio coordinate*/ + VPSS_CROP_ABS_COOR /*Absolute coordinate*/ +}VPSS_CROP_COORDINATE_E; + +/*Define attributes of CLIP function*/ +typedef struct hiVPSS_CROP_INFO_S +{ + HI_BOOL bEnable; /*CROP enable*/ + VPSS_CROP_COORDINATE_E enCropCoordinate; /*Coordinate mode of the crop start point*/ + RECT_S stCropRect; /*CROP rectangular*/ +}VPSS_CROP_INFO_S; + +/*Define attributes of vpss GROUP*/ +typedef struct hiVPSS_GRP_ATTR_S +{ + /*statistic attributes*/ + HI_U32 u32MaxW; /*MAX width of the group*/ + HI_U32 u32MaxH; /*MAX height of the group*/ + PIXEL_FORMAT_E enPixFmt; /*Pixel format*/ + + HI_BOOL bIeEn; /*Image enhance enable*/ + HI_BOOL bDciEn; /*Dynamic contrast Improve enable*/ + HI_BOOL bNrEn; /*Noise reduce enable*/ + HI_BOOL bHistEn; /*Hist enable*/ + HI_BOOL bEsEn; /*Edge smooth enable*/ + VPSS_DIE_MODE_E enDieMode; /*De-interlace enable*/ +}VPSS_GRP_ATTR_S; + +/*Define vpss frame control info*/ +typedef struct hiVPSS_FRAME_RATE_S +{ + HI_S32 s32SrcFrmRate; /* Input frame rate of a group*/ + HI_S32 s32DstFrmRate; /* Output frame rate of a channel group */ +} VPSS_FRAME_RATE_S; + +/*Define vpss channel's work mode*/ +typedef enum hiVPSS_CHN_MODE_E +{ + VPSS_CHN_MODE_AUTO = 0, /*Auto mode*/ + VPSS_CHN_MODE_USER /*User mode*/ +}VPSS_CHN_MODE_E; + +/*Define attributes of vpss channel's work mode*/ +typedef struct hiVPSS_CHN_MODE_S +{ + VPSS_CHN_MODE_E enChnMode; /*Vpss channel's work mode*/ + HI_U32 u32Width; /*Width of target image*/ + HI_U32 u32Height; /*Height of target image*/ + HI_BOOL bDouble; /*Field-frame transfer, only valid for VPSS_CHN2*/ + VPSS_FRAME_RATE_S stFrameRate; + ASPECT_RATIO_S stAspectRatio; + PIXEL_FORMAT_E enPixelFormat;/*Pixel format of target image*/ + COMPRESS_MODE_E enCompressMode; /*Compression mode of the output*/ +}VPSS_CHN_MODE_S; + + +/*Define detailed params for channel image process*/ +typedef struct hiVPSS_CHN_PARAM_S +{ + HI_U32 u32SpStrength; + HI_U32 u32SfStrength; + HI_U32 u32TfStrength; + HI_U32 u32CfStrength; + HI_U32 u32DeMotionBlurring; +} VPSS_CHN_PARAM_S; + +/*Define vpss prescale info*/ +typedef struct hiVPSS_PRESCALE_INFO_S +{ + HI_BOOL bPreScale; /*prescale enable*/ + SIZE_S stDestSize; /*destination size*/ +}VPSS_PRESCALE_INFO_S; + +/*Define vpss filter info*/ +typedef struct hiVPSS_SIZER_INFO_S +{ + HI_BOOL bSizer; + SIZE_S stSize; +}VPSS_SIZER_INFO_S; + + +/*Define attributes of vpss extend channel*/ +typedef struct hiVPSS_EXT_CHN_ATTR_S +{ + VPSS_CHN s32BindChn; /*channel bind to*/ + HI_U32 u32Width; /*Width of target image*/ + HI_U32 u32Height; /*Height of target image*/ + HI_S32 s32SrcFrameRate; /*Frame rate of source*/ + HI_S32 s32DstFrameRate; /*Frame rate of extend chn input&output*/ + PIXEL_FORMAT_E enPixelFormat; /*Pixel format of target image*/ +}VPSS_EXT_CHN_ATTR_S; + +typedef struct hiVPSS_REGION_INFO_S +{ + RECT_S *pstRegion; /*region attribute*/ + HI_U32 u32RegionNum; /*count of the region*/ +}VPSS_REGION_INFO_S; + +typedef enum hiVPSS_PRESCALE_MODE_E +{ + VPSS_PRESCALE_MODE_DEFAULT = 0, /*use vpss to prescale*/ + VPSS_PRESCALE_MODE_OTHER, /*use vgs to prescale*/ + VPSS_PRESCALE_MODE_BUTT +}VPSS_PRESCALE_MODE_E; + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ +#endif /* __HI_COMM_VPSS_H__ */ + + diff --git a/snes9x/unix/mpp/hi_common.h b/snes9x/unix/mpp/hi_common.h new file mode 100644 index 0000000..82df7d7 --- /dev/null +++ b/snes9x/unix/mpp/hi_common.h @@ -0,0 +1,382 @@ +/****************************************************************************** +Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi_common.h +Version : Initial Draft +Author : Hi3511 MPP Team +Created : 2006/11/09 +Last Modified : +Description : The common defination +Function List : +History : + 1.Date : 2009/03/03 + Author : z44949 + Modification: Created file +2.Date : 2009/07/01 + Author : z44949 + Modification: Move MPP_VER_PRIX to hi_defines.h +3.Date : 2009/08/13 + Author : y45339 + Modification: add some proc define + +4.Date : 2010/11/03 + Author : z44949 + Modification: Remove some unnecessary typedef + +******************************************************************************/ +#ifndef __HI_COMMON_H__ +#define __HI_COMMON_H__ + +#include "hi_type.h" +#include "hi_math.h" +#include "hi_defines.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#ifndef VER_X + #define VER_X 1 +#endif + +#ifndef VER_Y + #define VER_Y 0 +#endif + +#ifndef VER_Z + #define VER_Z 0 +#endif + +#ifndef VER_P + #define VER_P 0 +#endif + +#ifndef VER_B + #define VER_B 0 +#endif + +#ifdef HI_DEBUG + #define VER_D " Debug" +#else + #define VER_D " Release" +#endif + +#define __MK_VERSION(x,y,z,p,b) #x"."#y"."#z"."#p" B0"#b +#define MK_VERSION(x,y,z,p,b) __MK_VERSION(x,y,z,p,b) +#define MPP_VERSION CHIP_NAME MPP_VER_PRIX MK_VERSION(VER_X,VER_Y,VER_Z,VER_P,VER_B) VER_D + +#define VERSION_NAME_MAXLEN 64 +typedef struct hiMPP_VERSION_S +{ + HI_CHAR aVersion[VERSION_NAME_MAXLEN]; +}MPP_VERSION_S; + +typedef struct hiPOINT_S +{ + HI_S32 s32X; + HI_S32 s32Y; +}POINT_S; + +typedef struct hiSIZE_S +{ + HI_U32 u32Width; + HI_U32 u32Height; +} SIZE_S; + +typedef struct hiRECT_S +{ + HI_S32 s32X; + HI_S32 s32Y; + HI_U32 u32Width; + HI_U32 u32Height; +}RECT_S; + +typedef struct hiCROP_INFO_S +{ + HI_BOOL bEnable; + RECT_S stRect; +}CROP_INFO_S; + +typedef enum hiROTATE_E +{ + ROTATE_NONE = 0, /* no rotate */ + ROTATE_90 = 1, /* 90 degrees clockwise */ + ROTATE_180 = 2, /* 180 degrees clockwise */ + ROTATE_270 = 3, /* 270 degrees clockwise */ + ROTATE_BUTT +} ROTATE_E; + +typedef struct hiBORDER_S +{ + HI_U32 u32TopWidth; /* top border weight, in pixel*/ + HI_U32 u32BottomWidth; /* bottom border weight, in pixel*/ + HI_U32 u32LeftWidth; /* left border weight, in pixel*/ + HI_U32 u32RightWidth; /* right border weight, in pixel*/ + HI_U32 u32Color; /* border color, RGB888*/ +} BORDER_S; + +typedef enum hiASPECT_RATIO_E +{ + ASPECT_RATIO_NONE = 0, /* full screen */ + ASPECT_RATIO_AUTO = 1, /* ratio no change, 1:1*/ + ASPECT_RATIO_MANUAL = 2, /* ratio manual set */ + ASPECT_RATIO_BUTT +}ASPECT_RATIO_E; + +typedef struct hiASPECT_RATIO_S +{ + ASPECT_RATIO_E enMode; /* aspect ratio mode: none/auto/manual */ + HI_U32 u32BgColor; /* background color, RGB 888 */ + RECT_S stVideoRect; /* valid in ASPECT_RATIO_MANUAL mode */ +} ASPECT_RATIO_S; + +typedef HI_S32 AI_CHN; +typedef HI_S32 AO_CHN; +typedef HI_S32 AENC_CHN; +typedef HI_S32 ADEC_CHN; +typedef HI_S32 AUDIO_DEV; +typedef HI_S32 AVENC_CHN; +typedef HI_S32 VI_DEV; +typedef HI_S32 VI_WAY; +typedef HI_S32 VI_CHN; +typedef HI_S32 VO_DEV; +typedef HI_S32 VO_LAYER; +typedef HI_S32 VO_CHN; +typedef HI_S32 VO_WBC; +typedef HI_S32 GRAPHIC_LAYER; +typedef HI_S32 VENC_CHN; +typedef HI_S32 VDEC_CHN; +typedef HI_S32 VENC_GRP; +typedef HI_S32 VO_GRP; +typedef HI_S32 VDA_CHN; +typedef HI_S32 IVE_HANDLE; +typedef HI_S32 CLS_HANDLE; +typedef HI_S32 FD_CHN; +typedef HI_S32 MD_CHN; + + +#define HI_INVALID_CHN (-1) +#define HI_INVALID_WAY (-1) +#define HI_INVALID_LAYER (-1) +#define HI_INVALID_DEV (-1) +#define HI_INVALID_HANDLE (-1) +#define HI_INVALID_VALUE (-1) +#define HI_INVALID_TYPE (-1) + +typedef enum hiMOD_ID_E +{ + HI_ID_CMPI = 0, + HI_ID_VB = 1, + HI_ID_SYS = 2, + HI_ID_RGN = 3, + HI_ID_CHNL = 4, + HI_ID_VDEC = 5, + HI_ID_GROUP = 6, + HI_ID_VPSS = 7, + HI_ID_VENC = 8, + HI_ID_VDA = 9, + HI_ID_H264E = 10, + HI_ID_JPEGE = 11, + HI_ID_MPEG4E = 12, + HI_ID_H264D = 13, + HI_ID_JPEGD = 14, + HI_ID_VOU = 15, + HI_ID_VIU = 16, + HI_ID_DSU = 17, + HI_ID_VALG = 18, + HI_ID_RC = 19, + HI_ID_AIO = 20, + HI_ID_AI = 21, + HI_ID_AO = 22, + HI_ID_AENC = 23, + HI_ID_ADEC = 24, + HI_ID_AVENC = 25, + HI_ID_PCIV = 26, + HI_ID_PCIVFMW = 27, + HI_ID_ISP = 28, + HI_ID_IVE = 29, + + HI_ID_DCCM = 31, + HI_ID_DCCS = 32, + HI_ID_PROC = 33, + HI_ID_LOG = 34, + HI_ID_MST_LOG = 35, + HI_ID_VD = 36, + + HI_ID_VCMP = 38, + HI_ID_FB = 39, + HI_ID_HDMI = 40, + HI_ID_VOIE = 41, + HI_ID_TDE = 42, + HI_ID_USR = 43, + HI_ID_VEDU = 44, + HI_ID_VGS = 45, + HI_ID_H265E = 46, + HI_ID_FD = 47, + HI_ID_ODT = 48, //Object Detection and Tracing + HI_ID_VQA = 49, //Video Quality Analysis + HI_ID_LPR = 50, //License Plate Recognition + HI_ID_FISHEYE = 51, + + HI_ID_BUTT, +} MOD_ID_E; + +typedef struct hiMPP_CHN_S +{ + MOD_ID_E enModId; + HI_S32 s32DevId; + HI_S32 s32ChnId; +} MPP_CHN_S; + +#define MPP_MOD_VIU "vi" +#define MPP_MOD_VOU "vo" +#define MPP_MOD_HDMI "hdmi" +#define MPP_MOD_DSU "dsu" +#define MPP_MOD_VGS "vgs" + +#define MPP_MOD_CHNL "chnl" +#define MPP_MOD_VENC "venc" +#define MPP_MOD_GRP "grp" +#define MPP_MOD_VDA "vda" +#define MPP_MOD_VPSS "vpss" +#define MPP_MOD_RGN "rgn" +#define MPP_MOD_IVE "ive" +#define MPP_MOD_FD "fd" +#define MPP_MOD_MD "md" + +#define MPP_MOD_H264E "h264e" +#define MPP_MOD_H265E "h265e" +#define MPP_MOD_JPEGE "jpege" +#define MPP_MOD_MPEG4E "mpeg4e" + +#define MPP_MOD_VDEC "vdec" +#define MPP_MOD_H264D "h264d" +#define MPP_MOD_JPEGD "jpegd" + +#define MPP_MOD_AI "ai" +#define MPP_MOD_AO "ao" +#define MPP_MOD_AENC "aenc" +#define MPP_MOD_ADEC "adec" +#define MPP_MOD_AIO "aio" +#define MPP_MOD_ACODEC "acodec" + + +#define MPP_MOD_VB "vb" +#define MPP_MOD_SYS "sys" +#define MPP_MOD_CMPI "cmpi" + +#define MPP_MOD_PCIV "pciv" +#define MPP_MOD_PCIVFMW "pcivfmw" + +#define MPP_MOD_PROC "proc" +#define MPP_MOD_LOG "logmpp" +#define MPP_MOD_MST_LOG "mstlogmpp" + +#define MPP_MOD_DCCM "dccm" +#define MPP_MOD_DCCS "dccs" + +#define MPP_MOD_VCMP "vcmp" +#define MPP_MOD_FB "fb" + +#define MPP_MOD_RC "rc" + +#define MPP_MOD_VOIE "voie" + +#define MPP_MOD_TDE "tde" +#define MPP_MOD_ISP "isp" +#define MPP_MOD_USR "usr" + +/* We just coyp this value of payload type from RTP/RTSP definition */ +typedef enum +{ + PT_PCMU = 0, + PT_1016 = 1, + PT_G721 = 2, + PT_GSM = 3, + PT_G723 = 4, + PT_DVI4_8K = 5, + PT_DVI4_16K = 6, + PT_LPC = 7, + PT_PCMA = 8, + PT_G722 = 9, + PT_S16BE_STEREO = 10, + PT_S16BE_MONO = 11, + PT_QCELP = 12, + PT_CN = 13, + PT_MPEGAUDIO = 14, + PT_G728 = 15, + PT_DVI4_3 = 16, + PT_DVI4_4 = 17, + PT_G729 = 18, + PT_G711A = 19, + PT_G711U = 20, + PT_G726 = 21, + PT_G729A = 22, + PT_LPCM = 23, + PT_CelB = 25, + PT_JPEG = 26, + PT_CUSM = 27, + PT_NV = 28, + PT_PICW = 29, + PT_CPV = 30, + PT_H261 = 31, + PT_MPEGVIDEO = 32, + PT_MPEG2TS = 33, + PT_H263 = 34, + PT_SPEG = 35, + PT_MPEG2VIDEO = 36, + PT_AAC = 37, + PT_WMA9STD = 38, + PT_HEAAC = 39, + PT_PCM_VOICE = 40, + PT_PCM_AUDIO = 41, + PT_AACLC = 42, + PT_MP3 = 43, + PT_ADPCMA = 49, + PT_AEC = 50, + PT_X_LD = 95, + PT_H264 = 96, + PT_D_GSM_HR = 200, + PT_D_GSM_EFR = 201, + PT_D_L8 = 202, + PT_D_RED = 203, + PT_D_VDVI = 204, + PT_D_BT656 = 220, + PT_D_H263_1998 = 221, + PT_D_MP1S = 222, + PT_D_MP2P = 223, + PT_D_BMPEG = 224, + PT_MP4VIDEO = 230, + PT_MP4AUDIO = 237, + PT_VC1 = 238, + PT_JVC_ASF = 255, + PT_D_AVI = 256, + PT_DIVX3 = 257, + PT_AVS = 258, + PT_REAL8 = 259, + PT_REAL9 = 260, + PT_VP6 = 261, + PT_VP6F = 262, + PT_VP6A = 263, + PT_SORENSON = 264, + PT_H265 = 265, + PT_VP8 = 266, + PT_MVC = 267, + PT_MAX = 268, + /* add by hisilicon */ + PT_AMR = 1001, + PT_MJPEG = 1002, + PT_AMRWB = 1003, + PT_BUTT +}PAYLOAD_TYPE_E; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* _HI_COMMON_H_ */ + diff --git a/snes9x/unix/mpp/hi_debug.h b/snes9x/unix/mpp/hi_debug.h new file mode 100644 index 0000000..03a77b1 --- /dev/null +++ b/snes9x/unix/mpp/hi_debug.h @@ -0,0 +1,147 @@ +/****************************************************************************** +Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi_debug.h +Version : Initial Draft +Author : Hisilicon multimedia software group +Created : 2006/12/09 +Last Modified : +Description : all struct and maro definition for debug +Function List : +History : + 1.Date : 2006/11/03 + Author : c42025 + Modification: Created file + +2.Date : 2008/03/03 + Author : c42025 + Modification: 1. mv definition LOG_ERRLEVEL_E to here form file "hi_errno.h", + but it will be obsolete in next version. + 2. add new macro definition for debug levle. + 3. change macro defintion HI_TRACE + +3.Date : 2008/03/05 + Author : c42025 + Modification: Change the definition of LOG_ERRLEVEL_E + +4.Date : 2008/10/31 + Author : z44949 + Modification: Delete the definition of LOG_ERRLEVEL_E + +5.Date : 2010/11/03 + Author : z44949 + Modification: Remove some unnecessary typedef + +******************************************************************************/ +#ifndef __HI_DEBUG_H__ +#define __HI_DEBUG_H__ + +#ifndef __KERNEL__ +#include +#endif + +#include "hi_type.h" +#include "hi_common.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +#define _EX__FILE_LINE(fxx,lxx) "[File]:"fxx"\n[Line]:"#lxx"\n[Info]:" +#define EX__FILE_LINE(fxx,lxx) _EX__FILE_LINE(fxx,lxx) +#define __FILE_LINE__ EX__FILE_LINE(__FILE__, __LINE__) + +#define HI_DBG_EMERG 0 /* system is unusable */ +#define HI_DBG_ALERT 1 /* action must be taken immediately */ +#define HI_DBG_CRIT 2 /* critical conditions */ +#define HI_DBG_ERR 3 /* error conditions */ +#define HI_DBG_WARN 4 /* warning conditions */ +#define HI_DBG_NOTICE 5 /* normal but significant condition */ +#define HI_DBG_INFO 6 /* informational */ +#define HI_DBG_DEBUG 7 /* debug-level messages */ + +typedef struct hiLOG_LEVEL_CONF_S +{ + MOD_ID_E enModId; + HI_S32 s32Level; + HI_CHAR cModName[16]; +} LOG_LEVEL_CONF_S; + +#ifndef __KERNEL__ +/****************************************************************************** +** For User Mode : HI_PRINT, HI_ASSERT, HI_TRACE +******************************************************************************/ + +#define HI_PRINT printf + +/* #ifdef HI_DEBUG */ +#if 1 + /* Using samples: HI_ASSERT(x>y); */ + #define HI_ASSERT(expr) \ + do{ \ + if (!(expr)) { \ + printf("\nASSERT failed at:\n"\ + " >File name: %s\n" \ + " >Function : %s\n" \ + " >Line No. : %d\n" \ + " >Condition: %s\n", \ + __FILE__,__FUNCTION__, __LINE__, #expr);\ + _exit(-1);\ + } \ + }while(0) + + /* Using samples: + ** HI_TRACE(HI_DBG_DEBUG, HI_ID_CMPI, "Test %d, %s\n", 12, "Test"); + **/ + #define HI_TRACE(level, enModId, fmt...) fprintf(stderr,##fmt) +#else + #define HI_ASSERT(expr) + #define HI_TRACE(level, enModId, fmt...) +#endif + +#else +/****************************************************************************** +** For Linux Kernel : HI_PRINT, HI_ASSERT, HI_TRACE +******************************************************************************/ + +#define HI_PRINT printk + +extern HI_S32 HI_ChkLogLevel(HI_S32 s32Levle, MOD_ID_E enModId); +asmlinkage int HI_LOG(HI_S32 level, MOD_ID_E enModId,const char *fmt, ...); + +/* #ifdef HI_DEBUG */ +#if 1 + /* Using samples: HI_ASSERT(x>y); */ + #define HI_ASSERT(expr) \ + do{ \ + if (!(expr)) { \ + panic("\nASSERT failed at:\n" \ + " >File name: %s\n" \ + " >Function : %s\n" \ + " >Line No. : %d\n" \ + " >Condition: %s\n", \ + __FILE__,__FUNCTION__, __LINE__, #expr);\ + } \ + }while(0) + + /* Using samples: + ** HI_TRACE(HI_DBG_DEBUG, HI_ID_CMPI, "Test %d, %s\n", 12, "Test"); + **/ + #define HI_TRACE HI_LOG +#else + #define HI_ASSERT(expr) + #define HI_TRACE(level, enModId, fmt...) +#endif + +#endif /* end of __KERNEL__ */ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_DEBUG_H__ */ + diff --git a/snes9x/unix/mpp/hi_defines.h b/snes9x/unix/mpp/hi_defines.h new file mode 100644 index 0000000..19531d3 --- /dev/null +++ b/snes9x/unix/mpp/hi_defines.h @@ -0,0 +1,448 @@ +/****************************************************************************** + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi_defines.h +Version : Initial Draft +Author : Hisilicon multimedia software group +Created : 2005/4/23 +Last Modified : +Description : The common data type defination +Function List : +History : +******************************************************************************/ +#ifndef __HI_DEFINES_H__ +#define __HI_DEFINES_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + + +#define HI3536_V100 0x35360100 +#define HI3521A_V100 0x3521a100 +#define HI3520D_V300 0x3520d300 +#define HI3531A_V100 0x3531a100 +#define HI35xx_Vxxx 0x35000000 + +#ifndef HICHIP + #define HICHIP HI3521A_V100 +#endif + +#if HICHIP==HI3536_V100 + #define CHIP_NAME "Hi3536" + #define MPP_VER_PRIX "_MPP_V" +#elif HICHIP==HI3521A_V100 + #define CHIP_NAME "Hi3521A" + #define MPP_VER_PRIX "_MPP_V" +#elif HICHIP==HI35xx_Vxxx + #error HuHu, I am an dummy chip +#else + #error HICHIP define may be error +#endif + +#define LINE_LEN_BIT 5 +#define LINE_LEN (1<>= LINE_LEN_BIT; + end = addr + len*LINE_LEN; + + while(addr != end) + { + asm("mcr p15, 0, %0, c7, c6, 1"::"r"(addr)); + addr += LINE_LEN; + } + return; +} + +static inline void FlushDcache(unsigned long addr, unsigned long len) +{ + unsigned long end; + + //TODO: cacheË¢ÐÂÐèÒªÖØд + return ; + + addr &= LINE_BASE_MASK; + len >>= LINE_LEN_BIT; + end = addr + len*LINE_LEN; + + while(addr != end) + { + asm("mcr p15, 0, %0, c7, c10, 1"::"r"(addr)); + addr += LINE_LEN; + } + return; +} + +#define DEFAULT_ALIGN 16 +#define MAX_MMZ_NAME_LEN 16 + +#define MAX_NODE_NUM 16 + +/* For VDA */ +#define VDA_MAX_NODE_NUM 32 +#define VDA_MAX_INTERNAL 256 +#define VDA_CHN_NUM_MAX 128 +#define VDA_MAX_WIDTH 960 +#define VDA_MAX_HEIGHT 960 +#define VDA_MIN_WIDTH 32 +#define VDA_MIN_HEIGHT 32 + + +/* For VENC */ +#define VENC_MAX_NAME_LEN 16 +#define VENC_MAX_CHN_NUM 128 +#define VENC_MAX_GRP_NUM 128 +#define H264E_MAX_WIDTH 2592 +#define H264E_MAX_HEIGHT 2592 +#define H264E_MIN_WIDTH 160 +#define H264E_MIN_HEIGHT 64 +#define H265E_MAX_WIDTH 2592 +#define H265E_MAX_HEIGHT 2592 +#define H265E_MIN_WIDTH 128 +#define H265E_MIN_HEIGHT 128 +#define JPEGE_MAX_WIDTH 8192 +#define JPEGE_MAX_HEIGHT 8192 +#define JPEGE_MIN_WIDTH 32 +#define JPEGE_MIN_HEIGHT 32 +#define VENC_MAX_ROI_NUM 8 /* ×î´óÖ§³Ö8¸öROIÇøÓò */ +#define H264E_MIN_HW_INDEX 0 +#define H264E_MAX_HW_INDEX 11 +#define H264E_MIN_VW_INDEX 0 +#define H264E_MAX_VW_INDEX 5 +#define MPEG4E_MAX_HW_INDEX 1 +#define MPEG4E_MAX_VW_INDEX 0 + + +/*For RC*/ +#define RC_TEXTURE_THR_SIZE 12 +#define RC_RQRATIO_SIZE 8 + + + +/* For VDEC */ +#define VDEC_MAX_COMPRESS_WIDTH 1920 +#define VDEC_MAX_CHN_NUM 64 +#define VDH_VEDU_CHN 0 /*VDH ÓëVEDUÁÙ½çͨµÀ*/ +#define VEDU_MAX_CHN_NUM 65 // ÓëVFMWͨµÀÊýÒ»Ö£¬ÒòΪVEDUͨµÀºÅÓëVFMWͨµÀºÅÒ»Ö +#define MAX_VDEC_CHN VDEC_MAX_CHN_NUM +#define BUF_RESERVE_LENTH 64 /*reserve 64byte for hardware*/ +#define H264D_MAX_SLICENUM 137 +#define VEDU_H264D_ERRRATE 10 +#define VEDU_H264D_FULLERR 100 +#define H265_WIDTH_ALIGN 64 +#define H265_HEIGHT_ALIGN 64 +#define JPEG_WIDTH_ALIGN 64 +#define H264_WIDTH_ALIGN 16 +#define H264_HEIGHT_ALIGN 32 + + +/* for VDH-H264 */ +#define VDH_H264D_MAX_WIDTH 4096 +#define VDH_H264D_MAX_HEIGHT 4096 +#define VDH_H264D_MIN_WIDTH 80 +#define VDH_H264D_MIN_HEIGHT 64 +#define VDH_H264D_MAX_SPS 32 +#define VDH_H264D_MIN_SPS 1 +#define VDH_H264D_MAX_PPS 256 +#define VDH_H264D_MIN_PPS 1 +#define VDH_H264D_MAX_SLICE 136 +#define VDH_H264D_MIN_SLICE 1 + +/* for VDH-HEVC */ +#define VDH_H265D_MAX_WIDTH 4096 +#define VDH_H265D_MAX_HEIGHT 4096 +#define VDH_H265D_MIN_WIDTH 128 +#define VDH_H265D_MIN_HEIGHT 128 +#define VDH_H265D_MAX_VPS 16 +#define VDH_H265D_MIN_VPS 1 +#define VDH_H265D_MAX_SPS 16 +#define VDH_H265D_MIN_SPS 1 +#define VDH_H265D_MAX_PPS 64 +#define VDH_H265D_MIN_PPS 1 +#define VDH_H265D_MAX_SLICE 200 +#define VDH_H265D_MIN_SLICE 1 + + +/* for VDH-MPEG4 */ +#define VDH_MPEG4D_MAX_WIDTH 4096 +#define VDH_MPEG4D_MAX_HEIGHT 4096 +#define VDH_MPEG4D_MIN_WIDTH 64 +#define VDH_MPEG4D_MIN_HEIGHT 64 + + +/* for VEDU-H264 */ +#define VEDU_H264D_MAX_WIDTH 4096 +#define VEDU_H264D_MAX_HEIGHT 4096 +#define VEDU_H264D_MIN_WIDTH 80 +#define VEDU_H264D_MIN_HEIGHT 64 + + + +/* for JPEG */ +#define JPEGD_MAX_WIDTH 8192 +#define JPEGD_MAX_HEIGHT 8192 +#define JPEGD_MIN_WIDTH 8 +#define JPEGD_MIN_HEIGHT 8 + +/* for VPSS */ +#define VPSS_MIN_WIDTH 64 +#define VPSS_MIN_HEIGHT 64 +#define VPSS_MAX_WIDTH 4096 +#define VPSS_MAX_HEIGHT 4096 +#define VPSS_MAX_DEI_WIDTH 1280 +#define VPSS_MAX_PRESCALE_WIDTH 2560 +#define VPSS_MAX_GRP_NUM 256 +#define VPSS_VGS_GRP_NO 240 +#define VPSS_MAX_PHY_CHN_NUM 4 +#define VPSS_MAX_EXT_CHN_NUM 0 +#define VPSS_MAX_CHN_NUM (VPSS_MAX_PHY_CHN_NUM + VPSS_MAX_EXT_CHN_NUM) +#define VPSS_CHN0 0 +#define VPSS_CHN1 1 +#define VPSS_CHN2 2 +#define VPSS_CHN3 3 +#define VPSS_INVALID_CHN -1 +#define VPSS_LUMA_STAT_NUM 64 +#define VPSS_MAX_SPLIT_NODE_NUM 4 + +/* For PCIV */ +#define PCIV_MAX_CHN_NUM 128 /* max pciv channel number in each pciv device */ + +/* for REGION */ +#define RGN_HANDLE_MAX 1024 +#define OVERLAY_MAX_NUM_VENC 8 +#define OVERLAY_MAX_NUM_VPSS 8 +#define OVERLAYEX_MAX_NUM_PCIV 1 +#define COVER_MAX_NUM_VPSS 4 +#define LINE_MAX_NUM_VPSS 4 +#define MASAIC_MAX_NUM_VPSS 4 +#define OVERLAYEX_MAX_NUM_VPSS 8 +#define COVEREX_MAX_NUM_VPSS 4 +#define COVEREX_MAX_NUM_VO 4 +#define OVERLAYEX_MAX_NUM_VO 1 +#define LINE_MAX_NUM_VO 4 + + +#if 0 +#define MAX_COVER_NUM 4 +#define MAX_VIOVERLAY_NUM 8 +#define MAX_COVEREX_REGION_NUM 16 +#define MAX_REGION_NUM 8 +#define OVERLAY_START_X_ALIGN 8 +#define OVERLAY_START_Y_ALIGN 2 +#define MAX_VIOVERLAY_ALPHA 255 +#endif + + +/* number of channle and device on video input unit of chip + * Note! VIU_MAX_CHN_NUM is NOT equal to VIU_MAX_DEV_NUM + * multiplied by VIU_MAX_CHN_NUM, because all VI devices + * can't work at mode of 4 channles at the same time. + */ +#define VIU_MAX_DEV_NUM 4 +#define VIU_MAX_WAY_NUM_PER_DEV 4 +#define VIU_MAX_CHN_NUM_PER_DEV 4 +#define VIU_MAX_PHYCHN_NUM 16 + +#define VIU_EXT_CHN_START (VIU_MAX_PHYCHN_NUM + VIU_MAX_CAS_CHN_NUM) +#define VIU_MAX_EXT_CHN_NUM 0 +#define VIU_MAX_EXTCHN_BIND_PER_CHN 0 + +#define VIU_MAX_CAS_CHN_NUM 0 +#define VIU_SUB_CHN_START 16 /* useless in 3521A */ +#define VIU_CAS_CHN_START 16 /* ¶¨Ò弶ÁªÍ¨µÀÆðʼºê*/ + +#define VIU_MAX_CHN_NUM (VIU_MAX_PHYCHN_NUM + VIU_MAX_CAS_CHN_NUM + VIU_MAX_EXT_CHN_NUM) +#define VIU_CHNID_DEV_FACTOR 2 /* useless in 3521A */ + + +#define COVER_MAX_NUM_VI 4 +#define COVEREX_MAX_NUM_VI 0 +#define OVERLAY_MAX_NUM_VI 0 +#define OVERLAYEX_MAX_NUM_VI 0 + +/* max number of VBI region*/ +#define VIU_MAX_VBI_NUM 2 +/* max length of one VBI region (by word)*/ +#define VIU_MAX_VBI_LEN 0x20 + +/*get the subchn index by main chn */ +#define SUBCHN(ViChn) (ViChn + 16) + +/* define cascade chn */ +#define VI_CAS_CHN_1 1 +#define VI_CAS_CHN_2 2 + +#define VO_MIN_CHN_WIDTH 32 /* channel minimal width */ +#define VO_MIN_CHN_HEIGHT 32 /* channel minimal height */ + +#define VO_MAX_ZOOM_RATIO 1000 /* max zoom ratio, 1000 means 100% scale */ + +#if 0 +/* For VOU */ +#define VO_MAX_DEV_NUM 6 /* we have three VO physical device(HD,AD,SD) and three virtual device(VD1,VD2,VD3) */ +#define VO_MAX_PHY_DEV 3 /* max physical device number(HD,AD,SD) */ +#define VO_MAX_CHN_NUM 64 /* max channel number of each device */ +#define VO_SYNC_MAX_GRP 16 /* we limit total sync group as 16 on three device */ +#define VO_SYNC_MAX_CHN 64 /* each sync group can accommodate 64 channels */ +#define VO_MIN_TOLERATE 1 /* min play toleration 1ms */ +#define VO_MAX_TOLERATE 100000 /* max play toleration 100s */ +#define VO_MAX_SOLIDDRAW 128 /* max draw region number */ +#define VO_MIN_DISP_BUF 5 /* min display buffer number */ +#define VO_MAX_DISP_BUF 15 /* max display buffer number */ +#define VO_MIN_VIRT_BUF 3 /* min virtual device buffer number */ +#define VO_MAX_VIRT_BUF 15 /* max virtual device buffer number */ + +#define VIVO_CSCD_VBI_ID 0 +#define VIVO_CSCD_VBI_X 0 +#define VIVO_CSCD_VBI_Y 0 +#define VIVO_CSCD_VBI_LEN 2 +#define VIVO_CSCD_VBI_LOC VI_VBI_LOCAL_ODD_FRONT +#define VIVO_CSCD_VBI_DATA_WORD 0 +#define VIVO_CSCD_VBI_DATA_BIT (0x01 << 31) +#endif + +#define VO_MAX_DEV_NUM 6 /* max dev num */ +#define VO_MAX_LAYER_NUM 7 /* max layer num */ +#define VHD_MAX_CHN_NUM 32 /* max VHD chn num */ +#define VO_MAX_CHN_NUM VHD_MAX_CHN_NUM /* max chn num */ +#define VO_MAX_LAYER_IN_DEV 2 /* max layer num of each dev */ + +#define VO_MAX_CAS_DEV_NUM 2 /* max cascade dev num*/ +#define VO_CAS_DEV_1 7 /* cascade display device 1 */ +#define VO_CAS_DEV_2 8 /* cascade display device 2 */ +#define VO_CAS_MAX_PAT 128 /* cascade pattern max number */ +#define VO_CAS_MAX_POS_32RGN 32 /* cascade position max number */ +#define VO_CAS_MAX_POS_64RGN 64 /* cascade position max number */ + +#define VO_MAX_VIRT_DEV_NUM 4 /* max virtual dev num*/ +#define VO_VIRT_DEV_0 2 /* virtual display device 1 */ +#define VO_VIRT_DEV_1 3 /* virtual display device 2 */ +#define VO_VIRT_DEV_2 4 /* virtual display device 3 */ +#define VO_VIRT_DEV_3 5 /* virtual display device 4 */ + +#define VO_MAX_GFX_LAYER_PER_DEV 2 +#define VO_MAX_GRAPHICS_LAYER_NUM 3 +#define MDDRC_ZONE_MAX_NUM 32 + +#define VO_MAX_WBC_NUM 1 +#define VO_MAX_PRIORITY 2 +/* the startup condition of video compress */ +#define VIDEO_COMPRESS_WIDTH_THRESHOLD 352 + +#define VO_MIN_TOLERATE 1 /* min play toleration 1ms */ +#define VO_MAX_TOLERATE 100000 /* max play toleration 100s */ + +#define AI_DEV_MAX_NUM 2 +#define AO_DEV_MIN_NUM 0 +#define AO_DEV_MAX_NUM 2 +#define AIO_MAX_NUM 2 +#define AIO_MAX_CHN_NUM 16 + +#define AENC_MAX_CHN_NUM 32 +#define ADEC_MAX_CHN_NUM 32 + +#define RGN_MIN_WIDTH 2 +#define RGN_MIN_HEIGHT 2 +#define RGN_MAX_WIDTH 4096 +#define RGN_MAX_HEIGHT 4096 +#define RGN_ALIGN 2 + +/* VB size calculate for compressed frame. + [param input] + w: width + h: height + fmt: pixel format, 0: SP420, 1: SP422 + z: compress mode, 0: no compress, 1: default compress + [param output] + size: vb blk size + + */ +#define VB_W_ALIGN 16 +#define VB_H_ALIGN 32 +#define VB_ALIGN(x, a) ((a) * (((x) + (a) - 1) / (a))) + + + +/* VB size calculate for compressed frame. + [param input] + w: width + h: height + fmt: pixel format, 0: SP420, 1: SP422 + z: compress mode, 0: no compress, 1: default compress + [param output] + size: vb blk size + */ +#define VB_HEADER_STRIDE 16 + +#define VB_PIC_Y_HEADER_SIZE(Width, Height, size)\ + do{\ + size = VB_HEADER_STRIDE * (Height);\ + }while(0) + +#define VB_PIC_HEADER_SIZE(Width, Height, Type, size)\ + do{\ + if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 == Type)\ + {\ + size = VB_HEADER_STRIDE * (Height) * 2;\ + }\ + else\ + {\ + size = (VB_HEADER_STRIDE * (Height) * 3) >> 1;\ + }\ + }while(0) + + +#define VB_PIC_BLK_SIZE(Width, Height, Type, size)\ + do{\ + unsigned int u32AlignWidth;\ + unsigned int u32AlignHeight;\ + if (Type==PT_H264 || Type==PT_MP4VIDEO || Type==PT_MPEG2VIDEO)\ + {\ + u32AlignWidth = VB_ALIGN(Width,16);\ + u32AlignHeight= VB_ALIGN(Height,32);\ + size = ( (u32AlignWidth * u32AlignHeight) * 3) >> 1;\ + }\ + else if (Type==PT_H265)\ + {\ + u32AlignWidth = VB_ALIGN(Width,64);\ + u32AlignHeight= VB_ALIGN(Height,64);\ + size = ( (u32AlignWidth * u32AlignHeight) * 3) >> 1;\ + }\ + else\ + {\ + u32AlignWidth = VB_ALIGN(Width,64);\ + u32AlignHeight= VB_ALIGN(Height,16);\ + size = (u32AlignWidth * u32AlignHeight * 3) >> 1;\ + }\ + }while(0) + + + +#define VB_PMV_BLK_SIZE(Width, Height, enType, size)\ + do{\ + unsigned int WidthInMb, HeightInMb;\ + unsigned int ColMbSize;\ + WidthInMb = (enType == PT_H265) ? ((Width + 63) >> 4) : ((Width + 15) >> 4);\ + HeightInMb = (enType == PT_H265) ? ((Height + 63) >> 4) : ((Height + 15) >> 4);\ + ColMbSize = (enType == PT_H265) ? (4*4) : (16*4);\ + size = VB_ALIGN((ColMbSize * WidthInMb * HeightInMb), 128);\ + }while(0) + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_DEFINES_H__ */ + diff --git a/snes9x/unix/mpp/hi_errno.h b/snes9x/unix/mpp/hi_errno.h new file mode 100644 index 0000000..8ab3aa0 --- /dev/null +++ b/snes9x/unix/mpp/hi_errno.h @@ -0,0 +1,131 @@ +/****************************************************************************** +Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. +****************************************************************************** +File Name : hi_common.h +Version : Initial Draft +Author : Hi3511 MPP Team +Created : 2006/11/09 +Last Modified : +Description : define the format of error code +Function List : +History : + 1.Date : 2007/02/14 + Author : c42025 + Modification: Created file + + 2.Date : 2007/12/11 + Author : c42025 + Modification: add some MOD_ID for several modules + + 3.Date : 2008/02/03 + Author : c42025 + Modification: reoorder MOD_ID to cleanup modules at specified order + + 4.Date : 2008/03/01 + Author : c42025 + Modification: move LOG_ERRLEVEL_E to hi_debug.h, and add new definion + ERR_LEVLE_E, we should use this enumeration in our error code. + + 5.Date : 2008/04/30 + Author : c42025 + Modification: delete two error code "EN_ERR_NOCHN" and "EN_ERR_NODEV". + +******************************************************************************/ +#ifndef __HI_ERRNO_H__ +#define __HI_ERRNO_H__ + +#include "hi_debug.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + +/* 1010 0000b + * VTOP use APPID from 0~31 + * so, hisilicon use APPID based on 32 + */ +#define HI_ERR_APPID (0x80000000L + 0x20000000L) + +typedef enum hiERR_LEVEL_E +{ + EN_ERR_LEVEL_DEBUG = 0, /* debug-level */ + EN_ERR_LEVEL_INFO, /* informational */ + EN_ERR_LEVEL_NOTICE, /* normal but significant condition */ + EN_ERR_LEVEL_WARNING, /* warning conditions */ + EN_ERR_LEVEL_ERROR, /* error conditions */ + EN_ERR_LEVEL_CRIT, /* critical conditions */ + EN_ERR_LEVEL_ALERT, /* action must be taken immediately */ + EN_ERR_LEVEL_FATAL, /* just for compatibility with previous version */ + EN_ERR_LEVEL_BUTT +}ERR_LEVEL_E; + + +/****************************************************************************** +|----------------------------------------------------------------| +| 1 | APP_ID | MOD_ID | ERR_LEVEL | ERR_ID | +|----------------------------------------------------------------| +|<--><--7bits----><----8bits---><--3bits---><------13bits------->| +******************************************************************************/ + +#define HI_DEF_ERR( module, level, errid) \ + ((HI_S32)( (HI_ERR_APPID) | ((module) << 16 ) | ((level)<<13) | (errid) )) + +/* NOTE! the following defined all common error code, +** all module must reserved 0~63 for their common error code +*/ +typedef enum hiEN_ERR_CODE_E +{ + EN_ERR_INVALID_DEVID = 1, /* invlalid device ID */ + EN_ERR_INVALID_CHNID = 2, /* invlalid channel ID */ + EN_ERR_ILLEGAL_PARAM = 3, /* at lease one parameter is illagal + * eg, an illegal enumeration value */ + EN_ERR_EXIST = 4, /* resource exists */ + EN_ERR_UNEXIST = 5, /* resource unexists */ + + EN_ERR_NULL_PTR = 6, /* using a NULL point */ + + EN_ERR_NOT_CONFIG = 7, /* try to enable or initialize system, device + ** or channel, before configing attribute */ + + EN_ERR_NOT_SUPPORT = 8, /* operation or type is not supported by NOW */ + EN_ERR_NOT_PERM = 9, /* operation is not permitted + ** eg, try to change static attribute */ + + EN_ERR_NOMEM = 12,/* failure caused by malloc memory */ + EN_ERR_NOBUF = 13,/* failure caused by malloc buffer */ + + EN_ERR_BUF_EMPTY = 14,/* no data in buffer */ + EN_ERR_BUF_FULL = 15,/* no buffer for new data */ + + EN_ERR_SYS_NOTREADY = 16,/* System is not ready,maybe not initialed or + ** loaded. Returning the error code when opening + ** a device file failed. */ + + EN_ERR_BADADDR = 17,/* bad address, + ** eg. used for copy_from_user & copy_to_user */ + + EN_ERR_BUSY = 18,/* resource is busy, + ** eg. destroy a venc chn without unregister it */ + + EN_ERR_BUTT = 63,/* maxium code, private error code of all modules + ** must be greater than it */ +}EN_ERR_CODE_E; + + +/* +** following is an example for defining error code of VDA module +** #define HI_ERR_MD_INVALID_CHNID HI_DEF_ERR(HI_ID_VDA, EN_ERR_LEVEL_ERROR, EN_ERR_INVALID_CHNID) +** +*/ + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __HI_ERRNO_H__ */ + diff --git a/snes9x/unix/mpp/hi_io.h b/snes9x/unix/mpp/hi_io.h new file mode 100644 index 0000000..8ebaed4 --- /dev/null +++ b/snes9x/unix/mpp/hi_io.h @@ -0,0 +1,96 @@ +#ifndef __HI_IO_H__ +#define __HI_IO_H__ + +#include "hi_type.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* user and kernel are different. */ +HI_U8 IO_READ8(HI_U32 u32Addr); +HI_S32 IO_WRITE8(HI_U32 u32Addr, HI_U32 u32Value); +HI_U16 IO_READ16(HI_U32 u32Addr); +HI_S32 IO_WRITE16(HI_U32 u32Addr, HI_U32 u32Value); +HI_U32 IO_READ32(HI_U32 u32Addr); +HI_S32 IO_WRITE32(HI_U32 u32Addr, HI_U32 u32Value); +HI_U32 ISP_Mmap(void); +HI_U32 ISP_Munmap(void); +HI_U32 ISP_GetExtRegAddr(void); + +#define REG_ACCESS_WIDTH 0 // 1: 16bit 2: 8bit +#define EXT_REG_BASE 0x10200 +#define ISP_REG_BASE_ADDR 0x205a0000 + +#define EXT_REG_BASE_ISP 0x8000 +#define EXT_REG_BASE_VIU 0x8400 +#define EXT_REG_BASE_VPP 0x8600 +#define EXT_REG_BASE_VEDU 0x8800 +#define EXT_REG_BASE_VOU 0x8A00 + +/* Dynamic bus access functions, 4 byte align access */ +//TODO: allocate dev addr (such as ISP_REG_BASE_ADDR) according to devId. +#define __IO_CALC_ADDRESS_DYNAMIC(BASE, OFFSET) ((HI_U32)(((BASE >= EXT_REG_BASE)? 0 : ISP_REG_BASE_ADDR) + ((((BASE >= EXT_REG_BASE)? (BASE - EXT_REG_BASE) : BASE) + OFFSET)< lowThr, dstVal = maxVal.*/ + IVE_THRESH_MODE_TRUNC = 0x1, /*srcVal <= lowThr, dstVal = srcVal; srcVal > lowThr, dstVal = maxVal.*/ + IVE_THRESH_MODE_TO_MINVAL = 0x2, /*srcVal <= lowThr, dstVal = minVal; srcVal > lowThr, dstVal = srcVal.*/ + + IVE_THRESH_MODE_MIN_MID_MAX = 0x3, /*srcVal <= lowThr, dstVal = minVal; lowThr < srcVal <= highThr, dstVal = midVal; srcVal > highThr, dstVal = maxVal.*/ + IVE_THRESH_MODE_ORI_MID_MAX = 0x4, /*srcVal <= lowThr, dstVal = srcVal; lowThr < srcVal <= highThr, dstVal = midVal; srcVal > highThr, dstVal = maxVal.*/ + IVE_THRESH_MODE_MIN_MID_ORI = 0x5, /*srcVal <= lowThr, dstVal = minVal; lowThr < srcVal <= highThr, dstVal = midVal; srcVal > highThr, dstVal = srcVal.*/ + IVE_THRESH_MODE_MIN_ORI_MAX = 0x6, /*srcVal <= lowThr, dstVal = minVal; lowThr < srcVal <= highThr, dstVal = srcVal; srcVal > highThr, dstVal = maxVal.*/ + IVE_THRESH_MODE_ORI_MID_ORI = 0x7, /*srcVal <= lowThr, dstVal = srcVal; lowThr < srcVal <= highThr, dstVal = midVal; srcVal > highThr, dstVal = srcVal.*/ + + IVE_THRESH_MODE_BUTT +}IVE_THRESH_MODE_E; + +/* +* Thresh control parameters. +* Modified by Tan Bing, 2013-7-22 +*/ +typedef struct hiIVE_THRESH_CTRL_S +{ + IVE_THRESH_MODE_E enMode; + HI_U8 u8LowThr; /*user-defined threshold, 0<=u8LowThr<=255 */ + HI_U8 u8HighThr; /*user-defined threshold, if enMode0' and 'label = ArrayIndex+1'*/ +}IVE_CCBLOB_S; + +/* +*CCL control struct +*/ +typedef struct hiIVE_CCL_CTRL_S +{ + HI_U16 u16InitAreaThr; /*Init threshold of region area*/ + HI_U16 u16Step; /*Increase area step for once*/ +}IVE_CCL_CTRL_S; + +/* +*GMM control struct +*/ +typedef struct hiIVE_GMM_CTRL_S +{ + HI_U22Q10 u22q10NoiseVar; /*Initial noise Variance*/ + HI_U22Q10 u22q10MaxVar; /*Max Variance*/ + HI_U22Q10 u22q10MinVar; /*Min Variance*/ + HI_U0Q16 u0q16LearnRate; /*Learning rate*/ + HI_U0Q16 u0q16BgRatio; /*Background ratio*/ + HI_U8Q8 u8q8VarThr; /*Variance Threshold*/ + HI_U0Q16 u0q16InitWeight; /*Initial Weight*/ + HI_U8 u8ModelNum; /*Model number: 3 or 5*/ +}IVE_GMM_CTRL_S; + +/* +*CannyHysEdge control struct +*/ +typedef struct hiIVE_CANNY_HYS_EDGE_CTRL_S +{ + IVE_MEM_INFO_S stMem; + HI_U16 u16LowThr; + HI_U16 u16HighThr; + HI_S8 as8Mask[25]; +} IVE_CANNY_HYS_EDGE_CTRL_S; + +/* +*Canny stack size struct +*/ +typedef struct hiIVE_CANNY_STACK_SIZE_S +{ + HI_U32 u32StackSize; /*Stack size for output*/ + HI_U8 u8Reserved[12]; /*For 16 byte align*/ +}IVE_CANNY_STACK_SIZE_S; + +/* +*LBP compare mode +*/ +typedef enum hiIVE_LBP_CMP_MODE_E +{ + IVE_LBP_CMP_MODE_NORMAL = 0x0, /* P(x)-P(center)>= un8BitThr.s8Val, s(x)=1; else s(x)=0; */ + IVE_LBP_CMP_MODE_ABS = 0x1, /* Abs(P(x)-P(center))>=un8BitThr.u8Val, s(x)=1; else s(x)=0; */ + + IVE_LBP_CMP_MODE_BUTT +}IVE_LBP_CMP_MODE_E; + +/* +*LBP control struct +*/ +typedef struct hiIVE_LBP_CTRL_S +{ + IVE_LBP_CMP_MODE_E enMode; + IVE_8BIT_U un8BitThr; +}IVE_LBP_CTRL_S; + +/* +*Type of the GradientFilter output format +*/ +typedef enum hiIVE_NORM_GRAD_OUT_CTRL_E +{ + IVE_NORM_GRAD_OUT_CTRL_HOR_AND_VER = 0x0, + IVE_NORM_GRAD_OUT_CTRL_HOR = 0x1, + IVE_NORM_GRAD_OUT_CTRL_VER = 0x2, + IVE_NORM_GRAD_OUT_CTRL_COMBINE = 0x3, + + IVE_NORM_GRAD_OUT_CTRL_BUTT +}IVE_NORM_GRAD_OUT_CTRL_E; + +/* +*GradientFilter control parameters +*/ +typedef struct hiIVE_NORM_GRAD_CTRL_S +{ + IVE_NORM_GRAD_OUT_CTRL_E enOutCtrl; + HI_S8 as8Mask[25]; + HI_U8 u8Norm; +}IVE_NORM_GRAD_CTRL_S; + +/* +* LKOpticalFlow movement +*/ +typedef struct hiIVE_MV_S9Q7_S +{ + HI_S32 s32Status; /*Result of tracking: 0-success; -1-failure*/ + HI_S9Q7 s9q7Dx; /*X-direction component of the movement*/ + HI_S9Q7 s9q7Dy; /*Y-direction component of the movement*/ +}IVE_MV_S9Q7_S; + +typedef struct hiIVE_LK_OPTICAL_FLOW_CTRL_S +{ + HI_U16 u16CornerNum; /*Number of the feature points,<200*/ + HI_U0Q8 u0q8MinEigThr; /*Minimum eigenvalue threshold*/ + HI_U8 u8IterCount; /*Maximum iteration times*/ + HI_U0Q8 u0q8Epsilon; /*Threshold of iteration for dx^2 + dy^2 < u0q8Epsilon */ +}IVE_LK_OPTICAL_FLOW_CTRL_S; + +typedef struct hiIVE_ST_MAX_EIG_S +{ + HI_U16 u16MaxEig; /*Shi-Tomasi second step output MaxEig*/ + HI_U8 u8Reserved[14]; /*For 16 byte align*/ +}IVE_ST_MAX_EIG_S; + +/* +*ShiTomasi control parameters +*/ +typedef struct hiIVE_ST_CANDI_CORNER_CTRL_S +{ + IVE_MEM_INFO_S stMem; + HI_U0Q8 u0q8QualityLevel; +}IVE_ST_CANDI_CORNER_CTRL_S; + +typedef struct hiIVE_ST_CORNER_INFO_S +{ + HI_U16 u16CornerNum; + IVE_POINT_U16_S astCorner[IVE_ST_MAX_CORNER_NUM]; +}IVE_ST_CORNER_INFO_S; + +typedef struct hiIVE_ST_CORNER_CTRL_S +{ + HI_U16 u16MaxCornerNum; + HI_U16 u16MinDist; +}IVE_ST_CORNER_CTRL_S; + +/* +* GradFg mode enum +*/ +typedef enum hiIVE_GRAD_FG_MODE_E +{ + IVE_GRAD_FG_MODE_USE_CUR_GRAD = 0x0, + IVE_GRAD_FG_MODE_FIND_MIN_GRAD = 0x1, + + IVE_GRAD_FG_MODE_BUTT +}IVE_GRAD_FG_MODE_E; + +/* +* GradFg ctrl struct +*/ +typedef struct hiIVE_GRAD_FG_CTRL_S +{ + IVE_GRAD_FG_MODE_E enMode; /*Calculation mode*/ + HI_U16 u16EdwFactor; /*Edge width adjustment factor (range: 500 to 2000; default: 1000)*/ + HI_U8 u8CrlCoefThr; /*Gradient vector correlation coefficient threshold (ranges: 50 to 100; default: 80)*/ + HI_U8 u8MagCrlThr; /*Gradient amplitude threshold (range: 0 to 20; default: 4)*/ + HI_U8 u8MinMagDiff; /*Gradient magnitude difference threshold (range: 2 to 8; default: 2)*/ + HI_U8 u8NoiseVal; /*Gradient amplitude noise threshold (range: 1 to 8; default: 1)*/ + HI_U8 u8EdwDark; /*Black pixels enable flag (range: 0 (no), 1 (yes); default: 1)*/ +}IVE_GRAD_FG_CTRL_S; + +typedef struct hiIVE_CANDI_BG_PIX_S +{ + HI_U8Q4F4 u8q4f4Mean; /*Candidate background grays value */ + HI_U16 u16StartTime; /*Candidate Background start time */ + HI_U16 u16SumAccessTime; /*Candidate Background cumulative access time */ + HI_U16 u16ShortKeepTime; /*Candidate background short hold time*/ + HI_U8 u8ChgCond; /*Time condition for candidate background into the changing state*/ + HI_U8 u8PotenBgLife; /*Potential background cumulative access time */ +}IVE_CANDI_BG_PIX_S; + +typedef struct hiIVE_WORK_BG_PIX_S +{ + HI_U8Q4F4 u8q4f4Mean; /*0# background grays value */ + HI_U16 u16AccTime; /*Background cumulative access time */ + HI_U8 u8PreGray; /*Gray value of last pixel */ + HI_U5Q3 u5q3DiffThr; /*Differential threshold */ + HI_U8 u8AccFlag; /*Background access flag */ + HI_U8 u8BgGray[3]; /*1# ~ 3# background grays value */ +}IVE_WORK_BG_PIX_S; + +typedef struct hiIVE_BG_LIFE_S +{ + HI_U8 u8WorkBgLife[3]; /*1# ~ 3# background vitality */ + HI_U8 u8CandiBgLife; /*Candidate background vitality */ +}IVE_BG_LIFE_S; + +typedef struct hiIVE_BG_MODEL_PIX_S +{ + IVE_WORK_BG_PIX_S stWorkBgPixel; /*Working background */ + IVE_CANDI_BG_PIX_S stCandiPixel; /*Candidate background */ + IVE_BG_LIFE_S stBgLife; /*Background vitality */ +}IVE_BG_MODEL_PIX_S; + +typedef struct hiIVE_FG_STAT_DATA_S +{ + HI_U32 u32PixNum; + HI_U32 u32SumLum; + HI_U8 u8Reserved[8]; +}IVE_FG_STAT_DATA_S; + +typedef struct hiIVE_BG_STAT_DATA_S +{ + HI_U32 u32PixNum; + HI_U32 u32SumLum; + HI_U8 u8Reserved[8]; +}IVE_BG_STAT_DATA_S; + +typedef struct hiIVE_MATCH_BG_MODEL_CTRL_S +{ + HI_U32 u32CurFrmNum; /*Current frame timestamp, in frame units */ + HI_U32 u32PreFrmNum; /*Previous frame timestamp, in frame units */ + HI_U16 u16TimeThr; /*Potential background replacement time threshold (range: 2 to 100 frames; default: 20) */ + + HI_U8 u8DiffThrCrlCoef; /*Correlation coefficients between differential threshold and gray value (range: 0 to 5; default: 0) */ + HI_U8 u8DiffMaxThr; /*Maximum of background differential threshold (range: 3 to 15; default: 6) */ + HI_U8 u8DiffMinThr; /*Minimum of background differential threshold (range: 3 to 15; default: 4) */ + HI_U8 u8DiffThrInc; /*Dynamic Background differential threshold increment (range: 0 to 6; default: 0) */ + HI_U8 u8FastLearnRate; /*Quick background learning rate (range: 0 to 4; default: 2) */ + HI_U8 u8DetChgRegion; /*Whether to detect change region (range: 0 (no), 1 (yes); default: 0) */ +}IVE_MATCH_BG_MODEL_CTRL_S; + +typedef struct hiIVE_UPDATE_BG_MODEL_CTRL_S +{ + HI_U32 u32CurFrmNum; /*Current frame timestamp, in frame units */ + HI_U32 u32PreChkTime; /*The last time when background status is checked */ + HI_U32 u32FrmChkPeriod; /*Background status checking period (range: 0 to 2000 frames; default: 50) */ + + HI_U32 u32InitMinTime; /*Background initialization shortest time (range: 20 to 6000 frames; default: 100)*/ + HI_U32 u32StyBgMinBlendTime; /*Steady background integration shortest time (range: 20 to 6000 frames; default: 200)*/ + HI_U32 u32StyBgMaxBlendTime; /*Steady background integration longest time (range: 20 to 40000 frames; default: 1500)*/ + HI_U32 u32DynBgMinBlendTime; /*Dynamic background integration shortest time (range: 0 to 6000 frames; default: 0)*/ + HI_U32 u32StaticDetMinTime; /*Still detection shortest time (range: 20 to 6000 frames; default: 80)*/ + HI_U16 u16FgMaxFadeTime; /*Foreground disappearing longest time (range: 1 to 255 seconds; default: 15)*/ + HI_U16 u16BgMaxFadeTime; /*Background disappearing longest time (range: 1 to 255 seconds ; default: 60)*/ + + HI_U8 u8StyBgAccTimeRateThr; /*Steady background access time ratio threshold (range: 10 to 100; default: 80)*/ + HI_U8 u8ChgBgAccTimeRateThr; /*Change background access time ratio threshold (range: 10 to 100; default: 60)*/ + HI_U8 u8DynBgAccTimeThr; /*Dynamic background access time ratio threshold (range: 0 to 50; default: 0)*/ + HI_U8 u8DynBgDepth; /*Dynamic background depth (range: 0 to 3; default: 3)*/ + HI_U8 u8BgEffStaRateThr; /*Background state time ratio threshold when initializing (range: 90 to 100; default: 90)*/ + + HI_U8 u8AcceBgLearn; /*Whether to accelerate background learning (range: 0 (no), 1 (yes); default: 0)*/ + HI_U8 u8DetChgRegion; /*Whether to detect change region (range: 0 (no), 1 (yes); default: 0)*/ +} IVE_UPDATE_BG_MODEL_CTRL_S; + + +typedef enum hiIVE_ANN_MLP_ACTIV_FUNC_E +{ + IVE_ANN_MLP_ACTIV_FUNC_IDENTITY = 0x0, + IVE_ANN_MLP_ACTIV_FUNC_SIGMOID_SYM = 0x1, + IVE_ANN_MLP_ACTIV_FUNC_GAUSSIAN = 0x2, + + IVE_ANN_MLP_ACTIV_FUNC_BUTT +}IVE_ANN_MLP_ACTIV_FUNC_E; + +typedef struct hiIVE_ANN_MLP_MODEL_S +{ + IVE_ANN_MLP_ACTIV_FUNC_E enActivFunc; + IVE_MEM_INFO_S stWeight; + HI_U32 u32TotalWeightSize; + + HI_U16 au16LayerCount[8]; /*8 layers, including input and output layer, every layerCount<=256*/ + HI_U16 u16MaxCount; /*MaxCount<=256*/ + HI_U8 u8LayerNum; /*2 u16Thr, dstVal = maxVal.*/ + HI_U8 u8MinVal; /*Min value*/ + HI_U8 u8MaxVal; /*Max value*/ +}IVE_SAD_CTRL_S; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif/*_HI_IVE_H_*/ \ No newline at end of file diff --git a/snes9x/unix/mpp/hi_jpeg_api.h b/snes9x/unix/mpp/hi_jpeg_api.h new file mode 100644 index 0000000..1b94720 --- /dev/null +++ b/snes9x/unix/mpp/hi_jpeg_api.h @@ -0,0 +1,474 @@ +/****************************************************************************** +* +* Copyright (C) 2014 Hisilicon Technologies Co., Ltd. All rights reserved. +* +* This program is confidential and proprietary to Hisilicon Technologies Co., Ltd. (Hisilicon), +* and may not be copied, reproduced, modified, disclosed to others, published or used, in +* whole or in part, without the express prior written permission of Hisilicon. +* +****************************************************************************** +File Name : hi_jpeg_api.h +Version : Initial Draft +Author : +Created : 2014/06/20 +Description : The user will use this api to realize some function +Function List : + + +History : +Date Author Modification +2014/06/20 y00181162 Created file +******************************************************************************/ + +#ifndef __HI_JPEG_API_H__ +#define __HI_JPEG_API_H__ + + +/*********************************add include here******************************/ + +#include "jpeglib.h" +#include "hi_type.h" + +/*****************************************************************************/ + + +#ifdef __cplusplus +#if __cplusplus + extern "C" +{ +#endif +#endif /* __cplusplus */ + + + /***************************** Macro Definition ******************************/ + /** \addtogroup JPEG */ + /** @{ */ /** big endian +** IS_LITTLE_END() whether the system is little end mode +******************************************************************************/ +#define ENDIAN32( x ) \ + ( ( (x) << 24 ) | \ + ( ( (x) & 0x0000ff00 ) << 8 ) | \ + ( ( (x) & 0x00ff0000 ) >> 8 ) | \ + ( ( (x) >> 24 ) & 0x000000ff ) ) + +__inline static HI_BOOL IS_LITTLE_END(void) +{ + union unEND_TEST_U + { + HI_CHAR cTest[4]; + HI_U32 u32Test; + } unEndTest; + + unEndTest.cTest[0] = 0x01; + unEndTest.cTest[1] = 0x02; + unEndTest.cTest[2] = 0x03; + unEndTest.cTest[3] = 0x04; + + return (unEndTest.u32Test > 0x01020304) ? (HI_TRUE) : (HI_FALSE); +} + + +/****************************************************************************** +** FRACTION32(de,nu) fraction: nu(minator) / de(nominator). +** NUMERATOR32(x) of x(x is fraction) +** DENOMINATOR32(x) Denominator of x(x is fraction) + +** represent fraction in 32 bit. LSB 16 is numerator, MSB 16 is denominator +** It is integer if denominator is 0. +******************************************************************************/ +#define FRACTION32(de,nu) ( ((de) << 16) | (nu) ) +#define NUMERATOR32(x) ( (x) & 0xffff) +#define DENOMINATOR32(x) ( (x) >> 16 ) + +/****************************************************************************** +** RGB(r,g,b) assemble the r,g,b to 24bit color +** RGB_R(c) get RED from 24bit color +** RGB_G(c) get GREEN from 24bit color +** RGB_B(c) get BLUE from 24bit color +******************************************************************************/ +#define RGB(r,g,b) ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff)) +#define RGB_R(c) ( ((c) & 0xff0000) >> 16) +#define RGB_G(c) ( ((c) & 0xff00) >> 8) +#define RGB_B(c) ( (c) & 0xff) + +/****************************************************************************** +** YUV(y,u,v) assemble the y,u,v to 24bit color +** YUV_Y(c) get Y from 24bit color +** YUV_U(c) get U from 24bit color +** YUV_V(c) get V from 24bit color +******************************************************************************/ +#define YUV(y,u,v) ((((y) & 0xff) << 16) | (((u) & 0xff) << 8) | ((v) & 0xff)) +#define YUV_Y(c) ( ((c) & 0xff0000) >> 16) +#define YUV_U(c) ( ((c) & 0xff00) >> 8) +#define YUV_V(c) ( (c) & 0xff) + +/****************************************************************************** +** Rgb2Yc(r, g, b, *y, *u, *u) convert r,g,b to y,u,v +** Rgb2Yuv(rgb, *yuv) convert rgb to yuv +******************************************************************************/ +__inline static HI_VOID Rgb2Yc(HI_U8 r, HI_U8 g, HI_U8 b, HI_U8 * py, HI_U8 * pcb, HI_U8 * pcr) +{ + /* Y */ + *py = (HI_U8)(((r*66+g*129+b*25) >> 8) + 16); + + /* Cb */ + *pcb = (HI_U8)((((b*112-r*38)-g*74) >> 8) + 128); + + /* Cr */ + *pcr = (HI_U8)((((r*112-g*94)-b*18) >> 8) + 128); +} + +__inline static HI_U32 Rgb2Yuv(HI_U32 u32Rgb) +{ + HI_U8 y,u,v; + + Rgb2Yc(RGB_R(u32Rgb), RGB_G(u32Rgb), RGB_B(u32Rgb), &y, &u, &v); + + return YUV(y,u,v); +} + +/****************************************************************************** +** GetYCFromRGB(rgb, *y, *cbcr) convert rgb to yyyy, uvuv, +******************************************************************************/ +__inline static HI_VOID GetYCFromRGB(HI_U32 rgb, HI_U32 * pY, HI_U32 * pC) +{ + HI_U8 y, cb, cr; + HI_U32 color_y, color_c, tmp; + + Rgb2Yc(RGB_R(rgb), RGB_G(rgb), RGB_B(rgb), &y, &cb, &cr); + + tmp = y & 0xFF; + color_y = (tmp<<24) + (tmp<<16) + (tmp<<8) + tmp; + + tmp = cb & 0xFF; + color_c = (tmp<<24) + (tmp<<8); + + tmp = cr & 0xFF; + color_c = color_c + (tmp<<16) + tmp; + + *pY = color_y; + *pC = color_c; +} + +/******************************************************************************* +** FpsControl Useing Sample: +** FPS_CTRL_S g_stFpsCtrl; +** +** Take 12 frame uniform in 25. +** InitFps(&g_stFpsCtrl, 25, 12); +** +** { +** if(FpsControl(&g_stFpsCtrl)) printf("Yes, this frmae should be token"); +** } +** +*******************************************************************************/ +typedef struct hiFPS_CTRL_S +{ + HI_U32 u32Ffps; /* Full frame rate */ + HI_U32 u32Tfps; /* Target frame rate */ + HI_U32 u32FrmKey; /* update key frame */ +} FPS_CTRL_S; + +__inline static HI_VOID InitFps(FPS_CTRL_S *pFrmCtrl, HI_U32 u32FullFps, + HI_U32 u32TagFps) +{ + pFrmCtrl->u32Ffps = u32FullFps; + pFrmCtrl->u32Tfps = u32TagFps; + pFrmCtrl->u32FrmKey = 0; +} + +__inline static HI_BOOL FpsControl(FPS_CTRL_S *pFrmCtrl) +{ + HI_BOOL bReturn = HI_FALSE; + + pFrmCtrl->u32FrmKey += pFrmCtrl->u32Tfps; + if (pFrmCtrl->u32FrmKey >= pFrmCtrl->u32Ffps) + { + pFrmCtrl->u32FrmKey -= pFrmCtrl->u32Ffps; + bReturn = HI_TRUE; + } + + return bReturn; +} + +/******************************************************************************* +** GetSysTimeBySec +** GetSysTimeByUsec +*******************************************************************************/ +#ifdef __KERNEL__ + #include +#else + #include +#endif +__inline static HI_U32 GetSysTimeBySec(void) +{ + struct timeval stTime; + #ifdef __KERNEL__ + do_gettimeofday(&stTime); + #else + gettimeofday(&stTime, NULL); + #endif + return stTime.tv_sec; +} + +__inline static HI_U64 GetSysTimeByUsec(void) +{ + struct timeval stTime; + #ifdef __KERNEL__ + do_gettimeofday(&stTime); + #else + gettimeofday(&stTime, NULL); + #endif + return (stTime.tv_sec * 1000000LLU) + stTime.tv_usec; +} + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + + +#endif /* __HI_MATH_H__ */ + diff --git a/snes9x/unix/mpp/hi_md.h b/snes9x/unix/mpp/hi_md.h new file mode 100644 index 0000000..80e2973 --- /dev/null +++ b/snes9x/unix/mpp/hi_md.h @@ -0,0 +1,56 @@ +/****************************************************************************** + + Copyright (C), 2001-2014, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_md.h + Version : Initial Draft + Author : Hisilicon multimedia software (IVE) group + Created : 2014/11/10 + Description : + History : + 1.Date : 2014/11/10 + Author : c00211359 + Modification: Created file +******************************************************************************/ +#ifndef _HI_MD_H_ +#define _HI_MD_H_ + +#include "hi_ive.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif +/* +* Definition md algorithm mode +*/ +typedef enum hiMD_ALG_MODE_E +{ + MD_ALG_MODE_BG = 0x0,/*Base on background image*/ + MD_ALG_MODE_REF = 0x1,/*Base on reference image*/ + + MD_ALG_MODE_BUTT +}MD_ALG_MODE_E; +/* +* Definition of md attribute +*/ +typedef struct hiMD_ATTR_S +{ + MD_ALG_MODE_E enAlgMode; /*Md algorithm mode*/ + IVE_SAD_MODE_E enSadMode; /*Sad mode*/ + HI_U16 u16Width; /*Image width*/ + HI_U16 u16Height; /*Image height*/ + HI_U16 u16SadThr; /*Sad thresh*/ + IVE_CCL_CTRL_S stCclCtrl; /*Ccl ctrl*/ + IVE_ADD_CTRL_S stAddCtrl; /*Add ctrl*/ +}MD_ATTR_S; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif/*_HI_MD_H_*/ \ No newline at end of file diff --git a/snes9x/unix/mpp/hi_tde_api.h b/snes9x/unix/mpp/hi_tde_api.h new file mode 100644 index 0000000..0ea3467 --- /dev/null +++ b/snes9x/unix/mpp/hi_tde_api.h @@ -0,0 +1,392 @@ +/***************************************************************************** +* Copyright 2006 - 2050, Hisilicon Tech. Co., Ltd. +* ALL RIGHTS RESERVED +* FileName: hi_api_tde.h +* Description:TDE2 API define +* +* History: +* Version Date Author DefectNum Description +* +*****************************************************************************/ + +#ifndef _HI_API_TDE2_H_ +#define _HI_API_TDE2_H_ + +#ifdef __cplusplus + #if __cplusplus +extern "C" { + #endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "hi_type.h" +#include "hi_tde_type.h" + +#define HI_TDE_Open HI_TDE2_Open +#define HI_TDE_Close HI_TDE2_Close +#define HI_TDE_BeginJob HI_TDE2_BeginJob + +/****************************************************************************/ +/* TDE2 API define */ +/****************************************************************************/ + +/***************************************************************************** +* Function: HI_TDE2_Open +* Description: Opens the TDE device +* Input: None +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_Open(HI_VOID); + +/***************************************************************************** +* Function: HI_TDE2_Close +* Description: Closes the TDE device +* Input: None +* Output: None +* Return: None +* Others: None +*****************************************************************************/ +HI_VOID HI_TDE2_Close(HI_VOID); + +/***************************************************************************** +* Function: HI_TDE2_BeginJob +* Description: Creates a TDE job, get a TDE2 job handle +* Input: None +* Output: None +* Return: tde handle / Error code +* Others: None +*****************************************************************************/ +TDE_HANDLE HI_TDE2_BeginJob(HI_VOID); + +/***************************************************************************** +* Function: HI_TDE2_EndJob +* Description: Submits a TDE2 job +* Input: s32Handle: job handle +* bSync: if synchronous +* bBlock: if blocked +* u32TimeOut: timeout value(in 10ms) +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_EndJob(TDE_HANDLE s32Handle, HI_BOOL bSync, HI_BOOL bBlock, HI_U32 u32TimeOut); + +/***************************************************************************** +* Function: HI_TDE2_CancelJob +* Description: Cancels a specific TDE job, only successful before calling EndJob +* Input: s32Handle: job handle +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_CancelJob(TDE_HANDLE s32Handle); + +/***************************************************************************** +* Function: HI_TDE2_WaitForDone +* Description: Waits for a submitted job to finish +* Input: s32Handle: job handle +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_WaitForDone(TDE_HANDLE s32Handle); + +/***************************************************************************** +* Function: HI_TDE2_WaitAllDone +* Description: Waits for all submitted jobs to finish +* Input: None +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_WaitAllDone(HI_VOID); + + +/***************************************************************************** +* Function: HI_TDE2_Reset +* Description: Reset tde +* Input: None +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_Reset(HI_VOID); + +/***************************************************************************** +* Function: HI_TDE2_QuickCopy +* Description: Just quick copy, the size of source region and destination region should be the same, so is the color format +* Input: s32Handle: job handle +* pSrc: the source picture information +* pstSrcRect: the source picture operation region +* pDst: the destination picture information +* pstDstRect: the destination picture operation region +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_QuickCopy(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstSrc, TDE2_RECT_S *pstSrcRect, + TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect); + +/***************************************************************************** +* Function: HI_TDE2_QuickFill +* Description: Quick fill +* Input: s32Handle: job handle +* pDst: the destination picture information +* pstDstRect: the destination picture operation region +* u32FillData: the color value,its format should be the same to the destination picture +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_QuickFill(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect, + HI_U32 u32FillData); + +/***************************************************************************** +* Function: HI_TDE2_QuickResize +* Description: Adds the raster bitmap scaling operation to a TDE job +* Input: s32Handle: job handle +* pSrc: the source picture information +* pstSrcRect: the source picture operation region +* pDst: the destination picture information +* pstDstRect: the destination picture operation region +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_QuickResize(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstSrc, TDE2_RECT_S *pstSrcRect, + TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect); + +/***************************************************************************** +* Function: HI_TDE2_QuickFlicker +* Description: Adds the anti-flicker operation to a TDE job +* Input: s32Handle: job handle +* pSrc: the source picture information +* pstSrcRect: the source picture operation region +* pDst: the destination picture information +* pstDstRect: the destination picture operation region +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_QuickDeflicker(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstSrc, TDE2_RECT_S *pstSrcRect, + TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect); + +/***************************************************************************** +* Function: HI_TDE2_Blit +* Description: Adds the transfer operation with additional functions performed on + the raster bitmap to a TDE task +* Input: s32Handle: job handle +* pstBackGround: the background picture information +* pstBackGroundRect: the background picture operation region +* pstForeGround: the foreground picture information +* pstForeGroundRect: the foreground picture operation region +* pstDst: the destination picture information +* pstDstRect: the destination picture operation region +* pOpt: operation parameter settings +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_Bitblit(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstBackGround, TDE2_RECT_S *pstBackGroundRect, + TDE2_SURFACE_S* pstForeGround, TDE2_RECT_S *pstForeGroundRect, TDE2_SURFACE_S* pstDst, + TDE2_RECT_S *pstDstRect, TDE2_OPT_S* pstOpt); + +/***************************************************************************** +* Function: HI_TDE2_SolidDraw +* Description: Adds the filling operation with additional functions performed on + the raster bitmap to a TDE task +* Input: s32Handle: job handle +* pstForeGround: the foreground picture information +* pstForeGroundRect: the source picture operation region +* pstDst: the background picture information +* pstDstRect: the destination picture operation region +* pstFillColor: the color value +* pstOpt: operation parameter settings +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_SolidDraw(TDE_HANDLE s32Handle, TDE2_SURFACE_S* pstForeGround, TDE2_RECT_S *pstForeGroundRect, + TDE2_SURFACE_S *pstDst, + TDE2_RECT_S *pstDstRect, TDE2_FILLCOLOR_S *pstFillColor, + TDE2_OPT_S *pstOpt); + +/***************************************************************************** +* Function: HI_TDE2_MbBlit +* Description: Adds the transfer operation with additional functions performed on + the macroblock bitmap to a TDE task +* Input: s32Handle: job handle +* pstMB: Surface of the macroblock +* pstDst: Operating region of the macroblock +* pstDstRect: the destination picture operation region +* pstMbOpt: operation parameter settings +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_MbBlit(TDE_HANDLE s32Handle, TDE2_MB_S* pstMB, TDE2_RECT_S *pstMbRect, TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect, + TDE2_MBOPT_S* pstMbOpt); + +/***************************************************************************** +* Function: HI_TDE2_BitmapMaskRop +* Description: Adds the mask raster operation (ROP) operation performed + on the raster bitmap to a TDE task. +* Input: s32Handle: job handle +* pstBackGround: the background picture information +* pstBackGroundRect: the background picture operation region +* pstForeGround: the foreground picture information +* pstForeGroundRect: the source picture operation region +* pstMask: mask picture information +* pstMaskRect: operating region of the mask picture +* pstDst: the destination picture information +* pstDstRect: the destination picture operation region +* enRopCode_Color: ROP operation code of the color component +* enRopCode_Alpha: ROP operation code of the alpha component +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_BitmapMaskRop(TDE_HANDLE s32Handle, + TDE2_SURFACE_S* pstBackGround, TDE2_RECT_S *pstBackGroundRect, + TDE2_SURFACE_S* pstForeGround, TDE2_RECT_S *pstForeGroundRect, + TDE2_SURFACE_S* pstMask, TDE2_RECT_S *pstMaskRect, + TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect, + TDE2_ROP_CODE_E enRopCode_Color, TDE2_ROP_CODE_E enRopCode_Alpha); + +/***************************************************************************** +* Function: HI_TDE2_BitmapMaskBlend +* Description: Adds the mask blending operation performed on the raster + bitmap to a TDE task +* Input: s32Handle: job handle +* pstBackGround: the background picture information +* pstBackGroundRect: the background picture operation region +* pstForeGround: the foreground picture information +* pstForeGroundRect: the foreground picture operation region +* pstMask: mask picture information +* pstMaskRect: operating region of the mask picture +* pstDst: the destination picture information +* pstDstRect: the destination picture operation region +* u8Alpha: global alpha value during alpha blending +* enBlendMode: alpha blending mode +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_BitmapMaskBlend(TDE_HANDLE s32Handle, + TDE2_SURFACE_S* pstBackGround, TDE2_RECT_S *pstBackGroundRect, + TDE2_SURFACE_S* pstForeGround, TDE2_RECT_S *pstForeGroundRect, + TDE2_SURFACE_S* pstMask, TDE2_RECT_S *pstMaskRect, + TDE2_SURFACE_S* pstDst, TDE2_RECT_S *pstDstRect, + HI_U8 u8Alpha, TDE2_ALUCMD_E enBlendMode); + + + +/***************************************************************************** +* Function: HI_TDE2_SetDeflickerLevel +* Description: To set the anti-flicker level +* Input: enDeflickerLevel: anti-flicker level +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_SetDeflickerLevel(TDE_DEFLICKER_LEVEL_E enDeflickerLevel); + +/***************************************************************************** +* Function: HI_TDE2_GetDeflickerLevel +* Description: To get the anti-flicker level +* Input: pDeflickerLevel: to save the anti-flicker level +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_GetDeflickerLevel(TDE_DEFLICKER_LEVEL_E *pDeflickerLevel); + +/***************************************************************************** +* Function: HI_TDE2_SetAlphaThresholdValue +* Description: To set the anti-flicker level +* Input: u8ThresholdValue: Alpha threshold +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_SetAlphaThresholdValue(HI_U8 u8ThresholdValue); + +/***************************************************************************** +* Function: HI_TDE2_GetAlphaThresholdValue +* Description: To get the anti-flicker level +* Input: pu8ThresholdValue: to save the alpha threshold +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_GetAlphaThresholdValue(HI_U8 *pu8ThresholdValue); + +/***************************************************************************** +* Function: HI_TDE2_GetAlphaThresholdValue +* Description: To enable or disable alpha judgment +* Input: bEnAlphaThreshold: whether to enable alpha judgment +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_SetAlphaThresholdState(HI_BOOL bEnAlphaThreshold); + +/***************************************************************************** +* Function: HI_TDE2_GetAlphaThresholdState +* Description: To get alpha judgment state +* Input: p_bEnAlphaThreshold: To save the alpha judgment state +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_GetAlphaThresholdState(HI_BOOL * p_bEnAlphaThreshold); + +/***************************************************************************** +* Function: HI_TDE2_PatternFill +* Description: Pattern fill +Input: s32Handle: job handle +* pstBackGround: the background picture information +* pstBackGroundRect: the background picture operation region +* pstForeGround: the foreground picture information +* pstForeGroundRect: the foreground picture operation region +* pstDst: the destination picture information +* pstDstRect: the destination picture operation region +* pstOpt: operation parameter settings +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_PatternFill(TDE_HANDLE s32Handle, TDE2_SURFACE_S *pstBackGround, + TDE2_RECT_S *pstBackGroundRect, TDE2_SURFACE_S *pstForeGround, + TDE2_RECT_S *pstForeGroundRect, TDE2_SURFACE_S *pstDst, + TDE2_RECT_S *pstDstRect, TDE2_PATTERN_FILL_OPT_S *pstOpt); + +/***************************************************************************** +* Function: HI_TDE2_EnableRegionDeflicker +* Description: To enable or disable the regional anti-flicker function +* Input: bRegionDeflicker: enable flag +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_EnableRegionDeflicker(HI_BOOL bRegionDeflicker); +/***************************************************************************** +* Function: HI_TDE2_MultiBlending +* Description: multi blend surface by surface list +* Input: s32Handle: job handle + pstSurfaceList: composed surface list +* Output: None +* Return: Success / Error code +* Others: None +*****************************************************************************/ +HI_S32 HI_TDE2_MultiBlending(TDE_HANDLE s32Handle, TDE_SURFACE_LIST_S *pstSurfaceList); + + +#ifdef __cplusplus + #if __cplusplus +} + #endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _HI_API_TDE2_H_ */ diff --git a/snes9x/unix/mpp/hi_tde_errcode.h b/snes9x/unix/mpp/hi_tde_errcode.h new file mode 100644 index 0000000..f67acf4 --- /dev/null +++ b/snes9x/unix/mpp/hi_tde_errcode.h @@ -0,0 +1,55 @@ +/****************************************************************************** + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + ****************************************************************************** + File Name : tde_errcode.h +Version : Initial Draft +Author : Hisilicon multimedia software group +Created : 2005/4/23 +Last Modified : +Description : err code define +Function List : +History : May modify the code to errcode.h FOR hi3110 + ******************************************************************************/ +#ifndef __TDE_ERRCODE_H__ +#define __TDE_ERRCODE_H__ + +//#include "hi_debug.h" +#include "hi_type.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +//#define HI_ID_TDE 100 +/* tde start err no. */ +#define HI_ERR_TDE_BASE ((HI_S32)( ((0x80UL + 0x20UL)<<24) | (100 << 16 ) | (4 << 13) | 1 )) + +enum +{ + HI_ERR_TDE_DEV_NOT_OPEN = HI_ERR_TDE_BASE, /**< tde device not open yet */ + HI_ERR_TDE_DEV_OPEN_FAILED, /**< open tde device failed */ + HI_ERR_TDE_NULL_PTR, /**< input parameters contain null ptr */ + HI_ERR_TDE_NO_MEM, /**< malloc failed */ + HI_ERR_TDE_INVALID_HANDLE, /**< invalid job handle */ + HI_ERR_TDE_INVALID_PARA, /**< invalid parameter */ + HI_ERR_TDE_NOT_ALIGNED, /**< aligned error for position, stride, width */ + HI_ERR_TDE_MINIFICATION, /**< invalid minification */ + HI_ERR_TDE_CLIP_AREA, /**< clip area and operation area have no intersection */ + HI_ERR_TDE_JOB_TIMEOUT, /**< blocked job wait timeout */ + HI_ERR_TDE_UNSUPPORTED_OPERATION, /**< unsupported operation */ + HI_ERR_TDE_QUERY_TIMEOUT, /**< query time out */ + HI_ERR_TDE_INTERRUPT /**< blocked job was interrupted */ +}; + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __TDE_ERRCODE_H__*/ + + diff --git a/snes9x/unix/mpp/hi_tde_type.h b/snes9x/unix/mpp/hi_tde_type.h new file mode 100644 index 0000000..7d7ee3a --- /dev/null +++ b/snes9x/unix/mpp/hi_tde_type.h @@ -0,0 +1,512 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Huawei Tech. Co., Ltd. + + ****************************************************************************** + File Name : tde_type.h +Version : Initial Draft +Author : w54130 +Created : 2007/5/21 +Last Modified : +Description : TDE public type +Function List : +History : +1.Date : 2007/5/21 +Author : w54130 +Modification: Created file + + ******************************************************************************/ +#ifndef __TDE_TYPE_H__ +#define __TDE_TYPE_H__ + + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#include "hi_tde_errcode.h" + +/****************************************************************************/ +/* TDE2 types define */ +/****************************************************************************/ +/** TDE handle */ +typedef HI_S32 TDE_HANDLE; + +/** TDE callback */ +typedef HI_VOID (* TDE_FUNC_CB) (HI_VOID *pParaml, HI_VOID *pParamr); + + +/* color format */ +typedef enum hiTDE2_COLOR_FMT_E +{ + TDE2_COLOR_FMT_RGB444 = 0, /**< RGB444 format */ + TDE2_COLOR_FMT_BGR444, /**< BGR444 format */ + TDE2_COLOR_FMT_RGB555, /**< RGB555 format */ + TDE2_COLOR_FMT_BGR555, /**< BGR555 format */ + TDE2_COLOR_FMT_RGB565, /**< RGB565 format */ + TDE2_COLOR_FMT_BGR565, /**< BGR565 format */ + TDE2_COLOR_FMT_RGB888, /**< RGB888 format */ + TDE2_COLOR_FMT_BGR888, /**< BGR888 format */ + TDE2_COLOR_FMT_ARGB4444, /**< ARGB4444 format */ + TDE2_COLOR_FMT_ABGR4444, /**< ABGR4444 format */ + TDE2_COLOR_FMT_RGBA4444, /**< RGBA4444 format */ + TDE2_COLOR_FMT_BGRA4444, /**< BGRA4444 format */ + TDE2_COLOR_FMT_ARGB1555, /**< ARGB1555 format */ + TDE2_COLOR_FMT_ABGR1555, /**< ABGR1555 format */ + TDE2_COLOR_FMT_RGBA1555, /**< RGBA1555 format */ + TDE2_COLOR_FMT_BGRA1555, /**< BGRA1555 format */ + TDE2_COLOR_FMT_ARGB8565, /**< ARGB8565 format */ + TDE2_COLOR_FMT_ABGR8565, /**< ABGR8565 format */ + TDE2_COLOR_FMT_RGBA8565, /**< RGBA8565 format */ + TDE2_COLOR_FMT_BGRA8565, /**< BGRA8565 format */ + TDE2_COLOR_FMT_ARGB8888, /**< ARGB8888 format */ + TDE2_COLOR_FMT_ABGR8888, /**< ABGR8888 format */ + TDE2_COLOR_FMT_RGBA8888, /**< RGBA8888 format */ + TDE2_COLOR_FMT_BGRA8888, /**< BGRA8888 format */ + TDE2_COLOR_FMT_RABG8888, /** +/*************************** Structure Definition ****************************/ + +#define IOC_TYPE_HIFB 'F' +/** To obtain the colorkey of an overlay layer */ +#define FBIOGET_COLORKEY_HIFB _IOR(IOC_TYPE_HIFB, 90, HIFB_COLORKEY_S) +/** To set the colorkey of an overlay layer */ +#define FBIOPUT_COLORKEY_HIFB _IOW(IOC_TYPE_HIFB, 91, HIFB_COLORKEY_S) +/** To get the alpha of an overlay layer */ +#define FBIOGET_ALPHA_HIFB _IOR(IOC_TYPE_HIFB, 92, HIFB_ALPHA_S) +/** To set the alpha of an overlay layer */ +#define FBIOPUT_ALPHA_HIFB _IOW(IOC_TYPE_HIFB, 93, HIFB_ALPHA_S) +/** To get the origin of an overlay layer on the screen */ +#define FBIOGET_SCREEN_ORIGIN_HIFB _IOR(IOC_TYPE_HIFB, 94, HIFB_POINT_S) +/** To set the origin of an overlay layer on the screen */ +#define FBIOPUT_SCREEN_ORIGIN_HIFB _IOW(IOC_TYPE_HIFB, 95, HIFB_POINT_S) +/** To obtain the anti-flicker setting of an overlay layer */ +#define FBIOGET_DEFLICKER_HIFB _IOR(IOC_TYPE_HIFB, 98, HIFB_DEFLICKER_S) +/** To set the anti-flicker setting of an overlay layer */ +#define FBIOPUT_DEFLICKER_HIFB _IOW(IOC_TYPE_HIFB, 99, HIFB_DEFLICKER_S) +/** To wait for the vertical blanking region of an overlay layer */ +#define FBIOGET_VBLANK_HIFB _IO(IOC_TYPE_HIFB, 100) +/** To set the display state of an overlay layer */ +#define FBIOPUT_SHOW_HIFB _IOW(IOC_TYPE_HIFB, 101, HI_BOOL) +/** To obtain the display state of an overlay layer */ +#define FBIOGET_SHOW_HIFB _IOR(IOC_TYPE_HIFB, 102, HI_BOOL) +/** to obtain the capability of an overlay layer */ +#define FBIOGET_CAPABILITY_HIFB _IOR(IOC_TYPE_HIFB, 103, HIFB_CAPABILITY_S) +/** set the screen output size */ +#define FBIOPUT_SCREENSIZE _IOW(IOC_TYPE_HIFB, 130, HIFB_SIZE_S*) +/** get the screen output size */ +#define FBIOGET_SCREENSIZE _IOR(IOC_TYPE_HIFB, 131, HIFB_SIZE_S*) + +/** To display multiple surfaces in turn and set the alpha and colorkey attributes */ +#define FBIOFLIP_SURFACE _IOW(IOC_TYPE_HIFB, 132, HIFB_SURFACEEX_S) + +/**To set the compression function status of an overlay layer*/ +#define FBIOPUT_COMPRESSION_HIFB _IOW(IOC_TYPE_HIFB, 133, HI_BOOL) +/**To obtain the compression function status of an overlay layer*/ +#define FBIOGET_COMPRESSION_HIFB _IOR(IOC_TYPE_HIFB, 134, HI_BOOL) + + +typedef struct +{ + HI_U32 u32Width; + HI_U32 u32Height; +}HIFB_SIZE_S; + +static inline HI_U8 hifb_rgb(const struct fb_bitfield* pBit, HI_S32 color) +{ + return ((HI_U8)((((HI_U32)color)>>pBit->offset) << (8-pBit->length)) + + ((HI_U8)(((HI_U32)(color)>>pBit->offset) << (8-pBit->length)) >> pBit->length)); +} + +static inline HI_S32 hifb_color2key(const struct fb_var_screeninfo* pVar, HI_S32 color) +{ + if (pVar->bits_per_pixel <= 8) + { + return color; + } + else + { + HI_U8 r, g, b; + r = hifb_rgb(&pVar->red, color); + g = hifb_rgb(&pVar->green, color); + b = hifb_rgb(&pVar->blue, color); + return (r<<16) + (g<<8) + b; + } +} + +typedef struct +{ + HI_BOOL bKeyEnable; /* colorkey enable flag */ + HI_U32 u32Key; /* colorkey value, maybe contains alpha */ +}HIFB_COLORKEY_S; + +typedef struct +{ + HI_S32 x; + HI_S32 y; + HI_S32 w; + HI_S32 h; +} HIFB_RECT; + +typedef struct +{ + HI_S32 s32XPos; /**< horizontal position */ + HI_S32 s32YPos; /**< vertical position */ +}HIFB_POINT_S; + +typedef struct hiHIFB_DEFLICKER_S +{ + HI_U32 u32HDfLevel; /**< horizontal deflicker level */ + HI_U32 u32VDfLevel; /**< vertical deflicker level */ + HI_U8 *pu8HDfCoef; /**< horizontal deflicker coefficient */ + HI_U8 *pu8VDfCoef; /**< vertical deflicker coefficient */ +}HIFB_DEFLICKER_S; + +/** Alpha info */ +typedef struct +{ + HI_BOOL bAlphaEnable; /**< alpha enable flag */ + HI_BOOL bAlphaChannel; /**< alpha channel enable flag */ + HI_U8 u8Alpha0; /**< alpha0 value, used in ARGB1555 */ + HI_U8 u8Alpha1; /**< alpha1 value, used in ARGB1555 */ + HI_U8 u8GlobalAlpha; /**< global alpha value */ + HI_U8 u8Reserved; +}HIFB_ALPHA_S; + +typedef enum +{ + HIFB_FMT_RGB565 = 0, + HIFB_FMT_RGB888, /**< RGB888 24bpp */ + + HIFB_FMT_KRGB444, /**< RGB444 16bpp */ + HIFB_FMT_KRGB555, /**< RGB555 16bpp */ + HIFB_FMT_KRGB888, /**< RGB888 32bpp */ + + HIFB_FMT_ARGB4444, /**< ARGB4444 */ + HIFB_FMT_ARGB1555, /**< ARGB1555 */ + HIFB_FMT_ARGB8888, /**< ARGB8888 */ + HIFB_FMT_ARGB8565, /**< ARGB8565 */ + + HIFB_FMT_RGBA4444, /**< ARGB4444 */ + HIFB_FMT_RGBA5551, /**< RGBA5551 */ + HIFB_FMT_RGBA5658, /**< RGBA5658 */ + HIFB_FMT_RGBA8888, /**< RGBA8888 */ + + HIFB_FMT_BGR565, /**< BGR565 */ + HIFB_FMT_BGR888, /**< BGR888 */ + HIFB_FMT_ABGR4444, /**< ABGR4444 */ + HIFB_FMT_ABGR1555, /**< ABGR1555 */ + HIFB_FMT_ABGR8888, /**< ABGR8888 */ + HIFB_FMT_ABGR8565, /**< ABGR8565 */ + HIFB_FMT_KBGR444, /**< BGR444 16bpp */ + HIFB_FMT_KBGR555, /**< BGR555 16bpp */ + HIFB_FMT_KBGR888, /**< BGR888 32bpp */ + + HIFB_FMT_1BPP, /**< clut1 */ + HIFB_FMT_2BPP, /**< clut2 */ + HIFB_FMT_4BPP, /**< clut4 */ + HIFB_FMT_8BPP, /**< clut8 */ + HIFB_FMT_ACLUT44, /**< AClUT44*/ + HIFB_FMT_ACLUT88, /**< ACLUT88 */ + HIFB_FMT_PUYVY, /**< UYVY */ + HIFB_FMT_PYUYV, /**< YUYV */ + HIFB_FMT_PYVYU, /**< YVYU */ + HIFB_FMT_YUV888, /**< YUV888 */ + HIFB_FMT_AYUV8888, /**< AYUV8888 */ + HIFB_FMT_YUVA8888, /**< YUVA8888 */ + HIFB_FMT_BUTT +}HIFB_COLOR_FMT_E; + +typedef struct +{ + HI_BOOL bKeyRgb; + HI_BOOL bKeyAlpha; /**< whether support colorkey alpha */ + HI_BOOL bGlobalAlpha; /**< whether support global alpha */ + HI_BOOL bCmap; /**< whether support color map */ + HI_BOOL bHasCmapReg; /**< whether has color map register*/ + HI_BOOL bColFmt[HIFB_FMT_BUTT]; /**< support which color format */ + HI_BOOL bVoScale; /**< support vo scale*/ + HI_BOOL bLayerSupported; /**< whether support a certain layer, for example:x5 HD support HIFB_SD_0 not support HIFB_SD_1*/ + HI_U32 u32MaxWidth; /**< the max pixels per line */ + HI_U32 u32MaxHeight; /**< the max lines */ + HI_U32 u32MinWidth; /**< the min pixels per line */ + HI_U32 u32MinHeight; /**< the min lines */ + HI_U32 u32VDefLevel; /**< vertical deflicker level, 0 means vertical deflicker is unsupported */ + HI_U32 u32HDefLevel; /**< horizontal deflicker level, 0 means horizontal deflicker is unsupported */ + HI_BOOL bDcmp; + HI_BOOL bPreMul; +}HIFB_CAPABILITY_S; + +/*refresh mode*/ +typedef enum +{ + HIFB_LAYER_BUF_DOUBLE = 0x0, /**< 2 display buf in fb */ + HIFB_LAYER_BUF_ONE = 0x1, /**< 1 display buf in fb */ + HIFB_LAYER_BUF_NONE = 0x2, /**< no display buf in fb,the buf user refreshed will be directly set to VO*/ + HIFB_LAYER_BUF_DOUBLE_IMMEDIATE=0x3, /**< 2 display buf in fb, each refresh will be displayed*/ + HIFB_LAYER_BUF_BUTT +} HIFB_LAYER_BUF_E; + +/* surface info */ +typedef struct +{ + HI_U32 u32PhyAddr; /**< start physical address */ + HI_U32 u32Width; /**< width pixels */ + HI_U32 u32Height; /**< height pixels */ + HI_U32 u32Pitch; /**< line pixels */ + HIFB_COLOR_FMT_E enFmt; /**< color format */ +}HIFB_SURFACE_S; + +typedef struct +{ + HI_U32 u32PhyAddr; + HIFB_ALPHA_S stAlpha; + HIFB_COLORKEY_S stColorkey; +}HIFB_SURFACEEX_S; + +/* refresh surface info */ +typedef struct +{ + HIFB_SURFACE_S stCanvas; + HIFB_RECT UpdateRect; /* refresh region*/ +}HIFB_BUFFER_S; + +/* cursor info */ +typedef struct +{ + HIFB_SURFACE_S stCursor; + HIFB_POINT_S stHotPos; +} HIFB_CURSOR_S; + +/* DDR detect zone info */ +typedef struct +{ + HI_U32 u32StartSection; + HI_U32 u32ZoneNums; +} HIFB_DDRZONE_S; + +/* crusor handle */ +/* Attention:surface in cursor will be released by user*/ +#define FBIOPUT_CURSOR_INFO _IOW(IOC_TYPE_HIFB, 104, HIFB_CURSOR_S *) +#define FBIOGET_CURSOR_INFO _IOW(IOC_TYPE_HIFB, 105, HIFB_CURSOR_S *) + +#define FBIOPUT_CURSOR_STATE _IOW(IOC_TYPE_HIFB, 106, HI_BOOL *) +#define FBIOGET_CURSOR_STATE _IOW(IOC_TYPE_HIFB, 107, HI_BOOL *) + +#define FBIOPUT_CURSOR_POS _IOW(IOC_TYPE_HIFB, 108, HIFB_POINT_S *) +#define FBIOGET_CURSOR_POS _IOR(IOC_TYPE_HIFB, 109, HIFB_POINT_S *) + +#define FBIOPUT_CURSOR_COLORKEY _IOR(IOC_TYPE_HIFB, 110, HIFB_COLORKEY_S *) +#define FBIOGET_CURSOR_COLORKEY _IOW(IOC_TYPE_HIFB, 111, HIFB_COLORKEY_S *) +#define FBIOPUT_CURSOR_ALPHA _IOR(IOC_TYPE_HIFB, 112, HIFB_ALPHA_S *) +#define FBIOGET_CURSOR_ALPHA _IOW(IOC_TYPE_HIFB, 113, HIFB_ALPHA_S *) + +/** cursor will be separated from attached layer automatically if you attach cursor to another layer,that means +cursor can be attached to only one layer at any time*/ +#define FBIOPUT_CURSOR_ATTCHCURSOR _IOW(IOC_TYPE_HIFB, 114, HI_U32 *) +#define FBIOPUT_CURSOR_DETACHCURSOR _IOW(IOC_TYPE_HIFB, 115, HI_U32 *) + +/**antiflicker level*/ +/**Auto means fb will choose a appropriate antiflicker level automatically according to the color info of map*/ +typedef enum +{ + HIFB_LAYER_ANTIFLICKER_NONE = 0x0, /**< no antiflicker*/ + HIFB_LAYER_ANTIFLICKER_LOW = 0x1, /**< low level*/ + HIFB_LAYER_ANTIFLICKER_MIDDLE = 0x2,/**< middle level*/ + HIFB_LAYER_ANTIFLICKER_HIGH = 0x3, /**< high level*/ + HIFB_LAYER_ANTIFLICKER_AUTO = 0x4, /**< auto*/ + HIFB_LAYER_ANTIFLICKER_BUTT +}HIFB_LAYER_ANTIFLICKER_LEVEL_E; + +/*layer info maskbit*/ +typedef enum +{ + HIFB_LAYERMASK_BUFMODE = 0x1, /**< BUFMODE bitmask */ + HIFB_LAYERMASK_ANTIFLICKER_MODE = 0x2, /**< ANTIFLICKER_MODE bitmask */ + HIFB_LAYERMASK_POS = 0x4, /**< the position bitmask */ + HIFB_LAYERMASK_CANVASSIZE = 0x8, /**< canvassize bitmask */ + HIFB_LAYERMASK_DISPSIZE = 0x10, /**< displaysize bitmask */ + HIFB_LAYERMASK_SCREENSIZE = 0x20, /**< screensize bitmask */ + HIFB_LAYERMASK_BMUL = 0x40, /**< pre-mult bitmask */ + HIFB_LAYERMASK_BUTT +}HIFB_LAYER_INFO_MASKBIT; + +/**layer info*/ +typedef struct +{ + HIFB_LAYER_BUF_E BufMode; + HIFB_LAYER_ANTIFLICKER_LEVEL_E eAntiflickerLevel; + HI_S32 s32XPos; /**< the x pos of origion point in screen */ + HI_S32 s32YPos; /**< the y pos of origion point in screen */ + HI_S32 u32CanvasWidth; /**< the width of canvas buffer */ + HI_S32 u32CanvasHeight; /**< the height of canvas buffer */ + HI_U32 u32DisplayWidth; /**< the width of display buf in fb.for 0 buf ,there is no display buf in fb, so it's effectless*/ + HI_U32 u32DisplayHeight; /**< the height of display buf in fb. */ + HI_U32 u32ScreenWidth; /**< the width of screen */ + HI_U32 u32ScreenHeight; /**< the height of screen */ + HI_BOOL bPreMul; /**< The data drawed in buf is premul data or not*/ + HI_U32 u32Mask; /**< param modify mask bit*/ +}HIFB_LAYER_INFO_S; + +/** To set the layer information */ +#define FBIOPUT_LAYER_INFO _IOW(IOC_TYPE_HIFB, 120, HIFB_LAYER_INFO_S*) +/** To get the layer information */ +#define FBIOGET_LAYER_INFO _IOR(IOC_TYPE_HIFB, 121, HIFB_LAYER_INFO_S*) +/** To get canvas buf */ +#define FBIOGET_CANVAS_BUFFER _IOR(IOC_TYPE_HIFB, 123, HIFB_BUFFER_S*) +/** To refresh the displayed contents in extended mode */ +#define FBIO_REFRESH _IOW(IOC_TYPE_HIFB, 124, HIFB_BUFFER_S*) + +/**sync refresh*/ +#define FBIO_WAITFOR_FREFRESH_DONE _IO(IOC_TYPE_HIFB, 125) + +/**To set the DDR detect zone of an overlay layer*/ +#define FBIOPUT_MDDRDETECT_HIFB _IOW(IOC_TYPE_HIFB, 135, HIFB_DDRZONE_S*) +/**To get the DDR detect zone of an overlay layer*/ +#define FBIOGET_MDDRDETECT_HIFB _IOW(IOC_TYPE_HIFB, 136, HIFB_DDRZONE_S*) + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + + +#endif /* __HIFB_H__ */ + diff --git a/snes9x/unix/mpp/ivs_md.h b/snes9x/unix/mpp/ivs_md.h new file mode 100644 index 0000000..b625177 --- /dev/null +++ b/snes9x/unix/mpp/ivs_md.h @@ -0,0 +1,164 @@ +/****************************************************************************** + + Copyright (C), 2001-2014, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : ivs_md.h + Version : Initial Draft + Author : Hisilicon multimedia software (IVE) group + Created : 2014/11/10 + Description : + History : + 1.Date : 2014/11/10 + Author : c00211359 + Modification: Created file +******************************************************************************/ + +#ifndef _HI_IVS_MD_H_ +#define _HI_IVS_MD_H_ + +#include "hi_md.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +/***************************************************************************** +* Prototype : HI_IVS_MD_Init +* Description : Motion Detection(MD) initialization. +* Parameters : HI_VOID. +* +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_Init(HI_VOID); + +/***************************************************************************** +* Prototype : HI_IVS_MD_Exit +* Description : Motion Detection(MD) exit. +* Parameters : HI_VOID. +* +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_Exit(HI_VOID); + +/***************************************************************************** +* Prototype : HI_IVS_MD_CreateChn +* Description : Create Motion Detection(MD) Chn. +* Parameters : MD_CHN MdChn Md chn. +* MD_ATTR_S *pstMdAttr Md attribute parameters +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_CreateChn(MD_CHN MdChn,MD_ATTR_S *pstMdAttr); + +/***************************************************************************** +* Prototype : HI_IVS_MD_DestroyChn +* Description : Destroy Motion Detection(MD) chn. +* Parameters : MD_CHN MdChn Md chn that would be destroy. +* +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_DestroyChn(MD_CHN MdChn); + +/***************************************************************************** +* Prototype : HI_IVS_MD_SetChnAttr +* Description : Set Motion Detection(MD) chn attribute. +* Parameters : MD_CHN MdChn Md chn. +* MD_ATTR_S *pstMdAttr Md attribute parameters +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2015/04/10 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_SetChnAttr(MD_CHN MdChn,MD_ATTR_S *pstMdAttr); + +/***************************************************************************** +* Prototype : HI_IVS_MD_GetChnAttr +* Description : Get Motion Detection(MD) chn attribute. +* Parameters : MD_CHN MdChn Md chn. +* MD_ATTR_S *pstMdAttr Md attribute parameters +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2015/04/10 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_GetChnAttr(MD_CHN MdChn,MD_ATTR_S *pstMdAttr); + +/***************************************************************************** +* Prototype : HI_IVS_MD_GetBg +* Description : Get Motion Detection(MD) background image. +* Parameters : MD_CHN MdChn Md chn. +* IVE_DST_IMAGE_S *pstBg Output background image +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_GetBg(MD_CHN MdChn,IVE_DST_IMAGE_S *pstBg); + +/***************************************************************************** +* Prototype : HI_IVS_MD_Process +* Description : Motion Detection(MD) process. +* Parameters : MD_CHN MdChn Md chn. +* IVE_SRC_IMAGE_S *pstCur Current image +* IVE_SRC_IMAGE_S *pstRef Reference image +* IVE_DST_MEM_INFO_S *pstBlob Output blob +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014/11/11 +* Author : Chen Quanfu +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_IVS_MD_Process(MD_CHN MdChn,IVE_SRC_IMAGE_S *pstCur, + IVE_SRC_IMAGE_S *pstRef,IVE_DST_MEM_INFO_S *pstBlob); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif/*_HI_IVS_MD_H_*/ \ No newline at end of file diff --git a/snes9x/unix/mpp/jconfig.h b/snes9x/unix/mpp/jconfig.h new file mode 100644 index 0000000..9594ec5 --- /dev/null +++ b/snes9x/unix/mpp/jconfig.h @@ -0,0 +1,45 @@ +/* jconfig.h. Generated automatically by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#define INLINE __inline__ +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/snes9x/unix/mpp/jerror.h b/snes9x/unix/mpp/jerror.h new file mode 100644 index 0000000..e210687 --- /dev/null +++ b/snes9x/unix/mpp/jerror.h @@ -0,0 +1,451 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + + +#ifdef HI_ADVCA_FUNCTION_RELEASE +/** ¸ß°²°æ±¾²»ÄÜÓе÷ÊÔ×Ö·û´® **/ +JMESSAGE(JMSG_NOMESSAGE, "") +JMESSAGE(JERR_ARITH_NOTIMPL, "") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "") +JMESSAGE(JERR_BAD_BUFFER_MODE, "") +JMESSAGE(JERR_BAD_COMPONENT_ID, "") +JMESSAGE(JERR_BAD_DCT_COEF, "") +JMESSAGE(JERR_BAD_DCTSIZE, "") +JMESSAGE(JERR_BAD_HUFF_TABLE, "") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "") +JMESSAGE(JERR_BAD_J_COLORSPACE, "") +JMESSAGE(JERR_BAD_LENGTH, "") +JMESSAGE(JERR_BAD_LIB_VERSION, "") +JMESSAGE(JERR_BAD_MCU_SIZE, "") +JMESSAGE(JERR_BAD_POOL_ID, "") +JMESSAGE(JERR_BAD_PRECISION, "") +JMESSAGE(JERR_BAD_PROGRESSION, "") +JMESSAGE(JERR_BAD_PROG_SCRIPT, "") +JMESSAGE(JERR_BAD_SAMPLING, "") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "") +JMESSAGE(JERR_BAD_STATE, "") +JMESSAGE(JERR_BAD_STRUCT_SIZE, "") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "") +JMESSAGE(JERR_BUFFER_SIZE, "") +JMESSAGE(JERR_CANT_SUSPEND, "") +JMESSAGE(JERR_CCIR601_NOTIMPL, "") +JMESSAGE(JERR_COMPONENT_COUNT, "") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "") +JMESSAGE(JERR_DAC_INDEX, "") +JMESSAGE(JERR_DAC_VALUE, "") +JMESSAGE(JERR_DHT_INDEX, "") +JMESSAGE(JERR_DQT_INDEX, "") +JMESSAGE(JERR_EMPTY_IMAGE, "") +JMESSAGE(JERR_EMS_READ, "") +JMESSAGE(JERR_EMS_WRITE, "") +JMESSAGE(JERR_EOI_EXPECTED, "") +JMESSAGE(JERR_FILE_READ, "") +JMESSAGE(JERR_FILE_WRITE, "") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL,"") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "") +JMESSAGE(JERR_HUFF_MISSING_CODE, "") +JMESSAGE(JERR_IMAGE_TOO_BIG, "") +JMESSAGE(JERR_INPUT_EMPTY, "") +JMESSAGE(JERR_INPUT_EOF, "") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,"") +JMESSAGE(JERR_MISSING_DATA, "") +JMESSAGE(JERR_MODE_CHANGE, "") +JMESSAGE(JERR_NOTIMPL, "") +JMESSAGE(JERR_NOT_COMPILED, "") +JMESSAGE(JERR_NO_BACKING_STORE, "") +JMESSAGE(JERR_NO_HUFF_TABLE, "") +JMESSAGE(JERR_NO_IMAGE, "") +JMESSAGE(JERR_NO_QUANT_TABLE, "") +JMESSAGE(JERR_NO_SOI, "") +JMESSAGE(JERR_OUT_OF_MEMORY, "") +JMESSAGE(JERR_QUANT_COMPONENTS, "") +JMESSAGE(JERR_QUANT_FEW_COLORS, "") +JMESSAGE(JERR_QUANT_MANY_COLORS, "") +JMESSAGE(JERR_SOF_DUPLICATE, "") +JMESSAGE(JERR_SOF_NO_SOS, "") +JMESSAGE(JERR_SOF_UNSUPPORTED, "") +JMESSAGE(JERR_SOI_DUPLICATE, "") +JMESSAGE(JERR_SOS_NO_SOF, "") +JMESSAGE(JERR_TFILE_CREATE, "") +JMESSAGE(JERR_TFILE_READ, "") +JMESSAGE(JERR_TFILE_SEEK, "") +JMESSAGE(JERR_TFILE_WRITE, "") +JMESSAGE(JERR_TOO_LITTLE_DATA, "") +JMESSAGE(JERR_UNKNOWN_MARKER, "") +JMESSAGE(JERR_VIRTUAL_BUG, "") +JMESSAGE(JERR_WIDTH_OVERFLOW, "") +JMESSAGE(JERR_XMS_READ, "") +JMESSAGE(JERR_XMS_WRITE, "") +JMESSAGE(JMSG_COPYRIGHT, "") +JMESSAGE(JMSG_VERSION, "") +JMESSAGE(JTRC_16BIT_TABLES, "") +JMESSAGE(JTRC_ADOBE, "") +JMESSAGE(JTRC_APP0, "") +JMESSAGE(JTRC_APP14, "") +JMESSAGE(JTRC_DAC, "") +JMESSAGE(JTRC_DHT, "") +JMESSAGE(JTRC_DQT, "") +JMESSAGE(JTRC_DRI, "") +JMESSAGE(JTRC_EMS_CLOSE, "") +JMESSAGE(JTRC_EMS_OPEN, "") +JMESSAGE(JTRC_EOI, "") +JMESSAGE(JTRC_HUFFBITS, "") +JMESSAGE(JTRC_JFIF, "") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,"") +JMESSAGE(JTRC_JFIF_EXTENSION, "") +JMESSAGE(JTRC_JFIF_THUMBNAIL, "") +JMESSAGE(JTRC_MISC_MARKER, "") +JMESSAGE(JTRC_PARMLESS_MARKER, "") +JMESSAGE(JTRC_QUANTVALS, "") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "") +JMESSAGE(JTRC_QUANT_NCOLORS, "") +JMESSAGE(JTRC_QUANT_SELECTED, "") +JMESSAGE(JTRC_RECOVERY_ACTION, "") +JMESSAGE(JTRC_RST, "") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, "") +JMESSAGE(JTRC_SOF, "") +JMESSAGE(JTRC_SOF_COMPONENT, "") +JMESSAGE(JTRC_SOI, "") +JMESSAGE(JTRC_SOS, "") +JMESSAGE(JTRC_SOS_COMPONENT, "") +JMESSAGE(JTRC_SOS_PARAMS, "") +JMESSAGE(JTRC_TFILE_CLOSE, "") +JMESSAGE(JTRC_TFILE_OPEN, "") +JMESSAGE(JTRC_THUMB_JPEG, "") +JMESSAGE(JTRC_THUMB_PALETTE, "") +JMESSAGE(JTRC_THUMB_RGB, "") +JMESSAGE(JTRC_UNKNOWN_IDS, "") +JMESSAGE(JTRC_XMS_CLOSE, "") +JMESSAGE(JTRC_XMS_OPEN, "") +JMESSAGE(JWRN_ADOBE_XFORM, "") +JMESSAGE(JWRN_BOGUS_PROGRESSION, "") +JMESSAGE(JWRN_EXTRANEOUS_DATA, "") +JMESSAGE(JWRN_HIT_MARKER, "") +JMESSAGE(JWRN_HUFF_BAD_CODE, "") +JMESSAGE(JWRN_JFIF_MAJOR, "") +JMESSAGE(JWRN_JPEG_EOF, "") +JMESSAGE(JWRN_MUST_RESYNC, "") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "") +JMESSAGE(JWRN_TOO_MUCH_DATA, "") +/* add some error message by y00181162 */ +JMESSAGE(JERR_HDEC_INIT_FAILURE, "") +JMESSAGE(JERR_MMZ_STREAM_MEM_LACK, "") +JMESSAGE(JERR_MMZ_YUV_MEM_LACK, "") +JMESSAGE(JERR_MMZ_OUT_MEM_LACK, "") +JMESSAGE(JERR_CLIENT_DATA_ERR, "") +JMESSAGE(JWRN_IS_YCCK_CMYK_PIC, "") +JMESSAGE(JERR_STREAM_BACK_FAILURE, "") +JMESSAGE(JERR_HARD_CSC_FAILURE, "") +JMESSAGE(JERR_CROP_CANNOT_SUPPORT, "") + +JMESSAGE(JERR_HENC_INIT_FAILURE, "") +JMESSAGE(JERR_HENC_COLOR_NOSUPPORT, "") + +#else + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +/* add some error message by y00181162 */ +JMESSAGE(JERR_HDEC_INIT_FAILURE, "JPEG_HDEC_Init failure") +JMESSAGE(JERR_MMZ_STREAM_MEM_LACK, "lack of mem to alloc stream memory") +JMESSAGE(JERR_MMZ_YUV_MEM_LACK, "lack of mem to alloc yuv middle memory") +JMESSAGE(JERR_MMZ_OUT_MEM_LACK, "lack of mem to alloc output memory") +JMESSAGE(JERR_CLIENT_DATA_ERR, "the client data is different with our data") +JMESSAGE(JWRN_IS_YCCK_CMYK_PIC, "this picture is ycck or cmyk picture") +JMESSAGE(JERR_STREAM_BACK_FAILURE, "this stream back failure,no soft dec again") +JMESSAGE(JERR_HARD_CSC_FAILURE, "the hard color convert failure,so the dec failure") +JMESSAGE(JERR_CROP_CANNOT_SUPPORT, "can not support crop") + +JMESSAGE(JERR_HENC_INIT_FAILURE, "JPGE_HENC_Init failure") +JMESSAGE(JERR_HENC_COLOR_NOSUPPORT, "jpeg encode input colorspace is not support") + +#endif + + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/snes9x/unix/mpp/jmorecfg.h b/snes9x/unix/mpp/jmorecfg.h new file mode 100644 index 0000000..02e5dc4 --- /dev/null +++ b/snes9x/unix/mpp/jmorecfg.h @@ -0,0 +1,373 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +#define PACK_SHORT2_565(r,g,b) ((((r) >> 3) << 11)|(((g)>> 2) << 5)|(((b)>>3))) +#define PACK_SHORT_1555(a,r,g,b) (((a)<<15) | (((r) >> 3) << 10)|(((g)>> 3) << 5)|(((b)>>3))) +#define PACK_SHORT_565(r,g,b) ((((r)<<8)&0xf800)|(((g)<<3)&0x7E0)|((b)>>3)) +#define PACK_TWO_PIXELS(l,r) ((r<<16) | l) +#define PACK_NEED_ALIGNMENT(ptr) (((int)(ptr))&3) +#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32*)(addr)) = pixels) +#define DITHER_565_R(r, dither) ((r) + ((dither)&0xFF)) +#define DITHER_565_G(g, dither) ((g) + (((dither)&0xFF)>>1)) +#define DITHER_565_B(b, dither) ((b) + ((dither)&0xFF)) + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ +#define RGB_ALPHA 3 /* Offset of Alpha */ +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/snes9x/unix/mpp/jpeglib.h b/snes9x/unix/mpp/jpeglib.h new file mode 100644 index 0000000..325b904 --- /dev/null +++ b/snes9x/unix/mpp/jpeglib.h @@ -0,0 +1,1117 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /** error/unspecified **/ + JCS_GRAYSCALE, /** monochrome **/ + JCS_RGB, /** red/green/blue **/ + JCS_YCbCr, /** Y/Cb/Cr (also known as YUV) **/ + JCS_CMYK, /** C/M/Y/K **/ + JCS_YCCK, /** Y/Cb/Cr/K **/ + /** add color space output by y00181162 **/ + JCS_CrCbY, /** Y(8bits)/Cb(8bits)/Cr(8bits) (also known as YUV) **/ + JCS_BGR, /** red((at 16~24)8bits)/green((at 8~15)8bits)/blue((at 0~7)8bits) **/ + JCS_ABGR_8888, /** alpha((at 25~32)8bits)/red((at 16~24)8bits)/green((at 8~15)8bits)/blue((at 0~7)8bits) **/ + JCS_ARGB_8888, /** alpha((at 25~32)8bits)/blue((at 16~24)8bits)/green((at 8~15)8bits)/red((at 0~7)8bits) **/ + JCS_ABGR_1555, /** alpha((at 16)1bit)/red((at 10~15)5bits)/green((at 5~9)5bits)/blue((at 0~4)5bits) **/ + JCS_ARGB_1555, /** alpha((at 16)1bit)/blue((at 10~15)5bits)/green((at 5~9)5bits)/red((at 0~4)5bits) **/ + JCS_RGB_565, /** blue((at 11~16)5bits)/green((at 5~10)6bits)/red((at 0~4)5bits) **/ + JCS_BGR_565, /** red((at 11~16)5bits)/green((at 5~10)6bits)/blue((at 0~4)5bits) **/ + JCS_YUV400_SP, /** output color space yuv400 semi-planer **/ + JCS_YUV420_SP, /** output color space yuv420 semi-planer **/ + JCS_YUV422_SP_21, /** output color space yuv422 2*1 semi-planer **/ + JCS_YUV422_SP_12, /** output color space yuv422 1*2 semi-planer **/ + JCS_YUV444_SP, /** output color space yuv444 semi-planer **/ + JCS_YUV422_PACKAGE +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); + //JMETHOD(boolean, seek_input_data, (j_decompress_ptr cinfo, long byte_offset)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +/** add dec the stream by y00181162**/ +#define jpeg_mem_src jMemSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); +/** add dec the stream by y00181162**/ +EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo, + unsigned char * inbuffer, + unsigned long insize)); +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/snes9x/unix/mpp/list.h b/snes9x/unix/mpp/list.h new file mode 100644 index 0000000..4caf201 --- /dev/null +++ b/snes9x/unix/mpp/list.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) HighPoint Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/hptrr/list.h,v 1.2.2.1.4.1 2010/06/14 02:09:06 kensmith Exp $ + */ +/* + * $Id: list.h,v 1.6 2006/10/31 06:25:28 gmm Exp $ + * Copyright (C) 2004-2005 HighPoint Technologies, Inc. All rights reserved. + */ +#ifndef _HPT_LIST_H_ +#define _HPT_LIST_H_ + +#ifndef _LINUX_LIST_H + +#ifndef HPT_INLINE +#define HPT_INLINE __inline +#endif + +typedef unsigned long HPT_UPTR; + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { (ptr)->next = (ptr); (ptr)->prev = (ptr); } while (0) + +static HPT_INLINE void __list_add(struct list_head * _new, struct list_head * prev, struct list_head * next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +static HPT_INLINE void list_add(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head, head->next); +} + +static HPT_INLINE void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +static HPT_INLINE void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static HPT_INLINE void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static HPT_INLINE void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +static HPT_INLINE int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static HPT_INLINE void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +static HPT_INLINE void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +static HPT_INLINE void list_splice_init(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/*#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(HPT_UPTR)(&((type *)0)->member))) */ +#define list_entry(ptr, type, member) \ + ((type *)((unsigned long)(ptr)-((unsigned long)(&((type *)1)->member) - 1))) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define get_first_item(attached, type, member) \ + ((type *)((char *)((attached)->next)-(HPT_UPTR)(&((type *)0)->member))) + +#endif + +#endif diff --git a/snes9x/unix/mpp/mkp/mod_ext.h b/snes9x/unix/mpp/mkp/mod_ext.h new file mode 100644 index 0000000..6949fdb --- /dev/null +++ b/snes9x/unix/mpp/mkp/mod_ext.h @@ -0,0 +1,106 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi3511_ext.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2006/12/22 + Description : + History : + 1.Date : 2006/12/22 + Author : c42025 + Modification: Created file + + 2.Date : 2008/02/21 + Author : c42025 + Modification: add function CMPI_QueryModules, for solving AE6D02922 + + 3.Date : 2008/02/26 + Author : c42025 + Modification: Defect Form : AE6D02922, add two functions "FN_MOD_Notify" + and "FN_MOD_QueryState" . + + 4.Date : 2008/03/03 + Author : c42025 + Modification: add structure definition "MOD_NAME_S" + +******************************************************************************/ +#include +#include +#include +#include +#include + +#include "hi_type.h" +#include "hi_errno.h" + + +#ifndef __MOD_EXT_H__ +#define __MOD_EXT_H__ + +#define MAX_MPP_MODULES HI_ID_BUTT + +#define VERSION_MAGIC 20150804 + +#define MAX_MOD_NAME 16 + +typedef enum hiMOD_NOTICE_ID_E +{ + MOD_NOTICE_STOP = 0x11, +}MOD_NOTICE_ID_E; + +typedef enum hiMOD_STATE_E +{ + MOD_STATE_FREE = 0x11, + MOD_STATE_BUSY = 0X22, +}MOD_STATE_E; + +typedef HI_S32 FN_MOD_Init(HI_VOID *); +typedef HI_VOID FN_MOD_Exit(HI_VOID); +typedef HI_VOID FN_MOD_Notify(MOD_NOTICE_ID_E enNoticeId); +typedef HI_VOID FN_MOD_QueryState(MOD_STATE_E *pstState); +typedef HI_U32 FN_MOD_VerChecker(HI_VOID); + +typedef struct hiMPP_MODULE_S +{ + struct list_head list; + struct module *pstOwner; + + HI_CHAR aModName[MAX_MOD_NAME]; + MOD_ID_E enModId; + + FN_MOD_Init *pfnInit; + FN_MOD_Exit *pfnExit; + FN_MOD_QueryState *pfnQueryState; + FN_MOD_Notify *pfnNotify; + FN_MOD_VerChecker *pfnVerChecker; + + HI_BOOL bInited; + + HI_VOID *pstExportFuncs; + HI_VOID *pData; + + HI_CHAR *pVersion; +}UMAP_MODULE_S; + + +extern HI_CHAR *CMPI_GetModuleName(MOD_ID_E enModId); +extern UMAP_MODULE_S *CMPI_GetModuleById(MOD_ID_E enModId); +extern HI_VOID *CMPI_GetModuleFuncById(MOD_ID_E enModId); + +extern HI_VOID CMPI_StopModules(HI_VOID); +extern HI_S32 CMPI_QueryModules(HI_VOID); +extern HI_S32 CMPI_InitModules(HI_VOID); +extern HI_VOID CMPI_ExitModules(HI_VOID); +extern HI_S32 CMPI_RegisterModule(UMAP_MODULE_S *pstModules); +extern HI_VOID CMPI_UnRegisterModule(MOD_ID_E enModId); + +#define FUNC_ENTRY(type,id) ((type*)CMPI_GetModuleFuncById(id)) +#define CHECK_FUNC_ENTRY(id) (CMPI_GetModuleFuncById(id) != NULL) +#define FUNC_ENTRY_NULL(id) (!CHECK_FUNC_ENTRY(id)) + + +#endif /* __MOD_EXT_H__ */ + diff --git a/snes9x/unix/mpp/mpi_adec.h b/snes9x/unix/mpp/mpi_adec.h new file mode 100644 index 0000000..1cbec45 --- /dev/null +++ b/snes9x/unix/mpp/mpi_adec.h @@ -0,0 +1,53 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : ai.c + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/6/15 + Description : + History : + 1.Date : 2009/6/19 + Author : p00123320 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_ADEC_H__ +#define __MPI_ADEC_H__ + +#include "hi_common.h" +#include "hi_comm_aio.h" +#include "hi_comm_adec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +HI_S32 HI_MPI_ADEC_CreateChn(ADEC_CHN AdChn, ADEC_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_ADEC_DestroyChn(ADEC_CHN AdChn); + +HI_S32 HI_MPI_ADEC_SendStream(ADEC_CHN AdChn, const AUDIO_STREAM_S *pstStream, HI_BOOL bBlock); + +HI_S32 HI_MPI_ADEC_ClearChnBuf(ADEC_CHN AdChn); + +HI_S32 HI_MPI_ADEC_RegeisterDecoder(HI_S32 *ps32Handle, ADEC_DECODER_S *pstDecoder); +HI_S32 HI_MPI_ADEC_UnRegisterDecoder(HI_S32 s32Handle); + +HI_S32 HI_MPI_ADEC_GetFrame(ADEC_CHN AdChn, AUDIO_FRAME_INFO_S *pstFrmInfo, HI_BOOL bBlock); +HI_S32 HI_MPI_ADEC_ReleaseFrame(ADEC_CHN AdChn, AUDIO_FRAME_INFO_S *pstFrmInfo); +HI_S32 HI_MPI_ADEC_SendEndOfStream(ADEC_CHN AdChn, HI_BOOL bInstant); + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_ADEC_H__ */ + diff --git a/snes9x/unix/mpp/mpi_aenc.h b/snes9x/unix/mpp/mpi_aenc.h new file mode 100644 index 0000000..a6632da --- /dev/null +++ b/snes9x/unix/mpp/mpi_aenc.h @@ -0,0 +1,55 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : ai.c + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/6/15 + Description : + History : + 1.Date : 2009/6/15 + Author : p00123320 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_AENC_H__ +#define __MPI_AENC_H__ + +#include "hi_common.h" +#include "hi_comm_aio.h" +#include "hi_comm_aenc.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +#define AENC_ADAPT_MAGIC 0Xfcfcfcfc + +HI_S32 HI_MPI_AENC_CreateChn(AENC_CHN AeChn, const AENC_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_AENC_DestroyChn(AENC_CHN AeChn); + +HI_S32 HI_MPI_AENC_SendFrame(AENC_CHN AeChn, const AUDIO_FRAME_S *pstFrm, const AEC_FRAME_S *pstAecFrm); + +HI_S32 HI_MPI_AENC_GetStream(AENC_CHN AeChn, AUDIO_STREAM_S *pstStream, HI_S32 s32MilliSec); +HI_S32 HI_MPI_AENC_ReleaseStream(AENC_CHN AeChn, const AUDIO_STREAM_S *pstStream); + +HI_S32 HI_MPI_AENC_GetFd(AENC_CHN AeChn); + +HI_S32 HI_MPI_AENC_RegeisterEncoder(HI_S32 *ps32Handle, AENC_ENCODER_S *pstEncoder); +HI_S32 HI_MPI_AENC_UnRegisterEncoder(HI_S32 s32Handle); + +HI_S32 HI_MPI_AENC_SaveFile(AENC_CHN AeChn, AUDIO_SAVE_FILE_INFO_S *pstSaveFileInfo); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_AENC_H__ */ + diff --git a/snes9x/unix/mpp/mpi_ai.h b/snes9x/unix/mpp/mpi_ai.h new file mode 100644 index 0000000..709c368 --- /dev/null +++ b/snes9x/unix/mpp/mpi_ai.h @@ -0,0 +1,74 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_ai.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/5/5 + Description : + History : + 1.Date : 2009/5/5 + Author : p00123320 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_AI_H__ +#define __MPI_AI_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_aio.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +HI_S32 HI_MPI_AI_SetPubAttr(AUDIO_DEV AiDevId, const AIO_ATTR_S *pstAttr); +HI_S32 HI_MPI_AI_GetPubAttr(AUDIO_DEV AiDevId, AIO_ATTR_S *pstAttr); + +HI_S32 HI_MPI_AI_Enable(AUDIO_DEV AiDevId); +HI_S32 HI_MPI_AI_Disable(AUDIO_DEV AiDevId); + +HI_S32 HI_MPI_AI_EnableChn(AUDIO_DEV AiDevId, AI_CHN AiChn); +HI_S32 HI_MPI_AI_DisableChn(AUDIO_DEV AiDevId, AI_CHN AiChn); + +HI_S32 HI_MPI_AI_GetFrame(AUDIO_DEV AiDevId, AI_CHN AiChn, AUDIO_FRAME_S *pstFrm, AEC_FRAME_S *pstAecFrm, HI_S32 s32MilliSec); +HI_S32 HI_MPI_AI_ReleaseFrame(AUDIO_DEV AiDevId, AI_CHN AiChn, AUDIO_FRAME_S *pstFrm, AEC_FRAME_S *pstAecFrm); + +HI_S32 HI_MPI_AI_SetChnParam(AUDIO_DEV AiDevId, AI_CHN AiChn, AI_CHN_PARAM_S *pstChnParam); +HI_S32 HI_MPI_AI_GetChnParam(AUDIO_DEV AiDevId, AI_CHN AiChn, AI_CHN_PARAM_S *pstChnParam); + +HI_S32 HI_MPI_AI_SetVqeAttr(AUDIO_DEV AiDevId, AI_CHN AiChn, AUDIO_DEV AoDevId, AO_CHN AoChn, AI_VQE_CONFIG_S *pstVqeConfig); +HI_S32 HI_MPI_AI_GetVqeAttr(AUDIO_DEV AiDevId, AI_CHN AiChn, AI_VQE_CONFIG_S *pstVqeConfig); +HI_S32 HI_MPI_AI_EnableVqe(AUDIO_DEV AiDevId, AI_CHN AiChn); +HI_S32 HI_MPI_AI_DisableVqe(AUDIO_DEV AiDevId, AI_CHN AiChn); + +HI_S32 HI_MPI_AI_EnableReSmp(AUDIO_DEV AiDevId, AI_CHN AiChn, AUDIO_SAMPLE_RATE_E enOutSampleRate); +HI_S32 HI_MPI_AI_DisableReSmp(AUDIO_DEV AiDevId, AI_CHN AiChn); + +HI_S32 HI_MPI_AI_SetTrackMode(AUDIO_DEV AiDevId, AUDIO_TRACK_MODE_E enTrackMode); +HI_S32 HI_MPI_AI_GetTrackMode(AUDIO_DEV AiDevId, AUDIO_TRACK_MODE_E *penTrackMode); +HI_S32 HI_MPI_AI_SaveFile(AUDIO_DEV AiDevId, AI_CHN AiChn, AUDIO_SAVE_FILE_INFO_S *pstSaveFileInfo); + +HI_S32 HI_MPI_AI_ClrPubAttr(AUDIO_DEV AiDevId); + +HI_S32 HI_MPI_AI_GetFd(AUDIO_DEV AiDevId, AI_CHN AiChn); + +HI_S32 HI_MPI_AI_SetVqeVolume(AUDIO_DEV AiDevId, AI_CHN AiChn, HI_S32 s32VolumeDb); +HI_S32 HI_MPI_AI_GetVqeVolume(AUDIO_DEV AiDevId, AI_CHN AiChn, HI_S32 *ps32VolumeDb); + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_AI_H__ */ + diff --git a/snes9x/unix/mpp/mpi_ao.h b/snes9x/unix/mpp/mpi_ao.h new file mode 100644 index 0000000..13a90e0 --- /dev/null +++ b/snes9x/unix/mpp/mpi_ao.h @@ -0,0 +1,77 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_ao.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2009/5/5 + Description : + History : + 1.Date : 2009/5/5 + Author : p00123320 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_AO_H__ +#define __MPI_AO_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_aio.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +HI_S32 HI_MPI_AO_SetPubAttr(AUDIO_DEV AoDevId, const AIO_ATTR_S *pstAttr); +HI_S32 HI_MPI_AO_GetPubAttr(AUDIO_DEV AoDevId, AIO_ATTR_S *pstAttr); + +HI_S32 HI_MPI_AO_Enable(AUDIO_DEV AoDevId); +HI_S32 HI_MPI_AO_Disable(AUDIO_DEV AoDevId); + +HI_S32 HI_MPI_AO_EnableChn(AUDIO_DEV AoDevId, AO_CHN AoChn); +HI_S32 HI_MPI_AO_DisableChn(AUDIO_DEV AoDevId, AO_CHN AoChn); + +HI_S32 HI_MPI_AO_SendFrame(AUDIO_DEV AoDevId, AO_CHN AoChn, const AUDIO_FRAME_S *pstData, HI_S32 s32MilliSec); + +HI_S32 HI_MPI_AO_EnableReSmp(AUDIO_DEV AoDevId, AO_CHN AoChn, AUDIO_SAMPLE_RATE_E enInSampleRate); +HI_S32 HI_MPI_AO_DisableReSmp(AUDIO_DEV AoDevId, AO_CHN AoChn); + +HI_S32 HI_MPI_AO_ClearChnBuf(AUDIO_DEV AoDevId ,AO_CHN AoChn); +HI_S32 HI_MPI_AO_QueryChnStat(AUDIO_DEV AoDevId ,AO_CHN AoChn, AO_CHN_STATE_S *pstStatus); + +HI_S32 HI_MPI_AO_PauseChn(AUDIO_DEV AoDevId, AO_CHN AoChn); +HI_S32 HI_MPI_AO_ResumeChn(AUDIO_DEV AoDevId, AO_CHN AoChn); + +HI_S32 HI_MPI_AO_SetVolume(AUDIO_DEV AoDevId, HI_S32 s32VolumeDb); +HI_S32 HI_MPI_AO_GetVolume(AUDIO_DEV AoDevId, HI_S32 *ps32VolumeDb); + +HI_S32 HI_MPI_AO_SetMute(AUDIO_DEV AoDevId, HI_BOOL bEnable, AUDIO_FADE_S *pstFade); +HI_S32 HI_MPI_AO_GetMute(AUDIO_DEV AoDevId, HI_BOOL *pbEnable, AUDIO_FADE_S *pstFade); + +HI_S32 HI_MPI_AO_SetTrackMode(AUDIO_DEV AoDevId, AUDIO_TRACK_MODE_E enTrackMode); +HI_S32 HI_MPI_AO_GetTrackMode(AUDIO_DEV AoDevId, AUDIO_TRACK_MODE_E *penTrackMode); + +HI_S32 HI_MPI_AO_GetFd(AUDIO_DEV AoDevId, AO_CHN AoChn); + +HI_S32 HI_MPI_AO_ClrPubAttr(AUDIO_DEV AoDevId); +HI_S32 HI_MPI_AO_SetVqeAttr(AUDIO_DEV AoDevId, AO_CHN AoChn, AO_VQE_CONFIG_S *pstVqeConfig); +HI_S32 HI_MPI_AO_GetVqeAttr(AUDIO_DEV AoDevId, AO_CHN AoChn, AO_VQE_CONFIG_S *pstVqeConfig); +HI_S32 HI_MPI_AO_EnableVqe(AUDIO_DEV AoDevId, AO_CHN AoChn); +HI_S32 HI_MPI_AO_DisableVqe(AUDIO_DEV AoDevId, AO_CHN AoChn); + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_AO_H__ */ + diff --git a/snes9x/unix/mpp/mpi_hdmi.h b/snes9x/unix/mpp/mpi_hdmi.h new file mode 100644 index 0000000..438507a --- /dev/null +++ b/snes9x/unix/mpp/mpi_hdmi.h @@ -0,0 +1,55 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_hdmi.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2011/12/28 + Description : + History : + 1.Date : 2011/12/28 + Author : n00168968/q46153/l00168554 + Modification: Created file + +******************************************************************************/ + +#ifndef __MPI_HDMI_H__ +#define __MPI_HDMI_H__ + +#include "hi_comm_hdmi.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +HI_S32 HI_MPI_HDMI_Init(HI_HDMI_INIT_PARA_S *pstHdmiPara); +HI_S32 HI_MPI_HDMI_DeInit(void); +HI_S32 HI_MPI_HDMI_Open(HI_HDMI_ID_E enHdmi); +HI_S32 HI_MPI_HDMI_Close(HI_HDMI_ID_E enHdmi); +HI_S32 HI_MPI_HDMI_GetSinkCapability(HI_HDMI_ID_E enHdmi,HI_HDMI_SINK_CAPABILITY_S *pstSinkCap); +HI_S32 HI_MPI_HDMI_SetAttr(HI_HDMI_ID_E enHdmi, HI_HDMI_ATTR_S *pstAttr); +HI_S32 HI_MPI_HDMI_GetAttr(HI_HDMI_ID_E enHdmi, HI_HDMI_ATTR_S *pstAttr); +HI_S32 HI_MPI_HDMI_Start(HI_HDMI_ID_E enHdmi); +HI_S32 HI_MPI_HDMI_Stop(HI_HDMI_ID_E enHdmi); +HI_S32 HI_MPI_HDMI_SetAVMute(HI_HDMI_ID_E enHdmi, HI_BOOL bAvMute); +HI_S32 HI_MPI_HDMI_Force_GetEDID(HI_HDMI_ID_E enHdmi, HI_HDMI_EDID_S *pstEdidData); + +/* Normally, these functions are not necessary */ +HI_S32 HI_MPI_HDMI_SetDeepColor(HI_HDMI_ID_E enHdmi, HI_HDMI_DEEP_COLOR_E enDeepColor); +HI_S32 HI_MPI_HDMI_GetDeepColor(HI_HDMI_ID_E enHdmi, HI_HDMI_DEEP_COLOR_E *penDeepColor); + +HI_S32 HI_MPI_HDMI_SetInfoFrame(HI_HDMI_ID_E enHdmi, HI_HDMI_INFOFRAME_S *pstInfoFrame); +HI_S32 HI_MPI_HDMI_GetInfoFrame(HI_HDMI_ID_E enHdmi, HI_HDMI_INFOFRAME_TYPE_E enInfoFrameType, HI_HDMI_INFOFRAME_S *pstInfoFrame); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /*__MPI_HDMI_H__ */ + diff --git a/snes9x/unix/mpp/mpi_ive.h b/snes9x/unix/mpp/mpi_ive.h new file mode 100644 index 0000000..3d1aadd --- /dev/null +++ b/snes9x/unix/mpp/mpi_ive.h @@ -0,0 +1,1047 @@ +/****************************************************************************** + + Copyright (C), 2001-2014, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : hi_comm_ive.h + Version : Initial Draft + Author : Hisilicon multimedia software (IVE) group + Created : 2011/05/16 + Description : + History : + 1.Date : 2011/05/16 + Author : j00169368 + Modification: Created file + + 2.Date : 2013/07/01~2014/08/08 + Author : t00228657\c00211359\c00206215 + Modification: Add MPI function +******************************************************************************/ +#ifndef _HI_MPI_IVE_H_ +#define _HI_MPI_IVE_H_ + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#include "hi_ive.h" + +/***************************************************************************** +* Prototype : HI_MPI_IVE_DMA +* Description : Direct memory access (DMA): +* 1.Direct memory copy; +* 2. Copy with interval bytes; +* 3. Memset using 3 bytes; +* 4. Memset using 8 bytes; +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task. +* IVE_DATA_S *pstSrc Input source data.The input data is treated as U8C1 data. +* IVE_DATA_S *pstDst Output result data. +* IVE_DMA_CTRL_S *pstDmaCtrl DMA control parameter. +* HI_BOOL bInstant Flag indicating whether to generate an interrupt. +* If the output result blocks the next operation, +* set bInstant to HI_TRUE. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 32x1 pixels to 1920x1080 pixels. +* The stride must be 16-byte-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Data : 2013-07-19 +* Author : +* Modification : Modify parameters +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_DMA(IVE_HANDLE *pIveHandle, IVE_DATA_S *pstSrc, + IVE_DST_DATA_S *pstDst, IVE_DMA_CTRL_S *pstDmaCtrl,HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Filter +* Description : 5x5 template filter. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. +* The U8C1,SP420 and SP422 input formats are supported. +* IVE_DST_IMAGE_S *pstDst Output result, of same type with the input. +* IVE_FILTER_CTRL_S *pstFltCtrl Control parameters of filter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-07-23 +* Author : +* Modification : Modified function parameters + +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Filter(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_FILTER_CTRL_S *pstFltCtrl,HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_CSC +* Description : YUV2RGB\YUV2HSV\YUV2LAB\RGB2YUV color space conversion are supported. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data: +* 1. SP420\SP422 type for YUV2RGB\YUV2HSV\YUV2LAB; +* 2. U8C3_PACKAGE\U8C3_PLANAR type for RGB2YUV; +* IVE_DST_IMAGE_S *pstDst Output result: +* 1. U8C3_PACKAGE\U8C3_PLANAR typed for YUV2RGB\YUV2HSV\YUV2LAB; +* 2. SP420\SP422 type for RGB2YUV; +* IVE_CSC_CTRL_S *pstCscCtrl Control parameters for CSC +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-08-09 +* Author : +* Modification : Modified function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_CSC(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_CSC_CTRL_S *pstCscCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_FILTER_AND_CSC +* Description : Only support YUV2RGB color space conversion. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task. +* IVE_SRC_IMAGE_S *pstSrc Input source data.Only SP420\SP422 type are supported. +* IVE_DST_IMAGE_S *pstDst Output result.Only U8C3_PACKAGE\U8C3_PLANAR are supported. +* IVE_FILTER_AND_CSC_CTRL_S *pstFltCscCtrl Control parameters. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-08-09 +* Author : +* Modification : Modified function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_FilterAndCSC(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_FILTER_AND_CSC_CTRL_S *pstFltCscCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Sobel +* Description : SOBEL is used to extract the gradient information. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. Only the U8C1 input image is supported. +* IVE_DST_IMAGE_S *pstDstH The (horizontal) result of input image filtered by the input mask; +* IVE_DST_IMAGE_S *pstDstV The (vertical) result of input image filtered by the transposed mask; +* IVE_SOBEL_CTRL_S *pstSobelCtrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 1. Date : 2013-07-23 +* Author : +* Modification : Modified function parameters +* +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Sobel(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDstH, IVE_DST_IMAGE_S *pstDstV, + IVE_SOBEL_CTRL_S *pstSobelCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_MagAndAng +* Description : MagAndAng is used to extract the edge information. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_INFO_S *pstSrc Input source data. Only the U8C1 input format is supported. +* IVE_MEM_INFO_S *pstDstMag Output magnitude. +* IVE_MEM_INFO_S *pstDstAng Output angle. +* If the output mode is set to magnitude only, +* this item can be set to null. +* IVE_MAG_AND_ANG_CTRL_S *pstMagAndAngCtrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-07-17 +* Author : +* Modification : Modified function and control parameter name +* 3. Date : 2013-07-23 +* Author : +* Modification : Modified function parameters +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_MagAndAng(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDstMag, IVE_DST_IMAGE_S *pstDstAng, + IVE_MAG_AND_ANG_CTRL_S *pstMagAndAngCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Dilate +* Description : 5x5 template dilate. Only the U8C1 binary image input is supported.Or else the result is not expected. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input binary image, which consists of 0 or 255; +* IVE_DST_IMAGE_S *pstDst Output result. +* IVE_DILATE_CTRL_S *pstDilateCtrl Control parameters. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* The input value, output value, and mask value must be 0 or 255. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-07-23 +* Author : +* Modification : Modified parameters +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Dilate(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_DILATE_CTRL_S *pstDilateCtrl,HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Erode +* Parameters : 5x5 template erode. Only the U8C1 binary image input is supported.Or else the result is not correct. +* Input : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input binary image, which consists of 0 or 255; +* IVE_DST_IMAGE_S *pstDst Output result. +* IVE_ERODE_CTRL_S *pstErodeCtrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* The input value, output value, and mask value must be 0 or 255. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-07-23 +* Author : +* Modification : Modified parameters +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Erode(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_ERODE_CTRL_S *pstErodeCtrl,HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Thresh +* Description : Thresh operation to the input image. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result +* IVE_THRESH_CTRL_S *pstThrCtrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-07-23 +* Author : +* Modification : Modification +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Thresh(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_THRESH_CTRL_S *pstThrCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_And +* Description : Binary images' And operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 The input source1. Only U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 The input source2.Only U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result of " src1 & src2 ". +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_And(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Sub +* Description : Two gray images' Sub operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 Minuend of the input source.Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 Subtrahend of the input source.Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result of src1 minus src2 +* IVE_SUB_CTRL_S *pstSubCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-08-09 +* Author : +* Modification : Modified function parameter +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Sub(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstDst, IVE_SUB_CTRL_S *pstSubCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Or +* Description : Two binary images' Or operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 Input source1. Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 Input source2. Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result src1 or src2 +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-08-09 +* Author : +* Modification : Modified function parameter +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Or(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_INTEG +* Description : Calculate the input gray image's integral image. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data.Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result.Can be U32C1 or U64C1, relied on the control parameter. +* IVE_INTEG_CTRL_S *pstIntegCtrl Integ Control +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* The pixel can be 32bit or 64 bit relied on the control parameter. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-03-18 +* Author : +* Modification : Modified function +* 3. Date : 2013-07-15 +* Author : +* Modification : Modified function +* Spec : Modify IVE_INTEG_OUT_FMT_E to IVE_INTEG_CTRL_S +* 4. Date : 2013-07-23 +* Author : +* Modification : Modified parameters +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Integ(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_INTEG_CTRL_S *pstIntegCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Hist +* Description : Calculate the input gray image's histogram. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. Only the U8C1 input format is supported. +* IVE_DST_MEM_INFO_S *pstDst Output result. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Hist(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_MEM_INFO_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Thresh_S16 +* Description : S16 image's THRESH operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data.Only the S16 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result. +* IVE_THRESH_S16_CTRL_S *pstThrS16Ctrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data must be 2-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-05-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Thresh_S16(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_THRESH_S16_CTRL_S *pstThrS16Ctrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Thresh_U16 +* Description : U16 image's THRESH operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. Only the U16 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result +* IVE_THRESH_U16_CTRL_S *pstThrU16Ctrl Control parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data must be 2-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-05-16 +* Author : +* Modification : Created function +* 2. Date : 2013-08-07 +* Author : +* Modification : Implement function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Thresh_U16(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_THRESH_U16_CTRL_S *pstThrU16Ctrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_16BitTo8Bit +* Description : Scale the input 16bit data to the output 8bit data. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data.Only U16C1\S16C1 input is supported. +* IVE_DST_IMAGE_S *pstDst Output result +* IVE_16BITTO8BIT_CTRL_S *pst16BitTo8BitCtrl control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data must be 2-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-12 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_16BitTo8Bit(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_16BIT_TO_8BIT_CTRL_S *pst16BitTo8BitCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_OrdStatFilter +* Description : Order Statistic Filter. It can be used as median\max\min value filter. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data. Only U8C1 input is supported +* IVE_DST_IMAGE_S *pstDst Output result +* IVE_ORD_STAT_FILTER_CTRL_S *pstOrdStatFltCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-12 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_OrdStatFilter(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_ORD_STAT_FILTER_CTRL_S *pstOrdStatFltCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Map +* Description : Map a image to another through a lookup table. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source. Only the U8C1 input format is supported. +* IVE_SRC_MEM_INFO_S *pstMap Input lookup table. Must be an U8 array of size 256. +* IVE_DST_IMAGE_S *pstDst Output result. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-17 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Map(IVE_HANDLE *pIveHandle,IVE_SRC_IMAGE_S *pstSrc, + IVE_SRC_MEM_INFO_S *pstMap, IVE_DST_IMAGE_S *pstDst,HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_EqualizeHist +* Description : Enhance the input image's contrast through histogram equalization. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source.Only U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result. +* IVE_EQUALIZEHIST_CTRL_S *pstEqualizeHistCtrl EqualizeHist control parameter. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The physical addresses of map data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-07-17 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_EqualizeHist(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_EQUALIZE_HIST_CTRL_S *pstEqualizeHistCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Add +* Description : Two gray images' Add operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 Augend of the input source.Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 Addend of the input source.Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstDst Output result of src1 plus src2 +* IVE_ADD_CTRL_S *pstAddCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* History: +* +* 1. Date : 2013-07-17 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Add(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstDst, IVE_ADD_CTRL_S *pstAddCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Xor +* Description : Two binary images' Xor operation. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 The input source1.Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 The input source2. +* IVE_DST_IMAGE_S *pstDst Output result +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* History: +* +* 1. Date : 2013-07-17 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Xor(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_NCC +* Description : Calculate two gray images' NCC (Normalized Cross Correlation). +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 Input source1. Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 Input source2. Must be of the same type¡¢size of source1. +* IVE_DST_MEM_INFO_S *pstDst Output result +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_NCC(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_MEM_INFO_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_CCL +* Description : Connected Component Labeling. Only 8-Connected method is supported. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_IMAGE_S *pstSrcDst Input source +* IVE_MEM_INFO_S *pstBlob Output result of detected region; +* IVE_CCL_CTRL_S *pstCclCtrl CCL control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 720x640 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-1 +* Author : +* Modification : Created function +*****************************************************************************/ +HI_S32 HI_MPI_IVE_CCL(IVE_HANDLE *pIveHandle, IVE_IMAGE_S *pstSrcDst, + IVE_DST_MEM_INFO_S *pstBlob, IVE_CCL_CTRL_S *pstCclCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_GMM +* Description : Separate foreground and background using GMM(Gaussian Mixture Model) method; +* Gray or RGB GMM are supported. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source. Only support U8C1 or U8C3_PACKAGE input. +* IVE_DST_IMAGE_S *pstFg Output foreground (Binary) image. +* IVE_DST_IMAGE_S *pstBg Output background image. Of the sampe type of pstSrc. +* IVE_MEM_INFO_S *pstModel Model data. +* IVE_GMM_CTRL_S *pstGmmCtrl Control parameter. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 720x576 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-07 +* Author : +* Modification : Created function +*****************************************************************************/ +HI_S32 HI_MPI_IVE_GMM(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, IVE_DST_IMAGE_S *pstFg, + IVE_DST_IMAGE_S *pstBg, IVE_MEM_INFO_S *pstModel, IVE_GMM_CTRL_S *pstGmmCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_CannyHysEdge +* Description : The first part of canny Edge detection. Including step: gradient calculation, +* magnitude and angle calculation, hysteresis threshold, NMS(Non-Maximum Suppression) +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source. Only the U8C1 input format is supported +* IVE_DST_IMAGE_S *pstEdge Output result. +* IVE_DST_MEM_INFO_S *pstStack OutPut stack for CannyEdge +* IVE_CANNY_HYS_EDGE_CTRL_S *pstCannyHysEdgeCtrl Control parameter. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. . +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-12 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_CannyHysEdge(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, IVE_DST_IMAGE_S *pstEdge, + IVE_DST_MEM_INFO_S *pstStack, IVE_CANNY_HYS_EDGE_CTRL_S *pstCannyHysEdgeCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_CannyEdge +* Description : The second part of canny Edge detection: trace strong edge by weak edge. +* Parameters : IVE_IMAGE_S *pstEdge Input and Output source. Only the U8C1 format is supported +* IVE_MEM_INFO_S *pstStack stack for CannyEdge +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-12 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_CannyEdge(IVE_IMAGE_S *pstEdge, IVE_MEM_INFO_S *pstStack); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_LBP +* Description : LBP calculation using the original method and a extensional method. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source.Only the U8C1 inpu format is supported. +* IVE_DST_IMAGE_S *pstDst Output result +* IVE_LBP_CTRL_S *pstLbpCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-09-22 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_LBP(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDst, IVE_LBP_CTRL_S *pstLbpCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_NormGrad +* Description : Gradient calculation and the output is normalized to S8. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data +* IVE_DST_IMAGE_S *pstDstH The (horizontal) result of input image filtered by the input mask; +* IVE_DST_IMAGE_S *pstDstV The (vertical) result of input image filtered by the transposed mask; +* IVE_DST_IMAGE_S *pstDstHV Output the horizontal and vertical component in single image in package format. +* IVE_NORM_GRAD_CTRL_S *pstNormGradCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1024 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-12 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_NormGrad(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, + IVE_DST_IMAGE_S *pstDstH, IVE_DST_IMAGE_S *pstDstV, IVE_DST_IMAGE_S *pstDstHV, + IVE_NORM_GRAD_CTRL_S *pstNormGradCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_LKOpticalFlow +* Description : Calculate LK-Optical Flow in single-layer of the pyramid. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrcPre Pre-frame input source.Must be U8C1 image +* IVE_SRC_IMAGE_S *pstSrcCur Cur-frame input source.Same size¡¢type with pstPreSrc. +* IVE_SRC_MEM_INFO_S *pstPoint Intresting points coordinates in the cur-layer +* for LKOpticalFlow tracking. +* IVE_MEM_INFO_S *pstMv Accumlative movements of the interesting points in pre-layers +* or init 0s for the first-layer as input. init 0s . +* Movements of the interesting points being tracked in cur-layer +* as output. +* IVE_LKOPTICALFLOW_CTRL_S *pstLkOptiFlowCtrl Control parameters. +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 720x576 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-08-23 +* Author : +* Modification : Created function +****************************************************************************/ +HI_S32 HI_MPI_IVE_LKOpticalFlow(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrcPre, IVE_SRC_IMAGE_S *pstSrcCur, + IVE_SRC_MEM_INFO_S *pstPoint, IVE_MEM_INFO_S *pstMv, IVE_LK_OPTICAL_FLOW_CTRL_S *pstLkOptiFlowCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_STCandiCorner +* Description : The first part of corners detection using Shi-Tomasi-like method: calculate candidate corners. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc Input source data +* IVE_DST_IMAGE_S *pstCandiCorner Output result of eig +* IVE_ST_CANDI_CORNER_CTRL_S *pstStCandiCornerCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 720x576 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-09-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_STCandiCorner(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, IVE_DST_IMAGE_S *pstCandiCorner, + IVE_ST_CANDI_CORNER_CTRL_S *pstStCandiCornerCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_STCorner +* Description : The second part of corners detection using Shi-Tomasi-like method: select corners by certain rules. +* IVE_SRC_IMAGE_S *pstCandiCorner Input source data +* IVE_DST_MEM_INFO_S *pstCorner Output result of Corner +* IVE_ST_CORNER_CTRL_S *pstStCornerCtrl Control parameter +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 720x576 pixels. +* The physical addresses of the input data and output data must be 16-byte-aligned. +* The stride must be 16-pixel-aligned. +* History: +* +* 1. Date : 2013-09-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_STCorner(IVE_SRC_IMAGE_S * pstCandiCorner, IVE_DST_MEM_INFO_S *pstCorner, + IVE_ST_CORNER_CTRL_S *pstStCornerCtrl); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_GradFg +* Description : +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstBgDiffFg Background subtraction foreground image +* IVE_SRC_IMAGE_S *pstCurGrad Current gradient image, both horizontally and vertically +* graded in accordance with [xyxyxy ...] format +* IVE_SRC_IMAGE_S *pstBgGrad Background gradient image +* IVE_DST_IMAGE_S *pstGradFg Gradient foreground image +* IVE_GRAD_FG_CTRL_S *pstGradFgCtrl Gradient calculation parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2013-10-29 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_GradFg(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstBgDiffFg, IVE_SRC_IMAGE_S *pstCurGrad, + IVE_SRC_IMAGE_S *pstBgGrad, IVE_DST_IMAGE_S *pstGradFg, IVE_GRAD_FG_CTRL_S *pstGradFgCtrl, HI_BOOL bInstant); + + +/***************************************************************************** +* Prototype : HI_MPI_IVE_MatchBgModel +* Description : +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstCurImg Current grayscale image +* IVE_DATA_S *pstBgModel Background model data +* IVE_IMAGE_S *pstFgFlag Foreground status image +* IVE_DST_IMAGE_S *pstBgDiffFg Foreground image obtained by background matching, +* the background pixel value is 0, the foreground pixel +* value is the gray difference value +* IVE_DST_IMAGE_S *pstFrmDiffFg Foreground image obtained by interframe difference, +* the background pixel value is 0, the foreground pixel +* value is the gray difference value +* IVE_DST_MEM_INFO_S *pstStatData result status data +* IVE_MATCH_BG_MODEL_CTRL_S *pstMatchBgModelCtrl Background matching parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. + +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2013-10-29 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_MatchBgModel(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstCurImg, IVE_DATA_S *pstBgModel, + IVE_IMAGE_S *pstFgFlag, IVE_DST_IMAGE_S *pstBgDiffFg, IVE_DST_IMAGE_S *pstFrmDiffFg, IVE_DST_MEM_INFO_S *pstStatData, + IVE_MATCH_BG_MODEL_CTRL_S *pstMatchBgModelCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_UpdateBgModel +* Description : +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_DATA_S *pstBgModel Background model data +* IVE_IMAGE_S *pstFgFlag Foreground status image +* IVE_DST_IMAGE_S *pstBgImg Background grayscale image +* IVE_DST_IMAGE_S *pstChgStaImg Change state life image, for still detection +* IVE_DST_IMAGE_S *pstChgStaFg Change state grayscale image, for still detection +* IVE_DST_IMAGE_S *pstChgStaLife Change state foreground image, for still detection +* IVE_DST_MEM_INFO_S *pstStatData result status data +* IVE_UPDATE_BG_MODEL_CTRL_S *pstUpdateBgModelCtrl Background update parameters +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2013-10-29 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_UpdateBgModel(IVE_HANDLE *pIveHandle, IVE_DATA_S *pstBgModel, IVE_IMAGE_S *pstFgFlag, + IVE_DST_IMAGE_S *pstBgImg, IVE_DST_IMAGE_S *pstChgStaImg, IVE_DST_IMAGE_S *pstChgStaFg, IVE_DST_IMAGE_S *pstChgStaLife, + IVE_DST_MEM_INFO_S *pstStatData, IVE_UPDATE_BG_MODEL_CTRL_S *pstUpdateBgModelCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_ANN_MLP_LoadModel +* Description : Load ANN_MLP model data from ".bin" file. +* Parameters : HI_CHAR *pchFileName ANN_MLP model file name, must be ".bin" file. +* IVE_ANN_MLP_MODEL_S *pstAnnMlpModel ANN_MLP model data. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014-05-13 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_ANN_MLP_LoadModel(const HI_CHAR *pchFileName, IVE_ANN_MLP_MODEL_S *pstAnnMlpModel); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_ANN_MLP_UnloadModel +* Description : Unload ANN_MLP model data. +* Parameters : IVE_ANN_MLP_MODEL_S *pstAnnMlpModel ANN_MLP model data. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014-05-13 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_VOID HI_MPI_IVE_ANN_MLP_UnloadModel(IVE_ANN_MLP_MODEL_S *pstAnnMlpModel); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_ANN_MLP_Predict +* Description : +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_MEM_INFO_S *pstSrc Input sample +* IVE_SRC_MEM_INFO_S *pstActivFuncTable Look-up talbe for active function +* IVE_ANN_MLP_MODEL_S *pstAnnMlpModel ANN_MLP model +* IVE_DST_MEM_INFO_S *pstDst Output layer +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2013-11-28 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_ANN_MLP_Predict(IVE_HANDLE *pIveHandle, IVE_SRC_MEM_INFO_S *pstSrc, + IVE_LOOK_UP_TABLE_S *pstActivFuncTab, IVE_ANN_MLP_MODEL_S *pstAnnMlpModel, + IVE_DST_MEM_INFO_S *pstDst, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_SVM_LoadModel +* Description : Load SVM model data from ".bin" file. +* Parameters : HI_CHAR *pchFileName SVM model file name, must be ".bin" file. +* IVE_SVM_MODEL_S *pstSvmModel SVM model data. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014-05-13 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_SVM_LoadModel(const HI_CHAR *pchFileName, IVE_SVM_MODEL_S *pstSvmModel); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_SVM_UnloadModel +* Description : Unload SVM model data. +* Parameters : IVE_SVM_MODEL_S *pstSvmModel SVM model data. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2014-05-13 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_VOID HI_MPI_IVE_SVM_UnloadModel(IVE_SVM_MODEL_S *pstSvmModel); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_SVM_Predict +* Description : +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_MEM_INFO_S *pstSrc Input sample +* IVE_SRC_MEM_INFO_S *pstKernelTable Look-up talbe for active function +* IVE_SVM_MODEL_S *pstSvmModel SVM model +* IVE_DST_MEM_INFO_S *pstDstVote Output Votes' array of each class +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2013-11-28 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_SVM_Predict(IVE_HANDLE *pIveHandle, IVE_SRC_MEM_INFO_S *pstSrc, + IVE_LOOK_UP_TABLE_S *pstKernelTab, IVE_SVM_MODEL_S *pstSvmModel, + IVE_DST_MEM_INFO_S *pstDstVote, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_SAD +* Description : Sum of absolute differences. +* Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task +* IVE_SRC_IMAGE_S *pstSrc1 The input source1.Only the U8C1 input format is supported. +* IVE_SRC_IMAGE_S *pstSrc2 The input source2.Only the U8C1 input format is supported. +* IVE_DST_IMAGE_S *pstSad Output result of sad value.Only the U8C1/U16C1 format is supported. +* IVE_DST_IMAGE_S *pstThr Output result of thresh.Only the U8C1 format is supported. +* IVE_SAD_CTRL_S *pstSadCtrl Control parameter +* HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. +* The stride must be 16-pixel-aligned. +* The types, widths, heights of two input sources must be the same. +* Not support in hi3516a +* History: +* +* 1. Date : 2014-08-28 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_SAD(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc1, + IVE_SRC_IMAGE_S *pstSrc2, IVE_DST_IMAGE_S *pstSad,IVE_DST_IMAGE_S *pstThr, + IVE_SAD_CTRL_S *pstSadCtrl, HI_BOOL bInstant); + +/***************************************************************************** +* Prototype : HI_MPI_IVE_Query +* Description : This API is used to query the status of a called function by using the returned IveHandle of the function. + In block mode, the system waits until the function that is being queried is called. + In non-block mode, the current status is queried and no action is taken. +* Parameters : IVE_HANDLE IveHandle IveHandle of a called function. It is entered by users. +* HI_BOOL *pbFinish Returned status +* HI_BOOL bBlock Flag indicating the block mode or non-block mode +* HI_BOOL *pbFinish +* Return Value : HI_SUCCESS: Success;Error codes: Failure. +* Spec : +* History: +* +* 1. Date : 2011-05-16 +* Author : +* Modification : Created function +* +*****************************************************************************/ +HI_S32 HI_MPI_IVE_Query(IVE_HANDLE IveHandle, HI_BOOL *pbFinish, HI_BOOL bBlock); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif +#endif/*__MPI_IVE_H__*/ diff --git a/snes9x/unix/mpp/mpi_region.h b/snes9x/unix/mpp/mpi_region.h new file mode 100644 index 0000000..3728873 --- /dev/null +++ b/snes9x/unix/mpp/mpi_region.h @@ -0,0 +1,56 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_region.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2013/05/07 + Description : + History : + 1.Date : 2013/05/07 + Author : c00191088 + Modification: Created file + +******************************************************************************/ +#ifndef __MPI_REGION_H__ +#define __MPI_REGION_H__ + +#include "hi_comm_region.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +HI_S32 HI_MPI_RGN_Create(RGN_HANDLE Handle, const RGN_ATTR_S *pstRegion); +HI_S32 HI_MPI_RGN_Destroy(RGN_HANDLE Handle); + +HI_S32 HI_MPI_RGN_GetAttr(RGN_HANDLE Handle, RGN_ATTR_S *pstRegion); +HI_S32 HI_MPI_RGN_SetAttr(RGN_HANDLE Handle, const RGN_ATTR_S *pstRegion); + +HI_S32 HI_MPI_RGN_SetBitMap(RGN_HANDLE Handle, const BITMAP_S *pstBitmap); + +HI_S32 HI_MPI_RGN_AttachToChn(RGN_HANDLE Handle, const MPP_CHN_S *pstChn, const RGN_CHN_ATTR_S *pstChnAttr); +HI_S32 HI_MPI_RGN_DetachFromChn(RGN_HANDLE Handle, const MPP_CHN_S *pstChn); + +HI_S32 HI_MPI_RGN_SetDisplayAttr(RGN_HANDLE Handle, const MPP_CHN_S *pstChn, const RGN_CHN_ATTR_S *pstChnAttr); +HI_S32 HI_MPI_RGN_GetDisplayAttr(RGN_HANDLE Handle, const MPP_CHN_S *pstChn, RGN_CHN_ATTR_S *pstChnAttr); + +HI_S32 HI_MPI_RGN_SetAttachField(RGN_HANDLE Handle, VIDEO_FIELD_E enAttachField); +HI_S32 HI_MPI_RGN_GetAttachField(RGN_HANDLE Handle, VIDEO_FIELD_E *penAttachField); + +HI_S32 HI_MPI_RGN_GetCanvasInfo(RGN_HANDLE Handle, RGN_CANVAS_INFO_S *pstCanvasInfo); +HI_S32 HI_MPI_RGN_UpdateCanvas(RGN_HANDLE Handle); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __MPI_REGION_H__ */ + diff --git a/snes9x/unix/mpp/mpi_sys.h b/snes9x/unix/mpp/mpi_sys.h new file mode 100644 index 0000000..e37371b --- /dev/null +++ b/snes9x/unix/mpp/mpi_sys.h @@ -0,0 +1,102 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_sys.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2007/1/31 + Description : + History : + 1.Date : 2006/1/31 + Author : c42025 + Modification: Created file + + 2.Date : 2008/03/03 + Author : c42025 + Modification: add a new funtion "HI_MPI_SYS_GetVersion" + +******************************************************************************/ +#ifndef __MPI_SYS_H__ +#define __MPI_SYS_H__ + +#include "hi_type.h" +#include "hi_common.h" +#include "hi_comm_sys.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +HI_S32 HI_MPI_SYS_Init(); +HI_S32 HI_MPI_SYS_Exit(); + +HI_S32 HI_MPI_SYS_SetConf(const MPP_SYS_CONF_S *pstSysConf); +HI_S32 HI_MPI_SYS_GetConf(MPP_SYS_CONF_S *pstSysConf); + +HI_S32 HI_MPI_SYS_Bind(MPP_CHN_S *pstSrcChn, MPP_CHN_S *pstDestChn); +HI_S32 HI_MPI_SYS_UnBind(MPP_CHN_S *pstSrcChn, MPP_CHN_S *pstDestChn); +HI_S32 HI_MPI_SYS_GetBindbyDest(MPP_CHN_S *pstDestChn, MPP_CHN_S *pstSrcChn); + +HI_S32 HI_MPI_SYS_GetVersion(MPP_VERSION_S *pstVersion); + +/* +** u64Base is the global PTS of the system. +** ADVICE: +** 1. Better to call HI_MPI_SYS_GetCurPts on the host board to get u64Base. +** 2. When os start up, call HI_MPI_SYS_InitPtsBase to set the init PTS. +** 3. When media bussines is running, synchronize the PTS one time per minute +** by calling HI_MPI_SYS_SyncPts. +*/ +HI_S32 HI_MPI_SYS_GetCurPts(HI_U64 *pu64CurPts); +HI_S32 HI_MPI_SYS_InitPtsBase(HI_U64 u64PtsBase); +HI_S32 HI_MPI_SYS_SyncPts(HI_U64 u64PtsBase); + +/* alloc mmz memory in user context */ +HI_S32 HI_MPI_SYS_MmzAlloc(HI_U32 *pu32PhyAddr, HI_VOID **ppVirtAddr, + const HI_CHAR *strMmb, const HI_CHAR *strZone, HI_U32 u32Len); + +/* alloc mmz memory with cache */ +HI_S32 HI_MPI_SYS_MmzAlloc_Cached(HI_U32 *pu32PhyAddr, HI_VOID **ppVitAddr, + const HI_CHAR *pstrMmb, const HI_CHAR *pstrZone, HI_U32 u32Len); + +/* free mmz memory in user context */ +HI_S32 HI_MPI_SYS_MmzFree(HI_U32 u32PhyAddr, HI_VOID *pVirtAddr); + +/* fulsh cache */ +HI_S32 HI_MPI_SYS_MmzFlushCache(HI_U32 u32PhyAddr, HI_VOID *pVitAddr, HI_U32 u32Size); + +/* +** Call the mmap function to map physical address to virtual address +** The system function mmap is too complicated, so we packge it. +*/ +HI_VOID * HI_MPI_SYS_Mmap(HI_U32 u32PhyAddr, HI_U32 u32Size); +HI_S32 HI_MPI_SYS_Munmap(HI_VOID* pVirAddr, HI_U32 u32Size); + +/* +** Access the physical address. +** You can use this function to access memory address or register address. +*/ +HI_S32 HI_MPI_SYS_SetReg(HI_U32 u32Addr, HI_U32 u32Value); +HI_S32 HI_MPI_SYS_GetReg(HI_U32 u32Addr, HI_U32 *pu32Value); + +HI_S32 HI_MPI_SYS_SetMemConf(MPP_CHN_S *pstMppChn,const HI_CHAR *pcMmzName); +HI_S32 HI_MPI_SYS_GetMemConf(MPP_CHN_S *pstMppChn,HI_CHAR *pcMmzName); + +/* Close all the FD which is used by sys module */ +HI_S32 HI_MPI_SYS_CloseFd(HI_VOID); + + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /*__MPI_SYS_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vb.h b/snes9x/unix/mpp/mpi_vb.h new file mode 100644 index 0000000..7066963 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vb.h @@ -0,0 +1,60 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vb.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2007/10/15 + Description : + History : + 1.Date : 2007/10/15 + Author : c42025 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_VB_H__ +#define __MPI_VB_H__ + +#include "hi_comm_vb.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +VB_POOL HI_MPI_VB_CreatePool(HI_U32 u32BlkSize,HI_U32 u32BlkCnt,const HI_CHAR *pcMmzName); +HI_S32 HI_MPI_VB_DestroyPool(VB_POOL Pool); + +VB_BLK HI_MPI_VB_GetBlock(VB_POOL Pool, HI_U32 u32BlkSize,const HI_CHAR *pcMmzName); +HI_S32 HI_MPI_VB_ReleaseBlock(VB_BLK Block); + +HI_U32 HI_MPI_VB_Handle2PhysAddr(VB_BLK Block); +VB_POOL HI_MPI_VB_Handle2PoolId(VB_BLK Block); +HI_S32 HI_MPI_VB_InquireUserCnt(VB_BLK Block); + +HI_S32 HI_MPI_VB_Init(HI_VOID); +HI_S32 HI_MPI_VB_Exit(HI_VOID); +HI_S32 HI_MPI_VB_SetConf(const VB_CONF_S *pstVbConf); +HI_S32 HI_MPI_VB_GetConf(VB_CONF_S *pstVbConf); + +HI_S32 HI_MPI_VB_MmapPool(VB_POOL Pool); +HI_S32 HI_MPI_VB_MunmapPool(VB_POOL Pool); + +HI_S32 HI_MPI_VB_GetBlkVirAddr(VB_POOL Pool, HI_U32 u32PhyAddr, HI_VOID **ppVirAddr); + +HI_S32 HI_MPI_VB_InitModCommPool(VB_UID_E enVbUid); +HI_S32 HI_MPI_VB_ExitModCommPool(VB_UID_E enVbUid); + +HI_S32 HI_MPI_VB_SetModPoolConf(VB_UID_E enVbUid, const VB_CONF_S *pstVbConf); +HI_S32 HI_MPI_VB_GetModPoolConf(VB_UID_E enVbUid, VB_CONF_S *pstVbConf); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /*__MPI_VI_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vda.h b/snes9x/unix/mpp/mpi_vda.h new file mode 100644 index 0000000..8014f29 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vda.h @@ -0,0 +1,58 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vda.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2013/05/09 + Description : + History : + 1.Date : 2013/05/09 + Author : x00100808 + Modification: Created file + +******************************************************************************/ +#ifndef __MPI_VDA_H__ +#define __MPI_VDA_H__ + +#include "hi_comm_vda.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +HI_S32 HI_MPI_VDA_CreateChn(VDA_CHN VdaChn, const VDA_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VDA_DestroyChn(VDA_CHN VdaChn); + +HI_S32 HI_MPI_VDA_GetChnAttr(VDA_CHN VdaChn, VDA_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VDA_SetChnAttr(VDA_CHN VdaChn, const VDA_CHN_ATTR_S *pstAttr); + +HI_S32 HI_MPI_VDA_StartRecvPic(VDA_CHN VdaChn); +HI_S32 HI_MPI_VDA_StopRecvPic(VDA_CHN VdaChn); + +HI_S32 HI_MPI_VDA_GetData(VDA_CHN VdaChn, VDA_DATA_S *pstVdaData, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VDA_ReleaseData(VDA_CHN VdaChn, const VDA_DATA_S* pstVdaData); + +HI_S32 HI_MPI_VDA_ResetOdRegion(VDA_CHN VdaChn, HI_S32 s32RgnIndex); + +HI_S32 HI_MPI_VDA_Query(VDA_CHN VdaChn, VDA_CHN_STAT_S *pstChnStat); + +HI_S32 HI_MPI_VDA_GetFd(VDA_CHN VdaChn); + +HI_S32 HI_MPI_VDA_UpdateRef(VDA_CHN VdaChn, const VIDEO_FRAME_INFO_S *pstRefFrame); + +HI_S32 HI_MPI_VDA_SendPic(VDA_CHN VdaChn, const VIDEO_FRAME_INFO_S *pstUserFrame, HI_S32 s32MilliSec); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __MPI_VDA_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vdec.h b/snes9x/unix/mpp/mpi_vdec.h new file mode 100644 index 0000000..13a6d14 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vdec.h @@ -0,0 +1,90 @@ +/****************************************************************************** + + Copyright (C), 2013, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vdec.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2013/05/08 + Description : MPP Programe Interface for video decode + History : + 1.Date : 2013/05/08 + Author : l00226816 + Modification: Created file +******************************************************************************/ +#ifndef __MPI_VDEC_H__ +#define __MPI_VDEC_H__ + +#include "hi_common.h" +#include "hi_comm_video.h" +#include "hi_comm_vb.h" +#include "hi_comm_vdec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + + +HI_S32 HI_MPI_VDEC_CreateChn(VDEC_CHN VdChn, const VDEC_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VDEC_DestroyChn(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_GetChnAttr(VDEC_CHN VdChn, VDEC_CHN_ATTR_S *pstAttr); + +HI_S32 HI_MPI_VDEC_StartRecvStream(VDEC_CHN VdChn); +HI_S32 HI_MPI_VDEC_StopRecvStream(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_Query(VDEC_CHN VdChn,VDEC_CHN_STAT_S *pstStat); + +HI_S32 HI_MPI_VDEC_GetFd(VDEC_CHN VdChn); +HI_S32 HI_MPI_VDEC_CloseFd(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_ResetChn(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_SetChnParam(VDEC_CHN VdChn, VDEC_CHN_PARAM_S* pstParam); +HI_S32 HI_MPI_VDEC_GetChnParam(VDEC_CHN VdChn, VDEC_CHN_PARAM_S* pstParam); + +HI_S32 HI_MPI_VDEC_SetProtocolParam(VDEC_CHN VdChn,VDEC_PRTCL_PARAM_S *pstParam); +HI_S32 HI_MPI_VDEC_GetProtocolParam(VDEC_CHN VdChn,VDEC_PRTCL_PARAM_S *pstParam); + +/* s32MilliSec: -1 is block£¬ 0 is no block£¬other positive number is timeout */ +HI_S32 HI_MPI_VDEC_SendStream(VDEC_CHN VdChn, const VDEC_STREAM_S *pstStream, HI_S32 s32MilliSec); + +HI_S32 HI_MPI_VDEC_GetImage(VDEC_CHN VdChn, VIDEO_FRAME_INFO_S *pstFrameInfo,HI_S32 s32MilliSec); +HI_S32 HI_MPI_VDEC_ReleaseImage(VDEC_CHN VdChn, VIDEO_FRAME_INFO_S *pstFrameInfo); + +HI_S32 HI_MPI_VDEC_GetUserData(VDEC_CHN VdChn, VDEC_USERDATA_S *pstUserData, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VDEC_ReleaseUserData(VDEC_CHN VdChn, VDEC_USERDATA_S *pstUserData); + +HI_S32 HI_MPI_VDEC_SetRotate(VDEC_CHN VdChn, ROTATE_E enRotate); +HI_S32 HI_MPI_VDEC_GetRotate(VDEC_CHN VdChn, ROTATE_E *penRotate); + +HI_S32 HI_MPI_VDEC_GetChnLuma(VDEC_CHN VdChn, VDEC_CHN_LUM_S *pstLuma); + +HI_S32 HI_MPI_VDEC_SetUserPic(VDEC_CHN VdChn, VIDEO_FRAME_INFO_S *pstUsrPic); +HI_S32 HI_MPI_VDEC_EnableUserPic(VDEC_CHN VdChn, HI_BOOL bInstant); +HI_S32 HI_MPI_VDEC_DisableUserPic(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_SetDisplayMode(VDEC_CHN VdChn, VIDEO_DISPLAY_MODE_E enDisplayMode); +HI_S32 HI_MPI_VDEC_GetDisplayMode(VDEC_CHN VdChn, VIDEO_DISPLAY_MODE_E *penDisplayMode); + +HI_S32 HI_MPI_VDEC_SetChnVBCnt(VDEC_CHN VdChn, HI_U32 u32BlkCnt); +HI_S32 HI_MPI_VDEC_GetChnVBCnt(VDEC_CHN VdChn, HI_U32 *pu32BlkCnt); + +HI_S32 HI_MPI_VDEC_AttachVbPool(VDEC_CHN VdChn, VDEC_CHN_POOL_S *pstPool); +HI_S32 HI_MPI_VDEC_DetachVbPool(VDEC_CHN VdChn); + +HI_S32 HI_MPI_VDEC_SetModParam(VDEC_MOD_PARAM_S *pstModParam); +HI_S32 HI_MPI_VDEC_GetModParam(VDEC_MOD_PARAM_S *pstModParam); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + +#endif /* End of #ifndef __MPI_VDEC_H__ */ + diff --git a/snes9x/unix/mpp/mpi_venc.h b/snes9x/unix/mpp/mpi_venc.h new file mode 100644 index 0000000..2e861fb --- /dev/null +++ b/snes9x/unix/mpp/mpi_venc.h @@ -0,0 +1,145 @@ +/****************************************************************************** + + Copyright (C), 2001-2012, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_venc.h + Version : Initial Draft + Author : Hisilicon Hi35xx MPP Team + Created : 2006/11/22 + Last Modified : + Description : mpi functions declaration + Function List : + History : +******************************************************************************/ +#ifndef __MPI_VENC_H__ +#define __MPI_VENC_H__ + +#include "hi_common.h" +#include "hi_comm_video.h" +#include "hi_comm_venc.h" +#include "hi_comm_vb.h" + + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +HI_S32 HI_MPI_VENC_CreateChn(VENC_CHN VeChn, const VENC_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VENC_DestroyChn(VENC_CHN VeChn); +HI_S32 HI_MPI_VENC_ResetChn(VENC_CHN VeChn); + +HI_S32 HI_MPI_VENC_StartRecvPic(VENC_CHN VeChn); +HI_S32 HI_MPI_VENC_StartRecvPicEx(VENC_CHN VeChn, VENC_RECV_PIC_PARAM_S *pstRecvParam); +HI_S32 HI_MPI_VENC_StopRecvPic(VENC_CHN VeChn); + +HI_S32 HI_MPI_VENC_Query(VENC_CHN VeChn, VENC_CHN_STAT_S *pstStat); + +HI_S32 HI_MPI_VENC_SetChnAttr(VENC_CHN VeChn, const VENC_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VENC_GetChnAttr(VENC_CHN VeChn, VENC_CHN_ATTR_S *pstAttr); +/*-1:bolck 0:nonblock >0 : overtime */ +HI_S32 HI_MPI_VENC_GetStream(VENC_CHN VeChn, VENC_STREAM_S *pstStream, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VENC_ReleaseStream(VENC_CHN VeChn, VENC_STREAM_S *pstStream); + +HI_S32 HI_MPI_VENC_InsertUserData(VENC_CHN VeChn, HI_U8 *pu8Data, HI_U32 u32Len); +/*-1:bolck 0:nonblock >0 : overtime */ +HI_S32 HI_MPI_VENC_SendFrame(VENC_CHN VeChn, VIDEO_FRAME_INFO_S *pstFrame ,HI_S32 s32MilliSec); + +HI_S32 HI_MPI_VENC_SetMaxStreamCnt(VENC_CHN VeChn, HI_U32 u32MaxStrmCnt); +HI_S32 HI_MPI_VENC_GetMaxStreamCnt(VENC_CHN VeChn, HI_U32 *pu32MaxStrmCnt); + +HI_S32 HI_MPI_VENC_RequestIDR(VENC_CHN VeChn,HI_BOOL bInstant); + +HI_S32 HI_MPI_VENC_GetFd(VENC_CHN VeChn); +HI_S32 HI_MPI_VENC_CloseFd(VENC_CHN VeChn); + + +HI_S32 HI_MPI_VENC_SetRoiCfg(VENC_CHN VeChn, VENC_ROI_CFG_S *pstVencRoiCfg); +HI_S32 HI_MPI_VENC_GetRoiCfg(VENC_CHN VeChn, HI_U32 u32Index, VENC_ROI_CFG_S *pstVencRoiCfg); + +HI_S32 HI_MPI_VENC_SetRoiBgFrameRate(VENC_CHN VeChn, const VENC_ROIBG_FRAME_RATE_S *pstRoiBgFrmRate); +HI_S32 HI_MPI_VENC_GetRoiBgFrameRate(VENC_CHN VeChn, VENC_ROIBG_FRAME_RATE_S *pstRoiBgFrmRate); + +HI_S32 HI_MPI_VENC_SetH264SliceSplit(VENC_CHN VeChn, const VENC_PARAM_H264_SLICE_SPLIT_S *pstSliceSplit); +HI_S32 HI_MPI_VENC_GetH264SliceSplit(VENC_CHN VeChn, VENC_PARAM_H264_SLICE_SPLIT_S *pstSliceSplit); + +HI_S32 HI_MPI_VENC_SetH264InterPred(VENC_CHN VeChn, const VENC_PARAM_H264_INTER_PRED_S *pstH264InterPred); +HI_S32 HI_MPI_VENC_GetH264InterPred(VENC_CHN VeChn, VENC_PARAM_H264_INTER_PRED_S *pstH264InterPred); + +HI_S32 HI_MPI_VENC_SetH264IntraPred(VENC_CHN VeChn, const VENC_PARAM_H264_INTRA_PRED_S *pstH264IntraPred); +HI_S32 HI_MPI_VENC_GetH264IntraPred(VENC_CHN VeChn, VENC_PARAM_H264_INTRA_PRED_S *pstH264IntraPred); + +HI_S32 HI_MPI_VENC_SetH264Trans(VENC_CHN VeChn, const VENC_PARAM_H264_TRANS_S *pstH264Trans); +HI_S32 HI_MPI_VENC_GetH264Trans(VENC_CHN VeChn, VENC_PARAM_H264_TRANS_S *pstH264Trans); + +HI_S32 HI_MPI_VENC_SetH264Entropy(VENC_CHN VeChn, const VENC_PARAM_H264_ENTROPY_S *pstH264EntropyEnc); +HI_S32 HI_MPI_VENC_GetH264Entropy(VENC_CHN VeChn, VENC_PARAM_H264_ENTROPY_S *pstH264EntropyEnc); + +HI_S32 HI_MPI_VENC_SetH264Poc(VENC_CHN VeChn, const VENC_PARAM_H264_POC_S *pstH264Poc); +HI_S32 HI_MPI_VENC_GetH264Poc(VENC_CHN VeChn, VENC_PARAM_H264_POC_S *pstH264Poc); + +HI_S32 HI_MPI_VENC_SetH264Dblk(VENC_CHN VeChn, const VENC_PARAM_H264_DBLK_S *pstH264Dblk); +HI_S32 HI_MPI_VENC_GetH264Dblk(VENC_CHN VeChn, VENC_PARAM_H264_DBLK_S *pstH264Dblk); + +HI_S32 HI_MPI_VENC_SetH264Vui(VENC_CHN VeChn, const VENC_PARAM_H264_VUI_S *pstH264Vui); +HI_S32 HI_MPI_VENC_GetH264Vui(VENC_CHN VeChn, VENC_PARAM_H264_VUI_S *pstH264Vui); + +HI_S32 HI_MPI_VENC_SetJpegParam(VENC_CHN VeChn, const VENC_PARAM_JPEG_S *pstJpegParam); +HI_S32 HI_MPI_VENC_GetJpegParam(VENC_CHN VeChn, VENC_PARAM_JPEG_S *pstJpegParam); + + +HI_S32 HI_MPI_VENC_SetMjpegParam(VENC_CHN VeChn, const VENC_PARAM_MJPEG_S *pstMjpegParam); +HI_S32 HI_MPI_VENC_GetMjpegParam(VENC_CHN VeChn, VENC_PARAM_MJPEG_S *pstMjpegParam); + +HI_S32 HI_MPI_VENC_SetFrameRate(VENC_CHN VeChn, const VENC_FRAME_RATE_S *pstFrameRate); +HI_S32 HI_MPI_VENC_GetFrameRate(VENC_CHN VeChn, VENC_FRAME_RATE_S *pstFrameRate); + +HI_S32 HI_MPI_VENC_GetRcParam(VENC_CHN VeChn, VENC_RC_PARAM_S *pstRcParam); +HI_S32 HI_MPI_VENC_SetRcParam(VENC_CHN VeChn, const VENC_RC_PARAM_S *pstRcParam); + + +HI_S32 HI_MPI_VENC_SetRefParam(VENC_CHN VeChn, const VENC_PARAM_REF_S *pstRefParam); +HI_S32 HI_MPI_VENC_GetRefParam(VENC_CHN VeChn, VENC_PARAM_REF_S *pstRefParam); + +HI_S32 HI_MPI_VENC_SetColor2Grey(VENC_CHN VeChn, const VENC_COLOR2GREY_S *pstChnColor2Grey); +HI_S32 HI_MPI_VENC_GetColor2Grey(VENC_CHN VeChn, VENC_COLOR2GREY_S *pstChnColor2Grey); + +HI_S32 HI_MPI_VENC_SetCrop(VENC_CHN VeChn, const VENC_CROP_CFG_S *pstCropCfg); +HI_S32 HI_MPI_VENC_GetCrop(VENC_CHN VeChn, VENC_CROP_CFG_S *pstCropCfg); +HI_S32 HI_MPI_VENC_EnableIDR(VENC_CHN VeChn, HI_BOOL bEnableIDR); + +HI_S32 HI_MPI_VENC_SetH264IdrPicId( VENC_CHN VeChn, VENC_H264_IDRPICID_CFG_S* pstH264eIdrPicIdCfg ); +HI_S32 HI_MPI_VENC_GetH264IdrPicId( VENC_CHN VeChn, VENC_H264_IDRPICID_CFG_S* pstH264eIdrPicIdCfg ); + +HI_S32 HI_MPI_VENC_GetStreamBufInfo(VENC_CHN VeChn, VENC_STREAM_BUF_INFO_S *pstStreamBufInfo); + + +HI_S32 HI_MPI_VENC_SetRcPriority(VENC_CHN VeChn, VENC_RC_PRIORITY_E enRcPriority); +HI_S32 HI_MPI_VENC_GetRcPriority(VENC_CHN VeChn, VENC_RC_PRIORITY_E *penRcPriority); + + + +HI_S32 HI_MPI_VENC_SetFrameLostStrategy(VENC_CHN VeChn, const VENC_PARAM_FRAMELOST_S *pstFrmLostParam); +HI_S32 HI_MPI_VENC_GetFrameLostStrategy(VENC_CHN VeChn, VENC_PARAM_FRAMELOST_S *pstFrmLostParam); + + +HI_S32 HI_MPI_VENC_SetSuperFrameCfg(VENC_CHN VeChn, const VENC_SUPERFRAME_CFG_S *pstSuperFrmParam); +HI_S32 HI_MPI_VENC_GetSuperFrameCfg(VENC_CHN VeChn,VENC_SUPERFRAME_CFG_S *pstSuperFrmParam); + + +HI_S32 HI_MPI_VENC_AttachVbPool(VENC_CHN VeChn, VB_POOL hVbPool); +HI_S32 HI_MPI_VENC_DetachVbPool(VENC_CHN VeChn); + +HI_S32 HI_MPI_VENC_SetModParam(VENC_PARAM_MOD_S *pstModParam); +HI_S32 HI_MPI_VENC_GetModParam(VENC_PARAM_MOD_S *pstModParam); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_VENC_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vgs.h b/snes9x/unix/mpp/mpi_vgs.h new file mode 100644 index 0000000..cbd32cb --- /dev/null +++ b/snes9x/unix/mpp/mpi_vgs.h @@ -0,0 +1,157 @@ +/****************************************************************************** + + Copyright (C), 2013-2033, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vgs.h + Version : Initial Draft + Author : Hisilicon Hi35xx MPP Team + Created : 2013/07/24 + Last Modified : + Description : mpi functions declaration + Function List : + History : +******************************************************************************/ +#ifndef __MPI_VGS_H__ +#define __MPI_VGS_H__ + +#include "hi_common.h" +#include "hi_comm_video.h" +#include "hi_comm_vgs.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + +/***************************************************************************** + Prototype : HI_MPI_VGS_BeginJob + Description : Begin a vgs job,then add task into the job,vgs will finish all the task in the job. + Input : VGS_HANDLE *phHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2013/07/24 + Author : z00183560 + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_BeginJob(VGS_HANDLE *phHandle); + +/***************************************************************************** + Prototype : HI_MPI_VGS_EndJob + Description : End a job,all tasks in the job will be submmitted to vgs + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2013/07/24 + Author : z00183560 + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_EndJob(VGS_HANDLE hHandle); + +/***************************************************************************** + Prototype : HI_MPI_VGS_CancelJob + Description : Cancel a job ,then all tasks in the job will not be submmitted to vgs + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2013/07/24 + Author : z00183560 + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_CancelJob(VGS_HANDLE hHandle); + +/***************************************************************************** + Prototype : HI_MPI_VGS_AddScaleTask + Description : Add a task to a vgs job + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2013/07/24 + Author : z00183560 + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_AddScaleTask(VGS_HANDLE hHandle, VGS_TASK_ATTR_S *pstTask); + + +/***************************************************************************** + Prototype : HI_MPI_VGS_AddDrawLineTask + Description : add a draw line task into a job + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2014/01/27 + Author : + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_AddDrawLineTask(VGS_HANDLE hHandle, VGS_TASK_ATTR_S *pstTask, VGS_LINE_S astVgsDrawLine[], HI_U32 u32ArraySize); + +/***************************************************************************** + Prototype : HI_MPI_VGS_AddCoverTask + Description : add a draw point task into a job + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2014/01/27 + Author : + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_AddCoverTask(VGS_HANDLE hHandle, VGS_TASK_ATTR_S *pstTask, VGS_COVER_S astVgsAddCover[], HI_U32 u32ArraySize); + +/***************************************************************************** + Prototype : HI_MPI_VGS_AddOsdTask + Description : add a draw point task into a job + Input : VGS_HANDLE hHandle + Output : None + Return Value : + Calls : + Called By : + + History : + 1.Date : 2014/01/27 + Author : + Modification : Created function +<$/> +*****************************************************************************/ +HI_S32 HI_MPI_VGS_AddOsdTask(VGS_HANDLE hHandle, VGS_TASK_ATTR_S *pstTask, VGS_OSD_S astVgsAddOsd[], HI_U32 u32ArraySize); + + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_VGS_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vi.h b/snes9x/unix/mpp/mpi_vi.h new file mode 100644 index 0000000..c9f11e2 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vi.h @@ -0,0 +1,77 @@ +#ifndef __MPI_VI_H__ +#define __MPI_VI_H__ + + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +#include "hi_comm_vi.h" + +HI_S32 HI_MPI_VI_SetDevAttr(VI_DEV ViDev, const VI_DEV_ATTR_S *pstDevAttr); +HI_S32 HI_MPI_VI_GetDevAttr(VI_DEV ViDev, VI_DEV_ATTR_S *pstDevAttr); + +HI_S32 HI_MPI_VI_EnableDev(VI_DEV ViDev); +HI_S32 HI_MPI_VI_DisableDev(VI_DEV ViDev); + +HI_S32 HI_MPI_VI_SetChnAttr(VI_CHN ViChn, const VI_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VI_GetChnAttr(VI_CHN ViChn, VI_CHN_ATTR_S *pstAttr); + +/* The following 3 functions are only for vichn minor attributes */ +HI_S32 HI_MPI_VI_SetChnMinorAttr(VI_CHN ViChn,const VI_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VI_GetChnMinorAttr(VI_CHN ViChn,VI_CHN_ATTR_S *pstAttr); +HI_S32 HI_MPI_VI_ClearChnMinorAttr(VI_CHN ViChn); + +HI_S32 HI_MPI_VI_EnableChn(VI_CHN ViChn); +HI_S32 HI_MPI_VI_DisableChn(VI_CHN ViChn); + +HI_S32 HI_MPI_VI_GetFrame(VI_CHN ViChn, VIDEO_FRAME_INFO_S *pstFrameInfo, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VI_ReleaseFrame(VI_CHN ViChn, VIDEO_FRAME_INFO_S *pstFrameInfo); +HI_S32 HI_MPI_VI_SetFrameDepth(VI_CHN ViChn, HI_U32 u32Depth); +HI_S32 HI_MPI_VI_GetFrameDepth(VI_CHN ViChn, HI_U32 *pu32Depth); + +HI_S32 HI_MPI_VI_SetUserPic(VI_CHN ViChn, VI_USERPIC_ATTR_S *pstUsrPic); +HI_S32 HI_MPI_VI_EnableUserPic(VI_CHN ViChn); +HI_S32 HI_MPI_VI_DisableUserPic(VI_CHN ViChn); + +/* These functions are used to start the cascade mode. VI cascade mode can work normally Only when they have been called */ +HI_S32 HI_MPI_VI_SetVbiAttr(VI_CHN ViChn, VI_VBI_ARG_S *pstVbiAttr); +HI_S32 HI_MPI_VI_GetVbiAttr(VI_CHN ViChn, VI_VBI_ARG_S *pstVbiAttr); +HI_S32 HI_MPI_VI_EnableVbi(VI_CHN ViChn); +HI_S32 HI_MPI_VI_DisableVbi(VI_CHN ViChn); +HI_S32 HI_MPI_VI_EnableCascadeChn(VI_CHN ViChn); +HI_S32 HI_MPI_VI_DisableCascadeChn(VI_CHN ViChn); + +/* Normally, these functions are not necessary in typical business */ +HI_S32 HI_MPI_VI_BindChn(VI_CHN ViChn, const VI_CHN_BIND_ATTR_S *pstChnBindAttr); +HI_S32 HI_MPI_VI_UnBindChn(VI_CHN ViChn); +HI_S32 HI_MPI_VI_GetChnBind(VI_CHN ViChn, VI_CHN_BIND_ATTR_S *pstChnBindAttr); + +HI_S32 HI_MPI_VI_SetDevAttrEx(VI_DEV ViDev, const VI_DEV_ATTR_EX_S *pstDevAttrEx); +HI_S32 HI_MPI_VI_GetDevAttrEx(VI_DEV ViDev, VI_DEV_ATTR_EX_S *pstDevAttrEx); + +HI_S32 HI_MPI_VI_GetFd(VI_CHN ViChn); + +HI_S32 HI_MPI_VI_Query(VI_CHN ViChn, VI_CHN_STAT_S *pstStat); + +HI_S32 HI_MPI_VI_EnableChnInterrupt(VI_CHN ViChn); +HI_S32 HI_MPI_VI_DisableChnInterrupt(VI_CHN ViChn); + +HI_S32 HI_MPI_VI_GetChnLuma(VI_CHN ViChn, VI_CHN_LUM_S *pstLuma); +HI_S32 HI_MPI_VI_GetFileHandle(HI_S32 s32Id); + +HI_S32 HI_MPI_VI_SetSkipMode(VI_CHN ViChn, VI_SKIP_MODE_E enSkipMode); +HI_S32 HI_MPI_VI_GetSkipMode(VI_CHN ViChn, VI_SKIP_MODE_E* penSkipMode); +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /*__MPI_VI_H__ */ + + + diff --git a/snes9x/unix/mpp/mpi_vo.h b/snes9x/unix/mpp/mpi_vo.h new file mode 100644 index 0000000..6925a16 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vo.h @@ -0,0 +1,192 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vo.h + Version : Initial Draft + Author : Hisilicon multimedia software group + Created : 2013/05/08 + Description : + History : + 1.Date : 2013/05/08 + Author : d00224772 + Modification: Created file + +******************************************************************************/ +#ifndef __MPI_VO_H__ +#define __MPI_VO_H__ + +#include "hi_comm_vo.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" +{ +#endif +#endif /* __cplusplus */ + +/* Device Settings */ +HI_S32 HI_MPI_VO_SetPubAttr(VO_DEV VoDev, const VO_PUB_ATTR_S *pstPubAttr); +HI_S32 HI_MPI_VO_GetPubAttr(VO_DEV VoDev, VO_PUB_ATTR_S *pstPubAttr); + +HI_S32 HI_MPI_VO_Enable (VO_DEV VoDev); +HI_S32 HI_MPI_VO_Disable(VO_DEV VoDev); + +HI_S32 HI_MPI_VO_CloseFd(HI_VOID); + +/* Video Settings */ + +HI_S32 HI_MPI_VO_SetVideoLayerAttr(VO_LAYER VoLayer, const VO_VIDEO_LAYER_ATTR_S *pstLayerAttr); +HI_S32 HI_MPI_VO_GetVideoLayerAttr(VO_LAYER VoLayer, VO_VIDEO_LAYER_ATTR_S *pstLayerAttr); + +HI_S32 HI_MPI_VO_SetVideoLayerCompressAttr(VO_LAYER VoLayer, const VO_COMPRESS_ATTR_S *pstCompressAttr); +HI_S32 HI_MPI_VO_GetVideoLayerCompressAttr(VO_LAYER VoLayer, VO_COMPRESS_ATTR_S *pstCompressAttr); + +HI_S32 HI_MPI_VO_EnableVideoLayer (VO_LAYER VoLayer); +HI_S32 HI_MPI_VO_DisableVideoLayer(VO_LAYER VoLayer); + +HI_S32 HI_MPI_VO_BindVideoLayer(VO_LAYER VoLayer, VO_DEV VoDev); +HI_S32 HI_MPI_VO_UnBindVideoLayer(VO_LAYER VoLayer, VO_DEV VoDev); + +HI_S32 HI_MPI_VO_SetVideoLayerPriority(VO_LAYER VoLayer, HI_U32 u32Priority); +HI_S32 HI_MPI_VO_GetVideoLayerPriority(VO_LAYER VoLayer, HI_U32 *pu32Priority); + +HI_S32 HI_MPI_VO_SetVideoLayerCSC(VO_LAYER VoLayer, const VO_CSC_S *pstVideoCSC); +HI_S32 HI_MPI_VO_GetVideoLayerCSC(VO_LAYER VoLayer, VO_CSC_S *pstVideoCSC); + +HI_S32 HI_MPI_VO_SetVideoLayerPartitionMode(VO_LAYER VoLayer, VO_PART_MODE_E enPartMode); +HI_S32 HI_MPI_VO_GetVideoLayerPartitionMode(VO_LAYER VoLayer, VO_PART_MODE_E *penPartMode); + +HI_S32 HI_MPI_VO_SetAttrBegin(VO_LAYER VoLayer); +HI_S32 HI_MPI_VO_SetAttrEnd (VO_LAYER VoLayer); + +HI_S32 HI_MPI_VO_GetScreenFrame(VO_LAYER VoLayer, VIDEO_FRAME_INFO_S *pstVFrame, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VO_ReleaseScreenFrame(VO_LAYER VoLayer, VIDEO_FRAME_INFO_S *pstVFrame); + +HI_S32 HI_MPI_VO_SetDispBufLen(VO_LAYER VoLayer, HI_U32 u32BufLen); +HI_S32 HI_MPI_VO_GetDispBufLen(VO_LAYER VoLayer, HI_U32 *pu32BufLen); + +/* General Operation of Channel */ + +HI_S32 HI_MPI_VO_EnableChn (VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_DisableChn(VO_LAYER VoLayer, VO_CHN VoChn); + +HI_S32 HI_MPI_VO_SetChnAttr(VO_LAYER VoLayer, VO_CHN VoChn, const VO_CHN_ATTR_S *pstChnAttr); +HI_S32 HI_MPI_VO_GetChnAttr(VO_LAYER VoLayer, VO_CHN VoChn, VO_CHN_ATTR_S *pstChnAttr); + +HI_S32 HI_MPI_VO_SetChnParam(VO_LAYER VoLayer, VO_CHN VoChn, const VO_CHN_PARAM_S *pstChnParam); +HI_S32 HI_MPI_VO_GetChnParam(VO_LAYER VoLayer, VO_CHN VoChn, VO_CHN_PARAM_S *pstChnParam); + +HI_S32 HI_MPI_VO_SetChnDispPos(VO_LAYER VoLayer, VO_CHN VoChn, const POINT_S *pstDispPos); +HI_S32 HI_MPI_VO_GetChnDispPos(VO_LAYER VoLayer, VO_CHN VoChn, POINT_S *pstDispPos); + +HI_S32 HI_MPI_VO_SetChnField(VO_LAYER VoLayer, VO_CHN VoChn, const VO_DISPLAY_FIELD_E enField); +HI_S32 HI_MPI_VO_GetChnField(VO_LAYER VoLayer, VO_CHN VoChn, VO_DISPLAY_FIELD_E *pField); + +HI_S32 HI_MPI_VO_SetChnFrameRate(VO_LAYER VoLayer, VO_CHN VoChn, HI_S32 s32ChnFrmRate); +HI_S32 HI_MPI_VO_GetChnFrameRate(VO_LAYER VoLayer, VO_CHN VoChn, HI_S32 *ps32ChnFrmRate); + +HI_S32 HI_MPI_VO_GetChnFrame(VO_LAYER VoLayer, VO_CHN VoChn, VIDEO_FRAME_INFO_S *pstFrame, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VO_ReleaseChnFrame(VO_LAYER VoLayer, VO_CHN VoChn, const VIDEO_FRAME_INFO_S *pstFrame); + +HI_S32 HI_MPI_VO_PauseChn (VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_ResumeChn(VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_StepChn(VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_RefreshChn( VO_LAYER VoLayer, VO_CHN VoChn); + +HI_S32 HI_MPI_VO_ShowChn(VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_HideChn(VO_LAYER VoLayer, VO_CHN VoChn); + +HI_S32 HI_MPI_VO_SetZoomInWindow(VO_LAYER VoLayer, VO_CHN VoChn, const VO_ZOOM_ATTR_S *pstZoomAttr); +HI_S32 HI_MPI_VO_GetZoomInWindow(VO_LAYER VoLayer, VO_CHN VoChn, VO_ZOOM_ATTR_S *pstZoomAttr); + +HI_S32 HI_MPI_VO_SetPlayToleration(VO_LAYER VoLayer, HI_U32 u32Toleration); +HI_S32 HI_MPI_VO_GetPlayToleration(VO_LAYER VoLayer, HI_U32 *pu32Toleration); + +HI_S32 HI_MPI_VO_GetChnPts (VO_LAYER VoLayer, VO_CHN VoChn, HI_U64 *pu64ChnPts); +HI_S32 HI_MPI_VO_QueryChnStat(VO_LAYER VoLayer, VO_CHN VoChn, VO_QUERY_STATUS_S *pstStatus); + +HI_S32 HI_MPI_VO_SendFrame(VO_LAYER VoLayer, VO_CHN VoChn, VIDEO_FRAME_INFO_S *pstVFrame, HI_S32 s32MilliSec); + +HI_S32 HI_MPI_VO_ClearChnBuffer(VO_LAYER VoLayer, VO_CHN VoChn, HI_BOOL bClrAll); + +HI_S32 HI_MPI_VO_SetChnBorder(VO_LAYER VoLayer, VO_CHN VoChn, const VO_BORDER_S *pstBorder); +HI_S32 HI_MPI_VO_GetChnBorder(VO_LAYER VoLayer, VO_CHN VoChn, VO_BORDER_S *pstBorder); + +HI_S32 HI_MPI_VO_SetChnReceiveThreshold(VO_LAYER VoLayer, VO_CHN VoChn, HI_U32 u32Threshold); +HI_S32 HI_MPI_VO_GetChnReceiveThreshold(VO_LAYER VoLayer, VO_CHN VoChn, HI_U32 *pu32Threshold); + +HI_S32 HI_MPI_VO_GetChnRegionLuma(VO_LAYER VoLayer, VO_CHN VoChn, VO_REGION_INFO_S *pstRegionInfo, + HI_U32 *pu32LumaData, HI_S32 s32MilliSec); +/* WBC setting */ + +HI_S32 HI_MPI_VO_SetWbcSource(VO_WBC VoWbc, const VO_WBC_SOURCE_S *pstWbcSource); +HI_S32 HI_MPI_VO_GetWbcSource(VO_WBC VoWbc, VO_WBC_SOURCE_S *pstWbcSources); + +HI_S32 HI_MPI_VO_EnableWbc(VO_WBC VoWbc); +HI_S32 HI_MPI_VO_DisableWbc(VO_WBC VoWbc); + +HI_S32 HI_MPI_VO_SetWbcAttr(VO_WBC VoWbc, const VO_WBC_ATTR_S *pstWbcAttr); +HI_S32 HI_MPI_VO_GetWbcAttr(VO_WBC VoWbc, VO_WBC_ATTR_S *pstWbcAttr); + +HI_S32 HI_MPI_VO_SetWbcMode(VO_WBC VoWbc, VO_WBC_MODE_E enWbcMode); +HI_S32 HI_MPI_VO_GetWbcMode(VO_WBC VoWbc, VO_WBC_MODE_E *penWbcMode); + +HI_S32 HI_MPI_VO_SetWbcDepth(VO_WBC VoWbc, HI_U32 u32Depth); +HI_S32 HI_MPI_VO_GetWbcDepth(VO_WBC VoWbc, HI_U32 *pu32Depth); + +HI_S32 HI_MPI_VO_GetWbcFrame(VO_WBC VoWbc, VIDEO_FRAME_INFO_S *pstVFrame, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VO_ReleaseWbcFrame(VO_WBC VoWbc, VIDEO_FRAME_INFO_S *pstVFrame); + +/* GraphicLayer setting */ + +HI_S32 HI_MPI_VO_BindGraphicLayer(GRAPHIC_LAYER GraphicLayer, VO_DEV VoDev); +HI_S32 HI_MPI_VO_UnBindGraphicLayer(GRAPHIC_LAYER GraphicLayer, VO_DEV VoDev); + +HI_S32 HI_MPI_VO_SetGraphicLayerCSC(GRAPHIC_LAYER GraphicLayer, const VO_CSC_S *pstCSC); +HI_S32 HI_MPI_VO_GetGraphicLayerCSC(GRAPHIC_LAYER GraphicLayer, VO_CSC_S *pstCSC); + +/* Cascade setting */ + +HI_S32 HI_MPI_VO_SetCascadeAttr(const VO_CAS_ATTR_S *pstCasAttr); +HI_S32 HI_MPI_VO_GetCascadeAttr(VO_CAS_ATTR_S *pstCasAttr); + +HI_S32 HI_MPI_VO_EnableCascadeDev (VO_DEV VoCasDev); +HI_S32 HI_MPI_VO_DisableCascadeDev(VO_DEV VoCasDev); + +HI_S32 HI_MPI_VO_SetCascadePattern(VO_DEV VoCasDev, HI_U32 u32Pattern); +HI_S32 HI_MPI_VO_GetCascadePattern(VO_DEV VoCasDev, HI_U32 *pu32Pattern); + +HI_S32 HI_MPI_VO_CascadePosBindChn(HI_U32 u32Pos, VO_DEV VoCasDev, VO_CHN VoChn); +HI_S32 HI_MPI_VO_CascadePosUnBindChn(HI_U32 u32Pos, VO_DEV VoCasDev, VO_CHN VoChn); + +HI_S32 HI_MPI_VO_EnableCascade (HI_VOID); +HI_S32 HI_MPI_VO_DisableCascade(HI_VOID); + +/* VGA setting */ + +HI_S32 HI_MPI_VO_GetVgaParam(VO_DEV VoDev, VO_VGA_PARAM_S *pstVgaParam); +HI_S32 HI_MPI_VO_SetVgaParam(VO_DEV VoDev, VO_VGA_PARAM_S *pstVgaParam); + +HI_S32 HI_MPI_VO_SetDevFrameRate(VO_DEV VoDev, HI_U32 u32FrameRate); +HI_S32 HI_MPI_VO_GetDevFrameRate(VO_DEV VoDev, HI_U32 *pu32FrameRate); + +HI_S32 HI_MPI_VO_EnableRecvFrameRateMatch (VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 HI_MPI_VO_DisableRecvFrameRateMatch (VO_LAYER VoLayer, VO_CHN VoChn); + +/* HDMI setting */ +HI_S32 HI_MPI_VO_GetHdmiParam(VO_DEV VoDev, VO_HDMI_PARAM_S *pstHdmiParam); +HI_S32 HI_MPI_VO_SetHdmiParam(VO_DEV VoDev, VO_HDMI_PARAM_S *pstHdmiParam); + +HI_S32 HI_MPI_VO_SetVtth(VO_DEV VoDev, HI_U32 u32Vtth); +HI_S32 HI_MPI_VO_GetVtth(VO_DEV VoDev, HI_U32* pu32Vtth); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /*__MPI_VO_H__ */ + diff --git a/snes9x/unix/mpp/mpi_vpss.h b/snes9x/unix/mpp/mpi_vpss.h new file mode 100644 index 0000000..e041560 --- /dev/null +++ b/snes9x/unix/mpp/mpi_vpss.h @@ -0,0 +1,118 @@ +/****************************************************************************** + + Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd. + + ****************************************************************************** + File Name : mpi_vpss.h + Version : Initial Draft + Author : + Created : + Last Modified : + Description : mpi functions declaration + Function List : + History : + 1.Date : 20130508 + Author : l00183122 + Modification: Create +******************************************************************************/ +#ifndef __MPI_VPSS_H__ +#define __MPI_VPSS_H__ + +#include "hi_common.h" +#include "hi_comm_video.h" +#include "hi_comm_vpss.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* __cplusplus */ + + +HI_S32 HI_MPI_VPSS_CreateGrp(VPSS_GRP VpssGrp, VPSS_GRP_ATTR_S *pstGrpAttr); +HI_S32 HI_MPI_VPSS_DestroyGrp(VPSS_GRP VpssGrp); + +HI_S32 HI_MPI_VPSS_StartGrp(VPSS_GRP VpssGrp); +HI_S32 HI_MPI_VPSS_StopGrp(VPSS_GRP VpssGrp); + +HI_S32 HI_MPI_VPSS_ResetGrp(VPSS_GRP VpssGrp); + +HI_S32 HI_MPI_VPSS_EnableChn(VPSS_GRP VpssGrp, VPSS_CHN s32VpssChnl); +HI_S32 HI_MPI_VPSS_DisableChn(VPSS_GRP VpssGrp, VPSS_CHN s32VpssChnl); + +HI_S32 HI_MPI_VPSS_GetGrpAttr(VPSS_GRP VpssGrp, VPSS_GRP_ATTR_S *pstGrpAttr); +HI_S32 HI_MPI_VPSS_SetGrpAttr(VPSS_GRP VpssGrp, VPSS_GRP_ATTR_S *pstGrpAttr); + +HI_S32 HI_MPI_VPSS_EnableBackupFrame(VPSS_GRP VpssGrp); +HI_S32 HI_MPI_VPSS_DisableBackupFrame(VPSS_GRP VpssGrp); + + +HI_S32 HI_MPI_VPSS_GetChnAttr(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_ATTR_S *pstChnAttr); +HI_S32 HI_MPI_VPSS_SetChnAttr(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_ATTR_S *pstChnAttr); + +HI_S32 HI_MPI_VPSS_SetChnParam(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_PARAM_S *pstChnParam); +HI_S32 HI_MPI_VPSS_GetChnParam(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_PARAM_S *pstChnParam); + +HI_S32 HI_MPI_VPSS_SetGrpParam(VPSS_GRP VpssGrp, VPSS_GRP_PARAM_S *pstVpssParam); +HI_S32 HI_MPI_VPSS_GetGrpParam(VPSS_GRP VpssGrp, VPSS_GRP_PARAM_S *pstVpssParam); + +HI_S32 HI_MPI_VPSS_SetGrpAdvancedParam(VPSS_GRP VpssGrp, VPSS_NR_ADVANCED_PARAM_S *pstVpssParam); +HI_S32 HI_MPI_VPSS_GetGrpAdvancedParam(VPSS_GRP VpssGrp, VPSS_NR_ADVANCED_PARAM_S *pstVpssParam); + +HI_S32 HI_MPI_VPSS_SetGrpCrop(VPSS_GRP VpssGrp, VPSS_CROP_INFO_S *pstCropInfo); +HI_S32 HI_MPI_VPSS_GetGrpCrop(VPSS_GRP VpssGrp, VPSS_CROP_INFO_S *pstCropInfo); + +HI_S32 HI_MPI_VPSS_SetChnMode(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_MODE_S *pstVpssMode); +HI_S32 HI_MPI_VPSS_GetChnMode(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_CHN_MODE_S *pstVpssMode); + +HI_S32 HI_MPI_VPSS_SetDepth(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, HI_U32 u32Depth); +HI_S32 HI_MPI_VPSS_GetDepth(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, HI_U32 *pu32Depth); + +HI_S32 HI_MPI_VPSS_SendFrame(VPSS_GRP VpssGrp, VIDEO_FRAME_INFO_S *pstVideoFrame, HI_S32 s32MilliSec); + +HI_S32 HI_MPI_VPSS_GetChnFrame(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, + VIDEO_FRAME_INFO_S *pstVideoFrame, HI_S32 s32MilliSec); +HI_S32 HI_MPI_VPSS_ReleaseChnFrame(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VIDEO_FRAME_INFO_S *pstVideoFrame); + +HI_S32 HI_MPI_VPSS_GetGrpFrame(VPSS_GRP VpssGrp, VIDEO_FRAME_INFO_S *pstVideoFrame, HI_U32 u32FrameIndex); +HI_S32 HI_MPI_VPSS_ReleaseGrpFrame(VPSS_GRP VpssGrp, VIDEO_FRAME_INFO_S *pstVideoFrame); + +HI_S32 HI_MPI_VPSS_SetGrpDelay(VPSS_GRP VpssGrp, HI_U32 u32Delay); +HI_S32 HI_MPI_VPSS_GetGrpDelay(VPSS_GRP VpssGrp, HI_U32 *pu32Delay); + +HI_S32 HI_MPI_VPSS_SetPreScale(VPSS_GRP VpssGrp,VPSS_PRESCALE_INFO_S *pstPreScaleInfo); +HI_S32 HI_MPI_VPSS_GetPreScale(VPSS_GRP VpssGrp,VPSS_PRESCALE_INFO_S *pstPreScaleInfo); + +HI_S32 HI_MPI_VPSS_SetGrpSizer(VPSS_GRP VpssGrp, VPSS_SIZER_INFO_S *pstVpssSizerInfo); +HI_S32 HI_MPI_VPSS_GetGrpSizer(VPSS_GRP VpssGrp, VPSS_SIZER_INFO_S *pstVpssSizerInfo); + + +HI_S32 HI_MPI_VPSS_SetGrpFrameRate(VPSS_GRP VpssGrp, VPSS_FRAME_RATE_S *pstVpssFrameRate); +HI_S32 HI_MPI_VPSS_GetGrpFrameRate(VPSS_GRP VpssGrp, VPSS_FRAME_RATE_S *pstVpssFrameRate); + +HI_S32 HI_MPI_VPSS_SetChnOverlay(VPSS_GRP VpssGrp,VPSS_CHN VpssChn, HI_U32 u32OverlayMask); +HI_S32 HI_MPI_VPSS_GetChnOverlay(VPSS_GRP VpssGrp,VPSS_CHN VpssChn, HI_U32 *pu32OverlayMask); + + +HI_S32 HI_MPI_VPSS_GetGrpRegionLuma(VPSS_GRP VpssGrp,VPSS_REGION_INFO_S *pstRegionInfo, + HI_U32 *pu32LumaData,HI_S32 s32MilliSec); +HI_S32 HI_MPI_VPSS_GetChnRegionLuma(VPSS_GRP VpssGrp, VPSS_CHN VpssChn, VPSS_REGION_INFO_S *pstRegionInfo, + HI_U32 *pu32LumaData,HI_S32 s32MilliSec); + + +HI_S32 HI_MPI_VPSS_EnableUserFrameRateCtrl(VPSS_GRP VpssGrp); +HI_S32 HI_MPI_VPSS_DisableUserFrameRateCtrl(VPSS_GRP VpssGrp); + + +HI_S32 HI_MPI_VPSS_SetPreScaleMode(VPSS_GRP VpssGrp, VPSS_PRESCALE_MODE_E enVpssPreScaleMode); +HI_S32 HI_MPI_VPSS_GetPreScaleMode(VPSS_GRP VpssGrp, VPSS_PRESCALE_MODE_E* penVpssPreScaleMode); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* __MPI_VPSS_H__ */ + diff --git a/snes9x/unix/sample_comm.h b/snes9x/unix/sample_comm.h new file mode 100644 index 0000000..5b58e1a --- /dev/null +++ b/snes9x/unix/sample_comm.h @@ -0,0 +1,467 @@ +/****************************************************************************** + Hisilicon HI3531 sample programs head file. + + Copyright (C), 2010-2011, Hisilicon Tech. Co., Ltd. + ****************************************************************************** + Modification: 2011-2 Created +******************************************************************************/ + +#ifndef __SAMPLE_COMM_H__ +#define __SAMPLE_COMM_H__ + +#include +#include +#include "mpp/hi_common.h" +#include "mpp/hi_comm_sys.h" +#include "mpp/hi_comm_vb.h" +#include "mpp/hi_comm_vi.h" +#include "mpp/hi_comm_vo.h" +#include "mpp/hi_comm_venc.h" +#include "mpp/hi_comm_vpss.h" +#include "mpp/hi_comm_vdec.h" +#include "mpp/hi_comm_vda.h" +#include "mpp/hi_comm_region.h" +#include "mpp/hi_comm_adec.h" +#include "mpp/hi_comm_aenc.h" +#include "mpp/hi_comm_ai.h" +#include "mpp/hi_comm_ao.h" +#include "mpp/hi_comm_aio.h" +#include "mpp/hi_comm_hdmi.h" +#include "mpp/hi_defines.h" + +#include "mpp/mpi_sys.h" +#include "mpp/mpi_vb.h" +#include "mpp/mpi_vi.h" +#include "mpp/mpi_vo.h" +#include "mpp/mpi_venc.h" +#include "mpp/mpi_vpss.h" +#include "mpp/mpi_vdec.h" +#include "mpp/mpi_vda.h" +#include "mpp/mpi_region.h" +#include "mpp/mpi_adec.h" +#include "mpp/mpi_aenc.h" +#include "mpp/mpi_ai.h" +#include "mpp/mpi_ao.h" +#include "mpp/mpi_hdmi.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* Begin of #ifdef __cplusplus */ + +/******************************************************* + macro define +*******************************************************/ +#define CHECK_CHN_RET(express,Chn,name)\ + do{\ + HI_S32 Ret;\ + Ret = express;\ + if (HI_SUCCESS != Ret)\ + {\ + printf("\033[0;31m%s chn %d failed at %s: LINE: %d with %#x!\033[0;39m\n", name, Chn, __FUNCTION__, __LINE__, Ret);\ + fflush(stdout);\ + return Ret;\ + }\ + }while(0) + +#define CHECK_RET(express,name)\ + do{\ + HI_S32 Ret;\ + Ret = express;\ + if (HI_SUCCESS != Ret)\ + {\ + printf("\033[0;31m%s failed at %s: LINE: %d with %#x!\033[0;39m\n", name, __FUNCTION__, __LINE__, Ret);\ + return Ret;\ + }\ + }while(0) + +//#define SAMPLE_GLOBAL_NORM VIDEO_ENCODING_MODE_PAL +#define SAMPLE_PIXEL_FORMAT PIXEL_FORMAT_YUV_SEMIPLANAR_420 + +#define TW2865_FILE "/dev/tw2865dev" +#define TW2960_FILE "/dev/tw2960dev" +#define TLV320_FILE "/dev/tlv320aic31" +#define NVP6124_FILE "/dev/nvp6124" + + +#define SAMPLE_VO_DEV_DHD0 0 +#define SAMPLE_VO_DEV_DSD0 1 +#define SAMPLE_VO_DEV_VIRT0 2 +#define SAMPLE_VO_DEV_DSD1 -1 + +#define SAMPLE_VO_LAYER_VHD0 0 +#define SAMPLE_VO_LAYER_VSD0 2 +#define SAMPLE_VO_LAYER_VIRT0 3 +#define SAMPLE_VO_LAYER_VPIP 1 + +#define VO_LAYER_PIP 1 +#define VO_LAYER_PIP_STA 1 +#define VO_LAYER_PIP_END 1 +#define VO_DEV_HD_END 0 + + +#define SAMPLE_VO_WBC_BASE 0 +#define SAMPLE_VO_LAYER_PRIORITY_BASE 0 +#define SAMPLE_VO_LAYER_PRIORITY_PIP 1 +#define GRAPHICS_LAYER_HC0 2 + +#define SAMPLE_AUDIO_PTNUMPERFRM 320 +#define SAMPLE_AUDIO_TLV320_DEV 1 +#define SAMPLE_AUDIO_TW2865_DEV 0 +#define SAMPLE_AUDIO_HDMI_AO_DEV 1 +#define SAMPLE_AUDIO_AI_DEV 0 +#define SAMPLE_AUDIO_AO_DEV 0 + +#define SAMPLE_CIF_H264_PATH "../common/CIF.h264" +#define SAMPLE_1080P_H264_PATH "../common/1080P.h264" +#define SAMPLE_1080P_H265_PATH "../common/1080P.h265" +#define SAMPLE_4K_H264_PATH "../common/tmp1" +#define SAMPLE_4K_H265_PATH "../common/tmp2" +#define SAMPLE_1080P_MPEG4_PATH "../common/1080P.mpeg4" +#define SAMPLE_FIELD_H264_PATH "../common/D1_field.h264" +#define SAMPLE_1080P_JPEG_PATH "../common/1080P.jpg" +#define SAMPLE_4K_JPEG_PATH "../common/tmp3" + +#define SAMPLE_MAX_VDEC_CHN_CNT 8 + + +#define ALIGN_UP(x, a) ((x+a-1)&(~(a-1))) +#define ALIGN_BACK(x, a) ((a) * (((x) / (a)))) + +#define SAMPLE_SYS_ALIGN_WIDTH 16 +#define VO_BKGRD_BLUE 0x0000FF + +#define HD_WIDTH 1920 +#define HD_HEIGHT 1080 + +#define D1_WIDTH 720 +#define D1_HEIGHT 576 + +#define _720P_WIDTH 1280 +#define _720P_HEIGHT 720 + +#define SAMPLE_PRT(fmt...) \ + do {\ + printf("[%s]-%d: ", __FUNCTION__, __LINE__);\ + printf(fmt);\ + }while(0) + + +typedef enum sample_vi_mode_e +{ + SAMPLE_VI_MODE_16_D1, + SAMPLE_VI_MODE_16_960H, + SAMPLE_VI_MODE_16_1280H, + SAMPLE_VI_MODE_16_HALF720P, + + SAMPLE_VI_MODE_8_720P, + SAMPLE_VI_MODE_16_720P, + + SAMPLE_VI_MODE_4_1080P, + SAMPLE_VI_MODE_8_1080P, + SAMPLE_VI_MODE_16_1080P, + + SAMPLE_VI_MODE_4_3M, +}SAMPLE_VI_MODE_E; + +typedef enum sample_vi_6124_mode_e +{ + /*nextchip nvp6124/6114a*/ + SAMPLE_VI_MODE_6124_960H, + SAMPLE_VI_MODE_6124_HDX, //640x720 + SAMPLE_VI_MODE_6124_HD, //720p + SAMPLE_VI_MODE_6124_FHDX, //960x1080 + SAMPLE_VI_MODE_6124_FHD, //1080p + SAMPLE_VI_MODE_960H_720P_2MUX, + SAMPLE_VI_MODE_6124_2MUX_FHD, //1080p + SAMPLE_VI_MODE_6124_4MUX_HD, //4mux 720p + +}SAMPLE_VI_6124_MODE_E; + +enum +{ + NVP6124_VI_SD = 0, + NVP6124_VI_720P_2530, + NVP6124_VI_720P_5060, + NVP6124_VI_1080P_2530, + NVP6124_VI_1920H, + NVP6124_VI_BUTT +}; + +typedef enum sample_vi_6124_mux_e +{ + NVP6124_OUTMODE_1MUX_SD = 0, + NVP6124_OUTMODE_1MUX_HD, + NVP6124_OUTMODE_1MUX_HD5060, + NVP6124_OUTMODE_1MUX_FHD, + NVP6124_OUTMODE_2MUX_SD, + NVP6124_OUTMODE_2MUX_HD_X, + NVP6124_OUTMODE_2MUX_HD, + NVP6124_OUTMODE_2MUX_FHD_X, + NVP6124_OUTMODE_4MUX_SD, + NVP6124_OUTMODE_4MUX_HD_X, + NVP6124_OUTMODE_4MUX_HD, + NVP6124_OUTMODE_2MUX_FHD, + NVP6124_OUTMODE_BUTT +}SAMPLE_VI_6124_MUX_E; + +typedef struct sample_vi_param_s +{ + HI_S32 s32ViDevCnt; // VI Dev Total Count + HI_S32 s32ViDevInterval; // Vi Dev Interval + HI_S32 s32ViChnCnt; // Vi Chn Total Count + HI_S32 s32ViChnInterval; // VI Chn Interval +}SAMPLE_VI_PARAM_S; + +typedef enum sample_vi_chn_set_e +{ + VI_CHN_SET_NORMAL = 0, /* mirror, filp close */ + VI_CHN_SET_MIRROR, /* open MIRROR */ + VI_CHN_SET_FILP /* open filp */ +}SAMPLE_VI_CHN_SET_E; + +typedef enum sample_vo_mode_e +{ + VO_MODE_1MUX = 0, + VO_MODE_4MUX = 1, + VO_MODE_9MUX = 2, + VO_MODE_16MUX = 3, + VO_MODE_BUTT +}SAMPLE_VO_MODE_E; + +typedef struct hisample_MEMBUF_S +{ + VB_BLK hBlock; + VB_POOL hPool; + HI_U32 u32PoolId; + + HI_U32 u32PhyAddr; + HI_U8 *pVirAddr; + HI_S32 s32Mdev; +} SAMPLE_MEMBUF_S; + +typedef enum sample_rc_e +{ + SAMPLE_RC_CBR = 0, + SAMPLE_RC_VBR, + SAMPLE_RC_FIXQP +}SAMPLE_RC_E; + +typedef enum sample_rgn_change_type_e +{ + RGN_CHANGE_TYPE_FGALPHA = 0, + RGN_CHANGE_TYPE_BGALPHA, + RGN_CHANGE_TYPE_LAYER +}SAMPLE_RGN_CHANGE_TYPE_EN; + +typedef struct sample_vo_param_s +{ + VO_DEV VoDev; + HI_CHAR acMmzName[20]; + HI_U32 u32WndNum; + SAMPLE_VO_MODE_E enVoMode; + VO_PUB_ATTR_S stVoPubAttr; + HI_BOOL bVpssBind; +}SAMPLE_VO_PARAM_S; + +typedef struct sample_venc_getstream_s +{ + HI_BOOL bThreadStart; + HI_S32 s32Cnt; +}SAMPLE_VENC_GETSTREAM_PARA_S; + +typedef enum +{ + HIFB_LAYER_0 = 0x0, + HIFB_LAYER_1, + HIFB_LAYER_2, + HIFB_LAYER_CURSOR_0, + HIFB_LAYER_ID_BUTT +} HIFB_LAYER_ID_E; + +typedef enum hiVdecThreadCtrlSignal_E +{ + VDEC_CTRL_START, + VDEC_CTRL_PAUSE, + VDEC_CTRL_STOP, +}VdecThreadCtrlSignal_E; + +typedef struct hiVdecThreadParam +{ + HI_S32 s32ChnId; + PAYLOAD_TYPE_E enType; + HI_CHAR cFileName[100]; + HI_S32 s32StreamMode; + HI_S32 s32MilliSec; + HI_S32 s32MinBufSize; + HI_S32 s32IntervalTime; + VdecThreadCtrlSignal_E eCtrlSinal; + HI_U64 u64PtsInit; + HI_U64 u64PtsIncrease; + HI_BOOL bLoopSend; + HI_BOOL bManuSend; + HI_CHAR cUserCmd; +}VdecThreadParam; + +typedef enum hiAudioCodecType +{ + AUDIO_CODEC_INNER = 0, + AUDIO_CODEC_TLV320, + AUDIO_CODEC_HDMI, + AUDIO_CODEC_TW2865, + AUDIO_CODEC_BUTT +}AudioCodecType; + +typedef struct hiHDMI_CALLBACK_ARGS_S +{ + HI_HDMI_ID_E enHdmi; + HI_HDMI_VIDEO_FMT_E eForceFmt; +}HDMI_CALLBACK_ARGS_S; + +/******************************************************* + function announce +*******************************************************/ +HI_S32 SAMPLE_COMM_SYS_GetPicSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, SIZE_S *pstSize); +HI_U32 SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth,COMPRESS_MODE_E enCompFmt); +HI_S32 SAMPLE_COMM_SYS_MemConfig(HI_VOID); +HI_VOID SAMPLE_COMM_SYS_Exit(void); +HI_S32 SAMPLE_COMM_SYS_Init(VB_CONF_S *pstVbConf); +HI_S32 SAMPLE_COMM_SYS_Payload2FilePostfix(PAYLOAD_TYPE_E enPayload, HI_CHAR* szFilePostfix); + +HI_S32 SAMPLE_COMM_VI_Mode2Param(SAMPLE_VI_MODE_E enViMode, SAMPLE_VI_PARAM_S *pstViParam); +HI_S32 SAMPLE_COMM_VI_Mode2Size(SAMPLE_VI_MODE_E enViMode, VIDEO_NORM_E enNorm, RECT_S *pstCapRect, SIZE_S *pstDestSize); +VI_DEV SAMPLE_COMM_VI_GetDev(SAMPLE_VI_MODE_E enViMode, VI_CHN ViChn); +HI_S32 SAMPLE_COMM_VI_StartDev(VI_DEV ViDev, SAMPLE_VI_MODE_E enViMode); +HI_S32 SAMPLE_COMM_VI_ChnBindDev(VI_CHN ViChn, SAMPLE_VI_MODE_E enViMode); +HI_S32 SAMPLE_COMM_VI_StartChn(VI_CHN ViChn, RECT_S *pstCapRect, SIZE_S *pstTarSize, SAMPLE_VI_MODE_E enViMode, SAMPLE_VI_CHN_SET_E enViChnSet); +HI_S32 SAMPLE_COMM_VI_Start(SAMPLE_VI_MODE_E enViMode, VIDEO_NORM_E enNorm); +HI_S32 SAMPLE_COMM_VI_Stop(SAMPLE_VI_MODE_E enViMode); +HI_S32 SAMPLE_COMM_VI_BindVpss(SAMPLE_VI_MODE_E enViMode); +HI_S32 SAMPLE_COMM_VI_UnBindVpss(SAMPLE_VI_MODE_E enViMode); + +HI_VOID SAMPLE_COMM_VDEC_Sysconf(VB_CONF_S *pstVbConf, SIZE_S *pstSize); +HI_VOID SAMPLE_COMM_VDEC_ModCommPoolConf(VB_CONF_S *pstModVbConf, + PAYLOAD_TYPE_E enType, SIZE_S *pstSize, HI_S32 s32ChnNum); +HI_S32 SAMPLE_COMM_VDEC_InitModCommVb(VB_CONF_S *pstModVbConf); +HI_VOID SAMPLE_COMM_VDEC_ChnAttr(HI_S32 s32ChnNum, VDEC_CHN_ATTR_S *pstVdecChnAttr, PAYLOAD_TYPE_E enType, SIZE_S *pstSize); +HI_VOID SAMPLE_COMM_VDEC_VpssGrpAttr(HI_S32 s32ChnNum, VPSS_GRP_ATTR_S *pstVpssGrpAttr, SIZE_S *pstSize); +HI_VOID SAMPLE_COMM_VDEC_VoAttr(HI_S32 s32ChnNum, VO_DEV VoDev ,VO_PUB_ATTR_S *pstVoPubAttr, VO_VIDEO_LAYER_ATTR_S *pstVoLayerAttr); +HI_VOID SAMPLE_COMM_VDEC_ThreadParam(HI_S32 s32ChnNum, VdecThreadParam *pstVdecSend, VDEC_CHN_ATTR_S *pstVdecChnAttr, char *pStreamFileName); +HI_S32 Sample_COMM_VPSS_StartCover(HI_S32 VpssGrp); +HI_VOID Sample_COMM_SetCrop(HI_S32 VpssGrp); +HI_VOID Sample_MST_GetDefVoAttr(VO_DEV VoDev, VO_PUB_ATTR_S *pstPubAttr, VO_VIDEO_LAYER_ATTR_S *pstLayerAttr, + HI_S32 s32SquareSort, VO_CHN_ATTR_S *astChnAttr); +HI_VOID Sample_MST_StartPIPVideoLayer(VO_DEV VoDev, VO_VIDEO_LAYER_ATTR_S *pstLayerAttr, + VO_CHN_ATTR_S *astChnAttr, HI_S32 s32ChnNum); +HI_VOID SAMPLE_COMM_VDEC_CmdCtrl(HI_S32 s32ChnNum,VdecThreadParam *pstVdecSend); +HI_VOID SAMPLE_COMM_VDEC_StartSendStream(HI_S32 s32ChnNum, VdecThreadParam *pstVdecSend, pthread_t *pVdecThread); +HI_VOID SAMPLE_COMM_VDEC_StopSendStream(HI_S32 s32ChnNum, VdecThreadParam *pstVdecSend, pthread_t *pVdecThread); +HI_VOID* SAMPLE_COMM_VDEC_SendStream(HI_VOID *pArgs); +HI_VOID SAMPLE_COMM_VDEC_StartGetLuma(HI_S32 s32ChnNum, VdecThreadParam *pstVdecSend, pthread_t *pVdecThread); +HI_VOID SAMPLE_COMM_VDEC_StopGetLuma(HI_S32 s32ChnNum, VdecThreadParam *pstVdecSend, pthread_t *pVdecThread); +HI_VOID* SAMPLE_COMM_VDEC_GetChnLuma(HI_VOID *pArgs); +HI_S32 SAMPLE_COMM_VDEC_Start(HI_S32 s32ChnNum, VDEC_CHN_ATTR_S *pstAttr); +HI_S32 SAMPLE_COMM_VDEC_Stop(HI_S32 s32ChnNum); +HI_S32 SAMPLE_COMM_VDEC_BindVpss(VDEC_CHN VdChn, VPSS_GRP VpssGrp); +HI_S32 SAMPLE_COMM_VDEC_UnBindVpss(VDEC_CHN VdChn, VPSS_GRP VpssGrp); +HI_S32 SAMPLE_COMM_VDEC_BindVo(VDEC_CHN VdChn, VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 SAMPLE_COMM_VDEC_UnBindVo(VDEC_CHN VdChn, VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 SAMPLE_COMM_VDEC_BindVenc(VDEC_CHN VdChn,VENC_CHN VeChn); +HI_S32 SAMPLE_COMM_VDEC_UnBindVenc(VDEC_CHN VdChn,VENC_CHN VeChn); +HI_S32 SAMPLE_COMM_VDEC_MemConfig(HI_VOID); + +HI_S32 SAMPLE_COMM_VPSS_MemConfig(); +HI_S32 SAMPLE_COMM_VPSS_Start(HI_S32 s32GrpCnt, SIZE_S *pstSize, HI_S32 s32ChnCnt,VPSS_GRP_ATTR_S *pstVpssGrpAttr); +HI_S32 SAMPLE_COMM_VPSS_Stop(HI_S32 s32GrpCnt, HI_S32 s32ChnCnt) ; +HI_S32 SAMPLE_COMM_DisableVpssPreScale(VPSS_GRP VpssGrp,SIZE_S stSize); +HI_S32 SAMPLE_COMM_EnableVpssPreScale(VPSS_GRP VpssGrp,SIZE_S stSize); + +HI_S32 SAMPLE_COMM_VO_MemConfig(VO_DEV VoDev, HI_CHAR *pcMmzName); +HI_S32 SAMPLE_COMM_VO_StartDev(VO_DEV VoDev, VO_PUB_ATTR_S *pstPubAttr); +HI_S32 SAMPLE_COMM_VO_StopDev(VO_DEV VoDev); +HI_S32 SAMPLE_COMM_VO_StartLayer(VO_LAYER VoLayer,const VO_VIDEO_LAYER_ATTR_S *pstLayerAttr); +HI_S32 SAMPLE_COMM_VO_StopLayer(VO_LAYER VoLayer); +HI_S32 SAMPLE_COMM_VO_StartChn(VO_LAYER VoLayer, SAMPLE_VO_MODE_E enMode); +HI_S32 SAMPLE_COMM_VO_StopChn(VO_LAYER VoLayer, SAMPLE_VO_MODE_E enMode); +HI_S32 SAMPLE_COMM_VO_StartWbc(VO_WBC VoWbc,const VO_WBC_ATTR_S *pstWbcAttr); +HI_S32 SAMPLE_COMM_VO_StopWbc(VO_WBC VoWbc); +HI_S32 SAMPLE_COMM_WBC_BindVo(VO_WBC VoWbc,VO_WBC_SOURCE_S *pstWbcSource); +HI_S32 SAMPLE_COMM_VO_BindVoWbc(VO_DEV VoWbcDev, VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 SAMPLE_COMM_VO_UnBindVoWbc(VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 SAMPLE_COMM_VO_BindVpss(VO_LAYER VoLayer,VO_CHN VoChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_Vpss_BindVpss(VO_LAYER VoLayer,VO_CHN VoChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_VO_UnBindVpss(VO_LAYER VoLayer,VO_CHN VoChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_VO_BindVi(VO_LAYER VoLayer, VO_CHN VoChn, VI_CHN ViChn); +HI_S32 SAMPLE_COMM_VO_UnBindVi(VO_LAYER VoLayer, VO_CHN VoChn); +HI_S32 SAMPLE_COMM_VO_GetWH(VO_INTF_SYNC_E enIntfSync,HI_U32 *pu32W,HI_U32 *pu32H,HI_U32 *pu32Frm); +HI_S32 SAMPLE_COMM_VO_HdmiCallbackStart(VO_INTF_SYNC_E enIntfSync, HDMI_CALLBACK_ARGS_S *pstCallbackArgs); +HI_S32 SAMPLE_COMM_VO_HdmiStart(VO_INTF_SYNC_E enIntfSync); +HI_S32 SAMPLE_COMM_VO_HdmiStop(HI_VOID); +HI_S32 SAMPLE_COMM_VO_SnapStart(VENC_CHN VencChn, SIZE_S *pstSize); +HI_S32 SAMPLE_COMM_VO_SnapProcess(VENC_CHN VencChn); + +HI_S32 SAMPLE_COMM_VO_SaveSnap(VENC_STREAM_S *pstStream); +HI_S32 SAMPLE_COMM_VO_SnapStop(VENC_CHN VencChn); + +HI_S32 SAMPLE_COMM_VENC_MemConfig(HI_VOID); +HI_S32 SAMPLE_COMM_VENC_Start(VENC_CHN VencChn, PAYLOAD_TYPE_E enType, VIDEO_NORM_E enNorm, PIC_SIZE_E enSize, SAMPLE_RC_E enRcMode,HI_U32 u32Profile); +HI_S32 SAMPLE_COMM_VENC_Stop(VENC_CHN VencChn); +HI_S32 SAMPLE_COMM_VENC_SnapStart(VENC_CHN VencChn, SIZE_S *pstSize); +HI_S32 SAMPLE_COMM_VENC_SnapProcess(VENC_CHN VencChn, VPSS_GRP VpssGrp, VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_VENC_SnapStop(VENC_CHN VencChn); +HI_S32 SAMPLE_COMM_VENC_StartGetStream(HI_S32 s32Cnt); +HI_S32 SAMPLE_COMM_VENC_StopGetStream(); +HI_S32 SAMPLE_COMM_VENC_BindVpss(VENC_CHN VencChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_VENC_UnBindVpss(VENC_CHN VencChn,VPSS_GRP VpssGrp,VPSS_CHN VpssChn); +HI_S32 SAMPLE_COMM_VENC_BindVo(VO_DEV VoDev,VO_CHN VoChn,VENC_CHN VeChn); +HI_S32 SAMPLE_COMM_VENC_UnBindVo(VENC_CHN GrpChn,VO_DEV VoDev,VO_CHN VoChn); + +HI_S32 SAMPLE_COMM_VDA_MdStart(VDA_CHN VdaChn, HI_U32 u32Chn, SIZE_S *pstSize); +HI_S32 SAMPLE_COMM_VDA_OdStart(VDA_CHN VdaChn, HI_U32 u32Chn, SIZE_S *pstSize); +HI_VOID SAMPLE_COMM_VDA_MdStop(VDA_CHN VdaChn, HI_U32 u32Chn); +HI_VOID SAMPLE_COMM_VDA_OdStop(VDA_CHN VdaChn, HI_U32 u32Chn); + +HI_S32 SAMPLE_COMM_AUDIO_CreatTrdAiAo(AUDIO_DEV AiDev, AI_CHN AiChn, AUDIO_DEV AoDev, AO_CHN AoChn); +HI_S32 SAMPLE_COMM_AUDIO_CreatTrdAiAenc(AUDIO_DEV AiDev, AI_CHN AiChn, AENC_CHN AeChn); +HI_S32 SAMPLE_COMM_AUDIO_CreatTrdAoVolCtrl(AUDIO_DEV AiDev); +HI_S32 SAMPLE_COMM_AUDIO_DestoryTrdAi(AUDIO_DEV AiDev, AI_CHN AiChn); +HI_S32 SAMPLE_COMM_AUDIO_DestoryTrdAencAdec(AENC_CHN AeChn); +HI_S32 SAMPLE_COMM_AUDIO_DestoryTrdFileAdec(ADEC_CHN AdChn); +HI_S32 SAMPLE_COMM_AUDIO_DestoryTrdAoVolCtrl(AUDIO_DEV AiDev); +HI_S32 SAMPLE_COMM_AUDIO_DestoryAllTrd(); +HI_S32 SAMPLE_COMM_AUDIO_AoBindAdec(AUDIO_DEV AoDev, AO_CHN AoChn, ADEC_CHN AdChn); +HI_S32 SAMPLE_COMM_AUDIO_AoUnbindAdec(AUDIO_DEV AoDev, AO_CHN AoChn, ADEC_CHN AdChn); +HI_S32 SAMPLE_COMM_AUDIO_AoBindAi(AUDIO_DEV AiDev, AI_CHN AiChn, AUDIO_DEV AoDev, AO_CHN AoChn); +HI_S32 SAMPLE_COMM_AUDIO_AoUnbindAi(AUDIO_DEV AiDev, AI_CHN AiChn, AUDIO_DEV AoDev, AO_CHN AoChn); +HI_S32 SAMPLE_COMM_AUDIO_AencBindAi(AUDIO_DEV AiDev, AI_CHN AiChn, AENC_CHN AeChn); +HI_S32 SAMPLE_COMM_AUDIO_AencUnbindAi(AUDIO_DEV AiDev, AI_CHN AiChn, AENC_CHN AeChn); +HI_S32 SAMPLE_COMM_AUDIO_CfgAcodec(AIO_ATTR_S *pstAioAttr); +HI_S32 SAMPLE_COMM_AUDIO_DisableAcodec(); +HI_S32 SAMPLE_COMM_AUDIO_StartAi(AUDIO_DEV AiDevId, HI_S32 s32AiChnCnt, + AIO_ATTR_S* pstAioAttr, AUDIO_SAMPLE_RATE_E enOutSampleRate, HI_BOOL bResampleEn, AI_VQE_CONFIG_S* pstAiVqeAttr); + +HI_S32 SAMPLE_COMM_AUDIO_StopAi(AUDIO_DEV AiDevId, HI_S32 s32AiChnCnt, + HI_BOOL bResampleEn, HI_BOOL bVqeEn); + +HI_S32 SAMPLE_COMM_AUDIO_StartAo(AUDIO_DEV AoDevId, HI_S32 s32AoChnCnt, + AIO_ATTR_S* pstAioAttr, AUDIO_SAMPLE_RATE_E enInSampleRate, HI_BOOL bResampleEn); +HI_S32 SAMPLE_COMM_AUDIO_StopAo(AUDIO_DEV AoDevId, HI_S32 s32AoChnCnt, HI_BOOL bResampleEn); +HI_S32 SAMPLE_COMM_AUDIO_StartAenc(HI_S32 s32AencChnCnt, HI_U32 u32AencPtNumPerFrm, PAYLOAD_TYPE_E enType); +HI_S32 SAMPLE_COMM_AUDIO_StopAenc(HI_S32 s32AencChnCnt); +HI_S32 SAMPLE_COMM_AUDIO_StartAdec(ADEC_CHN AdChn, PAYLOAD_TYPE_E enType); +HI_S32 SAMPLE_COMM_AUDIO_StopAdec(ADEC_CHN AdChn); +HI_S32 SAMPLE_COMM_AUDIO_CfgTlv320(AIO_ATTR_S *pstAioAttr); + +HI_S32 SAMPLE_COMM_VENC_StartGetJPEG(HI_S32 s32Cnt); +HI_S32 SAMPLE_COMM_VI_MixCap_Start(SAMPLE_VI_MODE_E enViMode, VIDEO_NORM_E enNorm); +HI_S32 SAMPLE_COMM_VENC_StopGetJPEG(); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* End of #ifdef __cplusplus */ + + +#endif /* End of #ifndef __SAMPLE_COMMON_H__ */ diff --git a/snes9x/unix/sample_comm_sys.c b/snes9x/unix/sample_comm_sys.c new file mode 100644 index 0000000..6a16bcc --- /dev/null +++ b/snes9x/unix/sample_comm_sys.c @@ -0,0 +1,382 @@ +/****************************************************************************** + Some simple Hisilicon Hi3531 system functions. + + Copyright (C), 2010-2011, Hisilicon Tech. Co., Ltd. + ****************************************************************************** + Modification: 2011-2 Created +******************************************************************************/ +#ifdef __cplusplus +#if __cplusplus +extern "C"{ +#endif +#endif /* End of #ifdef __cplusplus */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sample_comm.h" + +/****************************************************************************** +* function : get picture size(w*h), according Norm and enPicSize +******************************************************************************/ +HI_S32 SAMPLE_COMM_SYS_GetPicSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, SIZE_S *pstSize) +{ + switch (enPicSize) + { + case PIC_QCIF: + pstSize->u32Width = D1_WIDTH / 4; + pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?144:120; + break; + case PIC_CIF: + pstSize->u32Width = D1_WIDTH / 2; + pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?288:240; + break; + case PIC_D1: + pstSize->u32Width = D1_WIDTH; + pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?576:480; + break; + case PIC_960H: + pstSize->u32Width = 960; + pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?576:480; + break; + case PIC_2CIF: + pstSize->u32Width = D1_WIDTH / 2; + pstSize->u32Height = (VIDEO_ENCODING_MODE_PAL==enNorm)?576:480; + break; + case PIC_QVGA: /* 320 * 240 */ + pstSize->u32Width = 320; + pstSize->u32Height = 240; + break; + case PIC_VGA: /* 640 * 480 */ + pstSize->u32Width = 640; + pstSize->u32Height = 480; + break; + case PIC_XGA: /* 1024 * 768 */ + pstSize->u32Width = 1024; + pstSize->u32Height = 768; + break; + case PIC_SXGA: /* 1400 * 1050 */ + pstSize->u32Width = 1400; + pstSize->u32Height = 1050; + break; + case PIC_UXGA: /* 1600 * 1200 */ + pstSize->u32Width = 1600; + pstSize->u32Height = 1200; + break; + case PIC_QXGA: /* 2048 * 1536 */ + pstSize->u32Width = 2048; + pstSize->u32Height = 1536; + break; + case PIC_WVGA: /* 854 * 480 */ + pstSize->u32Width = 854; + pstSize->u32Height = 480; + break; + case PIC_WSXGA: /* 1680 * 1050 */ + pstSize->u32Width = 1680; + pstSize->u32Height = 1050; + break; + case PIC_WUXGA: /* 1920 * 1200 */ + pstSize->u32Width = 1920; + pstSize->u32Height = 1200; + break; + case PIC_WQXGA: /* 2560 * 1600 */ + pstSize->u32Width = 2560; + pstSize->u32Height = 1600; + break; + case PIC_HD720: /* 1280 * 720 */ + pstSize->u32Width = 1280; + pstSize->u32Height = 720; + break; + case PIC_HD1080: /* 1920 * 1080 */ + pstSize->u32Width = 1920; + pstSize->u32Height = 1080; + break; + default: + return HI_FAILURE; + } + return HI_SUCCESS; +} + +/****************************************************************************** +* function : calculate VB Block size of Histogram. +******************************************************************************/ +HI_U32 SAMPLE_COMM_SYS_CalcHistVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, SIZE_S *pstHistBlkSize, HI_U32 u32AlignWidth) +{ + HI_S32 s32Ret; + SIZE_S stPicSize; + + s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, enPicSize, &stPicSize); + if (HI_SUCCESS != s32Ret) + { + SAMPLE_PRT("get picture size[%d] failed!\n", enPicSize); + return HI_FAILURE; + } + + SAMPLE_PRT("stPicSize.u32Width%d,pstHistBlkSize->u32Width%d\n,stPicSize.u32Height%d,pstHistBlkSize->u32Height%d\n", + stPicSize.u32Width,pstHistBlkSize->u32Width, + stPicSize.u32Height,pstHistBlkSize->u32Height ); + return (CEILING_2_POWER(44, u32AlignWidth)*CEILING_2_POWER(44, u32AlignWidth)*16*4); + + return HI_SUCCESS; +} + +/****************************************************************************** +* function : calculate VB Block size of picture. +******************************************************************************/ +HI_U32 SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth,COMPRESS_MODE_E enCompFmt) +{ + HI_S32 s32Ret = HI_FAILURE; + SIZE_S stSize; + HI_U32 u32Width = 0; + HI_U32 u32Height = 0; + HI_U32 u32BlkSize = 0; + HI_U32 u32HeaderSize = 0; + + s32Ret = SAMPLE_COMM_SYS_GetPicSize(enNorm, enPicSize, &stSize); + if (HI_SUCCESS != s32Ret) + { + SAMPLE_PRT("get picture size[%d] failed!\n", enPicSize); + return HI_FAILURE; + } + + if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 != enPixFmt && PIXEL_FORMAT_YUV_SEMIPLANAR_420 != enPixFmt) + { + SAMPLE_PRT("pixel format[%d] input failed!\n", enPixFmt); + return HI_FAILURE; + } + + if (16!=u32AlignWidth && 32!=u32AlignWidth && 64!=u32AlignWidth) + { + SAMPLE_PRT("system align width[%d] input failed!\n",\ + u32AlignWidth); + return HI_FAILURE; + } + if (704 == stSize.u32Width) + { + stSize.u32Width = 720; + } + //SAMPLE_PRT("w:%d, u32AlignWidth:%d\n", CEILING_2_POWER(stSize.u32Width,u32AlignWidth), u32AlignWidth); + + u32Width = CEILING_2_POWER(stSize.u32Width, u32AlignWidth); + u32Height = CEILING_2_POWER(stSize.u32Height,u32AlignWidth); + + if (PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt) + { + u32BlkSize = u32Width * u32Height * 2; + } + else + { + u32BlkSize = u32Width * u32Height * 3 / 2; + } + + + if(COMPRESS_MODE_SEG == enCompFmt) + { + VB_PIC_HEADER_SIZE(u32Width,u32Height,enPixFmt,u32HeaderSize); + } + + u32BlkSize += u32HeaderSize; + + return u32BlkSize; +} + +/****************************************************************************** +* function : Set system memory location +******************************************************************************/ +HI_S32 SAMPLE_COMM_SYS_MemConfig(HI_VOID) +{ + HI_S32 i = 0; + HI_S32 s32Ret = HI_SUCCESS; + + HI_CHAR * pcMmzName = NULL; + MPP_CHN_S stMppChnVO; + MPP_CHN_S stMppChnVPSS; + MPP_CHN_S stMppChnVENC; + MPP_CHN_S stMppChnVDEC; + + /* vdec chn config to mmz 'null' */ + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sample_comm.h" + + +static HI_S32 gs_s32SnapCnt = 0; + + +HI_S32 SAMPLE_COMM_VO_GetWH(VO_INTF_SYNC_E enIntfSync, HI_U32 *pu32W,HI_U32 *pu32H, HI_U32 *pu32Frm) +{ + switch (enIntfSync) + { + case VO_OUTPUT_PAL : *pu32W = 720; *pu32H = 576; *pu32Frm = 25; break; + case VO_OUTPUT_NTSC : *pu32W = 720; *pu32H = 480; *pu32Frm = 30; break; + case VO_OUTPUT_576P50 : *pu32W = 720; *pu32H = 576; *pu32Frm = 50; break; + case VO_OUTPUT_480P60 : *pu32W = 720; *pu32H = 480; *pu32Frm = 60; break; + case VO_OUTPUT_800x600_60: *pu32W = 800; *pu32H = 600; *pu32Frm = 60; break; + case VO_OUTPUT_720P50 : *pu32W = 1280; *pu32H = 720; *pu32Frm = 50; break; + case VO_OUTPUT_720P60 : *pu32W = 1280; *pu32H = 720; *pu32Frm = 60; break; + case VO_OUTPUT_1080I50 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 50; break; + case VO_OUTPUT_1080I60 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 60; break; + case VO_OUTPUT_1080P24 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 24; break; + case VO_OUTPUT_1080P25 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 25; break; + case VO_OUTPUT_1080P30 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 30; break; + case VO_OUTPUT_1080P50 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 50; break; + case VO_OUTPUT_1080P60 : *pu32W = 1920; *pu32H = 1080; *pu32Frm = 60; break; + case VO_OUTPUT_1024x768_60: *pu32W = 1024; *pu32H = 768; *pu32Frm = 60; break; + case VO_OUTPUT_1280x1024_60: *pu32W = 1280; *pu32H = 1024; *pu32Frm = 60; break; + case VO_OUTPUT_1366x768_60: *pu32W = 1366; *pu32H = 768; *pu32Frm = 60; break; + case VO_OUTPUT_1440x900_60: *pu32W = 1440; *pu32H = 900; *pu32Frm = 60; break; + case VO_OUTPUT_1280x800_60: *pu32W = 1280; *pu32H = 800; *pu32Frm = 60; break; + case VO_OUTPUT_1600x1200_60: *pu32W = 1600; *pu32H = 1200; *pu32Frm = 60; break; + case VO_OUTPUT_1680x1050_60: *pu32W = 1680; *pu32H = 1050; *pu32Frm = 60; break; + case VO_OUTPUT_1920x1200_60: *pu32W = 1920; *pu32H = 1200; *pu32Frm = 60; break; + case VO_OUTPUT_3840x2160_30: *pu32W = 3840; *pu32H = 2160; *pu32Frm = 30; break; + case VO_OUTPUT_3840x2160_60: *pu32W = 3840; *pu32H = 2160; *pu32Frm = 60; break; + case VO_OUTPUT_USER : *pu32W = 720; *pu32H = 576; *pu32Frm = 25; break; + default: + SAMPLE_PRT("vo enIntfSync not support!\n"); + return HI_FAILURE; + } + return HI_SUCCESS; +} + + +/****************************************************************************** +* function : Set system memory location +******************************************************************************/ +HI_S32 SAMPLE_COMM_VO_MemConfig(VO_DEV VoDev, HI_CHAR *pcMmzName) +{ + HI_S32 s32Ret = HI_SUCCESS; + MPP_CHN_S stMppChnVO; + + /* config vo dev */ + stMppChnVO.enModId = HI_ID_VOU; + stMppChnVO.s32DevId = VoDev; + stMppChnVO.s32ChnId = 0; + s32Ret = HI_MPI_SYS_SetMemConf(&stMppChnVO, pcMmzName); + if (s32Ret) + { + SAMPLE_PRT("HI_MPI_SYS_SetMemConf ERR !\n"); + return HI_FAILURE; + } + + return HI_SUCCESS; +} + +HI_S32 SAMPLE_COMM_VO_StartDev(VO_DEV VoDev, VO_PUB_ATTR_S *pstPubAttr) +{ + HI_S32 s32Ret = HI_SUCCESS; + + s32Ret = HI_MPI_VO_SetPubAttr(VoDev, pstPubAttr); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + + s32Ret = HI_MPI_VO_Enable(VoDev); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + + return s32Ret; +} + +HI_S32 SAMPLE_COMM_VO_StopDev(VO_DEV VoDev) +{ + HI_S32 s32Ret = HI_SUCCESS; + + s32Ret = HI_MPI_VO_Disable(VoDev); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + return s32Ret; +} + +HI_S32 SAMPLE_COMM_VO_StartLayer(VO_LAYER VoLayer,const VO_VIDEO_LAYER_ATTR_S *pstLayerAttr) +{ + HI_S32 s32Ret = HI_SUCCESS; + s32Ret = HI_MPI_VO_SetVideoLayerAttr(VoLayer, pstLayerAttr); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + + s32Ret = HI_MPI_VO_EnableVideoLayer(VoLayer); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + + return s32Ret; +} + +HI_S32 SAMPLE_COMM_VO_StopLayer(VO_LAYER VoLayer) +{ + HI_S32 s32Ret = HI_SUCCESS; + + s32Ret = HI_MPI_VO_DisableVideoLayer(VoLayer); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + return s32Ret; +} + +HI_S32 SAMPLE_COMM_VO_StartChn(VO_LAYER VoLayer, SAMPLE_VO_MODE_E enMode) +{ + HI_S32 i; + HI_S32 s32Ret = HI_SUCCESS; + HI_U32 u32WndNum = 0; + HI_U32 u32Square = 0; + HI_U32 u32Width = 0; + HI_U32 u32Height = 0; + VO_CHN_ATTR_S stChnAttr; + VO_VIDEO_LAYER_ATTR_S stLayerAttr; + HI_S32 s32ChnFrmRate; + + switch (enMode) + { + case VO_MODE_1MUX: + u32WndNum = 1; + u32Square = 1; + break; + case VO_MODE_4MUX: + u32WndNum = 4; + u32Square = 2; + break; + case VO_MODE_9MUX: + u32WndNum = 9; + u32Square = 3; + break; + case VO_MODE_16MUX: + u32WndNum = 16; + u32Square = 4; + break; + default: + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + + s32Ret = HI_MPI_VO_GetVideoLayerAttr(VoLayer, &stLayerAttr); + if (s32Ret != HI_SUCCESS) + { + SAMPLE_PRT("failed with %#x!\n", s32Ret); + return HI_FAILURE; + } + u32Width = stLayerAttr.stImageSize.u32Width; + u32Height = stLayerAttr.stImageSize.u32Height; + printf("u32Width:%d, u32Square:%d\n", u32Width, u32Square); + + if (stLayerAttr.u32DispFrmRt <= 0) + { + s32ChnFrmRate = 30; + } + else if (stLayerAttr.u32DispFrmRt > 30) + { + s32ChnFrmRate = stLayerAttr.u32DispFrmRt / 2; + } + else + { + s32ChnFrmRate = stLayerAttr.u32DispFrmRt; + } + + for (i=0; ienHdmi; + HI_HDMI_ATTR_S stHdmiAttr; + HI_HDMI_SINK_CAPABILITY_S stSinkCap; + HI_HDMI_INFOFRAME_S stHdmiInfoFrame; + + printf("\n --- hotplug event handling ---\n"); + + s32Ret = HI_MPI_HDMI_GetAttr(hHdmi, &stHdmiAttr); + if(HI_SUCCESS != s32Ret) + { + printf("HI_MPI_HDMI_GetAttr ERROR \n"); + return HI_FAILURE; + } + + s32Ret = HI_MPI_HDMI_GetSinkCapability(hHdmi, &stSinkCap); + if(HI_SUCCESS != s32Ret) + { + printf("HI_MPI_HDMI_GetSinkCapability ERROR \n"); + return HI_FAILURE; + } + + if (HI_FALSE == stSinkCap.bConnected ) + { + printf("stSinkCap.bConnected is HI_FALSE!\n"); + return HI_FAILURE; + } + + stHdmiAttr.enVidOutMode = HI_HDMI_VIDEO_MODE_YCBCR444; + + if(HI_TRUE == stSinkCap.bSupportHdmi) + { + stHdmiAttr.bEnableHdmi = HI_TRUE; + if(HI_TRUE != stSinkCap.bSupportYCbCr) + { + stHdmiAttr.enVidOutMode = HI_HDMI_VIDEO_MODE_RGB444; + } + } + else + { + stHdmiAttr.enVidOutMode = HI_HDMI_VIDEO_MODE_RGB444; + //read real edid ok && sink not support hdmi,then we run in dvi mode + stHdmiAttr.bEnableHdmi = HI_FALSE; + } + + if(HI_TRUE == stHdmiAttr.bEnableHdmi) + { + stHdmiAttr.bEnableVideo = HI_TRUE; + + stHdmiAttr.enDeepColorMode = HI_HDMI_DEEP_COLOR_OFF; + stHdmiAttr.bxvYCCMode = HI_FALSE; + + stHdmiAttr.bEnableAudio = HI_FALSE; + stHdmiAttr.enSoundIntf = HI_HDMI_SND_INTERFACE_I2S; + stHdmiAttr.bIsMultiChannel = HI_FALSE; + + stHdmiAttr.enBitDepth = HI_HDMI_BIT_DEPTH_16; + + stHdmiAttr.bEnableAviInfoFrame = HI_TRUE; + stHdmiAttr.bEnableAudInfoFrame = HI_TRUE; + stHdmiAttr.bEnableSpdInfoFrame = HI_FALSE; + stHdmiAttr.bEnableMpegInfoFrame = HI_FALSE; + + stHdmiAttr.bDebugFlag = HI_FALSE; + stHdmiAttr.bHDCPEnable = HI_FALSE; + + stHdmiAttr.b3DEnable = HI_FALSE; + + HI_MPI_HDMI_GetInfoFrame(hHdmi, HI_INFOFRAME_TYPE_AVI, &stHdmiInfoFrame); + stHdmiInfoFrame.unInforUnit.stAVIInfoFrame.enOutputType = stHdmiAttr.enVidOutMode; + HI_MPI_HDMI_SetInfoFrame(hHdmi, &stHdmiInfoFrame); + } + else + { + stHdmiAttr.bEnableVideo = HI_TRUE; + + stHdmiAttr.enVidOutMode = HI_HDMI_VIDEO_MODE_RGB444; + stHdmiAttr.enDeepColorMode = HI_HDMI_DEEP_COLOR_OFF; + + stHdmiAttr.bEnableAudio = HI_FALSE; + + stHdmiAttr.bEnableAviInfoFrame = HI_FALSE; + stHdmiAttr.bEnableAudInfoFrame = HI_FALSE; + } + + if ( pArgs->eForceFmt >= HI_HDMI_VIDEO_FMT_1080P_60 + && pArgs->eForceFmt < HI_HDMI_VIDEO_FMT_BUTT + && stSinkCap.bVideoFmtSupported[pArgs->eForceFmt] ) + { + printf("set force format=%d\n",pArgs->eForceFmt); + stHdmiAttr.enVideoFmt = pArgs->eForceFmt; + } + else + { + printf("not support expected format=%d, we set native format=%d\n",pArgs->eForceFmt,stSinkCap.enNativeVideoFormat); + stHdmiAttr.enVideoFmt = stSinkCap.enNativeVideoFormat; + } + + s32Ret = HI_MPI_HDMI_SetAttr(hHdmi, &stHdmiAttr); + if(HI_SUCCESS != s32Ret) + { + printf("HI_MPI_HDMI_SetAttr ERROR \n"); + return HI_FAILURE; + } + + /* HI_MPI_HDMI_SetAttr must before HI_MPI_HDMI_Start! */ + s32Ret = HI_MPI_HDMI_Start(hHdmi); + if(HI_SUCCESS != s32Ret) + { + printf("HI_MPI_HDMI_Start ERROR \n"); + return HI_FAILURE; + } + + return s32Ret; + +} + +static HI_S32 SAMPLE_COMM_HdmiUnPlugEvent(HI_VOID *pPrivateData) +{ + HI_S32 s32Ret = HI_SUCCESS; + HDMI_CALLBACK_ARGS_S *pArgs = (HDMI_CALLBACK_ARGS_S*)pPrivateData; + HI_HDMI_ID_E hHdmi = pArgs->enHdmi; + + printf("\n --- UnPlug event handling. --- \n"); + + s32Ret = HI_MPI_HDMI_Stop(hHdmi); + if(HI_SUCCESS != s32Ret) + { + printf("HI_MPI_HDMI_Stop ERROR \n"); + return HI_FAILURE; + } + + return s32Ret; +} + +HI_VOID SAMPLE_COMM_HdmiCallbackEvent(HI_HDMI_EVENT_TYPE_E event, HI_VOID *pPrivateData) +{ + printf("\ncallback fun HDMI_EventProc handling event:%d(0x%02x)\n",event,event); + switch ( event ) + { + case HI_HDMI_EVENT_HOTPLUG: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_HOTPLUG \n"); + SAMPLE_COMM_HdmiHotPlugEvent(pPrivateData); + break; + case HI_HDMI_EVENT_NO_PLUG: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_NO_PLUG \n"); + SAMPLE_COMM_HdmiUnPlugEvent(pPrivateData); + break; + case HI_HDMI_EVENT_EDID_FAIL: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_EDID_FAIL \n"); + break; + case HI_HDMI_EVENT_HDCP_FAIL: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_HDCP_FAIL \n"); + break; + case HI_HDMI_EVENT_HDCP_SUCCESS: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_HDCP_SUCCESS \n"); + break; + case HI_HDMI_EVENT_HDCP_USERSETTING: + printf("[HDMI EVENT]==>HI_HDMI_EVENT_HDCP_USERSETTING \n"); + break; + default: + printf("[HDMI EVENT]==>un-known event:%d\n",event); + return; + } + return; +} + +HI_S32 SAMPLE_COMM_VO_HdmiCallbackStart(VO_INTF_SYNC_E enIntfSync, HDMI_CALLBACK_ARGS_S *pstCallbackArgs) +{ + HI_HDMI_VIDEO_FMT_E enVideoFmt; + HI_HDMI_INIT_PARA_S stHdmiPara; + + SAMPLE_COMM_VO_HdmiConvertSync(enIntfSync, &enVideoFmt); + pstCallbackArgs->eForceFmt = enVideoFmt; + pstCallbackArgs->enHdmi = HI_HDMI_ID_0; + + stHdmiPara.enForceMode = HI_HDMI_FORCE_HDMI; + stHdmiPara.pCallBackArgs = (void *)pstCallbackArgs; + stHdmiPara.pfnHdmiEventCallback = SAMPLE_COMM_HdmiCallbackEvent; + + HI_MPI_HDMI_Init(&stHdmiPara); + + HI_MPI_HDMI_Open(HI_HDMI_ID_0); + + printf("HDMI start success.\n"); + return HI_SUCCESS; +} + +HI_S32 SAMPLE_COMM_VO_HdmiStart(VO_INTF_SYNC_E enIntfSync) +{ + HI_HDMI_ATTR_S stAttr; + HI_HDMI_VIDEO_FMT_E enVideoFmt; + HI_HDMI_INIT_PARA_S stHdmiPara; + + SAMPLE_COMM_VO_HdmiConvertSync(enIntfSync, &enVideoFmt); + + stHdmiPara.pfnHdmiEventCallback = NULL; + stHdmiPara.pCallBackArgs = NULL; + stHdmiPara.enForceMode = HI_HDMI_FORCE_HDMI; + HI_MPI_HDMI_Init(&stHdmiPara); + + HI_MPI_HDMI_Open(HI_HDMI_ID_0); + + HI_MPI_HDMI_GetAttr(HI_HDMI_ID_0, &stAttr); + + stAttr.bEnableHdmi = HI_TRUE; + + stAttr.bEnableVideo = HI_TRUE; + stAttr.enVideoFmt = enVideoFmt; + + stAttr.enVidOutMode = HI_HDMI_VIDEO_MODE_YCBCR444; + stAttr.enDeepColorMode = HI_HDMI_DEEP_COLOR_OFF; + stAttr.bxvYCCMode = HI_FALSE; + + stAttr.bEnableAudio = HI_FALSE; + stAttr.enSoundIntf = HI_HDMI_SND_INTERFACE_I2S; + stAttr.bIsMultiChannel = HI_FALSE; + + stAttr.enBitDepth = HI_HDMI_BIT_DEPTH_16; + + stAttr.bEnableAviInfoFrame = HI_TRUE; + stAttr.bEnableAudInfoFrame = HI_TRUE; + stAttr.bEnableSpdInfoFrame = HI_FALSE; + stAttr.bEnableMpegInfoFrame = HI_FALSE; + + stAttr.bDebugFlag = HI_FALSE; + stAttr.bHDCPEnable = HI_FALSE; + + stAttr.b3DEnable = HI_FALSE; + + HI_MPI_HDMI_SetAttr(HI_HDMI_ID_0, &stAttr); + + HI_MPI_HDMI_Start(HI_HDMI_ID_0); + + printf("HDMI start success.\n"); + return HI_SUCCESS; +} + +HI_S32 SAMPLE_COMM_VO_HdmiStop(HI_VOID) +{ + HI_MPI_HDMI_Stop(HI_HDMI_ID_0); + HI_MPI_HDMI_Close(HI_HDMI_ID_0); + HI_MPI_HDMI_DeInit(); + + return HI_SUCCESS; +} + +HI_S32 SAMPLE_COMM_VO_SnapStart(VENC_CHN VencChn, SIZE_S *pstSize) +{ + HI_S32 s32Ret; + VENC_CHN_ATTR_S stVencChnAttr; + VENC_ATTR_JPEG_S stJpegAttr; + + /****************************************** + step 1: Create Venc Channel + ******************************************/ + stVencChnAttr.stVeAttr.enType = PT_JPEG; + + stJpegAttr.u32MaxPicWidth = pstSize->u32Width; + stJpegAttr.u32MaxPicHeight = pstSize->u32Height; + stJpegAttr.u32PicWidth = pstSize->u32Width; + stJpegAttr.u32PicHeight = pstSize->u32Height; + stJpegAttr.u32BufSize = pstSize->u32Width * pstSize->u32Height * 2; + stJpegAttr.bByFrame = HI_TRUE;/*get stream mode is field mode or frame mode*/ + stJpegAttr.bSupportDCF = HI_FALSE; + memcpy(&stVencChnAttr.stVeAttr.stAttrJpeg, &stJpegAttr, sizeof(VENC_ATTR_JPEG_S)); + + s32Ret = HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr); + if (HI_SUCCESS != s32Ret) + { + SAMPLE_PRT("HI_MPI_VENC_CreateChn [%d] faild with %#x!\n",\ + VencChn, s32Ret); + return s32Ret; + } + return HI_SUCCESS; +} + +/****************************************************************************** +* funciton : Stop snap +******************************************************************************/ +HI_S32 SAMPLE_COMM_VO_SnapStop(VENC_CHN VencChn) +{ + HI_S32 s32Ret; + + s32Ret = HI_MPI_VENC_StopRecvPic(VencChn); + if (HI_SUCCESS != s32Ret) + { + SAMPLE_PRT("HI_MPI_VENC_StopRecvPic vechn[%d] failed with %#x!\n", VencChn, s32Ret); + return HI_FAILURE; + } + + s32Ret = HI_MPI_VENC_DestroyChn(VencChn); + if (HI_SUCCESS != s32Ret) + { + SAMPLE_PRT("HI_MPI_VENC_DestroyChn vechn[%d] failed with %#x!\n", VencChn, s32Ret); + return HI_FAILURE; + } + + return HI_SUCCESS; +} + + + diff --git a/snes9x/unix/snes9x b/snes9x/unix/snes9x new file mode 100755 index 0000000..6e231b3 Binary files /dev/null and b/snes9x/unix/snes9x differ diff --git a/snes9x/unzip/crypt.h b/snes9x/unzip/crypt.h new file mode 100644 index 0000000..29ba65c --- /dev/null +++ b/snes9x/unzip/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/snes9x/unzip/ioapi.c b/snes9x/unzip/ioapi.c new file mode 100644 index 0000000..51a9058 --- /dev/null +++ b/snes9x/unzip/ioapi.c @@ -0,0 +1,178 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/snes9x/unzip/ioapi.h b/snes9x/unzip/ioapi.h new file mode 100644 index 0000000..75171b9 --- /dev/null +++ b/snes9x/unzip/ioapi.h @@ -0,0 +1,78 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +#ifndef OF +#define OF(x) x +#endif + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/snes9x/unzip/iowin32.c b/snes9x/unzip/iowin32.c new file mode 100644 index 0000000..e502139 --- /dev/null +++ b/snes9x/unzip/iowin32.c @@ -0,0 +1,270 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK win32_read_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK win32_write_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK win32_tell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK win32_seek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK win32_close_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK win32_error_file_func OF(( + voidpf opaque, + voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + +voidpf ZCALLBACK win32_open_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = 0; + voidpf ret=NULL; + + dwDesiredAccess = dwShareMode = dwFlagsAndAttributes = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + dwDesiredAccess = GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + dwShareMode = FILE_SHARE_READ; + } + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + } + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + dwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + dwCreationDisposition = CREATE_ALWAYS; + } + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, + dwCreationDisposition, dwFlagsAndAttributes, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + hFile = NULL; + + if (hFile != NULL) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + if (ret==NULL) + CloseHandle(hFile); + else *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + + +uLong ZCALLBACK win32_read_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile !=NULL) + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +long ZCALLBACK win32_seek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque=NULL; +} diff --git a/snes9x/unzip/iowin32.h b/snes9x/unzip/iowin32.h new file mode 100644 index 0000000..c128770 --- /dev/null +++ b/snes9x/unzip/iowin32.h @@ -0,0 +1,21 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + This IO API version uses the Win32 API (for Microsoft Windows) + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/snes9x/unzip/miniunz.c b/snes9x/unzip/miniunz.c new file mode 100644 index 0000000..db1ddd4 --- /dev/null +++ b/snes9x/unzip/miniunz.c @@ -0,0 +1,599 @@ +/* + miniunz.c + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFile(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef WIN32 + ret = mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info gi; + int err; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (file_info.compressed_size*100)/file_info.uncompressed_size; + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } +#ifdef HAVE_BZIP2 + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } +#endif + else + string_method="Unkn. "; + + printf("%7lu %6s%c%7lu %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + file_info.uncompressed_size,string_method, + charCrypt, + file_info.compressed_size, + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo (uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.01e-jg, demo of zLib + Zip package written by Gilles Vollant\n"); + printf("minor updates, jg.\n"); + printf("more info at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n",filenameinzip,calculate_crc); + return err; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc_def ffunc; + fill_win32_filefunc(&ffunc); + zf = zipOpen2(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + /*the path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = fopen(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/snes9x/unzip/mztools.c b/snes9x/unzip/mztools.c new file mode 100644 index 0000000..8a50ee4 --- /dev/null +++ b/snes9x/unzip/mztools.c @@ -0,0 +1,281 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/snes9x/unzip/mztools.h b/snes9x/unzip/mztools.h new file mode 100644 index 0000000..eee78dc --- /dev/null +++ b/snes9x/unzip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/snes9x/unzip/unzip.c b/snes9x/unzip/unzip.c new file mode 100644 index 0000000..6ec5209 --- /dev/null +++ b/snes9x/unzip/unzip.c @@ -0,0 +1,1698 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + Read unzip.h for more info +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +#ifdef HAVE_BZIP2 + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +#endif + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +#ifdef HAVE_BZIP2 + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +#endif + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + +#ifdef HAVE_BZIP2 + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && + (!raw)) + { + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + } + else +#endif + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + unzFile file; + int* method; + int* level; + int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } +#ifdef HAVE_BZIP2 + else + if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; + } +#endif + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern uLong ZEXPORT unzGetOffset (file) + unzFile file; +{ + unz_s* s; + + if (file==NULL) + return 0; + s=(unz_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset (file, pos) + unzFile file; + uLong pos; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} diff --git a/snes9x/unzip/unzip.h b/snes9x/unzip/unzip.h new file mode 100644 index 0000000..94c1b69 --- /dev/null +++ b/snes9x/unzip/unzip.h @@ -0,0 +1,360 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff --git a/snes9x/unzip/zip.c b/snes9x/unzip/zip.c new file mode 100644 index 0000000..1451d61 --- /dev/null +++ b/snes9x/unzip/zip.c @@ -0,0 +1,1263 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.01h, December 28th, 2009 + + 27 Dec 2004 Rolf Kalbermatter + Modification to zipOpen2 to support globalComment retrieval. + + Copyright (C) 1998-2009 Gilles Vollant + + Read zip.h for more info +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] = + " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + uLong pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralheader; /* size of the central header for cur file */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile_info; + +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile_info ci; /* info on the file curretly writing */ + + uLong begin_pos; /* position of the beginning of the zipfile */ + uLong add_position_when_writting_offset; + uLong number_entry; +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif +} zip_internal; + + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(ldi) + linkedlist_datablock_internal* ldi; +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(ll) + linkedlist_data* ll; +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(ll) + linkedlist_data* ll; +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(ll,buf,len) + linkedlist_data* ll; + const void* buf; + uLong len; +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 or 4 (byte, short or long) +*/ + +local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, uLong x, int nbByte)); +local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong x; + int nbByte; +{ + unsigned char buf[4]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); +local void ziplocal_putValue_inmemory (dest, x, nbByte) + void* dest; + uLong x; + int nbByte; +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) + const tm_zip* ptm; + uLong dosDate; +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int ziplocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int ziplocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int ziplocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) + Fix from Riccardo Cohen +*/ +local uLong ziplocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def) + const char *pathname; + int append; + zipcharpc* globalcomment; + zlib_filefunc_def* pzlib_filefunc_def; +{ + zip_internal ziinit; + zip_internal* zi; + int err=ZIP_OK; + + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&ziinit.z_filefunc); + else + ziinit.z_filefunc = *pzlib_filefunc_def; + + ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) + (ziinit.z_filefunc.opaque, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + zi = (zip_internal*)ALLOC(sizeof(zip_internal)); + if (zi==NULL) + { + ZCLOSE(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory */ + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry; + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong size_comment; + + central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* zipfile global comment length */ + if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((central_pos0) + { + ziinit.globalcomment = (char*)ALLOC(size_comment+1); + if (ziinit.globalcomment) + { + size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); + ziinit.globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - + (offset_central_dir+size_central_dir); + ziinit.add_position_when_writting_offset = byte_before_the_zipfile; + + { + uLong size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir + byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + uLong read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&ziinit.central_dir,buf_read, + (uLong)read_this); + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + ziinit.begin_pos = byte_before_the_zipfile; + ziinit.number_entry = number_entry_CD; + + if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, + offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen (pathname, append) + const char *pathname; + int append; +{ + return zipOpen2(pathname,append,NULL,NULL); +} + +extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; + uLong versionMadeBy; + uLong flagBase; +{ + zip_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; + + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + + size_extrafield_global + size_comment; + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); + + ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + /* write the local header */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); + + if ((err==ZIP_OK) && (size_filename>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + + if ((err==ZIP_OK) && (size_extrafield_local>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) + !=size_extrafield_local) + err = ZIP_ERRNO; + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, + Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = 1; + } +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; + int raw; + int windowBits; + int memLevel; + int strategy; + const char* password; + uLong crcForCrypting; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0); +} + + +extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level) + zipFile file; + const char* filename; + const zip_fileinfo* zipfi; + const void* extrafield_local; + uInt size_extrafield_local; + const void* extrafield_global; + uInt size_extrafield_global; + const char* comment; + int method; + int level; +{ + return zipOpenNewFileInZip4 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0); +} + +local int zipFlushWriteBuffer(zi) + zip_internal* zi; +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, + zi->ci.buffered_data[i],t); +#endif + } + if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) + !=zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + zi->ci.pos_in_buffered_data = 0; + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (file, buf, len) + zipFile file; + const void* buf; + unsigned len; +{ + zip_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + for (i=0;ici.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) + zipFile file; + uLong uncompressed_size; + uLong crc32; +{ + zip_internal* zi; + uLong compressed_size; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err=deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = (uLong)zi->ci.stream.total_in; + } + compressed_size = (uLong)zi->ci.stream.total_out; +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + ziplocal_putValue_inmemory(zi->ci.central_header+20, + compressed_size,4); /*compr size*/ + if (zi->ci.stream.data_type == Z_ASCII) + ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + ziplocal_putValue_inmemory(zi->ci.central_header+24, + uncompressed_size,4); /*uncompr size*/ + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, + (uLong)zi->ci.size_centralheader); + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (ZSEEK(zi->z_filefunc,zi->filestream, + zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if (err==ZIP_OK) /* compressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + + if (ZSEEK(zi->z_filefunc,zi->filestream, + cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (file) + zipFile file; +{ + return zipCloseFileInZipRaw (file,0,0); +} + +extern int ZEXPORT zipClose (file, global_comment) + zipFile file; + const char* global_comment; +{ + zip_internal* zi; + int err = 0; + uLong size_centraldir = 0; + uLong centraldir_pos_inzip; + uInt size_global_comment; + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + if (global_comment==NULL) + size_global_comment = 0; + else + size_global_comment = (uInt)strlen(global_comment); + + centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + ldi->data,ldi->filled_in_this_block) + !=ldi->filled_in_this_block ) + err = ZIP_ERRNO; + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + if (err==ZIP_OK) /* Magic End */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + + if (err==ZIP_OK) /* size of the central directory */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the + starting disk number */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, + (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + + if (err==ZIP_OK) /* zipfile comment length */ + err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if ((err==ZIP_OK) && (size_global_comment>0)) + if (ZWRITE(zi->z_filefunc,zi->filestream, + global_comment,size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + + if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} diff --git a/snes9x/unzip/zip.h b/snes9x/unzip/zip.h new file mode 100644 index 0000000..39215ca --- /dev/null +++ b/snes9x/unzip/zip.h @@ -0,0 +1,257 @@ +/* zip.h -- IO for compress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + This unzip package allow creates .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + For uncompress .zip file, look at unzip.h + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.html for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _zip_H +#define _zip_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCtypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase)); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); +/* + Close the current file in the zipfile, for fiel opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip_H */