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