init commit

master
xerox 3 years ago
commit daa4f9a04f

@ -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

@ -0,0 +1,2 @@
# FBSnes9x - Unix Frame Buffer Port

505
snes9x/.gitignore vendored

@ -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

@ -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

@ -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

@ -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 <cmath>
#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);
}

@ -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

File diff suppressed because it is too large Load Diff

@ -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 <assert.h>
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

@ -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 <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#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<T> (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 T>
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 <new>
#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 <stdint.h> for int8_t etc.
#if defined (HAVE_STDINT_H)
#include <stdint.h>
#define BOOST
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
#elif defined (HAVE_INTTYPES_H)
#include <inttypes.h>
#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

@ -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

@ -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 <endian.h>
#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

@ -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 <assert.h>
// 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<class T>
inline T min( T x, T y )
{
if ( x < y )
return x;
return y;
}
template<class T>
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

@ -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;
}
}

@ -0,0 +1,34 @@
#include "SPC_DSP.h"
#include <stdio.h>
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;

@ -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;
}

@ -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"
}
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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

@ -0,0 +1,27 @@
class SMPDebugger : public SMP, public ChipDebugger {
public:
bool property(unsigned id, string &name, string &value);
function<bool ()> 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);
};

@ -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);
}

@ -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

@ -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;
}
}

@ -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;
}
}

@ -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<unsigned frequency>
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;

@ -0,0 +1,197 @@
#include "../snes/snes.hpp"
#include <stdio.h>
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

@ -0,0 +1,26 @@
template<unsigned cycle_frequency>
void SMP::Timer<cycle_frequency>::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<unsigned cycle_frequency>
void SMP::Timer<cycle_frequency>::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;
}

@ -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

@ -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 <cstring>
#include <cassert>
#if __cplusplus >= 201103L
#include <cstdint>
#else
#include <stdint.h>
#endif
#include <cmath>
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 */

@ -0,0 +1,291 @@
#include <vector>
#include <iostream>
#include <fstream>
#include <stack>
#include <stdio.h>
#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<bml_node *> 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;
}

@ -0,0 +1,27 @@
#ifndef __BML_H
#define __BML_H
#include <vector>
#include <string>
#include <fstream>
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<bml_node> child;
node_type type;
};
#endif

File diff suppressed because it is too large Load Diff

@ -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 <fstream>
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

@ -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 <math.h>
#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));
}

@ -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

File diff suppressed because it is too large Load Diff

@ -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 <ctype.h>
#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]);
}
}

@ -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 <vector>
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<struct SCheat> c;
};
struct SCheatData
{
std::vector<struct SCheatGroup> 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

@ -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 <ctype.h>
#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) -