pax_global_header 0000666 0000000 0000000 00000000064 12644314416 0014517 g ustar 00root root 0000000 0000000 52 comment=845bcea7e0ad47f8d66046712353206a53ddeb94
nestopia-1.47/ 0000775 0000000 0000000 00000000000 12644314416 0013274 5 ustar 00root root 0000000 0000000 nestopia-1.47/.gitignore 0000664 0000000 0000000 00000000116 12644314416 0015262 0 ustar 00root root 0000000 0000000 *.so
*.o
*.dylib
*.dll
*.nes
*.fds
*.ips
*.ups
/nestopia
*.js
*.bc
.npmignore
nestopia-1.47/AUTHORS 0000664 0000000 0000000 00000002546 12644314416 0014353 0 ustar 00root root 0000000 0000000 Authors
=======
Main Contributors
-----------------
Martin Freij - Original Author
R. Belmont - Initial Linux port
R. Danbrook - Cross-platform port, current maintainer
Community Contributors
----------------------
blargg
dragon2snow
emu-russia
Geestarraw
joepogo
Keith Kelly
lidnariq
lioncash
rnjacobs
shalma
steelywing
Squarepusher
themaister
W.M. Martinez
Special Thanks
--------------
Aaron Marsh
CyberWarriorX
hunterk
Kakashi
MottZilla
Ryphecha
Stephen Kitt
Included Sofware
----------------
blargg's NTSC filter
Copyright (C) 2006-2007 Shay Green
For details, read source/nes_ntsc/*
inih -- simple .INI file parser Copyright (c) 2009, Brush Technology
All rights reserved. For details, read source/unix/ini.h
LodePNG version 20141130
Copyright (c) 2005-2014 Lode Vandevenne
For details, read source/unix/png.h
zlib compression library
Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
For details, read source/zlib/*
nespad.svg based on work by Fant0men
http://commons.wikimedia.org/wiki/File:Nes_controller.svg
nestopia.svg based on work by Trollekop, with permission
http://trollekop.deviantart.com/art/Zombie-NES-controller-Color-160691868
------------------------------------------------------------------------
If you are not included in this file and should be, please let someone
know so you can be added to the list of contributors.
nestopia-1.47/COPYING 0000664 0000000 0000000 00000035422 12644314416 0014335 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
nestopia-1.47/Makefile 0000664 0000000 0000000 00000036205 12644314416 0014742 0 ustar 00root root 0000000 0000000 CC ?= cc
CXX ?= c++
CXXFLAGS ?= -O3 -g3
CPPFLAGS += -DNST_PRAGMA_ONCE
CFLAGS = $(shell sdl2-config --cflags)
INCLUDES = -Isource
WARNINGS = -Wno-write-strings
LDFLAGS = -Wl,--as-needed
LIBS = -lstdc++ -lm -lz
LIBS += $(shell sdl2-config --libs)
UNAME := $(shell uname)
BIN = nestopia
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
DATADIR ?= $(PREFIX)/share/nestopia
ifneq ($(findstring MINGW,$(UNAME)),)
DEFINES = -D_MINGW
LDFLAGS += -mconsole
LIBS += -lepoxy -lopengl32
else ifneq ($(findstring Darwin,$(UNAME)),)
DEFINES = -D_APPLE
DEFINES += -DDATADIR=\"$(DATADIR)\"
INCLUDES += -I/usr/local/include -I/usr/local/opt/libarchive/include
LDFLAGS = -Wl -L/usr/local/opt/libarchive/lib
LIBS += -larchive -lepoxy -lao
# GTK Stuff - Comment this section to disable GTK+
#CFLAGS += $(shell pkg-config --cflags gtk+-3.0)
#LIBS += $(shell pkg-config --libs gtk+-3.0)
#DEFINES += -D_GTK
#IOBJS += objs/unix/gtkui/gtkui.o
#IOBJS += objs/unix/gtkui/gtkui_archive.o
#IOBJS += objs/unix/gtkui/gtkui_callbacks.o
#IOBJS += objs/unix/gtkui/gtkui_cheats.o
#IOBJS += objs/unix/gtkui/gtkui_config.o
#IOBJS += objs/unix/gtkui/gtkui_dialogs.o
#OBJDIRS += objs/unix/gtkui
#WARNINGS += -Wno-deprecated-declarations
# end GTK
else
DEFINES = -DDATADIR=\"$(DATADIR)\"
LIBS += -larchive -lepoxy -lGL -lGLU -lao
# GTK Stuff - Comment this section to disable GTK+
CFLAGS += $(shell pkg-config --cflags gtk+-3.0)
LIBS += $(shell pkg-config --libs gtk+-3.0)
DEFINES += -D_GTK
IOBJS += objs/unix/gtkui/gtkui.o
IOBJS += objs/unix/gtkui/gtkui_archive.o
IOBJS += objs/unix/gtkui/gtkui_callbacks.o
IOBJS += objs/unix/gtkui/gtkui_cheats.o
IOBJS += objs/unix/gtkui/gtkui_config.o
IOBJS += objs/unix/gtkui/gtkui_dialogs.o
OBJDIRS += objs/unix/gtkui
WARNINGS += -Wno-deprecated-declarations
# end GTK
endif
# Core
OBJS += objs/core/NstApu.o
OBJS += objs/core/NstAssert.o
OBJS += objs/core/NstCartridge.o
OBJS += objs/core/NstCartridgeInes.o
OBJS += objs/core/NstCartridgeRomset.o
OBJS += objs/core/NstCartridgeUnif.o
OBJS += objs/core/NstCheats.o
OBJS += objs/core/NstChecksum.o
OBJS += objs/core/NstChips.o
OBJS += objs/core/NstCore.o
OBJS += objs/core/NstCpu.o
OBJS += objs/core/NstCrc32.o
OBJS += objs/core/NstFds.o
OBJS += objs/core/NstFile.o
OBJS += objs/core/NstImage.o
OBJS += objs/core/NstImageDatabase.o
OBJS += objs/core/NstLog.o
OBJS += objs/core/NstMachine.o
OBJS += objs/core/NstMemory.o
OBJS += objs/core/NstNsf.o
OBJS += objs/core/NstPatcher.o
OBJS += objs/core/NstPatcherIps.o
OBJS += objs/core/NstPatcherUps.o
OBJS += objs/core/NstPins.o
OBJS += objs/core/NstPpu.o
OBJS += objs/core/NstProperties.o
OBJS += objs/core/NstRam.o
OBJS += objs/core/NstSha1.o
OBJS += objs/core/NstSoundPcm.o
OBJS += objs/core/NstSoundPlayer.o
OBJS += objs/core/NstSoundRenderer.o
OBJS += objs/core/NstState.o
OBJS += objs/core/NstStream.o
OBJS += objs/core/NstTracker.o
OBJS += objs/core/NstTrackerMovie.o
OBJS += objs/core/NstTrackerRewinder.o
OBJS += objs/core/NstVector.o
OBJS += objs/core/NstVideoFilter2xSaI.o
OBJS += objs/core/NstVideoFilterHqX.o
OBJS += objs/core/NstVideoFilterNone.o
OBJS += objs/core/NstVideoFilterNtsc.o
OBJS += objs/core/NstVideoFilterNtscCfg.o
OBJS += objs/core/NstVideoFilterScaleX.o
OBJS += objs/core/NstVideoFilterxBR.o
OBJS += objs/core/NstVideoRenderer.o
OBJS += objs/core/NstVideoScreen.o
OBJS += objs/core/NstXml.o
OBJS += objs/core/NstZlib.o
# API
OBJS += objs/core/api/NstApiBarcodeReader.o
OBJS += objs/core/api/NstApiCartridge.o
OBJS += objs/core/api/NstApiCheats.o
OBJS += objs/core/api/NstApiDipSwitches.o
OBJS += objs/core/api/NstApiEmulator.o
OBJS += objs/core/api/NstApiFds.o
OBJS += objs/core/api/NstApiInput.o
OBJS += objs/core/api/NstApiMachine.o
OBJS += objs/core/api/NstApiMovie.o
OBJS += objs/core/api/NstApiNsf.o
OBJS += objs/core/api/NstApiRewinder.o
OBJS += objs/core/api/NstApiSound.o
OBJS += objs/core/api/NstApiTapeRecorder.o
OBJS += objs/core/api/NstApiUser.o
OBJS += objs/core/api/NstApiVideo.o
# Board
OBJS += objs/core/board/NstBoardAcclaimMcAcc.o
OBJS += objs/core/board/NstBoardAe.o
OBJS += objs/core/board/NstBoardAgci.o
OBJS += objs/core/board/NstBoardAveD1012.o
OBJS += objs/core/board/NstBoardAveNina.o
OBJS += objs/core/board/NstBoardAxRom.o
OBJS += objs/core/board/NstBoardBandai24c0x.o
OBJS += objs/core/board/NstBoardBandaiAerobicsStudio.o
OBJS += objs/core/board/NstBoardBandaiDatach.o
OBJS += objs/core/board/NstBoardBandaiKaraokeStudio.o
OBJS += objs/core/board/NstBoardBandaiLz93d50.o
OBJS += objs/core/board/NstBoardBandaiLz93d50ex.o
OBJS += objs/core/board/NstBoardBandaiOekaKids.o
OBJS += objs/core/board/NstBoardBenshengBs5.o
OBJS += objs/core/board/NstBoardBmc110in1.o
OBJS += objs/core/board/NstBoardBmc1200in1.o
OBJS += objs/core/board/NstBoardBmc150in1.o
OBJS += objs/core/board/NstBoardBmc15in1.o
OBJS += objs/core/board/NstBoardBmc20in1.o
OBJS += objs/core/board/NstBoardBmc21in1.o
OBJS += objs/core/board/NstBoardBmc22Games.o
OBJS += objs/core/board/NstBoardBmc31in1.o
OBJS += objs/core/board/NstBoardBmc35in1.o
OBJS += objs/core/board/NstBoardBmc36in1.o
OBJS += objs/core/board/NstBoardBmc64in1.o
OBJS += objs/core/board/NstBoardBmc72in1.o
OBJS += objs/core/board/NstBoardBmc76in1.o
OBJS += objs/core/board/NstBoardBmc800in1.o
OBJS += objs/core/board/NstBoardBmc8157.o
OBJS += objs/core/board/NstBoardBmc9999999in1.o
OBJS += objs/core/board/NstBoardBmcA65as.o
OBJS += objs/core/board/NstBoardBmcBallgames11in1.o
OBJS += objs/core/board/NstBoardBmcCh001.o
OBJS += objs/core/board/NstBoardBmcCtc65.o
OBJS += objs/core/board/NstBoardBmcFamily4646B.o
OBJS += objs/core/board/NstBoardBmcFk23c.o
OBJS += objs/core/board/NstBoardBmcGamestarA.o
OBJS += objs/core/board/NstBoardBmcGamestarB.o
OBJS += objs/core/board/NstBoardBmcGolden190in1.o
OBJS += objs/core/board/NstBoardBmcGoldenCard6in1.o
OBJS += objs/core/board/NstBoardBmcGoldenGame260in1.o
OBJS += objs/core/board/NstBoardBmcHero.o
OBJS += objs/core/board/NstBoardBmcMarioParty7in1.o
OBJS += objs/core/board/NstBoardBmcNovelDiamond.o
OBJS += objs/core/board/NstBoardBmcPowerjoy84in1.o
OBJS += objs/core/board/NstBoardBmcResetBased4in1.o
OBJS += objs/core/board/NstBoardBmcSuper22Games.o
OBJS += objs/core/board/NstBoardBmcSuper24in1.o
OBJS += objs/core/board/NstBoardBmcSuper40in1.o
OBJS += objs/core/board/NstBoardBmcSuper700in1.o
OBJS += objs/core/board/NstBoardBmcSuperBig7in1.o
OBJS += objs/core/board/NstBoardBmcSuperGun20in1.o
OBJS += objs/core/board/NstBoardBmcSuperHiK300in1.o
OBJS += objs/core/board/NstBoardBmcSuperHiK4in1.o
OBJS += objs/core/board/NstBoardBmcSuperVision16in1.o
OBJS += objs/core/board/NstBoardBmcT262.o
OBJS += objs/core/board/NstBoardBmcVrc4.o
OBJS += objs/core/board/NstBoardBmcVt5201.o
OBJS += objs/core/board/NstBoardBmcY2k64in1.o
OBJS += objs/core/board/NstBoardBtl2708.o
OBJS += objs/core/board/NstBoardBtl6035052.o
OBJS += objs/core/board/NstBoardBtlAx5705.o
OBJS += objs/core/board/NstBoardBtlDragonNinja.o
OBJS += objs/core/board/NstBoardBtlGeniusMerioBros.o
OBJS += objs/core/board/NstBoardBtlMarioBaby.o
OBJS += objs/core/board/NstBoardBtlPikachuY2k.o
OBJS += objs/core/board/NstBoardBtlShuiGuanPipe.o
OBJS += objs/core/board/NstBoardBtlSmb2a.o
OBJS += objs/core/board/NstBoardBtlSmb2b.o
OBJS += objs/core/board/NstBoardBtlSmb2c.o
OBJS += objs/core/board/NstBoardBtlSmb3.o
OBJS += objs/core/board/NstBoardBtlSuperBros11.o
OBJS += objs/core/board/NstBoardBtlT230.o
OBJS += objs/core/board/NstBoardBtlTobidaseDaisakusen.o
OBJS += objs/core/board/NstBoardBxRom.o
OBJS += objs/core/board/NstBoardCaltron.o
OBJS += objs/core/board/NstBoardCamerica.o
OBJS += objs/core/board/NstBoardCneDecathlon.o
OBJS += objs/core/board/NstBoardCnePsb.o
OBJS += objs/core/board/NstBoardCneShlz.o
OBJS += objs/core/board/NstBoardCony.o
OBJS += objs/core/board/NstBoard.o
OBJS += objs/core/board/NstBoardCxRom.o
OBJS += objs/core/board/NstBoardDiscrete.o
OBJS += objs/core/board/NstBoardDreamtech.o
OBJS += objs/core/board/NstBoardEvent.o
OBJS += objs/core/board/NstBoardFb.o
OBJS += objs/core/board/NstBoardFfe.o
OBJS += objs/core/board/NstBoardFujiya.o
OBJS += objs/core/board/NstBoardFukutake.o
OBJS += objs/core/board/NstBoardFutureMedia.o
OBJS += objs/core/board/NstBoardGouder.o
OBJS += objs/core/board/NstBoardGxRom.o
OBJS += objs/core/board/NstBoardHenggedianzi.o
OBJS += objs/core/board/NstBoardHes.o
OBJS += objs/core/board/NstBoardHosenkan.o
OBJS += objs/core/board/NstBoardIremG101.o
OBJS += objs/core/board/NstBoardIremH3001.o
OBJS += objs/core/board/NstBoardIremHolyDiver.o
OBJS += objs/core/board/NstBoardIremKaiketsu.o
OBJS += objs/core/board/NstBoardIremLrog017.o
OBJS += objs/core/board/NstBoardJalecoJf11.o
OBJS += objs/core/board/NstBoardJalecoJf13.o
OBJS += objs/core/board/NstBoardJalecoJf16.o
OBJS += objs/core/board/NstBoardJalecoJf17.o
OBJS += objs/core/board/NstBoardJalecoJf19.o
OBJS += objs/core/board/NstBoardJalecoSs88006.o
OBJS += objs/core/board/NstBoardJyCompany.o
OBJS += objs/core/board/NstBoardKaiser.o
OBJS += objs/core/board/NstBoardKasing.o
OBJS += objs/core/board/NstBoardKayH2288.o
OBJS += objs/core/board/NstBoardKayPandaPrince.o
OBJS += objs/core/board/NstBoardKonamiVrc1.o
OBJS += objs/core/board/NstBoardKonamiVrc2.o
OBJS += objs/core/board/NstBoardKonamiVrc3.o
OBJS += objs/core/board/NstBoardKonamiVrc4.o
OBJS += objs/core/board/NstBoardKonamiVrc6.o
OBJS += objs/core/board/NstBoardKonamiVrc7.o
OBJS += objs/core/board/NstBoardKonamiVsSystem.o
OBJS += objs/core/board/NstBoardMagicSeries.o
OBJS += objs/core/board/NstBoardMmc1.o
OBJS += objs/core/board/NstBoardMmc2.o
OBJS += objs/core/board/NstBoardMmc3.o
OBJS += objs/core/board/NstBoardMmc4.o
OBJS += objs/core/board/NstBoardMmc5.o
OBJS += objs/core/board/NstBoardMmc6.o
OBJS += objs/core/board/NstBoardNamcot163.o
OBJS += objs/core/board/NstBoardNamcot175.o
OBJS += objs/core/board/NstBoardNamcot34xx.o
OBJS += objs/core/board/NstBoardNanjing.o
OBJS += objs/core/board/NstBoardNihon.o
OBJS += objs/core/board/NstBoardNitra.o
OBJS += objs/core/board/NstBoardNtdec.o
OBJS += objs/core/board/NstBoardOpenCorp.o
OBJS += objs/core/board/NstBoardQj.o
OBJS += objs/core/board/NstBoardRcm.o
OBJS += objs/core/board/NstBoardRexSoftDb5z.o
OBJS += objs/core/board/NstBoardRexSoftSl1632.o
OBJS += objs/core/board/NstBoardRumbleStation.o
OBJS += objs/core/board/NstBoardSachen74x374.o
OBJS += objs/core/board/NstBoardSachenS8259.o
OBJS += objs/core/board/NstBoardSachenSa0036.o
OBJS += objs/core/board/NstBoardSachenSa0037.o
OBJS += objs/core/board/NstBoardSachenSa72007.o
OBJS += objs/core/board/NstBoardSachenSa72008.o
OBJS += objs/core/board/NstBoardSachenStreetHeroes.o
OBJS += objs/core/board/NstBoardSachenTca01.o
OBJS += objs/core/board/NstBoardSachenTcu.o
OBJS += objs/core/board/NstBoardSomeriTeamSl12.o
OBJS += objs/core/board/NstBoardSubor.o
OBJS += objs/core/board/NstBoardSunsoft1.o
OBJS += objs/core/board/NstBoardSunsoft2.o
OBJS += objs/core/board/NstBoardSunsoft3.o
OBJS += objs/core/board/NstBoardSunsoft4.o
OBJS += objs/core/board/NstBoardSunsoft5b.o
OBJS += objs/core/board/NstBoardSunsoftDcs.o
OBJS += objs/core/board/NstBoardSunsoftFme7.o
OBJS += objs/core/board/NstBoardSuperGameBoogerman.o
OBJS += objs/core/board/NstBoardSuperGameLionKing.o
OBJS += objs/core/board/NstBoardSuperGamePocahontas2.o
OBJS += objs/core/board/NstBoardTaitoTc0190fmc.o
OBJS += objs/core/board/NstBoardTaitoTc0190fmcPal16r4.o
OBJS += objs/core/board/NstBoardTaitoX1005.o
OBJS += objs/core/board/NstBoardTaitoX1017.o
OBJS += objs/core/board/NstBoardTengen.o
OBJS += objs/core/board/NstBoardTengenRambo1.o
OBJS += objs/core/board/NstBoardTxc.o
OBJS += objs/core/board/NstBoardTxcMxmdhtwo.o
OBJS += objs/core/board/NstBoardTxcPoliceman.o
OBJS += objs/core/board/NstBoardTxcTw.o
OBJS += objs/core/board/NstBoardTxRom.o
OBJS += objs/core/board/NstBoardUnlA9746.o
OBJS += objs/core/board/NstBoardUnlCc21.o
OBJS += objs/core/board/NstBoardUnlEdu2000.o
OBJS += objs/core/board/NstBoardUnlKingOfFighters96.o
OBJS += objs/core/board/NstBoardUnlKingOfFighters97.o
OBJS += objs/core/board/NstBoardUnlMortalKombat2.o
OBJS += objs/core/board/NstBoardUnlN625092.o
OBJS += objs/core/board/NstBoardUnlSuperFighter3.o
OBJS += objs/core/board/NstBoardUnlTf1201.o
OBJS += objs/core/board/NstBoardUnlWorldHero.o
OBJS += objs/core/board/NstBoardUnlXzy.o
OBJS += objs/core/board/NstBoardUxRom.o
OBJS += objs/core/board/NstBoardVsSystem.o
OBJS += objs/core/board/NstBoardWaixing.o
OBJS += objs/core/board/NstBoardWaixingFfv.o
OBJS += objs/core/board/NstBoardWaixingPs2.o
OBJS += objs/core/board/NstBoardWaixingSecurity.o
OBJS += objs/core/board/NstBoardWaixingSgz.o
OBJS += objs/core/board/NstBoardWaixingSgzlz.o
OBJS += objs/core/board/NstBoardWaixingSh2.o
OBJS += objs/core/board/NstBoardWaixingZs.o
OBJS += objs/core/board/NstBoardWhirlwind.o
OBJS += objs/core/board/NstBoardZz.o
# Input
OBJS += objs/core/input/NstInpAdapter.o
OBJS += objs/core/input/NstInpBandaiHyperShot.o
OBJS += objs/core/input/NstInpBarcodeWorld.o
OBJS += objs/core/input/NstInpCrazyClimber.o
OBJS += objs/core/input/NstInpDoremikkoKeyboard.o
OBJS += objs/core/input/NstInpExcitingBoxing.o
OBJS += objs/core/input/NstInpFamilyKeyboard.o
OBJS += objs/core/input/NstInpFamilyTrainer.o
OBJS += objs/core/input/NstInpHoriTrack.o
OBJS += objs/core/input/NstInpKonamiHyperShot.o
OBJS += objs/core/input/NstInpMahjong.o
OBJS += objs/core/input/NstInpMouse.o
OBJS += objs/core/input/NstInpOekaKidsTablet.o
OBJS += objs/core/input/NstInpPachinko.o
OBJS += objs/core/input/NstInpPad.o
OBJS += objs/core/input/NstInpPaddle.o
OBJS += objs/core/input/NstInpPartyTap.o
OBJS += objs/core/input/NstInpPokkunMoguraa.o
OBJS += objs/core/input/NstInpPowerGlove.o
OBJS += objs/core/input/NstInpPowerPad.o
OBJS += objs/core/input/NstInpRob.o
OBJS += objs/core/input/NstInpSuborKeyboard.o
OBJS += objs/core/input/NstInpTopRider.o
OBJS += objs/core/input/NstInpTurboFile.o
OBJS += objs/core/input/NstInpZapper.o
# VS System
OBJS += objs/core/vssystem/NstVsRbiBaseball.o
OBJS += objs/core/vssystem/NstVsSuperXevious.o
OBJS += objs/core/vssystem/NstVsSystem.o
OBJS += objs/core/vssystem/NstVsTkoBoxing.o
# Interface
IOBJS += objs/unix/main.o
IOBJS += objs/unix/cli.o
IOBJS += objs/unix/audio.o
IOBJS += objs/unix/video.o
IOBJS += objs/unix/input.o
IOBJS += objs/unix/config.o
IOBJS += objs/unix/cheats.o
IOBJS += objs/unix/cursor.o
IOBJS += objs/unix/ini.o
IOBJS += objs/unix/png.o
# object dirs
OBJDIRS += objs objs/core objs/core/api objs/core/board objs/core/input
OBJDIRS += objs/core/vssystem objs/nes_ntsc objs/unix
# Core rules
objs/core/%.o: source/core/%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
# Interface rules
objs/unix/%.o: source/unix/%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $(WARNINGS) $(DEFINES) $(CFLAGS) -c $< -o $@
all: maketree $(BIN)
core: maketree $(OBJS)
interface: maketree $(IOBJS)
maketree: $(sort $(OBJDIRS))
$(sort $(OBJDIRS)):
@mkdir -p $@
$(BIN): $(OBJS) $(IOBJS)
$(CC) $(LDFLAGS) $^ $(LIBS) -o $(BIN)
install:
mkdir -p $(BINDIR)
mkdir -p $(DATADIR)/icons
mkdir -p $(PREFIX)/share/pixmaps
install -m 0755 $(BIN) $(BINDIR)
install -m 0644 source/unix/icons/nestopia.desktop $(DATADIR)
install -m 0644 NstDatabase.xml $(DATADIR)
install -m 0644 source/unix/icons/*.png $(DATADIR)/icons
install -m 0644 source/unix/icons/*.svg $(DATADIR)/icons
install -m 0644 source/unix/icons/nestopia.svg $(PREFIX)/share/pixmaps
xdg-desktop-menu install --novendor $(DATADIR)/nestopia.desktop
uninstall:
xdg-desktop-menu uninstall $(DATADIR)/nestopia.desktop
rm $(PREFIX)/share/pixmaps/nestopia.svg
rm $(BINDIR)/$(BIN)
rm -rf $(DATADIR)
clean:
rm -f $(OBJS) $(IOBJS) $(BIN)
nestopia-1.47/NstDatabase.xml 0000775 0000000 0000000 00003663576 12644314416 0016244 0 ustar 00root root 0000000 0000000
nestopia-1.47/README.md 0000664 0000000 0000000 00000000501 12644314416 0014547 0 ustar 00root root 0000000 0000000 This project is a fork of the original Nestopia source code, plus the
Linux port. The purpose of the project is to enhance the original, and
ensure it continues to work on modern operating systems.
The following platforms are supported:
* Linux, FreeBSD, OpenBSD, NetBSD, OS X, Windows
* Anything supported by libretro
nestopia-1.47/README.unix 0000664 0000000 0000000 00000004704 12644314416 0015143 0 ustar 00root root 0000000 0000000 Nestopia is a portable open source NES/Famicom emulator written in C++.
It is designed to be as accurate as possible and supports a large number
of peripherals.
Nestopia UE (Undead Edition) is a fork of the original source code, with
enhancements from members of the emulation community.
Compiling
=========
Linux:
* Make sure you have the proper development libraries installed.
In Debian:
apt-get install libglew-dev libsdl2-dev libgtk-3-dev libarchive-dev libao-dev
* cd to the nestopia source directory:
make
* Install globally and add menu entries:
sudo make install
Free/Open/NetBSD:
* Make sure you have GNU make and all dependencies installed from ports,
pkgsrc or binary packages. Also make sure to have xdg-utils installed.
* cd to the nestopia source directory:
gmake
* Install globally and add menu entries:
sudo gmake install
Modes
=====
* CLI mode has a command line interface only.
* GUI mode has a GTK+ GUI, and is *nix only.
* CLI mode should work on any platform, and GUI builds can be disabled
by modifying the Makefile accordingly. Comment lines 32-42 to build
a CLI-only binary. Binaries with support for a GUI can still be run
in CLI mode.
Post-Installation
=================
* Copy the Famicom Disk System rom (not included) to ~/.nestopia:
cp disksys.rom ~/.nestopia/disksys.rom
Configuration
=============
* CLI mode can only be configured by editing the config files or passing
command line arguments.
* GUI mode can be configured by editing config files, passing arguments,
or from the Configuration window.
* Config files: ~/.nestopia/nestopia.conf and ~/.nestopia/input.conf
Patching
========
* For soft-patching to work, the patch must be in the same directory as
the rom, and the filename must be exactly the same as the rom
filename, but with the .ips extension.
Hardcoded Keys
==============
Esc = Exit (CLI mode)
` = Alternate Speed (Fast-forward)
F1, F2 = Insert Coins
F3 = Flip FDS Disk
F4 = Switch FDS Disk
F5 = Quick Save (slot 1)
F6 = Quick Save (slot 2)
F7 = Quick Load (slot 1)
F8 = Quick Load (slot 2)
F9 = Screenshot
F12 = Reset
Backspace = Rewind
\ = Stop Rewinding
F = Toggle Fullscreen
T = Toggle Filters
G = Toggle Scale factor
Copyright
=========
This program is licensed under the GNU GPLv2. For details, read COPYING.
nestopia-1.47/changelog.txt 0000664 0000000 0000000 00000163675 12644314416 0016006 0 ustar 00root root 0000000 0000000 ----------------------------------------------------------------
1.47
----------------------------------------------------------------
Shell:
Additions:
- On-screen text when saving/loading states
- Basic NSF player
- PNG Screenshots
- Quick State Save/Load menu items
- Open Recent menu item
- Ability to pause games when configuration dialog is open
- Customizable NTSC filter options
- Support for Mac OS X
Changes:
- Updated to modern OpenGL (version 3.2 minimum)
Fixes:
- Empty audio buffer when volume is set to 0
- Input config now accepts joystick buttons over 10
libretro:
Additions:
- Game Genie Sound Distortion option
- Region selection core option
Changes:
- Default to "consumer" palette
- Vertical and Horizontal overscan options separated
Fixes:
- Fixed FDS save path
Core:
Additions:
- Added support for MC-ACC (perilsensitive)
- Added NstDatabase.xml entries (clobber)
- Added support for NES 2.0 submappers
- Added support for mapper 4.1
- Added support for mapper 4.3
- Added support for mapper 23.15
- Added support for mapper 25.15
- Added support for mapper 32.1
- Added support for mapper 68.1
- Added support for mapper 71.1
- Added support for mapper 78.1
- Added support for mapper 78.3
Fixes:
- Reverted fix for Mapper 79
- Fixed Burai Fighter status area (perilsensitive)
- FME-7 IRQ Fix (lidnariq)
- Disabled buggy audio sync
----------------------------------------------------------------
1.46.1/1.46.2
----------------------------------------------------------------
Unix Shell:
Fixes:
- Input config bugfixes
- Only go fullscreen when the game is actually playing
----------------------------------------------------------------
1.46
----------------------------------------------------------------
Unix Shell:
Additions:
- Mask Overscan option
- Disable GUI option
- Command line interface
- Scale Factor and Filters can be changed while playing
- Zapper support
- Palette and Picture options
- Ability to turn Vsync on/off
- Alternate emulation speed
- libao audio output (handles ALSA, OSS, Pulse, etc)
- More volume controls
- Turbo Buttons A and B
Changes:
- Ported to SDL 2.0
- Completely rewrote config file handling
- Completely rewrote input config and input handling
- Completely rewrote cheats
- Removed ALSA and OSS audio output
Windows Shell:
Fixes:
- xBR dialog now updates video output when options change
libretro:
Additions:
- Ability to load NstDatabase.xml (needed for some games)
- Overscan masking (themaister)
- Palette options
- Zapper support
Changes:
- Region detection based on NstDatabase.xml
Core:
Additions:
- Game Genie sound distortion option
- Mapper 210 (NAMCOT-175, NAMCOT-340)
Fixes:
- Hard Drivin' now playable (dragon2snow)
- Kaettekita Mario Bros. fix (dragon2snow)
- Fix for rewinder sound issue (steelywing)
- Typos and syntax error fixes (lioncash)
- Fix for Mickey's Safari in Letterland (joepogo, james)
----------------------------------------------------------------
1.45
----------------------------------------------------------------
Unix Shell:
Additions:
- Added the ability to switch FDS disks for multi-disk games
- xBR filter options
- Support for more archive formats through libarchive
- Differentiated Soft/Hard Reset
Changes:
- Removed internal zip and 7zip decoders in favour of libarchive
- Replaced gtk_key_snooper with key_press_event and key_release_event
Fixes:
- 7zip CRC check segfault
Windows Shell:
Additions:
- xBR filter options
Changes:
- Redundant TV Aspect checkbox removed from NTSC filter dialog
- Modified default sound settings to avoid desync
libretro:
Additions:
- blargg's NTSC filter core option
- L/R now insert coins on Vs. System games
Core:
Additions:
- xBR filter added - Hyllian, notBald
Fixes:
- Triangle volume bug in Dendy mode - emu-russia
- NTSC filter background colour fix - blargg
----------------------------------------------------------------
1.44
----------------------------------------------------------------
Unix Shell:
Additions:
- Support for FreeBSD, OpenBSD, and NetBSD
- TV Aspect Ratio option added
- 2xSaI filter option exposed
Changes:
- Renamed Linux port to Unix port
- Removed status bar
- General UI improvements
- Stop warning about unused results
- SDL is the default sound API on Linux, the only one on the BSDs
- Drag and Drop re-enabled
Fixes:
- Fixed SDL sound crashes
- Fixed Movie Record crash
- Loading a state when none exists no longer resets
- Fixed bug that causes "Enter" to toggle fullscreen
- GUI responsiveness glitches when failing to output sound fixed
Windows Shell:
Fixes:
- TV Aspect is more accurate - W.M. Martinez
libretro:
Additions:
- libretro port done by Themaister and twinaphex
Core:
Fixes:
- Merged a fix for Mapper 79 that affects "Puzzle (Unl)" - shalma
- Fixed a PPU bug that causes problems in "The Young Indiana Jones
Chronicles" - Art Vandelae, plasturion, and James
- Mapper 143 fix that affects "Dancing Blocks (Unl)" - shalma
----------------------------------------------------------------
1.43
----------------------------------------------------------------
Linux Shell:
Additions:
- Fullscreen defaults to native screen resolution
Changes:
- Completely rewrote the GUI (except for Cheat Manager and Archive Selector)
- More traditional look and feel
- Improved input configuration
- Keyboard shortcuts
- More functionality exposed directly through GUI
- Better looking icons
Windows Shell:
Changes:
- Updated icons, about dialog, copyright
- Merged the remaining features from Unofficial 1.41.1
----------------------------------------------------------------
1.42
----------------------------------------------------------------
Linux Shell:
Additions:
- Added native support for D-pads (Hat Switches)
- Added an About dialog box
- Added icons and a desktop menu entry
Fixes:
- Fixed the 100% CPU usage bug
- Fixed the "Error writing setting!" bug (patch from Arch Linux)
----------------------------------------------------------------
1.41
----------------------------------------------------------------
Linux shell:
Fixes:
- Fixed a braindead SRAM path issue
Windows Shell:
Changes:
- Merged win32 fixes from Unofficial Build 1.41.1
----------------------------------------------------------------
1.40-undead
----------------------------------------------------------------
Linux Shell:
Additions:
- Added install/uninstall targets to Makefile
Changes:
- Ported to GTK+3
- Changed default sound API to ALSA (SDL audio has problems on some computers)
- Changed default renderer to OpenGL with a scale factor of 2
- Changed binary name to "nestopia"
- SRAM now saves to ~/.nestopia/save (for people who have roms on a read-only network share)
- Automatically install a new nstcontrols file to ~/.nestopia if it doesn't exist
- Install NstDatabase.xml to a proper location on the filesystem instead of forcing the user to manually copy it to ~/.nestopia
Fixes:
- Fixed numerous compiler warnings.
----------------------------------------------------------------
Unofficial 1.41.1 - by Geestarraw (geestarraw@gmail.com) (May 17, 2011)
----------------------------------------------------------------
Shell:
Changes:
- Added fullscreen support for non-primary monitor displays.
- Modified Video Options dialog component layout and added device index to
identify mutiple monitors.
- Refactoring.
- Code documentation.
Fixes:
- Fixed so menu is still displayed after fullscreen monitor to monitor switch.
Project:
Changes:
- Converted solution and projects to Visual Studio 2010.
- Improved version enumeration previously locked to x.xx (exactly 3 digits) to
be anything from y.y, y.y.y, and y.y.y.y (where y can be up to 4 digits).
- Changed build output target to nestopia.exe.
Fixes:
- Fixed bug in version enumeration always excluding highest version number.
- Moved unofficial 1.41 release notes to official changelog file.
----------------------------------------------------------------
Unofficial 1.41 - by Keith Kelly (c0d3h4x0r@hotmail.com) (March 29, 2010)
----------------------------------------------------------------
This is an unofficial maintenance release I created to fix an annoying joystick lag issue.
This lag was particularly bad when VSync was enabled. The original Nestopia author (Martin
Freij) appears to have abandoned the official Nestopia project on SourceForge and has not
responded to any of my e-mails, so I am left with no choice but to provide this unofficial
release as a public service to the emulation community.
Changes:
1. Removed manual option to set priority of Nestopia's main emulation loop thread. Instead,
Nestopia now boosts its own process base priority AND its own main emulation thread priority
whenever it is the active foreground window (and/or running in full-screen mode). This brings
Nestopia much closer to real-time performance and responsiveness.
2. Removed some screwy input polling logic, and added some calls to input.Poll(), to ensure
that the input devices are always polled immediately before the input state is utilized.
This was the key change that got rid of most of the lag.
3. Removed some screwy input timing logic that was causing input polling to work only on
certain clock intervals, rather than allowing it to work every time it was called.
(As far as I can tell on my own hardware configuration, these three changes taken together
have completely eliminated the lag problems that have been present in Nestopia for several
releases. Your mileage may vary.)
4. Updated the Visual Studio solution/project to build successfully under Visual C++ 2008
Express Edition.
5. Added this releasenotes.txt file and bumped the version number to 1.41.
----------------------------------------------------------------
1.40 Release A-H - by R. Belmont
----------------------------------------------------------------
Linux Shell:
Additions:
- XML ROM support
- More flexible video configuration including OpenGL hardware scaling
- Input mapping in the GUI
- Cheat Manager with flexible support and import/export capability (win32 compatible format)
- Core logging is now enabled to the terminal you start NEStopia from for easier diagnosis of problems
- Automatic soft-patching added
- Coin inputs added for Vs. system
- Audio filters added for fun
- [Release C] Proper default nstcontrols file included
- [Release E] Added SDL audio driver, should be most compatible
- [Release G] Cheat Manager now shows descriptions on imported XML files. Also fixed a CM crash.
Changes:
- Complains more if it's unable to write to the settings file
- Archive browser comes up automatically if you select a zip or 7zip archive with multiple NES files in it
- Option to select favored console
- [Release E] Refactored to get UI code out of main.cpp
- [Release G] Settings window auto-hides during emulation [enik]
Fixes:
- Fixed bug where keyboard input could stick
- [Release B] Cleaned up some crashy issues with the control configurator
- [Release D] Fixed ability to remap "meta" keys (keys that control NEStopia itself), fixed documentation on defaults.
- [Release E] Fixed quicksave/quickload
- [Release F] Fixed keyboard to ignore numlock/capslock
- [Release G] Taskbar description is set properly for the game window [enik]
----------------------------------------------------------------
1.40
----------------------------------------------------------------
Shell:
Additions:
- New cheat dialog features and improvements.
- Automatic cheat load/save support in Paths dialog.
- Option to mute sound when running in alt. speed mode.
Changes:
- Icon improvements by Pongbashi.
- Default fullscreen resolution depending on monitor's aspect ratio.
- Refactoring.
Fixes:
- Various minor things.
Core:
Additions:
- Preliminary Dendy console support. Fixes Magistr (Subor) and
some other 'clone exclusives'. Info from Flamer and HardWareMan.
- DMC DMA read conflicts. Info from blargg and bunnyboy.
- Mapper 177, 179, 219 and 221. Info from CaH4e3.
- Database entries.
Changes:
- Better and more flexible PPU address line implementation at the
expense of some speed.
- Database entries.
- Refactoring.
Fixes:
- Wrong palette sometimes when switching to/from VS images.
- Wrong image information sometimes, e.g. battery when there isn't any.
- Save state NTSC/PAL mode saving.
- Minor save state inaccuacy fix with tape recording.
----------------------------------------------------------------
1.39
----------------------------------------------------------------
Shell:
Additions:
- "Don't show again" checkbox in DIP switches popup window.
- Soft-patching status in image info dialog.
Changes:
- More descriptive error messages.
- Refactoring.
Fixes:
- Netplay file opening error leading to crash.
- Recent files locking bug on exit.
- Last visited image file directory bug on exit.
- Esc not working sometimes when disabling dialog
controls (Windows quirk).
- Crash on cancel when exporting to AVI.
- Correct screen height with NTSC filter when exporting to AVI.
- Typos in GUI.
Core:
Additions:
- Core API documentation in HTML through cppdoc.
- UPS patching format support.
- Database lookup on soft-patching.
- Database entries. Info from Bootgod.
- More recognized boards. Info from Bootgod.
Changes:
- FDS saves through UPS instead of IPS.
- Database entries. Info from Bootgod.
- Refactoring.
Fixes:
- FDS file saving bug.
- NTSC burst phase incrementing bug.
- Potential memory leak in database loader.
- UTF16 to wchar_t portability fix in XML parser.
- Const-correctness bug caught by GCC 4.0.
----------------------------------------------------------------
1.38
----------------------------------------------------------------
Shell:
Additions:
- Option to select favored console in preferences dialog.
Changes:
- Some video filtering work offloaded to the GPU.
- Most settings now stored in XML format.
- Misc launcher dialog display properties.
- Refactoring.
Fixes:
- Netplay input communication.
- Netplay movie recording bug (menu item accidently grayed).
Core:
Additions:
- ROM sets and external database support using new XML format
co-developed with Bootgod.
- Mapper 36, 103, 104, 106, 120, 126, 175, 176, 223 and 224.
Info from mad dumper, CaH4e3 and Temryu.
- UNIF boards GS-2013 and BS-5. info from CaH4e3.
- Emulation of bus conflicts for certain boards.
- Database entries.
Changes:
- PPU power/reset timing and register states. Info from blargg.
- Misc IRQ/NMI/BRK/DMA special-case behavior. Info from blargg.
- NTSC/PAL switch during emulation will now force a hard-reset.
- Misc mapper emulation improvements. Info from Bootgod.
- NES-EVENT board timer more accurate.
- Board names. Info from Bootgod.
- Refactoring and mapper codebase overhaul.
- Speed optimizations (accuracy NOT compromised!).
- Mappers 21, 23, 25 and 185 no longer supported using plain iNES
files because of format restrictions.
Fixes:
- MMC3 soft-reset IRQ bug.
- Database entries.
----------------------------------------------------------------
1.37
----------------------------------------------------------------
Shell:
Additions:
- Menu option for DIP switch window popup on file load.
- Movie recording now supported during netplay.
Changes:
- Smaller netplay data packets.
- Minor GUI adjustments.
- Refactoring.
Fixes:
- Scaling artifacts with NTSC filter on certain resolutions.
- Auto NTSC/PAL window resize bug.
- Sound stuttering on window clicks.
- Netplay bugs/quirks.
- Joystick auto-calibration bug.
Core:
Additions:
- Mapper 63.
- Mapper 121 and 134. Info from CaH4e3.
- Mapper 136 for Sachen board SA-002 3011. Info from Enri.
- Mapper 178 for "San Guo Zhong Lie Zhuan (Ch)". Info from temryu.
- UNIF boards: AX5705, T-230, CTC-65 and 190IN1. Info from CaH4e3.
- Adaptive sound streaming synchronization.
- More optimization hints for GCC.
- Database entries.
Changes:
- Movie file format rewritten. Older files will no longer work (sorry, had to
be done sooner or later). New format is much more flexible and extendable.
- Lower memory consumption.
- APU speed optimizations.
- Most DIP switches are now configurable through dialogs instead being
soft-reset-triggered.
- Board names. Info from Pongbashi and Bootgod.
- Refactoring.
Fixes:
- Mapper 41 and 43.
- Mapper 112. Fixes "Fighting Hero III". Info from temryu.
- Minor save state inaccuracy.
- FDS sound emulation inaccuracy.
Fixes "Nazo no Magazine Disk - Nazoraa Land Dai 3 Gou".
- Small rewinder bug.
- Database entries.
----------------------------------------------------------------
1.36
----------------------------------------------------------------
Shell:
Additions:
- Joystick calibrate button in the input dialog.
Changes:
- Now possible to make save states (slots only) during netplay.
- Some error messages more descriptive.
- Log file now enabled by default.
- Lazy loading of some resources, notably the launcher file database.
- Various aesthetic GUI fixes and improvements.
- Refactoring.
Fixes:
- Lightgun trigger no longer registered if screen is occluded by a window.
- Various things, subtle and not-so-subtle.
Core:
Additions:
- Power Glove peripheral support.
- Mapper 38, 108 and 173. Info from CaH4e3.
- UNIF boards: TF1201, KS7038 and GS-2004. Info from CaH4e3.
- Mapper 150 reset-triggered DIP switch toggling.
- Database entries.
Changes:
- Speed optimizations (NO accuracy trade-off).
- blargg's nes_ntsc updated to version 0.2.2.
- HSB/RGB calculation method.
- 8bit video mode rendering removed.
- 2xSaI filters removed. Use hqx or ScaleX instead.
- Even stricter ANSI/ISO compliance.
- More compiler options and detections through the preprocessor. Refer
to "NstApiConfig.hpp" as starting point for porting work.
- Board names. Info from Pongbashi.
- Refactoring.
Fixes:
- Mapper 234.
- Mapper 242. Fixes "Dragon Quest VIII (Ch)".
- Database entries.
- Various things, subtle and not-so-subtle.
----------------------------------------------------------------
1.35
----------------------------------------------------------------
Shell:
Additions:
- Memory pool select for sound buffers.
- Famicom and NES four player adapter select in menu.
- More cartridge info in image file dialog.
Changes:
- Better sound synchronization.
- Launcher fixes and improvements.
- Workaround for bugs in E-MU sound drivers.
- Workaround for bug in ::D3DXSaveSurfaceToFile() using D3DXIFF_BMP.
- MBC strings now passed in netplay chat.
- Aspect ratio option now preserved on ALT+S in fullscreen mode.
- VSync now disabled by default.
Fixes:
- Settings for compressed palette and FDS BIOS files now properly saved on exit.
- AVISTREAMINFO::fccHandler.
- Relative paths in Paths dialog.
Core:
Additions:
- Preliminary support for NES 2.0 file headers.
- R.O.B / Famicom Robot peripheral support.
- Mapper 14, 196, 214 and 169 (partially). Info from CaH4e3.
- Mapper 171 (KAISER KS7058) for "Tui Do Woo Ma Jeung".
- Mapper 172 (IDEA-TEK CNROM +SECURITY) for "1991 Du Ma Racing" (unaltered version).
- Database entries.
Changes:
- PAL APU noise channel rates and frame sequencer steps. Info from Blargg.
- Emphasis color calculations on user palettes.
- Better board type detection for several mappers, particulary 1 and 4.
- Board names. Info from Pongbashi.
- Removed worthless mapper 100.
- Refactoring.
Fixes:
- Mapper 12 to use MMC3A revision. Fixes "Dragon Ball Z 5".
- Mapper 15, 147 and 222. Info from CaH4e3.
- Mapper 99, PRG-ROM bank switching. Fixes "VS Gumshoe".
- Mapper 115 and moved "Bao Qing Tian" to it.
- Mapper 156. Fixes "Ko Ko Eo Deu Ben Ce" and "Metal Force".
- Mapper 163. Info from CaH4e3 and tpu.
- Mapper 230. Fixes "Contra" in "22-in-1".
- Mapper 232. Fixes the Quattro games.
- Right mouse button for light gun firing off-screen.
- Minor sound volume control bug.
- AbsX 3-byte NOP instruction timing.
- Database entries.
----------------------------------------------------------------
1.34
----------------------------------------------------------------
Shell:
Changes:
- Better method for CPU/GPU frame synchronization. Disabled when triple
buffering is enabled.
- Suitable default settings for auto frame skip, triple buffering and
clock source based on system info.
- Blargg's nes_ntsc back again with new version 0.2.1.
- AVISTREAMINFO::szName no longer used since its presence seem to cause
loading failures in some AVI file editors.
Fixes:
- Frame timing bug. Could cause severe slowdown on some systems.
- Wrong speed at higher refresh rates.
- Non-blocking input key commands.
Core:
Fixes:
- "Quattro Sports: BMX Simulator" now responds to input again.
----------------------------------------------------------------
1.33b
----------------------------------------------------------------
Shell:
Fixes:
- Removed use of DirectInput8 event notifications. Caused too much
problems and some joysticks refused to work with it.
----------------------------------------------------------------
1.33
----------------------------------------------------------------
Shell:
Additions:
- Adjustable screen curvature.
- Auto scale option for Hqx and ScaleX video filters.
- Auto color settings option for NTSC filter.
- 'Condition' column in launcher.
- Hex and current entry view in palette editor.
- Fast way to supply a missing FDS BIOS file on disk image loading.
- 'Default' button in FDS dialog.
- More FDS info in log file and image info dialog.
Changes:
- Reduced input latency and improved overall frame flow by rearranging
wait loops and making use of Direct3D9 query events (or dummy texture
locks if unsupported) to force CPU/GPU sync on each frame.
- Improved emu input granularity with use of DirectInput8 event notification.
Fixes "BMX Simulator" in "Quattro Sports".
- Reclaim of ::Sleep() time on timed intervals in frame timer.
- Warning message now issued whenever the database corrects a nes file with bad header.
- Filelist controls now accept double clicks.
- Pressing ESC now closes most dialogs.
- No menu check marks when disk is ejected.
- WMM timer now used by default because of QPF/QPC unsafety on dual-core CPUs.
- Refactoring.
Fixes:
- Wrong HSB values in palette editor.
- Speed throttle bug when vsync was enabled.
- Incorrect window size on startup after a previous exit with a PAL sized window.
- Auto cursor hiding (didn't always work).
Core:
Additions:
- Hq4x video filter.
- Support for extended 512*3 byte palettes (for emphasis colors).
- FDS screen text for disk reads/writes.
- Database entries.
Changes:
- Better RGB to YUV conversion for VS System.
- Better VS System detection strategy.
- VS DIP switch descriptions for "Battle City", "RBI Baseball", "Super Sky Kid"
and "Super Xevious".
- Rewinder optimizations. Faster but more memory consuming.
- More accurate FDS disk drive emulation. Fixes "Aspic-Majaou no Noroi",
"Hao Kun no Fushigina Tabi" and possibly others.
- Switched to Blargg's snes_ntsc in order to make it work with custom palettes.
- Refactoring and optimizations.
Fixes:
- Mapper 117. Fixes "La Bi Xiao Xin". Info from tpu.
- Change side bug for single sided FDS disks.
- Game Genie decoder bug when using certain compare values.
- Database entries.
----------------------------------------------------------------
1.32
----------------------------------------------------------------
Shell:
Additions:
- Language plugin system using compiled resource DLLs. LDK included in the source.
- Date and time for last state slot write now displayed in the menu.
- Most option dialogs now carry a cancel button.
- Launcher window size preserved and optionally saved on exit.
- More detailed info in some error messages.
Changes:
- Various aesthetic fixes and improvements to the GUI.
- Alternative screen font for a few selected countries.
- Many hardcoded strings moved to the resource string table.
- No default directory creation if already user specified.
- Swapped load/save state keys (N/SHIFT+N) for a more standard setup.
- Different meaning to the SHIFT+0/0 key for save/load state slots.
SHIFT+0 to overwrite oldest slot, 0 to load from newest slot.
- Auto monitor frequency option in video dialog now enabled by default.
- Updated to newer version of unrar.dll.
- unrar.dll and kaillera.dll now only loaded on demand.
- Lots of refactoring.
- Cleaned up tabs and spaces in source files via internal utility.
- Cleaned up HTML in readme file.
Fixes:
- More menu/dialog items grayed out when not applicable.
- Menu disappearance sometimes after exiting menus/dialogs in fullscreen mode.
- Filter settings now properly reset on 'Default' button clicks in the video options dialog.
- Display of the 'Name' and 'Maker' launcher column entries now in proper ANSI code page.
- Directory string parsing bug if failed to create a default directory.
- Auto window sizing quirk.
- Incorrect image file properties in some of the database corrected entries in the launcher dialog.
Refresh your file list to force the fix to take effect.
Core:
Additions:
- Pachinko (via mouse wheel) and Hori Track (via mouse) controllers. Info from Enri.
- Nantettatte Baseball Double Cassette System for mapper 68. Info from CaH4e3 and Enri.
- Mapper 170 for "Fujiya Thinking Games". Info from Enri.
- Mapper 197 for "Super Fighter III". Info from CaH4e3.
- Backup-switch for the Family BASIC and Playbox BASIC cartridges (DIP Switches dialog). Info from Enri.
- RP2C04 VS Unisystem palettes. Info from Quietust and Kevtris.
- New entries for auto-detection of controllers.
- Database entries.
Changes:
- Moved "Subor (Russian)" to mapper 166.
- Moved "Seicross (J)" back to mapper 185.
- Controller names. Info from Pongbashi.
Fixes:
- DIP switch setting for "VS.Bomb Jack".
- Lightgun in "VS.Duck Hunt" and "VS.Hogan's Alley" now works again.
- Database entries.
----------------------------------------------------------------
1.31
----------------------------------------------------------------
Shell:
Fixes:
- NSF text info bug from v1.30.
----------------------------------------------------------------
1.30
----------------------------------------------------------------
Shell:
Changes:
- Updated 7zxa.dll.
Fixes:
- NSF text info is now displayed in the proper ANSI code page.
Core:
Additions:
- Bandai Karaoke Studio michrophone support through keyboard.
- Sound sample support for:
"Family Trainer - Aerobics Studio" -> "ftaerobi"
"Moe Pro! '90 - Kandou Hen" -> "moepro90"
"Moe Pro! - Saikyou Hen" -> "mpsaikyo"
"Moero!! Pro Tennis" -> "mptennis"
"Moero!! Pro Yakyuu" -> "moepro"
"Moero!! Pro Yakyuu '88 - Ketteiban" -> "moepro88"
"Shin Moero!! Pro Yakyuu" -> "smoepro"
"Terao no Dosukoi Oozumou" -> "terao"
Info from Hap and Pongbashi.
- Mapper 132. Info from CaH4e3.
- Unif Boards "UNL-603-5052", "A65AS" and "EDU2000". Info from CaH4e3.
- Mouse support for "Educational Computer 2000". Info from CaH4e3.
Changes:
- Board/Chip names. Info from Pongbashi.
- Moved the following games to new mappers:
"Crystalis (ch)" -> mapper 195
"Captain Tsubasa Vol 2 - Super Striker (ch)" -> mapper 195
"Dragon Ball Z 2 - Gekishin Freeza! (ch)" -> mapper 199
"Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (ch)" -> mapper 199
"San Guo Zhi 2 (ch)" -> mapper 199
Fixes:
- More accurate PAL APU DMC rates. Info from Blargg.
- Mapper 4. Now defaulting to MMC3B IRQ hardware. Fixes "Star Trek - 25th Anniversary".
- Mapper 19. Fixes "Final Lap".
- Mapper 60, menu select for "TN 95-in-1" and "Super 35-in-1" via soft reset. Info from CaH4e3.
- Mapper 163. Fixes "Kou Dai Bao Shi - Hong (ch)" and "Kou Dai Bao Shi - Lan (ch)".
- Mapper 198, CHR banking. Fixes "Super Fighter III". Info from CaH4e3.
- Mapper 209, CHR 4K PPU latch mode. Fixes "Power Rangers" and others. Info from CaH4e3.
- Database entries.
----------------------------------------------------------------
1.29
----------------------------------------------------------------
Shell:
Additions:
- TV Aspect option.
- UI contrast slider.
Changes:
- UI color slider scales.
- Increase of auto-fire speed and granularity.
- Smoother fullscreen entering/exiting.
- Real-time updates with the video filter UI controls.
- Better compability across different compilers.
Fixes:
- Horizontal scroll-bar in the 'Open' dialog for compressed files.
- User input bug in the 'UNIF-to-mapper' dialog.
- NTSC/PAL window size issue on startup.
- Various GUI fixes.
Core:
Additions:
- UNIF boards "KOF97", "64-IN-1 No Repeat", "SHERO", "T-262" and "FK23C". Info from CaH4e3.
- Mapper 43 and 236. Info from FE.
- Database entries.
Changes:
- Update to version 0.2.0 of Blargg's NTSC video filter.
- Board/Chip names. Info from Pongbashi.
- Rewinder no longer forces alignment to a specific frame.
- Sprite overflow timing and flag quirks. Info from Blargg.
- Automatic use of ::_controlfp(..) for FPU double-precision mode or better.
- Mapper 95 now derived from NAMCOT 118 instead of MMC3.
- Mappers 189, 198 and 208 now derived from MMC3.
- Mapper 211 now derived from JY-xxx (90).
- Various mapper code cleanups.
- Moved the following games to new mappers:
"SMB+Tetris+NWC" -> mapper 37
"Jia A Fung Yun (chinese)" -> mapper 74
"Aladdin (pirate)" -> mapper 90
"Seicross (redump)" -> mapper 181
"Ying Lie Qun Xia Zhuan (chinese)" -> mapper 192
"Young Chivalry (chinese)" -> mapper 192
"Dai-2-Ji - Super Robot Taisen (chinese)" -> mapper 194
Fixes:
- APU sample rate counter overflow bug.
- Rewinder stop bug when running at non-default speed.
- FDS IRQ counter. Fixes "Druid - Kyoufu no Tobira".
- Mapper 45, no bankswitching with CHR-RAM. Fixes "Famicom Yarou Vol.1 7-in-1".
- Mapper 57, menu switch on soft-reset. Info from CaH4e3.
- Mapper 58, 115, 222, 150 and 188. Info from CaH4e3.
- Mapper 74. Fixes "Sangokushi (chinese)" and others.
- Mapper 83, language mode on soft-reset for "World Heroes 2" and "Fatal Fury 2".
- Mapper 90/209/211, M2 based IRQ counter added. Fixes "Goal!!" in "45-in-1".
- Mapper 117, IRQ counter. Fixes "San Guo Zhi 4 - Chi Bi Feng Yun".
- Mapper 255, menu screen bugs as on the real cart.
- Soft reset for mapper 230 and 255.
- Small VRC7 sound chip load-state bug.
- Database entries.
----------------------------------------------------------------
1.28
----------------------------------------------------------------
Windows:
Additions:
- Sound volume level sliders.
- More NTSC video filter options.
- Scanline darkening level sliders.
Changes:
- Pressing the ALT-key when the menu is hidden should no longer
cause "hickups" during play.
- Recent files/directories menu lock state is now saved on exit.
Fixes:
- Window placement bug.
Emulator:
Additions:
- Non-linear APU sound output.
- Mapper 116 for "AV-Girl Fighting".
- Mapper 163 and 167. Info from tpu.
- Database entries.
Changes:
- Update to version 0.1.7 of Blargg's NTSC composite video filter.
- Fine-tuned the volume levels of the external sound chips.
- More accurate SUNSOFT5B sound chip emulation.
- Moved "Shanghai" to mapper 93.
- Patch for "Dragon Ball Z II - Gekishin Freeza!! (redump)" to
use the proper EEPROM type.
- 'No Sprite Limit' option should now be more responsive to games
that make heavy use of OAM cycling.
Fixes:
- Mapper 45, 53, 74, 90, 93, 164 and 165.
- Dip-switch and input fixes for some VS.System games.
- Database entries.
----------------------------------------------------------------
1.27
----------------------------------------------------------------
Windows:
Additions:
- Any input key may now be mapped to a joystick.
- Alternative set of icons provided by Pongbashi.
Changes:
- Auto-monitor-frequency setting is now applied after exiting the dialog.
Fixes:
- Grayed Power-off menu item.
- Controllers in netplay.
Emulator:
Additions:
- Mapper 102 (SUNSOFT-3R) for "Shanghai (redump)".
- RP2C03B/RC2C05-03 palette. Info from Kevtris.
- Color decoder control via R-Y/G-Y/B-Y angle+gain. Comes with three presets.
- Support for NSF files that use more than one external soundchip.
Changes:
- More accurate NES chroma/luma coefficients. Info from Blargg.
Fixes:
- Mapper 83. Fixes intro in "World Heroes 2".
- Mapper 185. Patch for "Seicross (redump)".
- APU triangle step-sequencer reset bug.
- Some NSF player bugs.
- Some database entries.
----------------------------------------------------------------
1.26
----------------------------------------------------------------
Windows:
Additions:
- Automatic joystick axes recalibration.
- More video filter options.
Changes:
- ::GetLongPathName() is now used in conjunction with ::GetCommandLine().
- Better logic for when and when not to preserve the NES picture scale factor in fullscreen.
- Minor aestetic fixes.
Fixes:
- Crash on start in 98/ME.
- Crash on exit when two or more video devices are present.
- Invalid fullscreen view on dual displays.
- Parameter change in ::CompareString() for 98/ME/2k compatibility.
- Correct LIB linking order for MSLU.
- Bug in WM_DROPFILES and WM_COPYDATA handlers.
- Certain input keys are now ignored. Fixes some japanese keyboards.
- Can now parse unquoted filenames from the command-line.
Emulator:
Additions:
- MD5 instead of CRC when checking for modified data.
- New image file CRCs for auto detection of controllers.
- Database entries.
Changes:
- NTSC filter optimizations.
- Minor palette modifications.
- __attribute__ ((fastcall)) removed. Seems to be broken in GCC.
Fixes:
- Some NTSC filter bugs.
- Patch for "My Life My Love - Boku no Yume - Watashi no Negai" to use another revision of the MMC3 chip.
- NST_ASSERT() macro bug on platforms other than Win32.
----------------------------------------------------------------
1.25
----------------------------------------------------------------
Windows:
Fixes:
- Configuration file parse error after cheats were saved.
- Unquoted executable name on the command line.
- Archive filenames using non-ascii characters.
- File association bug.
- Katakana characters when using the 'clipboard-to-NES-screen' feature.
- Slight texel-to-pixel mapping inaccuracy.
Emulator:
Additions:
- NTSC composite video emulation. Requires a fast computer. Implementation by
Blargg and NewRisingSun.
- Mapper 27.
Changes:
- Took out the database names. Too many errors.
Fixes:
- Mapper 16 IRQ timing. Fixes SD Gundam Gaiden - Knight Gundam Monogatari 2 - Hikari no Kishi.
- King of Fighters 99 (no-frame-IRQ hack).
- Save state errors with MMC3 games.
- Blitter producing garbage on screen (rare occasions).
- Some ISO C++ misstakes.
----------------------------------------------------------------
1.24
----------------------------------------------------------------
Windows Port:
Additions:
- Unicode support. Win98/Me users need to obtain the Unicode Layer DLL (unicows.dll) from Microsoft's
site and place it in the same directory as Nestopia.
Evil hotlink: http://download.microsoft.com/download/b/7/5/b75eace3-00e2-4aa0-9a6f-0b6882c71642/unicows.exe
- Palette editor (video options dialog).
- NSV movie to AVI converter.
- Several new NSP file commands.
- Clipboard text can now be pasted into the screen through the menu or F12 when the Family Basic or
Subor keyboard is in use.
Changes:
- Original kailleraclient.dll replaced with Anti3D's version.
- Localized keyboard layout names.
- Better DirectInput to Family Basic keyboard mapping.
- Default save file path is now .\save instead of .\cartridge for consistency as some of the new save file
types aren't technically part of a cartridge.
- Various aestetic fixes.
Fixes:
- Menu->File->Sound Recorder->Rewind command is now disabled during recording.
- Workaround for the notorious VC8 iostream memory leak bug.
Emulation Core:
Additions:
- VRC7 sound chip (Lagrange Point).
- Mappers 137,138,139,141,143,145,146,147,148 and 149. Info from CaH4e3.
- UNIF boards 8157 and CC-21. Info from CaH4e3.
- Family Trainer, Subor Keyboard, Doremikko Keyboard (partial) and Party Tap expansion port devices.
- Turbo File using *.tf as file extension (some games by ASCII).
- Data Recorder using *.tp as file extension (Family Basic, Mach Rider, Excitebike, others).
- Datach Joint ROM System and Barcode Battler.
- 24C01+24C02 serial EEPROM for mapper 16 and 157.
- Secondary controller pad microphone via button press.
- Sound samples for Moero!! Pro Yakyuu.
- Option for allowing up/down and left/right button presses simultaneously.
- Some game database entries.
Fixes:
- FME-07 sound pitch.
- Mappers 76 and 83.
- Longer delay for FDS block-start reads. Fixes Time Twist.
- Some game database entries.
- NSF player bug with some FDS songs.
- Frame IRQ disabled by default (hack) for King of Fighters 97/98 and Sonic 3D Blast 6.
- Coefficients for the color emphasis modes. Info from Quietust.
----------------------------------------------------------------
1.23
----------------------------------------------------------------
Windows Port:
- Upgraded compiler.
- Added an option in the video dialog to automatically take advantage of other
display frequencies. It's disabled by default for compatibility reasons
but should be enabled for best performance.
- IDirect3DDevice9::SetDialogBoxMode() and D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
are now ONLY set when a menu or window is visible in full-screen mode. Improves
speed and vsync timing.
- Added an option for tripple-buffering in the timing dialog.
- Emulation is now stopped upon menubar activation.
- The last selected file type in the launcher dialog is now remembered throughout
the application lifetime.
- File names that are too long to fit inside the screen message field are now
truncated using ellipses.
- Minor bug fixes.
----------------------------------------------------------------
1.22
----------------------------------------------------------------
Windows Port:
- Added support for RAR and 7-Zip files.
- Enabled use of XP visual styles.
- Cleaned up the GUI a bit and fixed proper tab ordering.
- Added cheat search support.
- Added some joystick options. People having joystick problems in earlier versions can now disable the buggy axes.
- Improved auto frame skipping performance.
- Fixed an FDS BIOS path saving bug.
- Fixed an auto IPS patching bug.
- Fixed a Wave file recording bug.
- Fixed an Alt+Tab from fullscreen bug.
- Fixed a cheats delete/clear bug.
Emulation Core:
- Added real-time rewinding support (up to 1 minute). To use it, assign it to any key and enable it in the Timing dialog.
- Added support for cheats in the whole address range.
- Added support for "Pro Action Rocky" cheat codes.
- Added DPCM channel sample interpolation and DC offset removal.
- Improved PPU vblank timing and flag behaviour, info from Blargg.
- Fixed mapper 6 and moved "Mi Hu Chen (hFFE)" to it, info from CaH4e3.
- Moved "Shin Samurai Spirits 2", "Power Rangers III" and "Power Rangers IV" to mapper 209.
- Moved "Mortal Kombat 3 - Special 56 People" to mapper 90.
- Hacked mapper 90, more games are playable now,
- Added mapper 148 and moved "Sugoro Quest - Dice no Senshitachi (asia)" to it.
- Added mapper 183, info from CaH4e3.
- Added mapper 186, info from CaH4e3.
- Fixed mapper 187, "King Of Fighters 96" is now playable.
- Added mapper 216, info from CaH4e3.
- Added DreamTech UNIF board, info from CaH4e3.
- Added H2288 UNIF board, info from Kevtris and CaH4e3.
- Added proper handling of FDS disk insert/eject during movie playing/recording.
----------------------------------------------------------------
1.21
----------------------------------------------------------------
- Adjusted PPU cold reset timing, fixes Time Lord.
- Removed $4017.7 check for DMC IRQ, fixes Silent Service and Time Lord.
- Added an option for preserving the window size and position after exit.
- Added A12 hook for $2007(R/W).
- Added a newer version of ZLib.
- Fixed a window focus bug.
- Fixed a window size on startup bug.
- Fixed two minor APU save/load state bugs.
- Fixed a minor PPU sprite overflow bug.
- Corrected a VS palette entry, VS.Goonies looks better now.
- Options in the machine section in the menu are now saved on exit.
- Improved compatibility with DirectInput devices.
----------------------------------------------------------------
1.20
----------------------------------------------------------------
Given the fact that it has taken almost two years to complete this release
I've basically lost track of the shitload of changes and fixes I've made
throughout this time, but I'll try to cover the most notable new additions.
But first, I'd like to thank all the beta testers who helped shaping up
this release, especially Hellsbane, Michael Walsemann, Benjamin Siskoo
and Robert Tuccitto for their dedicated time and effort in searching for
bugs.
The Windows port has been rewritten from scratch (which proved to be more
time consuming than I initially thought). The emulation core has gone
through a complete overhaul as well.
Some of the new features:
- DirectDraw kicked out and replaced by Direct3D (DirectX 9.0c now required)
- More video filtering options
- More multitasking friendly
- Configurable menu keys
- Less cumbersome to take screenshots and no more GDI+ requirement
- Selectable auto-fire speed
- Recent directories
- Ability to lock and clear the recent files and directories lists
- Selectable LED source for FDS disk access
- Alternative emulation speed via assignable key/button
- Ability to change the menu color
- Changes to brightness/saturation/hue takes effect immediately
- More logfile (disabled by default now) diagnostics
- Cursor gets auto-hidden
- Many hard-coded strings now moved into the resource section
- Image info for FDS and NSF files
- Can make IPS files out of changes to FDS disk files
- Can edit iNes file headers
- Hq2x/Hq3x filter support
- Additional GUI improvements
New iNes mappers:
53, 56, 142, 158, 164, 165, 193, 203, 204, 205, 206, 207, 208,
209, 210, 211, 212, 213, 215, 217
Fixed iNes mappers:
*many*
New UNIF boards:
Mario 1 Malee 2, Novel Diamond 9999999-in-1, Super Game 8237
Super 24-in-1, WS 40-in-1
New controllers:
Oeka Kids Tablet, Hyper Shot, Crazy Climber, Mahjong, Exciting Boxing
Top Rider, Pokkun Moguraa
Other emu core related things:
- More standard conformant C++ code
- Easier to port to other platforms using a new written API
- Many speed optimizations (but at NO cost of emulation accuracy)
- Save state and movie file formats rewritten, old files will no longer work
- More accurate APU and PPU emulation thanks to RE work by Blargg, Kevtris and Quietust
- Perfectly time-aligned sound sample output by using a common clocking rate
- Uses new updated palette by BMF
- Better (but not perfect) NTSC color generation algorithm based on tweaks by AWJ
- ROM database fixes and additions
- Support for phantom stereo sound output
- More accurate FDS emulation
- Better sound quality with the external sound chips
- Auto-selects between Famicom and NES 4-player adapter based on game CRC
- More accurate emulation for several controllers
- More accurate hard/soft reset behaviour
That covers most of it. If you like this release and would like to thank me for
eating Nestopia, sleeping Nestopia and breathing Nestopia during these past two years
consider donating a few bucks through the pay-pal link at http://sourceforge.net/projects/nestopia.
----------------------------------------------------------------
1.09
----------------------------------------------------------------
-Added netplay (Kaillera).
-Added Scale2x/3x graphic filters.
-Menu can now be toggled in window mode.
-'Unlimited Sprites' bug fixed.
-Fixed FDS IRQ counter, glitches gone in SMB2(j).
-Fixed mapper 5, glitches gone in all KOEI games plus others. Save games and
states fixed as well.
-Added mapper 12, info from VirtuaNES.
-Tweaked mapper 17 IRQ counter, fixes a few more FFE F8 games.
-Reassigned mapper 48 to 33 (Flintstones - The Rescue of Dino & Hoppy (j)).
-Fixed mapper 65, glitches gone in "Kaiketsu Yanchamaru 3 - Taiketsu! Zouringen" among others.
-Fixed mapper 69, "Honoo no Toukyuuji - Dodge Danpei" plus others work.
-Fixed mapper 182, glitches gone in "Super Donkey Kong".
-Added mapper 200, info from CaH4e3.
-Added mapper 201, info from CaH4e3.
-Added mapper 202, info from CaH4e3.
-Fixed mapper 245, "Yong Zhe Dou E Long - Dragon Quest 7" plus others work.
-Fixed mapper 249, glitches gone in "Shui Hu Zhuan" plus others.
-Added mapper 252, info from saro.
-Added mapper 254, info from VirtuaNES.
-A warning message is displayed when encrypted games are loaded.
-Added auto PRG-ROM size correction on known 512k MMC1 games (Dragon Warrior/Quest 4).
-OAM address is now cleared on VBLANK start, fixes sprite errors in "Titanic 1912",
"Godzilla" and possibly other games.
-Made some PPU optimizations (scanline tile caching).
-Fixed a minor thread priority bug.
-Fixed a PPU reset bug, fixes machine resets in "Knight Rider".
-Changed the way CPU RAM gets initialized during power on, fixes first intro screen in
"Super Donkey Kong - Xiang Jiao Chuan".
-Removed IRQ triggering hacks for mappers 19,21,23,25,33,40,50,65,67,83 and 183.
-Swapped p1/p2 controls on some VS games.
----------------------------------------------------------------
1.08
----------------------------------------------------------------
-Added a launcher.
-Added support for drag-drop files.
-Added some more options in the preferences dialog.
-Changed so that relative paths are preserved.
-Fixed mapper 1, glitches gone in "Air Fortress".
-Fixed mapper 4, sound in "Startropics" & "Startropics 2 - Zoda's Revenge" works (MMC6B games which differs from MMC3).
-Fixed mapper 10, "Fire Emblem" plus others work.
-Fixed mapper 18, "Toukon Club" plus others work (minor glitches still there though).
-Fixed mapper 19, "Family Circuit '91" and "Wagan Land 3" plus others work.
-Fixed mapper 23, all valid versions of "Akumajou Special - Boku Dracula Kun" should now work.
-Fixed mapper 32, "Ai Sensei no Oshiete - Watashi no Hoshi" and "Major League" works.
-Fixed mapper 33, glitches gone in "Captain Saver".
-Fixed mapper 51, "11-in-one Ball Games" works again.
-Fixed mapper 58, "Study and Game 32-in-1" works.
-Fixed mapper 60, "Reset Based 4-in-1" works.
-Fixed mapper 62, "Super 700-in-1" works.
-Fixed mapper 68, "Maharaja" works.
-Fixed mapper 70, less glitches in "Gegege no Kitarou 2 - Youkai Gundan no Chousen".
-Fixed mapper 82, glitches gone in "Kyuukyoku Harikiri Stadium 3" plus others.
-Fixed mapper 87, "City Connection", "Ninja Jajamaru Kun" plus others work.
-Fixed mapper 88, glitches gone in "Dragon Spirit - Aratanaru Densetsu" plus others.
-Fixed mapper 90, less glitches in "Mortal Kombat 3 - Special 56 Peoples".
-Fixed mapper 101, "Urusei Yatsura - Lum no Wedding Bell" works.
-Fixed mapper 113, glitches gone in "16 Mahjang".
-Fixed mapper 119, glitches gone in "Pinbot" and "Highspeed".
-Fixed mapper 185, "Bird Week" works.
-Fixed Game Genie bug (certain codes would either not work or crash the application).
-Improved CPU/PPU synchronization. Screen shaking gone in many games ("Times of Lore", "Kick Master").
-Tweaked the DMC and noise channel's output frequencies for PAL mode. PAL sound is now more accurate.
-Tweaked the DMC DMA/IRQ counters. Most games relying on correctly timed DMC IRQ triggering should now
work (Codemasters games, Ian Bell's Tank Demo).
----------------------------------------------------------------
1.07
----------------------------------------------------------------
-Added support for file associations (preferences dialog).
-Added an option to select between single and multiple application instances (preferences dialog).
-Fixed a bug that caused the key mapping for a second joystick device to be reset every time Nestopia was restarted.
-Changed so that all Game Genie codes are saved on exit.
-Moved most of the on-screen-messages into the resource string table to make life easier for people making translation patches.
-Updated the rom database. Thanks again to [yang] for the new compilation.
-Fixed so that ns1..ns9 (save slots) files will show up when browsing files.
-Added command line parameter support.
-Added a status bar (menu).
-Added an FPS counter (menu).
-Added an option to force the window on top (menu).
-Added an option to disable the performance counter timer (timer dialog).
-Added an option to disable configuration saving on exit (preferences dialog).
-Added some more shortcut keys to the menu.
-Better multitasking.
-Added automatic thread priority control (preferences dialog).
-Changed so that even a totally screwed up iNes file header may pass thru the loader if the file can be found in the database.
-Improved the timers.
-Made new icons.
-Many bug fixes.
----------------------------------------------------------------
1.06
----------------------------------------------------------------
-Fixed the input bug that sneaked up in v1.05. IDirectInputDevice8::Poll() was the cause. I forgot it could return
DI_NOEFFECT which is not the same as DI_OK. The bug affected devices that didn't need manual polling.
-Fixed a bug that caused all soundcards without support for hardware-mixed secondary buffers to not work.
-Did some small optimizations in the PPU core.
-Changed so that state slots are flushed to files (if enabled) every time the user saves instead of only during load/close.
-Modified the path dialog. Two check mark buttons now control the auto loading and saving of state slots.
-Less sound stutter when toggling the menu in fullscreen.
-Tweaked the render queue and put a limit on how many frames behind the GPU can be. This is to prevent sudden jerks and input lag.
----------------------------------------------------------------
1.05
----------------------------------------------------------------
-Corrected the CRC database searcher (several games had the wrong name displayed in the title bar)
-Fixed a bug that made the user defined paths not to be saved properly.
-Changed so that images with support for both PAL and NTSC will prioritize NTSC and not PAL as in
earlier versions when "auto mode" is selected.
-Added mapper 107 ("Magic Dragon")
-Added mapper 134 ("Olympiq IQ")
-Added mapper 135 ("Super Pang")
-Added mapper 198 (chinese version of "Destiny of an Emperor")
-Fixed a bug in the UNIF loader that caused all files having a board name beginning with
NES-,UNL-,HVC-,BTL- or BMC- to be parsed wrongly.
-Fixed a bug that caused the application to hang and/or crash when Alt-Tabbing.
-Removed most of the sound clicks and pops heard when the audio gets disabled (menu entering, window moving etc).
-Made so that all the save slots automatically gets imported/exported to/from files using .ns1
through ns9 on load/close. It's ON by default.
-Fixed a PPU bug that could cause the application to crash when loading up a game in the middle of an NSF tune.
-Fixed the frame rate timer. In previous versions it had the potential to cause serious lagging.
-Fixed the fullscreen mode cursor, sometimes it could get visible/invisible when it really shouldn't.
-Changed to using C++ exceptions, way better error handling now.
-Added the option to add custom keys to the "save to next slot" and "load from last slot" commands.
-Added 8bit graphic mode. filters are not supported for this one.
-Improved the TV-mode graphic filter and removed all visual artifacts in the marginals.
-Added an option in the preferences dialog to disable the use of the ROM database.
-Added more logfile info.
----------------------------------------------------------------
1.04
----------------------------------------------------------------
-Added a TV-mode graphic filter.
-Moved the timing options into a separate dialog and added some more features. Speed throttling can now be toggled by F5 (default).
-Did some further improvements to the sound quality.
-Fixed mapper 64, "Skull & Crossbones" and "Klax" are now playable, thanks to Xodnizel for his findings on this insane mapper.
-Fixed mapper 70, "Kamen Rider Kurabu" and "Space Shadow" are now playable.
-Fixed mapper 83, "Garou Densetsu 2 (Fatal Fury)" and "World Heroes 2" are now playable.
-Added mapper 133 ("Jovial Race")
-Fixed mapper 232, "Maxi 15" is now playable.
-Fixed mapper 244, now "Decathlon (Asia)" suffers from less glitches.
-Changed the configuration file, now it's text based and more hacker friendly.
-Changed the shortcut key for fullscreen/window mode switch to ALT+RETURN.
-In addition to the right mouse button ESCAPE now also toggles the menu in fullscreen mode.
-Fixed a bug that prevented new battery-ram files from being created.
-Cleaned up a few things in the DirectSound manager. Hopefully this fixes the sound problems a few people have had.
-Added many new file CRC's to the internal database. Thanks to [yang] for the assembling.
-Now Nestopia remembers the last selected screen/window size.
-Optimized the scanline graphic filter renderer.
-Added some more logfile output messages.
----------------------------------------------------------------
1.03
----------------------------------------------------------------
-Added 2xSaI, Super 2xSaI and Super Eagle graphic filters.
-Added support for all the graphic filters in window mode.
-Added game configuration file support.
-Improved sound quality.
-Added some more file CRC's to the zapper-auto-detector.
-Added an option to map all keys in one go.
-Added an option in the preferences dialog to force the application's thread to be in high priority mode.
-Corrected an entry in the pAPU's length counter LUT.
-Changed the square channel's default frequency limit. This fixes the sound in "Mega Man 2" and possibly a few other games.
-Fixed a bug that caused some save states not to load correctly.
-Lowered the output volume on the FDS sound chip.
-Fixed mapper 78, "Holy Diver" and "Uchuusen - Cosmo Carrier" are now playable.
-Fixed a frame IRQ counter bug, now "Akagawa no Yuurei Ressha" and "Dragon Warrior" among others work as they should.
-Fixed a bug which sometimes caused the user defined IPS path to be ignored.
-Rewrote a few parts in the movie player/recorder. Should be more stable now.
-Cleaned up a few thing in the GUI.
----------------------------------------------------------------
1.02
----------------------------------------------------------------
-Added UNIF support.
-Fixed a bug in the Game Genie decoder, now eight-character codes works correctly.
-Added support for more axis buttons (sliders, pov etc). Havn't tested them tough as I don't have that kind of
joystick, can anyone confirm they work?
-Fixed so that Nestopia will recognise the Twin Famicom BIOS ROM.
-Added adjustable dipswitches for "Nintendo World Championship" (mapper 105), now you can control and display the timer.
-Fixed mapper 91 (IRQ counter thing), now all mapper 91 games shows the correct graphic.
-Fixed mapper 187, now "Street Fighter Zero 2 '97" works.
-Fixed a bug in the Sunsoft FME-07 sound core.
-Did some cleanup in the application error handling routines - no more page-faults on known errors.
-No more distortion in screen when enabling/disabling the menu in fullscreen mode (LockWindowUpdate() to the rescue).
-Fixed a bug which sometimes caused the window, when coming out of fullscreen, to be maximized and stretched to the size of the desktop.
-Fixed a bug that caused the switching from window to fullscreen with the same display mode to fail.
-Fixed a bug in the PDXSTRING class, nothing that affected previous versions of Nestopia though.
-Lowered the system requirements to Pentium MMX, users with processors that lacks the CMOV instruction can now run Nestopia.
-Added some menu options to control the size of the window/screen (works both in window and fullscreen mode).
----------------------------------------------------------------
1.01
----------------------------------------------------------------
Fixed a bug that caused the application to exit with the "DirectSoundCreate8() failed" message.
----------------------------------------------------------------
1.00
----------------------------------------------------------------
Initial release.
nestopia-1.47/doc/ 0000775 0000000 0000000 00000000000 12644314416 0014041 5 ustar 00root root 0000000 0000000 nestopia-1.47/doc/details/ 0000775 0000000 0000000 00000000000 12644314416 0015466 5 ustar 00root root 0000000 0000000 nestopia-1.47/doc/details/api/ 0000775 0000000 0000000 00000000000 12644314416 0016237 5 ustar 00root root 0000000 0000000 nestopia-1.47/doc/details/api/Nes..Api..BarcodeReader.html 0000664 0000000 0000000 00000021607 12644314416 0023205 0 ustar 00root root 0000000 0000000
Nestopia Core API: Nes::Api::BarcodeReader
ReadRomset( std::istream& stream, Machine::FavoredSystem system, bool askProfile, Nes::Api::Cartridge::Profile& profile )
Creates a profile of an XML ROM set file.
public bool Is( uint flags1, uint flags2 ) const throw();
Returns a machine state.
Parameters:
flags1 - OR:ed flags to check
flags2 - OR:ed flags to check
Returns:
true if both parameters has at least one flag evaluated to true
Is
public uint Is( uint flags ) const throw();
Returns a machine state.
Parameters:
flags - OR:ed flags to check
Returns:
OR:ed flags evaluated to true
IsLocked
public bool IsLocked() const;
Tells if the machine is in a locked state.
A locked state means that the machine can't respond to
certain operations because it's doing something special,
like playing a movie or rewinding.
public virtual Result GetContent( const void*& mem, ulong& size ) const throw();
Returns a pointer to the content to be saved and its size.
Used only with the SAVE_xx action callbacks.
Parameters:
mem - pointer to content
size - size of content
result - code
GetContent
public virtual Result GetContent( std::ostream& stream ) const throw();
Saves the content into an output stream.
Used only with the SAVE_xx action callbacks.
Parameters:
stream - output stream
result - code
GetId
public virtual uint GetId() const throw();
Returns the sound file ID to load.
Used only with the LOAD_SAMPLE_xx action callbacks.
Returns:
sample id
GetMaxSize
public virtual ulong GetMaxSize() const throw();
Returns the maximum allowed size for the content to load.
Used only with the LOAD_xx action callbacks.
Returns:
max size
GetName
public virtual const wchar_t* GetName() const throw();
Returns the name of the file to load.
Used only with the LOAD_ROM and LOAD_SAMPLE action callbacks.
Returns:
filename
GetPatchContent
public virtual Result GetPatchContent( Nes::Api::User::File::Patch patch, std::ostream& stream ) const throw();
Saves the patch content into an output stream.
Used only with the FDS_SAVE action callback.
Parameters:
patch - patch format to use
stream - output stream
SetContent
public virtual Result SetContent( const void* mem, ulong size ) throw();
Loads content into the core.
Used only with the LOAD_xx action callbacks.
This method can't be used for audio or patch content. Instead, use LoadSampleContent(..)
and SetPatchContent(..) for those.
Parameters:
mem - content
size - size of content
Returns:
result code
SetContent
public virtual Result SetContent( std::istream& stream ) throw();
Loads content into the core through stream.
Used only with the LOAD_xx action callbacks.
This method can't be used for audio or patch content. Instead, use LoadSampleContent(..)
and SetPatchContent(..) for those.
Parameters:
stream - input stream
Returns:
result code
SetPatchContent
public virtual Result SetPatchContent( std::istream& stream ) throw();
Loads patch content into the core.
Used only with LOAD_FDS action callback.
Parameters:
stream - input stream to patch
Returns:
result code
SetSampleContent
public virtual Result SetSampleContent( const void* mem, ulong length, bool stereo, uint bits, ulong rate ) throw();
Loads audio content into the core.
Used only with the LOAD_SAMPLE and LOAD_SAMPLE_xx action callbacks.
api
Typedef Nes::Core::Sound::Output::LockCallback
Sound lock callback prototype.
Called right before the core is about to render sound for one frame. Non-written
samples will be saved for the next frame.
Parameters:
userData - optional user data
output - object to this class
Returns:
true if output memory is valid and samples can be written to it
Length in number of samples for one frame.
Assign 0 to length[1] if circular buffers aren't needed.
Length doesn't neccesarily need to be the same value for every frame as long
as they eventually add up in relation to the emulation speed. The requested
number of samples will always be written even if the length is greater
than what the sound engine normally produces. Non-written samples for one frame will
be carried over to the next through an internal buffer.
This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
Link to Non-frame version.
nestopia-1.47/libretro/ 0000775 0000000 0000000 00000000000 12644314416 0015116 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/Makefile 0000664 0000000 0000000 00000016443 12644314416 0016566 0 ustar 00root root 0000000 0000000 DEBUG = 0
HAS_GCC = 1
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
platform = osx
else ifneq ($(findstring win,$(shell uname -a)),)
platform = win
endif
endif
# system platform
system_platform = unix
ifeq ($(shell uname -a),)
EXE_EXT = .exe
system_platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
system_platform = osx
else ifneq ($(findstring MINGW,$(shell uname -a)),)
system_platform = win
endif
LIBRETRO_DIR := libretro
TARGET_NAME := nestopia
# Unix
ifeq ($(platform), unix)
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,-version-script=link.T -Wl,-no-undefined
# OS X
else ifeq ($(platform), osx)
TARGET := $(TARGET_NAME)_libretro.dylib
fpic := -fPIC
SHARED := -dynamiclib
OSXVER = `sw_vers -productVersion | cut -d. -f 2`
OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
ifndef ($(NOUNIVERSAL))
CFLAGS += $(ARCHFLAGS)
CXXFLAGS += $(ARCHFLAGS)
LDFLAGS += $(ARCHFLAGS)
endif
# iOS
else ifneq (,$(findstring ios,$(platform)))
TARGET := $(TARGET_NAME)_libretro_ios.dylib
fpic := -fPIC
SHARED := -dynamiclib
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
endif
CC = cc -arch armv7 -isysroot $(IOSSDK)
CXX = c++ -arch armv7 -isysroot $(IOSSDK)
ifeq ($(platform),ios9)
CC += -miphoneos-version-min=8.0
CXX += -miphoneos-version-min=8.0
PLATFORM_DEFINES += -miphoneos-version-min=8.0
else
CC += -miphoneos-version-min=5.0
CXX += -miphoneos-version-min=5.0
PLATFORM_DEFINES += -miphoneos-version-min=5.0
endif
# Theos
else ifeq ($(platform), theos_ios)
HAS_GCC := 0
DEPLOYMENT_IOSVERSION = 5.0
TARGET = iphone:latest:$(DEPLOYMENT_IOSVERSION)
ARCHS = armv7 armv7s
TARGET_IPHONEOS_DEPLOYMENT_VERSION=$(DEPLOYMENT_IOSVERSION)
THEOS_BUILD_DIR := objs
include $(THEOS)/makefiles/common.mk
LIBRARY_NAME = $(TARGET_NAME)_libretro_ios
# QNX
else ifeq ($(platform), qnx)
TARGET := $(TARGET_NAME)_libretro_qnx.so
fpic := -fPIC
SHARED := -lcpp -lm -shared -Wl,-version-script=link.T -Wl,-no-undefined
HAS_GCC := 0
CC = qcc -Vgcc_ntoarmv7le
CXX = QCC -Vgcc_ntoarmv7le_cpp
AR = QCC -Vgcc_ntoarmv7le
PLATFORM_DEFINES := -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
# PS3
else ifeq ($(platform), ps3)
HAVE_GCC_WARNINGS := 0
TARGET := $(TARGET_NAME)_libretro_ps3.a
CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe
CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
PLATFORM_DEFINES := -D__CELLOS_LV2__
STATIC_LINKING = 1
# sncps3
else ifeq ($(platform), sncps3)
HAVE_GCC_WARNINGS := 0
TARGET := $(TARGET_NAME)_libretro_ps3.a
HAS_GCC := 0
CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
PLATFORM_DEFINES := -D__CELLOS_LV2__
STATIC_LINKING = 1
# PSP
else ifeq ($(platform), psp1)
TARGET := $(TARGET_NAME)_libretro_psp1.a
CC = psp-gcc$(EXE_EXT)
CXX = psp-g++$(EXE_EXT)
AR = psp-ar$(EXE_EXT)
PLATFORM_DEFINES := -DPSP -G0
STATIC_LINKING = 1
# Vita
else ifeq ($(platform), vita)
TARGET := $(TARGET_NAME)_libretro_vita.a
CC = arm-vita-eabi-gcc$(EXE_EXT)
AR = arm-vita-eabi-ar$(EXE_EXT)
PLATFORM_DEFINES := -DVITA
STATIC_LINKING = 1
# CTR(3DS)
else ifeq ($(platform), ctr)
TARGET := $(TARGET_NAME)_libretro_ctr.a
CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT)
AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT)
PLATFORM_DEFINES := -DARM11 -D_3DS
PLATFORM_DEFINES += -march=armv6k -mtune=mpcore -mfloat-abi=hard
PLATFORM_DEFINES += -mword-relocations
PLATFORM_DEFINES += -fomit-frame-pointer -fstrict-aliasing -ffast-math
CXXFLAGS += -fno-rtti
STATIC_LINKING = 1
# Lightweight PS3 Homebrew SDK
else ifeq ($(platform), psl1ght)
TARGET := $(TARGET_NAME)_libretro_psl1ght.a
CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT)
AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
PLATFORM_DEFINES := -D__CELLOS_LV2__
STATIC_LINKING = 1
# Xbox 360
else ifeq ($(platform), xenon)
TARGET := $(TARGET_NAME)_libretro_xenon360.a
CC = xenon-gcc$(EXE_EXT)
CXX = xenon-g++$(EXE_EXT)
AR = xenon-ar$(EXE_EXT)
PLATFORM_DEFINES := -D__LIBXENON__
STATIC_LINKING = 1
# Nintendo Game Cube
else ifeq ($(platform), ngc)
TARGET := $(TARGET_NAME)_libretro_ngc.a
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
PLATFORM_DEFINES += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float
STATIC_LINKING = 1
# Nintendo Wii
else ifeq ($(platform), wii)
TARGET := $(TARGET_NAME)_libretro_wii.a
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
PLATFORM_DEFINES += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float
STATIC_LINKING = 1
# ARM
else ifneq (,$(findstring armv,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,-version-script=link.T -Wl,-no-undefined
ifneq (,$(findstring cortexa5,$(platform)))
PLATFORM_DEFINES += -marm -mcpu=cortex-a5
else ifneq (,$(findstring cortexa8,$(platform)))
PLATFORM_DEFINES += -marm -mcpu=cortex-a8
else ifneq (,$(findstring cortexa9,$(platform)))
PLATFORM_DEFINES += -marm -mcpu=cortex-a9
else ifneq (,$(findstring cortexa15a7,$(platform)))
PLATFORM_DEFINES += -marm -mcpu=cortex-a15.cortex-a7
else
PLATFORM_DEFINES += -marm
endif
ifneq (,$(findstring softfloat,$(platform)))
PLATFORM_DEFINES += -mfloat-abi=softfp
else ifneq (,$(findstring hardfloat,$(platform)))
PLATFORM_DEFINES += -mfloat-abi=hard
endif
PLATFORM_DEFINES += -DARM
else ifeq ($(platform),emscripten)
TARGET := $(TARGET_NAME)_libretro.bc
# Windows
else
TARGET := $(TARGET_NAME)_libretro.dll
CC = gcc
CXX = g++
SHARED := -shared -static-libgcc -static-libstdc++ -Wl,-no-undefined -Wl,-version-script=link.T
endif
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -g
CXXFLAGS += -O0 -g
else ifeq ($(platform), ps3)
CFLAGS += -O2
CXXFLAGS += -O2
else
CFLAGS += -O3
CXXFLAGS += -O3
endif
CORE_DIR = ..
include Makefile.common
OBJS := $(SOURCES_CXX:.cpp=.o)
ifeq ($(HAS_GCC), 1)
GCC_FLAGS := -Wno-deprecated -Wno-write-strings
C_VER = -std=gnu99
else
endif
DEFINES := -D__LIBRETRO__ $(PLATFORM_DEFINES) $(GCC_FLAGS) $(GCC_WARNINGS) -DNST_NO_ZLIB $(INCFLAGS)
CFLAGS += $(fpic) $(DEFINES) $(C_VER)
CXXFLAGS += $(fpic) $(DEFINES) -fno-rtti
INCDIRS := -I$(CORE_DIR) -I$(CORE_DIR)/source
ifeq ($(platform), theos_ios)
COMMON_FLAGS := -DIOS $(DEFINES) $(INCFLAGS) $(INCDIRS) -I$(THEOS_INCLUDE_PATH) -Wno-error
$(LIBRARY_NAME)_CFLAGS += $(CFLAGS) $(COMMON_FLAGS)
$(LIBRARY_NAME)_CXXFLAGS += $(CXXFLAGS) $(COMMON_FLAGS)
${LIBRARY_NAME}_FILES = $(SOURCES_CXX) $(SOURCES_C)
include $(THEOS_MAKE_PATH)/library.mk
else
all: $(TARGET)
$(TARGET): $(OBJS)
ifeq ($(STATIC_LINKING), 1)
$(AR) rcs $@ $(OBJS)
else
$(CXX) -o $@ $(SHARED) $(OBJS) $(LDFLAGS) $(LIBS)
endif
%.o: %.cpp
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS)
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS)
clean-objs:
rm -f $(OBJS)
clean:
rm -f $(OBJS)
rm -f $(TARGET)
.PHONY: clean clean-objs
endif
nestopia-1.47/libretro/Makefile.common 0000664 0000000 0000000 00000044254 12644314416 0020056 0 ustar 00root root 0000000 0000000 INCFLAGS := -I$(CORE_DIR)/libretro -I$(CORE_DIR)
# Core
SOURCES_CXX += $(CORE_DIR)/source/core/NstApu.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstAssert.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCartridge.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCartridgeInes.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCartridgeRomset.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCartridgeUnif.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCheats.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstChecksum.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstChips.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCore.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCpu.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstCrc32.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstFds.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstFile.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstImage.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstImageDatabase.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstLog.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstMachine.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstMemory.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstNsf.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstPatcher.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstPatcherIps.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstPatcherUps.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstPins.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstPpu.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstProperties.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstRam.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstSha1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstSoundPcm.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstSoundPlayer.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstSoundRenderer.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstState.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstStream.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstTracker.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstTrackerMovie.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstTrackerRewinder.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVector.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVideoFilterNone.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVideoFilterNtsc.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVideoFilterNtscCfg.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVideoRenderer.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstVideoScreen.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstXml.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/NstZlib.cpp
# API
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiBarcodeReader.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiCartridge.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiCheats.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiDipSwitches.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiEmulator.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiFds.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiInput.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiMachine.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiMovie.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiNsf.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiRewinder.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiSound.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiTapeRecorder.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiUser.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/api/NstApiVideo.cpp
# Board
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAcclaimMcAcc.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAe.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAgci.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAveD1012.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAveNina.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardAxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandai24c0x.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiAerobicsStudio.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiDatach.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiKaraokeStudio.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiLz93d50.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiLz93d50ex.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBandaiOekaKids.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBenshengBs5.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc110in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc1200in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc150in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc15in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc20in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc21in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc22Games.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc31in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc35in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc36in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc64in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc72in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc76in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc800in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc8157.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmc9999999in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcA65as.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcBallgames11in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcCh001.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcCtc65.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcFamily4646B.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcFk23c.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcGamestarA.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcGamestarB.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcGolden190in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcGoldenCard6in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcGoldenGame260in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcHero.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcMarioParty7in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcNovelDiamond.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcPowerjoy84in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcResetBased4in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuper22Games.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuper24in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuper40in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuper700in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuperBig7in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuperGun20in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuperHiK300in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuperHiK4in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcSuperVision16in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcT262.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcVrc4.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcVt5201.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBmcY2k64in1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtl2708.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtl6035052.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlAx5705.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlDragonNinja.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlGeniusMerioBros.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlMarioBaby.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlPikachuY2k.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlShuiGuanPipe.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlSmb2a.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlSmb2b.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlSmb2c.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlSmb3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlSuperBros11.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlT230.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBtlTobidaseDaisakusen.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardBxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCaltron.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCamerica.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCneDecathlon.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCnePsb.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCneShlz.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCony.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoard.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardCxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardDiscrete.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardDreamtech.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardEvent.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardFb.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardFfe.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardFujiya.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardFukutake.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardFutureMedia.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardGouder.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardGxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardHenggedianzi.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardHes.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardHosenkan.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardIremG101.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardIremH3001.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardIremHolyDiver.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardIremKaiketsu.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardIremLrog017.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoJf11.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoJf13.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoJf16.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoJf17.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoJf19.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJalecoSs88006.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardJyCompany.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKaiser.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKasing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKayH2288.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKayPandaPrince.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc4.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc6.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVrc7.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardKonamiVsSystem.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMagicSeries.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc4.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc5.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc6.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot163.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot175.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot34xx.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNanjing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNihon.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNitra.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNtdec.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardOpenCorp.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardQj.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardRcm.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardRexSoftDb5z.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardRexSoftSl1632.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardRumbleStation.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachen74x374.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenS8259.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenSa0036.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenSa0037.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenSa72007.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenSa72008.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenStreetHeroes.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenTca01.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSachenTcu.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSomeriTeamSl12.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSubor.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoft1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoft2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoft3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoft4.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoft5b.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoftDcs.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSunsoftFme7.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSuperGameBoogerman.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSuperGameLionKing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardSuperGamePocahontas2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTaitoTc0190fmc.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTaitoTc0190fmcPal16r4.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTaitoX1005.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTaitoX1017.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTengen.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTengenRambo1.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxc.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcMxmdhtwo.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcPoliceman.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcTw.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlA9746.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlCc21.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlEdu2000.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters96.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters97.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlMortalKombat2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlN625092.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlSuperFighter3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlTf1201.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlWorldHero.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlXzy.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardVsSystem.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingFfv.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingPs2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingSecurity.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingSgz.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingSgzlz.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingSh2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWaixingZs.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardWhirlwind.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardZz.cpp
# Input
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpAdapter.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpBandaiHyperShot.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpBarcodeWorld.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpCrazyClimber.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpDoremikkoKeyboard.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpExcitingBoxing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpFamilyKeyboard.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpFamilyTrainer.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpHoriTrack.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpKonamiHyperShot.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpMahjong.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpMouse.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpOekaKidsTablet.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPachinko.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPad.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPaddle.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPartyTap.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPokkunMoguraa.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPowerGlove.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpPowerPad.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpRob.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpSuborKeyboard.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpTopRider.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpTurboFile.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/input/NstInpZapper.cpp
# VS System
SOURCES_CXX += $(CORE_DIR)/source/core/vssystem/NstVsRbiBaseball.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/vssystem/NstVsSuperXevious.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/vssystem/NstVsSystem.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/vssystem/NstVsTkoBoxing.cpp
# libretro
SOURCES_CXX += $(CORE_DIR)/libretro/libretro.cpp
nestopia-1.47/libretro/control 0000664 0000000 0000000 00000000330 12644314416 0016515 0 ustar 00root root 0000000 0000000 Package: com.libretro.nestopia
Name: nestopia
Depends:
Version: 0.0.1
Architecture: iphoneos-arm
Description: Libretro iOS core of Nestopia
Maintainer: libretro
Author: libretro
Section: System
Tag: role::developer
nestopia-1.47/libretro/jni/ 0000775 0000000 0000000 00000000000 12644314416 0015676 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/jni/Android.mk 0000664 0000000 0000000 00000001132 12644314416 0017604 0 ustar 00root root 0000000 0000000 LOCAL_SHORT_COMMANDS := true
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libretro
ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -DANDROID_ARM
LOCAL_ARM_MODE := arm
endif
ifeq ($(TARGET_ARCH),x86)
LOCAL_CFLAGS += -DANDROID_X86
endif
ifeq ($(TARGET_ARCH),mips)
LOCAL_CFLAGS += -DANDROID_MIPS
endif
CORE_DIR = ../..
include $(CORE_DIR)/libretro/Makefile.common
LOCAL_SRC_FILES += $(SOURCES_CXX) $(SOURCES_C)
LOCAL_CXXFLAGS += -DANDROID -D__LIBRETRO__ -DINLINE=inline -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DNST_NO_ZLIB -fexceptions $(INCFLAGS)
include $(BUILD_SHARED_LIBRARY)
nestopia-1.47/libretro/jni/Application.mk 0000664 0000000 0000000 00000000051 12644314416 0020466 0 ustar 00root root 0000000 0000000 APP_STL := gnustl_static
APP_ABI := all
nestopia-1.47/libretro/libretro.cpp 0000664 0000000 0000000 00000072026 12644314416 0017453 0 ustar 00root root 0000000 0000000 #include "libretro.h"
#include
#include
#include
#include
#include
#include
#include
#include "../source/core/api/NstApiMachine.hpp"
#include "../source/core/api/NstApiEmulator.hpp"
#include "../source/core/api/NstApiVideo.hpp"
#include "../source/core/api/NstApiCheats.hpp"
#include "../source/core/api/NstApiSound.hpp"
#include "../source/core/api/NstApiInput.hpp"
#include "../source/core/api/NstApiCartridge.hpp"
#include "../source/core/api/NstApiUser.hpp"
#include "../source/core/api/NstApiFds.hpp"
#define NST_VERSION "1.48-WIP"
#ifdef _WIN32
#define snprintf _snprintf
#endif
using namespace Nes;
static retro_log_printf_t log_cb;
static retro_video_refresh_t video_cb;
static retro_audio_sample_t audio_cb;
static retro_audio_sample_batch_t audio_batch_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
#ifdef _3DS
extern "C" void* linearMemAlign(size_t size, size_t alignment);
extern "C" void linearFree(void* mem);
static uint32_t* video_buffer = NULL;
#else
static uint32_t video_buffer[Api::Video::Output::NTSC_WIDTH * Api::Video::Output::HEIGHT];
#endif
static int16_t audio_buffer[(44100 / 50)];
static int16_t audio_stereo_buffer[2 * (44100 / 50)];
static Api::Emulator emulator;
static Api::Machine *machine;
static Api::Fds *fds;
static char g_basename[256];
static char g_rom_dir[256];
static char *g_save_dir;
static unsigned blargg_ntsc;
static bool fds_auto_insert;
static bool overscan_v;
static bool overscan_h;
int16_t video_width = Api::Video::Output::WIDTH;
size_t pitch;
static Api::Video::Output *video;
static Api::Sound::Output *audio;
static Api::Input::Controllers *input;
static Api::Machine::FavoredSystem favsystem;
static void *sram;
static unsigned long sram_size;
static bool is_pal;
static bool dbpresent;
int crossx = 0;
int crossy = 0;
void draw_crosshair(int x, int y)
{
uint32_t w = 0xFFFFFFFF;
uint32_t b = 0x00000000;
for(int i = -3; i < 4; i++) {
video_buffer[256 * y + x + i] = b;
video_buffer[256 * (y + i) + x] = b;
}
for(int i = -2; i < 3; i += 2) {
video_buffer[256 * y + x + i] = w;
video_buffer[256 * (y + i) + x] = w;
}
}
static void NST_CALLBACK file_io_callback(void*, Api::User::File &file)
{
const void *addr;
unsigned long addr_size;
char slash;
#ifdef _WIN32
slash = '\\';
#else
slash = '/';
#endif
switch (file.GetAction())
{
case Api::User::File::LOAD_BATTERY:
case Api::User::File::LOAD_EEPROM:
case Api::User::File::LOAD_TAPE:
case Api::User::File::LOAD_TURBOFILE:
file.GetRawStorage(sram, sram_size);
break;
case Api::User::File::SAVE_BATTERY:
case Api::User::File::SAVE_EEPROM:
case Api::User::File::SAVE_TAPE:
case Api::User::File::SAVE_TURBOFILE:
file.GetContent(addr, addr_size);
if (addr != sram || sram_size != addr_size)
if (log_cb)
log_cb(RETRO_LOG_INFO, "[Nestopia]: SRAM changed place in RAM!\n");
break;
case Api::User::File::LOAD_FDS:
{
char base[256];
snprintf(base, sizeof(base), "%s%c%s.sav", g_save_dir, slash, g_basename);
if (log_cb)
log_cb(RETRO_LOG_INFO, "Want to load FDS sav from: %s\n", base);
std::ifstream in_tmp(base,std::ifstream::in|std::ifstream::binary);
if (!in_tmp.is_open())
return;
file.SetPatchContent(in_tmp);
}
break;
case Api::User::File::SAVE_FDS:
{
char base[256];
snprintf(base, sizeof(base), "%s%c%s.sav", g_save_dir, slash, g_basename);
if (log_cb)
log_cb(RETRO_LOG_INFO, "Want to save FDS sav to: %s\n", base);
std::ofstream out_tmp(base,std::ifstream::out|std::ifstream::binary);
if (out_tmp.is_open())
file.GetPatchContent(Api::User::File::PATCH_UPS, out_tmp);
}
break;
default:
break;
}
}
static void check_system_specs(void)
{
unsigned level = 6;
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
}
void retro_init(void)
{
struct retro_log_callback log;
#ifdef _3DS
video_buffer = (uint32_t*)linearMemAlign(Api::Video::Output::NTSC_WIDTH * Api::Video::Output::HEIGHT * sizeof(uint32_t), 0x80);
#endif
machine = new Api::Machine(emulator);
input = new Api::Input::Controllers;
Api::User::fileIoCallback.Set(file_io_callback, 0);
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
else
log_cb = NULL;
check_system_specs();
}
void retro_deinit(void)
{
if (machine->Is(Nes::Api::Machine::DISK))
{
if (fds)
delete fds;
fds = 0;
}
delete machine;
delete video;
delete audio;
delete input;
machine = 0;
video = 0;
audio = 0;
input = 0;
#ifdef _3DS
linearFree(video_buffer);
video_buffer = NULL;
#endif
}
unsigned retro_api_version(void)
{
return RETRO_API_VERSION;
}
void retro_set_controller_port_device(unsigned, unsigned)
{
}
void retro_get_system_info(struct retro_system_info *info)
{
memset(info, 0, sizeof(*info));
info->library_name = "Nestopia";
info->library_version = "v" NST_VERSION;
info->need_fullpath = false;
info->valid_extensions = "nes|fds";
}
void retro_get_system_av_info(struct retro_system_av_info *info)
{
const retro_system_timing timing = { is_pal ? 50.0 : 60.0, 44100.0 };
info->timing = timing;
// It's better if the size is based on NTSC_WIDTH if the filter is on
const retro_game_geometry geom = {
Api::Video::Output::WIDTH - (overscan_h ? 16 : 0),
Api::Video::Output::HEIGHT - (overscan_v ? 16 : 0),
Api::Video::Output::NTSC_WIDTH,
Api::Video::Output::HEIGHT,
4.0 / 3.0,
};
info->geometry = geom;
}
void retro_set_environment(retro_environment_t cb)
{
environ_cb = cb;
static const struct retro_variable vars[] = {
{ "nestopia_blargg_ntsc_filter", "Blargg NTSC filter; disabled|composite|svideo|rgb" },
{ "nestopia_palette", "Palette; consumer|canonical|alternative|rgb|raw" },
{ "nestopia_nospritelimit", "Remove 8-sprites-per-scanline hardware limit; disabled|enabled" },
{ "nestopia_fds_auto_insert", "Automatically insert first FDS disk on reset; enabled|disabled" },
{ "nestopia_overscan_v", "Mask Overscan (Vertical); enabled|disabled" },
{ "nestopia_overscan_h", "Mask Overscan (Horizontal); disabled|enabled" },
{ "nestopia_genie_distortion", "Game Genie Sound Distortion; disabled|enabled" },
{ "nestopia_favored_system", "Favored System; auto|ntsc|pal|famicom|dendy" },
{ NULL, NULL },
};
cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
}
void retro_set_audio_sample(retro_audio_sample_t cb)
{
audio_cb = cb;
}
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
audio_batch_cb = cb;
}
void retro_set_input_poll(retro_input_poll_t cb)
{
input_poll_cb = cb;
}
void retro_set_input_state(retro_input_state_t cb)
{
input_state_cb = cb;
}
void retro_set_video_refresh(retro_video_refresh_t cb)
{
video_cb = cb;
}
void retro_reset(void)
{
machine->Reset(false);
if (machine->Is(Nes::Api::Machine::DISK))
{
fds->EjectDisk();
if (fds_auto_insert)
fds->InsertDisk(0, 0);
}
}
typedef struct
{
unsigned retro;
unsigned nes;
} keymap;
static const keymap bindmap[] = {
{ RETRO_DEVICE_ID_JOYPAD_A, Core::Input::Controllers::Pad::A },
{ RETRO_DEVICE_ID_JOYPAD_B, Core::Input::Controllers::Pad::B },
{ RETRO_DEVICE_ID_JOYPAD_SELECT, Core::Input::Controllers::Pad::SELECT },
{ RETRO_DEVICE_ID_JOYPAD_START, Core::Input::Controllers::Pad::START },
{ RETRO_DEVICE_ID_JOYPAD_UP, Core::Input::Controllers::Pad::UP },
{ RETRO_DEVICE_ID_JOYPAD_DOWN, Core::Input::Controllers::Pad::DOWN },
{ RETRO_DEVICE_ID_JOYPAD_LEFT, Core::Input::Controllers::Pad::LEFT },
{ RETRO_DEVICE_ID_JOYPAD_RIGHT, Core::Input::Controllers::Pad::RIGHT },
};
static void update_input()
{
input_poll_cb();
input->pad[0].buttons = 0;
input->pad[1].buttons = 0;
input->pad[2].buttons = 0;
input->pad[3].buttons = 0;
input->zapper.fire = 0;
input->vsSystem.insertCoin = 0;
if (Api::Input(emulator).GetConnectedController(1) == 5) {
static int zapx = overscan_h ? 8 : 0;
static int zapy = overscan_v ? 8 : 0;
zapx += input_state_cb(1, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_X);
zapy += input_state_cb(1, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_Y);
if (zapx >= 256) { crossx = 255; }
else if (zapx <= 0) { crossx = 0; }
else {crossx = zapx; }
if (zapy >= 240) { crossy = 239; }
else if (zapy <= 0) { crossy = 0; }
else {crossy = zapy; }
if (input_state_cb(1, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER)) {
input->zapper.x = zapx;
input->zapper.y = zapy;
input->zapper.fire = 1;
}
if (input_state_cb(1, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TURBO)) {
input->zapper.x = ~1U;
input->zapper.fire = 1;
}
}
for (unsigned p = 0; p < 4; p++)
for (unsigned bind = 0; bind < sizeof(bindmap) / sizeof(bindmap[0]); bind++)
input->pad[p].buttons |= input_state_cb(p, RETRO_DEVICE_JOYPAD, 0, bindmap[bind].retro) ? bindmap[bind].nes : 0;
if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X))
input->vsSystem.insertCoin |= Core::Input::Controllers::VsSystem::COIN_1;
if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y))
input->vsSystem.insertCoin |= Core::Input::Controllers::VsSystem::COIN_2;
if (machine->Is(Nes::Api::Machine::DISK))
{
bool curL = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L);
static bool prevL = false;
if (curL && !prevL)
{
if (!fds->IsAnyDiskInserted())
fds->InsertDisk(0, 0);
else if (fds->CanChangeDiskSide())
fds->ChangeSide();
}
prevL = curL;
bool curR = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R);
static bool prevR = false;
if (curR && !prevR && (fds->GetNumDisks() > 1))
{
int currdisk = fds->GetCurrentDisk();
fds->EjectDisk();
fds->InsertDisk(!currdisk, 0);
}
prevR = curR;
}
}
static void check_variables(void)
{
static bool last_ntsc_val_same;
struct retro_variable var = {0};
Api::Sound sound(emulator);
Api::Video video(emulator);
Api::Video::RenderState renderState;
Api::Machine machine(emulator);
Api::Video::RenderState::Filter filter;
var.key = "nestopia_favored_system";
is_pal = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "auto") == 0)
{
if (dbpresent)
{
machine.SetMode(machine.GetDesiredMode());
if (machine.GetMode() == Api::Machine::PAL)
{
is_pal = true;
favsystem = Api::Machine::FAVORED_NES_PAL;
machine.SetMode(Api::Machine::PAL);
}
else
{
favsystem = Api::Machine::FAVORED_NES_NTSC;
machine.SetMode(Api::Machine::NTSC);
}
}
}
else if (strcmp(var.value, "ntsc") == 0)
{
favsystem = Api::Machine::FAVORED_NES_NTSC;
machine.SetMode(Api::Machine::NTSC);
}
else if (strcmp(var.value, "pal") == 0)
{
favsystem = Api::Machine::FAVORED_NES_PAL;
machine.SetMode(Api::Machine::PAL);
is_pal = true;
}
else if (strcmp(var.value, "famicom") == 0)
{
favsystem = Api::Machine::FAVORED_FAMICOM;
machine.SetMode(Api::Machine::NTSC);
}
else if (strcmp(var.value, "dendy") == 0)
{
favsystem = Api::Machine::FAVORED_DENDY;
machine.SetMode(Api::Machine::PAL);
}
else
{
favsystem = Api::Machine::FAVORED_NES_NTSC;
machine.SetMode(Api::Machine::NTSC);
}
}
if (audio) delete audio;
audio = new Api::Sound::Output(audio_buffer, is_pal ? 44100 / 50 : 44100 / 60);
var.key = "nestopia_genie_distortion";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "disabled") == 0)
sound.SetGenie(0);
else if (strcmp(var.value, "enabled") == 0)
sound.SetGenie(1);
}
var.key = "nestopia_nospritelimit";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "disabled") == 0)
video.EnableUnlimSprites(false);
else if (strcmp(var.value, "enabled") == 0)
video.EnableUnlimSprites(true);
}
var.key = "nestopia_fds_auto_insert";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
fds_auto_insert = (strcmp(var.value, "enabled") == 0);
var.key = "nestopia_blargg_ntsc_filter";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "disabled") == 0)
blargg_ntsc = 0;
else if (strcmp(var.value, "composite") == 0)
blargg_ntsc = 2;
else if (strcmp(var.value, "svideo") == 0)
blargg_ntsc = 3;
else if (strcmp(var.value, "rgb") == 0)
blargg_ntsc = 4;
}
switch(blargg_ntsc)
{
case 0:
filter = Api::Video::RenderState::FILTER_NONE;
video_width = Api::Video::Output::WIDTH;
break;
case 1:
filter = Api::Video::RenderState::FILTER_NTSC;
video_width = Api::Video::Output::NTSC_WIDTH;
break;
case 2:
filter = Api::Video::RenderState::FILTER_NTSC;
video.SetSharpness(Api::Video::DEFAULT_SHARPNESS_COMP);
video.SetColorResolution(Api::Video::DEFAULT_COLOR_RESOLUTION_COMP);
video.SetColorBleed(Api::Video::DEFAULT_COLOR_BLEED_COMP);
video.SetColorArtifacts(Api::Video::DEFAULT_COLOR_ARTIFACTS_COMP);
video.SetColorFringing(Api::Video::DEFAULT_COLOR_FRINGING_COMP);
video_width = Api::Video::Output::NTSC_WIDTH;
break;
case 3:
filter = Api::Video::RenderState::FILTER_NTSC;
video.SetSharpness(Api::Video::DEFAULT_SHARPNESS_SVIDEO);
video.SetColorResolution(Api::Video::DEFAULT_COLOR_RESOLUTION_SVIDEO);
video.SetColorBleed(Api::Video::DEFAULT_COLOR_BLEED_SVIDEO);
video.SetColorArtifacts(Api::Video::DEFAULT_COLOR_ARTIFACTS_SVIDEO);
video.SetColorFringing(Api::Video::DEFAULT_COLOR_FRINGING_SVIDEO);
video_width = Api::Video::Output::NTSC_WIDTH;
break;
case 4:
filter = Api::Video::RenderState::FILTER_NTSC;
video.SetSharpness(Api::Video::DEFAULT_SHARPNESS_RGB);
video.SetColorResolution(Api::Video::DEFAULT_COLOR_RESOLUTION_RGB);
video.SetColorBleed(Api::Video::DEFAULT_COLOR_BLEED_RGB);
video.SetColorArtifacts(Api::Video::DEFAULT_COLOR_ARTIFACTS_RGB);
video.SetColorFringing(Api::Video::DEFAULT_COLOR_FRINGING_RGB);
video_width = Api::Video::Output::NTSC_WIDTH;
break;
}
var.key = "nestopia_palette";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
if (strcmp(var.value, "consumer") == 0) {
video.GetPalette().SetMode(Api::Video::Palette::MODE_YUV);
video.SetDecoder(Api::Video::DECODER_CONSUMER);
}
else if (strcmp(var.value, "canonical") == 0) {
video.GetPalette().SetMode(Api::Video::Palette::MODE_YUV);
video.SetDecoder(Api::Video::DECODER_CANONICAL);
}
else if (strcmp(var.value, "alternative") == 0) {
video.GetPalette().SetMode(Api::Video::Palette::MODE_YUV);
video.SetDecoder(Api::Video::DECODER_ALTERNATIVE);
}
else if (strcmp(var.value, "rgb") == 0) {
video.GetPalette().SetMode(Api::Video::Palette::MODE_RGB);
}
else if (strcmp(var.value, "raw") == 0) {
/* outputs raw chroma/level/emphasis in the R/G/B channels
* that can be decoded by the frontend (using shaders for example)
* the following formulas can be used to extract the
* values back from a normalized R/G/B triplet
* chroma = floor((R * 15.0) + 0.5)
* level = floor((G * 3.0) + 0.5)
* emphasis = floor((B * 7.0) + 0.5) */
unsigned char raw_palette[512][3];
int i;
for (i = 0; i < 512; i++)
{
raw_palette[i][0] = (((i >> 0) & 0xF) * 255) / 15;
raw_palette[i][1] = (((i >> 4) & 0x3) * 255) / 3;
raw_palette[i][2] = (((i >> 6) & 0x7) * 255) / 7;
}
video.GetPalette().SetMode(Api::Video::Palette::MODE_CUSTOM);
video.GetPalette().SetCustom(raw_palette, Api::Video::Palette::EXT_PALETTE);
}
}
var.key = "nestopia_overscan_v";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
overscan_v = (strcmp(var.value, "enabled") == 0);
var.key = "nestopia_overscan_h";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
overscan_h = (strcmp(var.value, "enabled") == 0);
pitch = video_width * 4;
renderState.filter = filter;
renderState.width = video_width;
renderState.height = Api::Video::Output::HEIGHT;
renderState.bits.count = 32;
renderState.bits.mask.r = 0x00ff0000;
renderState.bits.mask.g = 0x0000ff00;
renderState.bits.mask.b = 0x000000ff;
if (NES_FAILED(video.SetRenderState( renderState )) && log_cb)
log_cb(RETRO_LOG_INFO, "Nestopia core rejected render state\n");;
retro_reset();
}
void retro_run(void)
{
update_input();
emulator.Execute(video, audio, input);
if (Api::Input(emulator).GetConnectedController(1) == 5)
draw_crosshair(crossx, crossy);
unsigned frames = is_pal ? 44100 / 50 : 44100 / 60;
for (unsigned i = 0; i < frames; i++)
audio_stereo_buffer[(i << 1) + 0] = audio_stereo_buffer[(i << 1) + 1] = audio_buffer[i];
audio_batch_cb(audio_stereo_buffer, frames);
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
{
check_variables();
delete video;
video = 0;
video = new Api::Video::Output(video_buffer, video_width * sizeof(uint32_t));
}
// Absolute mess of inline if statements...
video_cb(video_buffer + (overscan_v ? ((overscan_h ? 8 : 0) + (blargg_ntsc ? Api::Video::Output::NTSC_WIDTH : Api::Video::Output::WIDTH) * 8) : (overscan_h ? 8 : 0) + 0),
video_width - (overscan_h ? 16 : 0),
Api::Video::Output::HEIGHT - (overscan_v ? 16 : 0),
pitch);
}
static void extract_basename(char *buf, const char *path, size_t size)
{
const char *base = strrchr(path, '/');
if (!base)
base = strrchr(path, '\\');
if (!base)
base = path;
if (*base == '\\' || *base == '/')
base++;
strncpy(buf, base, size - 1);
buf[size - 1] = '\0';
char *ext = strrchr(buf, '.');
if (ext)
*ext = '\0';
}
static void extract_directory(char *buf, const char *path, size_t size)
{
strncpy(buf, path, size - 1);
buf[size - 1] = '\0';
char *base = strrchr(buf, '/');
if (!base)
base = strrchr(buf, '\\');
if (base)
*base = '\0';
else
buf[0] = '\0';
}
bool retro_load_game(const struct retro_game_info *info)
{
const char *dir;
char slash;
char db_path[256];
#if defined(_WIN32)
slash = '\\';
#else
slash = '/';
#endif
struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "(VSSystem) Coin 1" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "(VSSystem) Coin 2" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Eject Disk" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "(VSSystem) Coin 1" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "(VSSystem) Coin 2" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Eject Disk" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "(VSSystem) Coin 1" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "(VSSystem) Coin 2" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Eject Disk" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "(VSSystem) Coin 1" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "(VSSystem) Coin 2" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Eject Disk" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0 },
};
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
if (!environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) || !dir)
return false;
snprintf(db_path, sizeof(db_path), "%s%cNstDatabase.xml", dir, slash);
if (log_cb)
log_cb(RETRO_LOG_INFO, "NstDatabase.xml path: %s\n", db_path);
Api::Cartridge::Database database(emulator);
std::ifstream *db_file = new std::ifstream(db_path, std::ifstream::in|std::ifstream::binary);
if (db_file->is_open())
{
database.Load(*db_file);
database.Enable(true);
dbpresent = true;
}
else
{
if (log_cb)
log_cb(RETRO_LOG_WARN, "NstDatabase.xml required to detect region and some mappers.\n");
delete db_file;
dbpresent = false;
}
if (info->path != NULL)
{
extract_basename(g_basename, info->path, sizeof(g_basename));
extract_directory(g_rom_dir, info->path, sizeof(g_rom_dir));
}
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
{
if (log_cb)
log_cb(RETRO_LOG_ERROR, "XRGB8888 is not supported.\n");
return false;
}
std::stringstream ss(std::string(reinterpret_cast(info->data),
reinterpret_cast(info->data) + info->size));
if (info->path && (strstr(info->path, ".fds") || strstr(info->path, ".FDS")))
{
fds = new Api::Fds(emulator);
if (fds)
{
char fds_bios_path[256];
/* search for BIOS in system directory */
bool found = false;
snprintf(fds_bios_path, sizeof(fds_bios_path), "%s%cdisksys.rom", dir, slash);
if (log_cb)
log_cb(RETRO_LOG_INFO, "FDS BIOS path: %s\n", fds_bios_path);
std::ifstream *fds_bios_file = new std::ifstream(fds_bios_path, std::ifstream::in|std::ifstream::binary);
if (fds_bios_file->is_open())
fds->SetBIOS(fds_bios_file);
else
{
delete fds_bios_file;
return false;
}
}
else
return false;
}
if (!environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &g_save_dir))
{
if (log_cb)
log_cb(RETRO_LOG_ERROR, "Could not find save directory.\n");
}
is_pal = false;
check_variables();
if (machine->Load(ss, favsystem))
return false;
Api::Video ivideo(emulator);
ivideo.SetSharpness(Api::Video::DEFAULT_SHARPNESS_RGB);
ivideo.SetColorResolution(Api::Video::DEFAULT_COLOR_RESOLUTION_RGB);
ivideo.SetColorBleed(Api::Video::DEFAULT_COLOR_BLEED_RGB);
ivideo.SetColorArtifacts(Api::Video::DEFAULT_COLOR_ARTIFACTS_RGB);
ivideo.SetColorFringing(Api::Video::DEFAULT_COLOR_FRINGING_RGB);
Api::Video::RenderState state;
state.filter = Api::Video::RenderState::FILTER_NONE;
state.width = 256;
state.height = 240;
state.bits.count = 32;
state.bits.mask.r = 0x00ff0000;
state.bits.mask.g = 0x0000ff00;
state.bits.mask.b = 0x000000ff;
ivideo.SetRenderState(state);
Api::Sound isound(emulator);
isound.SetSampleBits(16);
isound.SetSampleRate(44100);
isound.SetSpeaker(Api::Sound::SPEAKER_MONO);
if (dbpresent)
{
Api::Input(emulator).AutoSelectController(0);
Api::Input(emulator).AutoSelectController(1);
Api::Input(emulator).AutoSelectController(2);
Api::Input(emulator).AutoSelectController(3);
}
else
{
Api::Input(emulator).ConnectController(0, Api::Input::PAD1);
Api::Input(emulator).ConnectController(1, Api::Input::PAD2);
//Api::Input(emulator).ConnectController(1, Api::Input::ZAPPER);
Api::Input(emulator).ConnectController(2, Api::Input::PAD3);
Api::Input(emulator).ConnectController(3, Api::Input::PAD4);
}
machine->Power(true);
check_variables();
if (fds_auto_insert && machine->Is(Nes::Api::Machine::DISK))
fds->InsertDisk(0, 0);
video = new Api::Video::Output(video_buffer, video_width * sizeof(uint32_t));
if (log_cb)
log_cb(RETRO_LOG_INFO, "[Nestopia]: Machine is %s.\n", is_pal ? "PAL" : "NTSC");
return true;
}
void retro_unload_game(void)
{
machine->Unload();
sram = 0;
sram_size = 0;
}
unsigned retro_get_region(void)
{
return is_pal ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
}
bool retro_load_game_special(unsigned, const struct retro_game_info *, size_t)
{
return false;
}
size_t retro_serialize_size(void)
{
std::stringstream ss;
if (machine->SaveState(ss, Api::Machine::NO_COMPRESSION))
return 0;
return ss.str().size();
}
bool retro_serialize(void *data, size_t size)
{
std::stringstream ss;
if (machine->SaveState(ss, Api::Machine::NO_COMPRESSION))
return false;
std::string state = ss.str();
if (state.size() > size)
return false;
std::copy(state.begin(), state.end(), reinterpret_cast(data));
return true;
}
bool retro_unserialize(const void *data, size_t size)
{
std::stringstream ss(std::string(reinterpret_cast(data),
reinterpret_cast(data) + size));
return !machine->LoadState(ss);
}
void *retro_get_memory_data(unsigned id)
{
if (id != RETRO_MEMORY_SAVE_RAM)
return 0;
return sram;
}
size_t retro_get_memory_size(unsigned id)
{
if (id != RETRO_MEMORY_SAVE_RAM)
return 0;
return sram_size;
}
void retro_cheat_reset(void)
{
Nes::Api::Cheats cheater(emulator);
cheater.ClearCodes();
}
void retro_cheat_set(unsigned index, bool enabled, const char *code)
{
Nes::Api::Cheats cheater(emulator);
Nes::Api::Cheats::Code ggCode;
if (Nes::Api::Cheats::GameGenieDecode(code, ggCode) == RESULT_OK)
cheater.SetCode(ggCode);
if (Nes::Api::Cheats::ProActionRockyDecode(code, ggCode) == RESULT_OK)
cheater.SetCode(ggCode);
}
nestopia-1.47/libretro/libretro.h 0000775 0000000 0000000 00000257402 12644314416 0017126 0 ustar 00root root 0000000 0000000 /* Copyright (C) 2010-2014 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LIBRETRO_H__
#define LIBRETRO_H__
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __cplusplus
#if defined(_MSC_VER) && !defined(SN_TARGET_PS3)
/* Hack applied for MSVC when compiling in C89 mode
* as it isn't C99-compliant. */
#define bool unsigned char
#define true 1
#define false 0
#else
#include
#endif
#endif
/* Used for checking API/ABI mismatches that can break libretro
* implementations.
* It is not incremented for compatible changes to the API.
*/
#define RETRO_API_VERSION 1
/*
* Libretro's fundamental device abstractions.
*
* Libretro's input system consists of some standardized device types,
* such as a joypad (with/without analog), mouse, keyboard, lightgun
* and a pointer.
*
* The functionality of these devices are fixed, and individual cores
* map their own concept of a controller to libretro's abstractions.
* This makes it possible for frontends to map the abstract types to a
* real input device, and not having to worry about binding input
* correctly to arbitrary controller layouts.
*/
#define RETRO_DEVICE_TYPE_SHIFT 8
#define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)
#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)
/* Input disabled. */
#define RETRO_DEVICE_NONE 0
/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo
* controller, but with additional L2/R2/L3/R3 buttons, similar to a
* PS1 DualShock. */
#define RETRO_DEVICE_JOYPAD 1
/* The mouse is a simple mouse, similar to Super Nintendo's mouse.
* X and Y coordinates are reported relatively to last poll (poll callback).
* It is up to the libretro implementation to keep track of where the mouse
* pointer is supposed to be on the screen.
* The frontend must make sure not to interfere with its own hardware
* mouse pointer.
*/
#define RETRO_DEVICE_MOUSE 2
/* KEYBOARD device lets one poll for raw key pressed.
* It is poll based, so input callback will return with the current
* pressed state.
* For event/text based keyboard input, see
* RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
*/
#define RETRO_DEVICE_KEYBOARD 3
/* Lightgun X/Y coordinates are reported relatively to last poll,
* similar to mouse. */
#define RETRO_DEVICE_LIGHTGUN 4
/* The ANALOG device is an extension to JOYPAD (RetroPad).
* Similar to DualShock it adds two analog sticks.
* This is treated as a separate device type as it returns values in the
* full analog range of [-0x8000, 0x7fff]. Positive X axis is right.
* Positive Y axis is down.
* Only use ANALOG type when polling for analog values of the axes.
*/
#define RETRO_DEVICE_ANALOG 5
/* Abstracts the concept of a pointing mechanism, e.g. touch.
* This allows libretro to query in absolute coordinates where on the
* screen a mouse (or something similar) is being placed.
* For a touch centric device, coordinates reported are the coordinates
* of the press.
*
* Coordinates in X and Y are reported as:
* [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
* and 0x7fff corresponds to the far right/bottom of the screen.
* The "screen" is here defined as area that is passed to the frontend and
* later displayed on the monitor.
*
* The frontend is free to scale/resize this screen as it sees fit, however,
* (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
* game image, etc.
*
* To check if the pointer coordinates are valid (e.g. a touch display
* actually being touched), PRESSED returns 1 or 0.
*
* If using a mouse on a desktop, PRESSED will usually correspond to the
* left mouse button, but this is a frontend decision.
* PRESSED will only return 1 if the pointer is inside the game screen.
*
* For multi-touch, the index variable can be used to successively query
* more presses.
* If index = 0 returns true for _PRESSED, coordinates can be extracted
* with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with
* index = 1, and so on.
* Eventually _PRESSED will return false for an index. No further presses
* are registered at this point. */
#define RETRO_DEVICE_POINTER 6
/* Buttons for the RetroPad (JOYPAD).
* The placement of these is equivalent to placements on the
* Super Nintendo controller.
* L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */
#define RETRO_DEVICE_ID_JOYPAD_B 0
#define RETRO_DEVICE_ID_JOYPAD_Y 1
#define RETRO_DEVICE_ID_JOYPAD_SELECT 2
#define RETRO_DEVICE_ID_JOYPAD_START 3
#define RETRO_DEVICE_ID_JOYPAD_UP 4
#define RETRO_DEVICE_ID_JOYPAD_DOWN 5
#define RETRO_DEVICE_ID_JOYPAD_LEFT 6
#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7
#define RETRO_DEVICE_ID_JOYPAD_A 8
#define RETRO_DEVICE_ID_JOYPAD_X 9
#define RETRO_DEVICE_ID_JOYPAD_L 10
#define RETRO_DEVICE_ID_JOYPAD_R 11
#define RETRO_DEVICE_ID_JOYPAD_L2 12
#define RETRO_DEVICE_ID_JOYPAD_R2 13
#define RETRO_DEVICE_ID_JOYPAD_L3 14
#define RETRO_DEVICE_ID_JOYPAD_R3 15
/* Index / Id values for ANALOG device. */
#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
#define RETRO_DEVICE_ID_ANALOG_X 0
#define RETRO_DEVICE_ID_ANALOG_Y 1
/* Id values for MOUSE. */
#define RETRO_DEVICE_ID_MOUSE_X 0
#define RETRO_DEVICE_ID_MOUSE_Y 1
#define RETRO_DEVICE_ID_MOUSE_LEFT 2
#define RETRO_DEVICE_ID_MOUSE_RIGHT 3
#define RETRO_DEVICE_ID_MOUSE_WHEELUP 4
#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5
#define RETRO_DEVICE_ID_MOUSE_MIDDLE 6
/* Id values for LIGHTGUN types. */
#define RETRO_DEVICE_ID_LIGHTGUN_X 0
#define RETRO_DEVICE_ID_LIGHTGUN_Y 1
#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3
#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4
#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5
#define RETRO_DEVICE_ID_LIGHTGUN_START 6
/* Id values for POINTER. */
#define RETRO_DEVICE_ID_POINTER_X 0
#define RETRO_DEVICE_ID_POINTER_Y 1
#define RETRO_DEVICE_ID_POINTER_PRESSED 2
/* Returned from retro_get_region(). */
#define RETRO_REGION_NTSC 0
#define RETRO_REGION_PAL 1
/* Id values for LANGUAGE */
enum retro_language
{
RETRO_LANGUAGE_ENGLISH = 0,
RETRO_LANGUAGE_JAPANESE = 1,
RETRO_LANGUAGE_FRENCH = 2,
RETRO_LANGUAGE_SPANISH = 3,
RETRO_LANGUAGE_GERMAN = 4,
RETRO_LANGUAGE_ITALIAN = 5,
RETRO_LANGUAGE_DUTCH = 6,
RETRO_LANGUAGE_PORTUGUESE = 7,
RETRO_LANGUAGE_RUSSIAN = 8,
RETRO_LANGUAGE_KOREAN = 9,
RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10,
RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 11,
RETRO_LANGUAGE_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
RETRO_LANGUAGE_DUMMY = INT_MAX
};
/* Passed to retro_get_memory_data/size().
* If the memory type doesn't apply to the
* implementation NULL/0 can be returned.
*/
#define RETRO_MEMORY_MASK 0xff
/* Regular save RAM. This RAM is usually found on a game cartridge,
* backed up by a battery.
* If save game data is too complex for a single memory buffer,
* the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
* callback can be used. */
#define RETRO_MEMORY_SAVE_RAM 0
/* Some games have a built-in clock to keep track of time.
* This memory is usually just a couple of bytes to keep track of time.
*/
#define RETRO_MEMORY_RTC 1
/* System ram lets a frontend peek into a game systems main RAM. */
#define RETRO_MEMORY_SYSTEM_RAM 2
/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
#define RETRO_MEMORY_VIDEO_RAM 3
/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
enum retro_key
{
RETROK_UNKNOWN = 0,
RETROK_FIRST = 0,
RETROK_BACKSPACE = 8,
RETROK_TAB = 9,
RETROK_CLEAR = 12,
RETROK_RETURN = 13,
RETROK_PAUSE = 19,
RETROK_ESCAPE = 27,
RETROK_SPACE = 32,
RETROK_EXCLAIM = 33,
RETROK_QUOTEDBL = 34,
RETROK_HASH = 35,
RETROK_DOLLAR = 36,
RETROK_AMPERSAND = 38,
RETROK_QUOTE = 39,
RETROK_LEFTPAREN = 40,
RETROK_RIGHTPAREN = 41,
RETROK_ASTERISK = 42,
RETROK_PLUS = 43,
RETROK_COMMA = 44,
RETROK_MINUS = 45,
RETROK_PERIOD = 46,
RETROK_SLASH = 47,
RETROK_0 = 48,
RETROK_1 = 49,
RETROK_2 = 50,
RETROK_3 = 51,
RETROK_4 = 52,
RETROK_5 = 53,
RETROK_6 = 54,
RETROK_7 = 55,
RETROK_8 = 56,
RETROK_9 = 57,
RETROK_COLON = 58,
RETROK_SEMICOLON = 59,
RETROK_LESS = 60,
RETROK_EQUALS = 61,
RETROK_GREATER = 62,
RETROK_QUESTION = 63,
RETROK_AT = 64,
RETROK_LEFTBRACKET = 91,
RETROK_BACKSLASH = 92,
RETROK_RIGHTBRACKET = 93,
RETROK_CARET = 94,
RETROK_UNDERSCORE = 95,
RETROK_BACKQUOTE = 96,
RETROK_a = 97,
RETROK_b = 98,
RETROK_c = 99,
RETROK_d = 100,
RETROK_e = 101,
RETROK_f = 102,
RETROK_g = 103,
RETROK_h = 104,
RETROK_i = 105,
RETROK_j = 106,
RETROK_k = 107,
RETROK_l = 108,
RETROK_m = 109,
RETROK_n = 110,
RETROK_o = 111,
RETROK_p = 112,
RETROK_q = 113,
RETROK_r = 114,
RETROK_s = 115,
RETROK_t = 116,
RETROK_u = 117,
RETROK_v = 118,
RETROK_w = 119,
RETROK_x = 120,
RETROK_y = 121,
RETROK_z = 122,
RETROK_DELETE = 127,
RETROK_KP0 = 256,
RETROK_KP1 = 257,
RETROK_KP2 = 258,
RETROK_KP3 = 259,
RETROK_KP4 = 260,
RETROK_KP5 = 261,
RETROK_KP6 = 262,
RETROK_KP7 = 263,
RETROK_KP8 = 264,
RETROK_KP9 = 265,
RETROK_KP_PERIOD = 266,
RETROK_KP_DIVIDE = 267,
RETROK_KP_MULTIPLY = 268,
RETROK_KP_MINUS = 269,
RETROK_KP_PLUS = 270,
RETROK_KP_ENTER = 271,
RETROK_KP_EQUALS = 272,
RETROK_UP = 273,
RETROK_DOWN = 274,
RETROK_RIGHT = 275,
RETROK_LEFT = 276,
RETROK_INSERT = 277,
RETROK_HOME = 278,
RETROK_END = 279,
RETROK_PAGEUP = 280,
RETROK_PAGEDOWN = 281,
RETROK_F1 = 282,
RETROK_F2 = 283,
RETROK_F3 = 284,
RETROK_F4 = 285,
RETROK_F5 = 286,
RETROK_F6 = 287,
RETROK_F7 = 288,
RETROK_F8 = 289,
RETROK_F9 = 290,
RETROK_F10 = 291,
RETROK_F11 = 292,
RETROK_F12 = 293,
RETROK_F13 = 294,
RETROK_F14 = 295,
RETROK_F15 = 296,
RETROK_NUMLOCK = 300,
RETROK_CAPSLOCK = 301,
RETROK_SCROLLOCK = 302,
RETROK_RSHIFT = 303,
RETROK_LSHIFT = 304,
RETROK_RCTRL = 305,
RETROK_LCTRL = 306,
RETROK_RALT = 307,
RETROK_LALT = 308,
RETROK_RMETA = 309,
RETROK_LMETA = 310,
RETROK_LSUPER = 311,
RETROK_RSUPER = 312,
RETROK_MODE = 313,
RETROK_COMPOSE = 314,
RETROK_HELP = 315,
RETROK_PRINT = 316,
RETROK_SYSREQ = 317,
RETROK_BREAK = 318,
RETROK_MENU = 319,
RETROK_POWER = 320,
RETROK_EURO = 321,
RETROK_UNDO = 322,
RETROK_LAST,
RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};
enum retro_mod
{
RETROKMOD_NONE = 0x0000,
RETROKMOD_SHIFT = 0x01,
RETROKMOD_CTRL = 0x02,
RETROKMOD_ALT = 0x04,
RETROKMOD_META = 0x08,
RETROKMOD_NUMLOCK = 0x10,
RETROKMOD_CAPSLOCK = 0x20,
RETROKMOD_SCROLLOCK = 0x40,
RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
};
/* If set, this call is not part of the public libretro API yet. It can
* change or be removed at any time. */
#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
/* Environment callback to be used internally in frontend. */
#define RETRO_ENVIRONMENT_PRIVATE 0x20000
/* Environment commands. */
#define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * --
* Sets screen rotation of graphics.
* Is only implemented if rotation can be accelerated by hardware.
* Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180,
* 270 degrees counter-clockwise respectively.
*/
#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * --
* Boolean value whether or not the implementation should use overscan,
* or crop away overscan.
*/
#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 /* bool * --
* Boolean value whether or not frontend supports frame duping,
* passing NULL to video frame callback.
*/
/* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
* and reserved to avoid possible ABI clash.
*/
#define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * --
* Sets a message to be displayed in implementation-specific manner
* for a certain amount of 'frames'.
* Should not be used for trivial messages, which should simply be
* logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
* fallback, stderr).
*/
#define RETRO_ENVIRONMENT_SHUTDOWN 7 /* N/A (NULL) --
* Requests the frontend to shutdown.
* Should only be used if game has a specific
* way to shutdown the game from a menu item or similar.
*/
#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
/* const unsigned * --
* Gives a hint to the frontend how demanding this implementation
* is on a system. E.g. reporting a level of 2 means
* this implementation should run decently on all frontends
* of level 2 and up.
*
* It can be used by the frontend to potentially warn
* about too demanding implementations.
*
* The levels are "floating".
*
* This function can be called on a per-game basis,
* as certain games an implementation can play might be
* particularly demanding.
* If called, it should be called in retro_load_game().
*/
#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
/* const char ** --
* Returns the "system" directory of the frontend.
* This directory can be used to store system specific
* content such as BIOSes, configuration data, etc.
* The returned value can be NULL.
* If so, no such directory is defined,
* and it's up to the implementation to find a suitable directory.
*
* NOTE: Some cores used this folder also for "save" data such as
* memory cards, etc, for lack of a better place to put it.
* This is now discouraged, and if possible, cores should try to
* use the new GET_SAVE_DIRECTORY.
*/
#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
/* const enum retro_pixel_format * --
* Sets the internal pixel format used by the implementation.
* The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
* This pixel format however, is deprecated (see enum retro_pixel_format).
* If the call returns false, the frontend does not support this pixel
* format.
*
* This function should be called inside retro_load_game() or
* retro_get_system_av_info().
*/
#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
/* const struct retro_input_descriptor * --
* Sets an array of retro_input_descriptors.
* It is up to the frontend to present this in a usable way.
* The array is terminated by retro_input_descriptor::description
* being set to NULL.
* This function can be called at any time, but it is recommended
* to call it as early as possible.
*/
#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12
/* const struct retro_keyboard_callback * --
* Sets a callback function used to notify core about keyboard events.
*/
#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13
/* const struct retro_disk_control_callback * --
* Sets an interface which frontend can use to eject and insert
* disk images.
* This is used for games which consist of multiple images and
* must be manually swapped out by the user (e.g. PSX).
*/
#define RETRO_ENVIRONMENT_SET_HW_RENDER 14
/* struct retro_hw_render_callback * --
* Sets an interface to let a libretro core render with
* hardware acceleration.
* Should be called in retro_load_game().
* If successful, libretro cores will be able to render to a
* frontend-provided framebuffer.
* The size of this framebuffer will be at least as large as
* max_width/max_height provided in get_av_info().
* If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or
* NULL to retro_video_refresh_t.
*/
#define RETRO_ENVIRONMENT_GET_VARIABLE 15
/* struct retro_variable * --
* Interface to acquire user-defined information from environment
* that cannot feasibly be supported in a multi-system way.
* 'key' should be set to a key which has already been set by
* SET_VARIABLES.
* 'data' will be set to a value or NULL.
*/
#define RETRO_ENVIRONMENT_SET_VARIABLES 16
/* const struct retro_variable * --
* Allows an implementation to signal the environment
* which variables it might want to check for later using
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should be called as early as possible (ideally in
* retro_set_environment).
*
* 'data' points to an array of retro_variable structs
* terminated by a { NULL, NULL } element.
* retro_variable::key should be namespaced to not collide
* with other implementations' keys. E.g. A core called
* 'foo' should use keys named as 'foo_option'.
* retro_variable::value should contain a human readable
* description of the key as well as a '|' delimited list
* of expected values.
*
* The number of possible options should be very limited,
* i.e. it should be feasible to cycle through options
* without a keyboard.
*
* First entry should be treated as a default.
*
* Example entry:
* { "foo_option", "Speed hack coprocessor X; false|true" }
*
* Text before first ';' is description. This ';' must be
* followed by a space, and followed by a list of possible
* values split up with '|'.
*
* Only strings are operated on. The possible values will
* generally be displayed and stored as-is by the frontend.
*/
#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17
/* bool * --
* Result is set to true if some variables are updated by
* frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE.
* Variables should be queried with GET_VARIABLE.
*/
#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18
/* const bool * --
* If true, the libretro implementation supports calls to
* retro_load_game() with NULL as argument.
* Used by cores which can run without particular game data.
* This should be called within retro_set_environment() only.
*/
#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19
/* const char ** --
* Retrieves the absolute path from where this libretro
* implementation was loaded.
* NULL is returned if the libretro was loaded statically
* (i.e. linked statically to frontend), or if the path cannot be
* determined.
* Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can
* be loaded without ugly hacks.
*/
/* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
* It was not used by any known core at the time,
* and was removed from the API. */
#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
/* const struct retro_audio_callback * --
* Sets an interface which is used to notify a libretro core about audio
* being available for writing.
* The callback can be called from any thread, so a core using this must
* have a thread safe audio implementation.
* It is intended for games where audio and video are completely
* asynchronous and audio can be generated on the fly.
* This interface is not recommended for use with emulators which have
* highly synchronous audio.
*
* The callback only notifies about writability; the libretro core still
* has to call the normal audio callbacks
* to write audio. The audio callbacks must be called from within the
* notification callback.
* The amount of audio data to write is up to the implementation.
* Generally, the audio callback will be called continously in a loop.
*
* Due to thread safety guarantees and lack of sync between audio and
* video, a frontend can selectively disallow this interface based on
* internal configuration. A core using this interface must also
* implement the "normal" audio interface.
*
* A libretro core using SET_AUDIO_CALLBACK should also make use of
* SET_FRAME_TIME_CALLBACK.
*/
#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
/* const struct retro_frame_time_callback * --
* Lets the core know how much time has passed since last
* invocation of retro_run().
* The frontend can tamper with the timing to fake fast-forward,
* slow-motion, frame stepping, etc.
* In this case the delta time will use the reference value
* in frame_time_callback..
*/
#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
/* struct retro_rumble_interface * --
* Gets an interface which is used by a libretro core to set
* state of rumble motors in controllers.
* A strong and weak motor is supported, and they can be
* controlled indepedently.
*/
#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
/* uint64_t * --
* Gets a bitmask telling which device type are expected to be
* handled properly in a call to retro_input_state_t.
* Devices which are not handled or recognized always return
* 0 in retro_input_state_t.
* Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG).
* Should only be called in retro_run().
*/
#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_sensor_interface * --
* Gets access to the sensor interface.
* The purpose of this interface is to allow
* setting state related to sensors such as polling rate,
* enabling/disable it entirely, etc.
* Reading sensor state is done via the normal
* input_state_callback API.
*/
#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* struct retro_camera_callback * --
* Gets an interface to a video camera driver.
* A libretro core can use this interface to get access to a
* video camera.
* New video frames are delivered in a callback in same
* thread as retro_run().
*
* GET_CAMERA_INTERFACE should be called in retro_load_game().
*
* Depending on the camera implementation used, camera frames
* will be delivered as a raw framebuffer,
* or as an OpenGL texture directly.
*
* The core has to tell the frontend here which types of
* buffers can be handled properly.
* An OpenGL texture can only be handled when using a
* libretro GL core (SET_HW_RENDER).
* It is recommended to use a libretro GL core when
* using camera interface.
*
* The camera is not started automatically. The retrieved start/stop
* functions must be used to explicitly
* start and stop the camera driver.
*/
#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
/* struct retro_log_callback * --
* Gets an interface for logging. This is useful for
* logging in a cross-platform way
* as certain platforms cannot use use stderr for logging.
* It also allows the frontend to
* show logging information in a more suitable way.
* If this interface is not used, libretro cores should
* log to stderr as desired.
*/
#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28
/* struct retro_perf_callback * --
* Gets an interface for performance counters. This is useful
* for performance logging in a cross-platform way and for detecting
* architecture-specific features, such as SIMD support.
*/
#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29
/* struct retro_location_callback * --
* Gets access to the location interface.
* The purpose of this interface is to be able to retrieve
* location-based information from the host device,
* such as current latitude / longitude.
*/
#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30
/* const char ** --
* Returns the "content" directory of the frontend.
* This directory can be used to store specific assets that the
* core relies upon, such as art assets,
* input data, etc etc.
* The returned value can be NULL.
* If so, no such directory is defined,
* and it's up to the implementation to find a suitable directory.
*/
#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
/* const char ** --
* Returns the "save" directory of the frontend.
* This directory can be used to store SRAM, memory cards,
* high scores, etc, if the libretro core
* cannot use the regular memory interface (retro_get_memory_data()).
*
* NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for
* similar things before.
* They should still check GET_SYSTEM_DIRECTORY if they want to
* be backwards compatible.
* The path here can be NULL. It should only be non-NULL if the
* frontend user has set a specific save path.
*/
#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
/* const struct retro_system_av_info * --
* Sets a new av_info structure. This can only be called from
* within retro_run().
* This should *only* be used if the core is completely altering the
* internal resolutions, aspect ratios, timings, sampling rate, etc.
* Calling this can require a full reinitialization of video/audio
* drivers in the frontend,
*
* so it is important to call it very sparingly, and usually only with
* the users explicit consent.
* An eventual driver reinitialize will happen so that video and
* audio callbacks
* happening after this call within the same retro_run() call will
* target the newly initialized driver.
*
* This callback makes it possible to support configurable resolutions
* in games, which can be useful to
* avoid setting the "worst case" in max_width/max_height.
*
* ***HIGHLY RECOMMENDED*** Do not call this callback every time
* resolution changes in an emulator core if it's
* expected to be a temporary change, for the reasons of possible
* driver reinitialization.
* This call is not a free pass for not trying to provide
* correct values in retro_get_system_av_info(). If you need to change
* things like aspect ratio or nominal width/height,
* use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant
* of SET_SYSTEM_AV_INFO.
*
* If this returns false, the frontend does not acknowledge a
* changed av_info struct.
*/
#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33
/* const struct retro_get_proc_address_interface * --
* Allows a libretro core to announce support for the
* get_proc_address() interface.
* This interface allows for a standard way to extend libretro where
* use of environment calls are too indirect,
* e.g. for cases where the frontend wants to call directly into the core.
*
* If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK
* **MUST** be called from within retro_set_environment().
*/
#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
/* const struct retro_subsystem_info * --
* This environment call introduces the concept of libretro "subsystems".
* A subsystem is a variant of a libretro core which supports
* different kinds of games.
* The purpose of this is to support e.g. emulators which might
* have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
* It can also be used to pick among subsystems in an explicit way
* if the libretro implementation is a multi-system emulator itself.
*
* Loading a game via a subsystem is done with retro_load_game_special(),
* and this environment call allows a libretro core to expose which
* subsystems are supported for use with retro_load_game_special().
* A core passes an array of retro_game_special_info which is terminated
* with a zeroed out retro_game_special_info struct.
*
* If a core wants to use this functionality, SET_SUBSYSTEM_INFO
* **MUST** be called from within retro_set_environment().
*/
#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
/* const struct retro_controller_info * --
* This environment call lets a libretro core tell the frontend
* which controller types are recognized in calls to
* retro_set_controller_port_device().
*
* Some emulators such as Super Nintendo
* support multiple lightgun types which must be specifically
* selected from.
* It is therefore sometimes necessary for a frontend to be able
* to tell the core about a special kind of input device which is
* not covered by the libretro input API.
*
* In order for a frontend to understand the workings of an input device,
* it must be a specialized type
* of the generic device types already defined in the libretro API.
*
* Which devices are supported can vary per input port.
* The core must pass an array of const struct retro_controller_info which
* is terminated with a blanked out struct. Each element of the struct
* corresponds to an ascending port index to
* retro_set_controller_port_device().
* Even if special device types are set in the libretro core,
* libretro should only poll input based on the base input device types.
*/
#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_memory_map * --
* This environment call lets a libretro core tell the frontend
* about the memory maps this core emulates.
* This can be used to implement, for example, cheats in a core-agnostic way.
*
* Should only be used by emulators; it doesn't make much sense for
* anything else.
* It is recommended to expose all relevant pointers through
* retro_get_memory_* as well.
*
* Can be called from retro_init and retro_load_game.
*/
#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
/* const struct retro_game_geometry * --
* This environment call is similar to SET_SYSTEM_AV_INFO for changing
* video parameters, but provides a guarantee that drivers will not be
* reinitialized.
* This can only be called from within retro_run().
*
* The purpose of this call is to allow a core to alter nominal
* width/heights as well as aspect ratios on-the-fly, which can be
* useful for some emulators to change in run-time.
*
* max_width/max_height arguments are ignored and cannot be changed
* with this call as this could potentially require a reinitialization or a
* non-constant time operation.
* If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required.
*
* A frontend must guarantee that this environment call completes in
* constant time.
*/
#define RETRO_ENVIRONMENT_GET_USERNAME 38
/* const char **
* Returns the specified username of the frontend, if specified by the user.
* This username can be used as a nickname for a core that has online facilities
* or any other mode where personalization of the user is desirable.
* The returned value can be NULL.
* If this environ callback is used by a core that requires a valid username,
* a default username should be specified by the core.
*/
#define RETRO_ENVIRONMENT_GET_LANGUAGE 39
/* unsigned * --
* Returns the specified language of the frontend, if specified by the user.
* It can be used by the core for localization purposes.
*/
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
#define RETRO_MEMDESC_ALIGN_4 (2 << 16)
#define RETRO_MEMDESC_ALIGN_8 (3 << 16)
#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
#define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
#define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
struct retro_memory_descriptor
{
uint64_t flags;
/* Pointer to the start of the relevant ROM or RAM chip.
* It's strongly recommended to use 'offset' if possible, rather than
* doing math on the pointer.
*
* If the same byte is mapped my multiple descriptors, their descriptors
* must have the same pointer.
* If 'start' does not point to the first byte in the pointer, put the
* difference in 'offset' instead.
*
* May be NULL if there's nothing usable here (e.g. hardware registers and
* open bus). No flags should be set if the pointer is NULL.
* It's recommended to minimize the number of descriptors if possible,
* but not mandatory. */
void *ptr;
size_t offset;
/* This is the location in the emulated address space
* where the mapping starts. */
size_t start;
/* Which bits must be same as in 'start' for this mapping to apply.
* The first memory descriptor to claim a certain byte is the one
* that applies.
* A bit which is set in 'start' must also be set in this.
* Can be zero, in which case each byte is assumed mapped exactly once.
* In this case, 'len' must be a power of two. */
size_t select;
/* If this is nonzero, the set bits are assumed not connected to the
* memory chip's address pins. */
size_t disconnect;
/* This one tells the size of the current memory area.
* If, after start+disconnect are applied, the address is higher than
* this, the highest bit of the address is cleared.
*
* If the address is still too high, the next highest bit is cleared.
* Can be zero, in which case it's assumed to be infinite (as limited
* by 'select' and 'disconnect'). */
size_t len;
/* To go from emulated address to physical address, the following
* order applies:
* Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'.
*
* The address space name must consist of only a-zA-Z0-9_-,
* should be as short as feasible (maximum length is 8 plus the NUL),
* and may not be any other address space plus one or more 0-9A-F
* at the end.
* However, multiple memory descriptors for the same address space is
* allowed, and the address space name can be empty. NULL is treated
* as empty.
*
* Address space names are case sensitive, but avoid lowercase if possible.
* The same pointer may exist in multiple address spaces.
*
* Examples:
* blank+blank - valid (multiple things may be mapped in the same namespace)
* 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace)
* 'A'+'B' - valid (neither is a prefix of each other)
* 'S'+blank - valid ('S' is not in 0-9A-F)
* 'a'+blank - valid ('a' is not in 0-9A-F)
* 'a'+'A' - valid (neither is a prefix of each other)
* 'AR'+blank - valid ('R' is not in 0-9A-F)
* 'ARB'+blank - valid (the B can't be part of the address either, because
* there is no namespace 'AR')
* blank+'B' - not valid, because it's ambigous which address space B1234
* would refer to.
* The length can't be used for that purpose; the frontend may want
* to append arbitrary data to an address, without a separator. */
const char *addrspace;
};
/* The frontend may use the largest value of 'start'+'select' in a
* certain namespace to infer the size of the address space.
*
* If the address space is larger than that, a mapping with .ptr=NULL
* should be at the end of the array, with .select set to all ones for
* as long as the address space is big.
*
* Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags):
* SNES WRAM:
* .start=0x7E0000, .len=0x20000
* (Note that this must be mapped before the ROM in most cases; some of the
* ROM mappers
* try to claim $7E0000, or at least $7E8000.)
* SNES SPC700 RAM:
* .addrspace="S", .len=0x10000
* SNES WRAM mirrors:
* .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000
* .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000
* SNES WRAM mirrors, alternate equivalent descriptor:
* .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF
* (Various similar constructions can be created by combining parts of
* the above two.)
* SNES LoROM (512KB, mirrored a couple of times):
* .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024
* .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024
* SNES HiROM (4MB):
* .flags=CONST, .start=0x400000, .select=0x400000, .len=4*1024*1024
* .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024
* SNES ExHiROM (8MB):
* .flags=CONST, .offset=0, .start=0xC00000, .select=0xC00000, .len=4*1024*1024
* .flags=CONST, .offset=4*1024*1024, .start=0x400000, .select=0xC00000, .len=4*1024*1024
* .flags=CONST, .offset=0x8000, .start=0x808000, .select=0xC08000, .len=4*1024*1024
* .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024
* Clarify the size of the address space:
* .ptr=NULL, .select=0xFFFFFF
* .len can be implied by .select in many of them, but was included for clarity.
*/
struct retro_memory_map
{
const struct retro_memory_descriptor *descriptors;
unsigned num_descriptors;
};
struct retro_controller_description
{
/* Human-readable description of the controller. Even if using a generic
* input device type, this can be set to the particular device type the
* core uses. */
const char *desc;
/* Device type passed to retro_set_controller_port_device(). If the device
* type is a sub-class of a generic input device type, use the
* RETRO_DEVICE_SUBCLASS macro to create an ID.
*
* E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */
unsigned id;
};
struct retro_controller_info
{
const struct retro_controller_description *types;
unsigned num_types;
};
struct retro_subsystem_memory_info
{
/* The extension associated with a memory type, e.g. "psram". */
const char *extension;
/* The memory type for retro_get_memory(). This should be at
* least 0x100 to avoid conflict with standardized
* libretro memory types. */
unsigned type;
};
struct retro_subsystem_rom_info
{
/* Describes what the content is (SGB BIOS, GB ROM, etc). */
const char *desc;
/* Same definition as retro_get_system_info(). */
const char *valid_extensions;
/* Same definition as retro_get_system_info(). */
bool need_fullpath;
/* Same definition as retro_get_system_info(). */
bool block_extract;
/* This is set if the content is required to load a game.
* If this is set to false, a zeroed-out retro_game_info can be passed. */
bool required;
/* Content can have multiple associated persistent
* memory types (retro_get_memory()). */
const struct retro_subsystem_memory_info *memory;
unsigned num_memory;
};
struct retro_subsystem_info
{
/* Human-readable string of the subsystem type, e.g. "Super GameBoy" */
const char *desc;
/* A computer friendly short string identifier for the subsystem type.
* This name must be [a-z].
* E.g. if desc is "Super GameBoy", this can be "sgb".
* This identifier can be used for command-line interfaces, etc.
*/
const char *ident;
/* Infos for each content file. The first entry is assumed to be the
* "most significant" content for frontend purposes.
* E.g. with Super GameBoy, the first content should be the GameBoy ROM,
* as it is the most "significant" content to a user.
* If a frontend creates new file paths based on the content used
* (e.g. savestates), it should use the path for the first ROM to do so. */
const struct retro_subsystem_rom_info *roms;
/* Number of content files associated with a subsystem. */
unsigned num_roms;
/* The type passed to retro_load_game_special(). */
unsigned id;
};
typedef void (*retro_proc_address_t)(void);
/* libretro API extension functions:
* (None here so far).
*
* Get a symbol from a libretro core.
* Cores should only return symbols which are actual
* extensions to the libretro API.
*
* Frontends should not use this to obtain symbols to standard
* libretro entry points (static linking or dlsym).
*
* The symbol name must be equal to the function name,
* e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
* The returned function pointer must be cast to the corresponding type.
*/
typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym);
struct retro_get_proc_address_interface
{
retro_get_proc_address_t get_proc_address;
};
enum retro_log_level
{
RETRO_LOG_DEBUG = 0,
RETRO_LOG_INFO,
RETRO_LOG_WARN,
RETRO_LOG_ERROR,
RETRO_LOG_DUMMY = INT_MAX
};
/* Logging function. Takes log level argument as well. */
typedef void (*retro_log_printf_t)(enum retro_log_level level,
const char *fmt, ...);
struct retro_log_callback
{
retro_log_printf_t log;
};
/* Performance related functions */
/* ID values for SIMD CPU features */
#define RETRO_SIMD_SSE (1 << 0)
#define RETRO_SIMD_SSE2 (1 << 1)
#define RETRO_SIMD_VMX (1 << 2)
#define RETRO_SIMD_VMX128 (1 << 3)
#define RETRO_SIMD_AVX (1 << 4)
#define RETRO_SIMD_NEON (1 << 5)
#define RETRO_SIMD_SSE3 (1 << 6)
#define RETRO_SIMD_SSSE3 (1 << 7)
#define RETRO_SIMD_MMX (1 << 8)
#define RETRO_SIMD_MMXEXT (1 << 9)
#define RETRO_SIMD_SSE4 (1 << 10)
#define RETRO_SIMD_SSE42 (1 << 11)
#define RETRO_SIMD_AVX2 (1 << 12)
#define RETRO_SIMD_VFPU (1 << 13)
#define RETRO_SIMD_PS (1 << 14)
#define RETRO_SIMD_AES (1 << 15)
typedef uint64_t retro_perf_tick_t;
typedef int64_t retro_time_t;
struct retro_perf_counter
{
const char *ident;
retro_perf_tick_t start;
retro_perf_tick_t total;
retro_perf_tick_t call_cnt;
bool registered;
};
/* Returns current time in microseconds.
* Tries to use the most accurate timer available.
*/
typedef retro_time_t (*retro_perf_get_time_usec_t)(void);
/* A simple counter. Usually nanoseconds, but can also be CPU cycles.
* Can be used directly if desired (when creating a more sophisticated
* performance counter system).
* */
typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void);
/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
typedef uint64_t (*retro_get_cpu_features_t)(void);
/* Asks frontend to log and/or display the state of performance counters.
* Performance counters can always be poked into manually as well.
*/
typedef void (*retro_perf_log_t)(void);
/* Register a performance counter.
* ident field must be set with a discrete value and other values in
* retro_perf_counter must be 0.
* Registering can be called multiple times. To avoid calling to
* frontend redundantly, you can check registered field first. */
typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter);
/* Starts a registered counter. */
typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter);
/* Stops a registered counter. */
typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter);
/* For convenience it can be useful to wrap register, start and stop in macros.
* E.g.:
* #ifdef LOG_PERFORMANCE
* #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
* #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
* #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
* #else
* ... Blank macros ...
* #endif
*
* These can then be used mid-functions around code snippets.
*
* extern struct retro_perf_callback perf_cb; * Somewhere in the core.
*
* void do_some_heavy_work(void)
* {
* RETRO_PERFORMANCE_INIT(cb, work_1;
* RETRO_PERFORMANCE_START(cb, work_1);
* heavy_work_1();
* RETRO_PERFORMANCE_STOP(cb, work_1);
*
* RETRO_PERFORMANCE_INIT(cb, work_2);
* RETRO_PERFORMANCE_START(cb, work_2);
* heavy_work_2();
* RETRO_PERFORMANCE_STOP(cb, work_2);
* }
*
* void retro_deinit(void)
* {
* perf_cb.perf_log(); * Log all perf counters here for example.
* }
*/
struct retro_perf_callback
{
retro_perf_get_time_usec_t get_time_usec;
retro_get_cpu_features_t get_cpu_features;
retro_perf_get_counter_t get_perf_counter;
retro_perf_register_t perf_register;
retro_perf_start_t perf_start;
retro_perf_stop_t perf_stop;
retro_perf_log_t perf_log;
};
/* FIXME: Document the sensor API and work out behavior.
* It will be marked as experimental until then.
*/
enum retro_sensor_action
{
RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
RETRO_SENSOR_ACCELEROMETER_DISABLE,
RETRO_SENSOR_DUMMY = INT_MAX
};
/* Id values for SENSOR types. */
#define RETRO_SENSOR_ACCELEROMETER_X 0
#define RETRO_SENSOR_ACCELEROMETER_Y 1
#define RETRO_SENSOR_ACCELEROMETER_Z 2
typedef bool (*retro_set_sensor_state_t)(unsigned port,
enum retro_sensor_action action, unsigned rate);
typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id);
struct retro_sensor_interface
{
retro_set_sensor_state_t set_sensor_state;
retro_sensor_get_input_t get_sensor_input;
};
enum retro_camera_buffer
{
RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,
RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,
RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
};
/* Starts the camera driver. Can only be called in retro_run(). */
typedef bool (*retro_camera_start_t)(void);
/* Stops the camera driver. Can only be called in retro_run(). */
typedef void (*retro_camera_stop_t)(void);
/* Callback which signals when the camera driver is initialized
* and/or deinitialized.
* retro_camera_start_t can be called in initialized callback.
*/
typedef void (*retro_camera_lifetime_status_t)(void);
/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
* Width, height and pitch are similar to retro_video_refresh_t.
* First pixel is top-left origin.
*/
typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
unsigned width, unsigned height, size_t pitch);
/* A callback for when OpenGL textures are used.
*
* texture_id is a texture owned by camera driver.
* Its state or content should be considered immutable, except for things like
* texture filtering and clamping.
*
* texture_target is the texture target for the GL texture.
* These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly
* more depending on extensions.
*
* affine points to a packed 3x3 column-major matrix used to apply an affine
* transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0))
* After transform, normalized texture coord (0, 0) should be bottom-left
* and (1, 1) should be top-right (or (width, height) for RECTANGLE).
*
* GL-specific typedefs are avoided here to avoid relying on gl.h in
* the API definition.
*/
typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id,
unsigned texture_target, const float *affine);
struct retro_camera_callback
{
/* Set by libretro core.
* Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER).
*/
uint64_t caps;
unsigned width; /* Desired resolution for camera. Is only used as a hint. */
unsigned height;
retro_camera_start_t start; /* Set by frontend. */
retro_camera_stop_t stop; /* Set by frontend. */
/* Set by libretro core if raw framebuffer callbacks will be used. */
retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;
/* Set by libretro core if OpenGL texture callbacks will be used. */
retro_camera_frame_opengl_texture_t frame_opengl_texture;
/* Set by libretro core. Called after camera driver is initialized and
* ready to be started.
* Can be NULL, in which this callback is not called.
*/
retro_camera_lifetime_status_t initialized;
/* Set by libretro core. Called right before camera driver is
* deinitialized.
* Can be NULL, in which this callback is not called.
*/
retro_camera_lifetime_status_t deinitialized;
};
/* Sets the interval of time and/or distance at which to update/poll
* location-based data.
*
* To ensure compatibility with all location-based implementations,
* values for both interval_ms and interval_distance should be provided.
*
* interval_ms is the interval expressed in milliseconds.
* interval_distance is the distance interval expressed in meters.
*/
typedef void (*retro_location_set_interval_t)(unsigned interval_ms,
unsigned interval_distance);
/* Start location services. The device will start listening for changes to the
* current location at regular intervals (which are defined with
* retro_location_set_interval_t). */
typedef bool (*retro_location_start_t)(void);
/* Stop location services. The device will stop listening for changes
* to the current location. */
typedef void (*retro_location_stop_t)(void);
/* Get the position of the current location. Will set parameters to
* 0 if no new location update has happened since the last time. */
typedef bool (*retro_location_get_position_t)(double *lat, double *lon,
double *horiz_accuracy, double *vert_accuracy);
/* Callback which signals when the location driver is initialized
* and/or deinitialized.
* retro_location_start_t can be called in initialized callback.
*/
typedef void (*retro_location_lifetime_status_t)(void);
struct retro_location_callback
{
retro_location_start_t start;
retro_location_stop_t stop;
retro_location_get_position_t get_position;
retro_location_set_interval_t set_interval;
retro_location_lifetime_status_t initialized;
retro_location_lifetime_status_t deinitialized;
};
enum retro_rumble_effect
{
RETRO_RUMBLE_STRONG = 0,
RETRO_RUMBLE_WEAK = 1,
RETRO_RUMBLE_DUMMY = INT_MAX
};
/* Sets rumble state for joypad plugged in port 'port'.
* Rumble effects are controlled independently,
* and setting e.g. strong rumble does not override weak rumble.
* Strength has a range of [0, 0xffff].
*
* Returns true if rumble state request was honored.
* Calling this before first retro_run() is likely to return false. */
typedef bool (*retro_set_rumble_state_t)(unsigned port,
enum retro_rumble_effect effect, uint16_t strength);
struct retro_rumble_interface
{
retro_set_rumble_state_t set_rumble_state;
};
/* Notifies libretro that audio data should be written. */
typedef void (*retro_audio_callback_t)(void);
/* True: Audio driver in frontend is active, and callback is
* expected to be called regularily.
* False: Audio driver in frontend is paused or inactive.
* Audio callback will not be called until set_state has been
* called with true.
* Initial state is false (inactive).
*/
typedef void (*retro_audio_set_state_callback_t)(bool enabled);
struct retro_audio_callback
{
retro_audio_callback_t callback;
retro_audio_set_state_callback_t set_state;
};
/* Notifies a libretro core of time spent since last invocation
* of retro_run() in microseconds.
*
* It will be called right before retro_run() every frame.
* The frontend can tamper with timing to support cases like
* fast-forward, slow-motion and framestepping.
*
* In those scenarios the reference frame time value will be used. */
typedef int64_t retro_usec_t;
typedef void (*retro_frame_time_callback_t)(retro_usec_t usec);
struct retro_frame_time_callback
{
retro_frame_time_callback_t callback;
/* Represents the time of one frame. It is computed as
* 1000000 / fps, but the implementation will resolve the
* rounding to ensure that framestepping, etc is exact. */
retro_usec_t reference;
};
/* Pass this to retro_video_refresh_t if rendering to hardware.
* Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
* */
#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
/* Invalidates the current HW context.
* Any GL state is lost, and must not be deinitialized explicitly.
* If explicit deinitialization is desired by the libretro core,
* it should implement context_destroy callback.
* If called, all GPU resources must be reinitialized.
* Usually called when frontend reinits video driver.
* Also called first time video driver is initialized,
* allowing libretro core to initialize resources.
*/
typedef void (*retro_hw_context_reset_t)(void);
/* Gets current framebuffer which is to be rendered to.
* Could change every frame potentially.
*/
typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void);
/* Get a symbol from HW context. */
typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym);
enum retro_hw_context_type
{
RETRO_HW_CONTEXT_NONE = 0,
/* OpenGL 2.x. Driver can choose to use latest compatibility context. */
RETRO_HW_CONTEXT_OPENGL = 1,
/* OpenGL ES 2.0. */
RETRO_HW_CONTEXT_OPENGLES2 = 2,
/* Modern desktop core GL context. Use version_major/
* version_minor fields to set GL version. */
RETRO_HW_CONTEXT_OPENGL_CORE = 3,
/* OpenGL ES 3.0 */
RETRO_HW_CONTEXT_OPENGLES3 = 4,
/* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
* use the corresponding enums directly. */
RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
RETRO_HW_CONTEXT_DUMMY = INT_MAX
};
struct retro_hw_render_callback
{
/* Which API to use. Set by libretro core. */
enum retro_hw_context_type context_type;
/* Called when a context has been created or when it has been reset.
* An OpenGL context is only valid after context_reset() has been called.
*
* When context_reset is called, OpenGL resources in the libretro
* implementation are guaranteed to be invalid.
*
* It is possible that context_reset is called multiple times during an
* application lifecycle.
* If context_reset is called without any notification (context_destroy),
* the OpenGL context was lost and resources should just be recreated
* without any attempt to "free" old resources.
*/
retro_hw_context_reset_t context_reset;
/* Set by frontend. */
retro_hw_get_current_framebuffer_t get_current_framebuffer;
/* Set by frontend. */
retro_hw_get_proc_address_t get_proc_address;
/* Set if render buffers should have depth component attached. */
bool depth;
/* Set if stencil buffers should be attached. */
bool stencil;
/* If depth and stencil are true, a packed 24/8 buffer will be added.
* Only attaching stencil is invalid and will be ignored. */
/* Use conventional bottom-left origin convention. If false,
* standard libretro top-left origin semantics are used. */
bool bottom_left_origin;
/* Major version number for core GL context or GLES 3.1+. */
unsigned version_major;
/* Minor version number for core GL context or GLES 3.1+. */
unsigned version_minor;
/* If this is true, the frontend will go very far to avoid
* resetting context in scenarios like toggling fullscreen, etc.
*/
bool cache_context;
/* The reset callback might still be called in extreme situations
* such as if the context is lost beyond recovery.
*
* For optimal stability, set this to false, and allow context to be
* reset at any time.
*/
/* A callback to be called before the context is destroyed in a
* controlled way by the frontend. */
retro_hw_context_reset_t context_destroy;
/* OpenGL resources can be deinitialized cleanly at this step.
* context_destroy can be set to NULL, in which resources will
* just be destroyed without any notification.
*
* Even when context_destroy is non-NULL, it is possible that
* context_reset is called without any destroy notification.
* This happens if context is lost by external factors (such as
* notified by GL_ARB_robustness).
*
* In this case, the context is assumed to be already dead,
* and the libretro implementation must not try to free any OpenGL
* resources in the subsequent context_reset.
*/
/* Creates a debug context. */
bool debug_context;
};
/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
* Called by the frontend in response to keyboard events.
* down is set if the key is being pressed, or false if it is being released.
* keycode is the RETROK value of the char.
* character is the text character of the pressed key. (UTF-32).
* key_modifiers is a set of RETROKMOD values or'ed together.
*
* The pressed/keycode state can be indepedent of the character.
* It is also possible that multiple characters are generated from a
* single keypress.
* Keycode events should be treated separately from character events.
* However, when possible, the frontend should try to synchronize these.
* If only a character is posted, keycode should be RETROK_UNKNOWN.
*
* Similarily if only a keycode event is generated with no corresponding
* character, character should be 0.
*/
typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode,
uint32_t character, uint16_t key_modifiers);
struct retro_keyboard_callback
{
retro_keyboard_event_t callback;
};
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
* Should be set for implementations which can swap out multiple disk
* images in runtime.
*
* If the implementation can do this automatically, it should strive to do so.
* However, there are cases where the user must manually do so.
*
* Overview: To swap a disk image, eject the disk image with
* set_eject_state(true).
* Set the disk index with set_image_index(index). Insert the disk again
* with set_eject_state(false).
*/
/* If ejected is true, "ejects" the virtual disk tray.
* When ejected, the disk image index can be set.
*/
typedef bool (*retro_set_eject_state_t)(bool ejected);
/* Gets current eject state. The initial state is 'not ejected'. */
typedef bool (*retro_get_eject_state_t)(void);
/* Gets current disk index. First disk is index 0.
* If return value is >= get_num_images(), no disk is currently inserted.
*/
typedef unsigned (*retro_get_image_index_t)(void);
/* Sets image index. Can only be called when disk is ejected.
* The implementation supports setting "no disk" by using an
* index >= get_num_images().
*/
typedef bool (*retro_set_image_index_t)(unsigned index);
/* Gets total number of images which are available to use. */
typedef unsigned (*retro_get_num_images_t)(void);
struct retro_game_info;
/* Replaces the disk image associated with index.
* Arguments to pass in info have same requirements as retro_load_game().
* Virtual disk tray must be ejected when calling this.
*
* Replacing a disk image with info = NULL will remove the disk image
* from the internal list.
* As a result, calls to get_image_index() can change.
*
* E.g. replace_image_index(1, NULL), and previous get_image_index()
* returned 4 before.
* Index 1 will be removed, and the new index is 3.
*/
typedef bool (*retro_replace_image_index_t)(unsigned index,
const struct retro_game_info *info);
/* Adds a new valid index (get_num_images()) to the internal disk list.
* This will increment subsequent return values from get_num_images() by 1.
* This image index cannot be used until a disk image has been set
* with replace_image_index. */
typedef bool (*retro_add_image_index_t)(void);
struct retro_disk_control_callback
{
retro_set_eject_state_t set_eject_state;
retro_get_eject_state_t get_eject_state;
retro_get_image_index_t get_image_index;
retro_set_image_index_t set_image_index;
retro_get_num_images_t get_num_images;
retro_replace_image_index_t replace_image_index;
retro_add_image_index_t add_image_index;
};
enum retro_pixel_format
{
/* 0RGB1555, native endian.
* 0 bit must be set to 0.
* This pixel format is default for compatibility concerns only.
* If a 15/16-bit pixel format is desired, consider using RGB565. */
RETRO_PIXEL_FORMAT_0RGB1555 = 0,
/* XRGB8888, native endian.
* X bits are ignored. */
RETRO_PIXEL_FORMAT_XRGB8888 = 1,
/* RGB565, native endian.
* This pixel format is the recommended format to use if a 15/16-bit
* format is desired as it is the pixel format that is typically
* available on a wide range of low-power devices.
*
* It is also natively supported in APIs like OpenGL ES. */
RETRO_PIXEL_FORMAT_RGB565 = 2,
/* Ensure sizeof() == sizeof(int). */
RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX
};
struct retro_message
{
const char *msg; /* Message to be displayed. */
unsigned frames; /* Duration in frames of message. */
};
/* Describes how the libretro implementation maps a libretro input bind
* to its internal input system through a human readable string.
* This string can be used to better let a user configure input. */
struct retro_input_descriptor
{
/* Associates given parameters with a description. */
unsigned port;
unsigned device;
unsigned index;
unsigned id;
/* Human readable description for parameters.
* The pointer must remain valid until
* retro_unload_game() is called. */
const char *description;
};
struct retro_system_info
{
/* All pointers are owned by libretro implementation, and pointers must
* remain valid until retro_deinit() is called. */
const char *library_name; /* Descriptive name of library. Should not
* contain any version numbers, etc. */
const char *library_version; /* Descriptive version of core. */
const char *valid_extensions; /* A string listing probably content
* extensions the core will be able to
* load, separated with pipe.
* I.e. "bin|rom|iso".
* Typically used for a GUI to filter
* out extensions. */
/* If true, retro_load_game() is guaranteed to provide a valid pathname
* in retro_game_info::path.
* ::data and ::size are both invalid.
*
* If false, ::data and ::size are guaranteed to be valid, but ::path
* might not be valid.
*
* This is typically set to true for libretro implementations that must
* load from file.
* Implementations should strive for setting this to false, as it allows
* the frontend to perform patching, etc. */
bool need_fullpath;
/* If true, the frontend is not allowed to extract any archives before
* loading the real content.
* Necessary for certain libretro implementations that load games
* from zipped archives. */
bool block_extract;
};
struct retro_game_geometry
{
unsigned base_width; /* Nominal video width of game. */
unsigned base_height; /* Nominal video height of game. */
unsigned max_width; /* Maximum possible width of game. */
unsigned max_height; /* Maximum possible height of game. */
float aspect_ratio; /* Nominal aspect ratio of game. If
* aspect_ratio is <= 0.0, an aspect ratio
* of base_width / base_height is assumed.
* A frontend could override this setting,
* if desired. */
};
struct retro_system_timing
{
double fps; /* FPS of video content. */
double sample_rate; /* Sampling rate of audio. */
};
struct retro_system_av_info
{
struct retro_game_geometry geometry;
struct retro_system_timing timing;
};
struct retro_variable
{
/* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
* If NULL, obtains the complete environment string if more
* complex parsing is necessary.
* The environment string is formatted as key-value pairs
* delimited by semicolons as so:
* "key1=value1;key2=value2;..."
*/
const char *key;
/* Value to be obtained. If key does not exist, it is set to NULL. */
const char *value;
};
struct retro_game_info
{
const char *path; /* Path to game, UTF-8 encoded.
* Usually used as a reference.
* May be NULL if rom was loaded from stdin
* or similar.
* retro_system_info::need_fullpath guaranteed
* that this path is valid. */
const void *data; /* Memory buffer of loaded game. Will be NULL
* if need_fullpath was set. */
size_t size; /* Size of memory buffer. */
const char *meta; /* String of implementation specific meta-data. */
};
/* Callbacks */
/* Environment callback. Gives implementations a way of performing
* uncommon tasks. Extensible. */
typedef bool (*retro_environment_t)(unsigned cmd, void *data);
/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian
* unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
*
* Width and height specify dimensions of buffer.
* Pitch specifices length in bytes between two lines in buffer.
*
* For performance reasons, it is highly recommended to have a frame
* that is packed in memory, i.e. pitch == width * byte_per_pixel.
* Certain graphic APIs, such as OpenGL ES, do not like textures
* that are not packed in memory.
*/
typedef void (*retro_video_refresh_t)(const void *data, unsigned width,
unsigned height, size_t pitch);
/* Renders a single audio frame. Should only be used if implementation
* generates a single sample at a time.
* Format is signed 16-bit native endian.
*/
typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
/* Renders multiple audio frames in one go.
*
* One frame is defined as a sample of left and right channels, interleaved.
* I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
* Only one of the audio callbacks must ever be used.
*/
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data,
size_t frames);
/* Polls input. */
typedef void (*retro_input_poll_t)(void);
/* Queries for input for player 'port'. device will be masked with
* RETRO_DEVICE_MASK.
*
* Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that
* have been set with retro_set_controller_port_device()
* will still use the higher level RETRO_DEVICE_JOYPAD to request input.
*/
typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device,
unsigned index, unsigned id);
/* Sets callbacks. retro_set_environment() is guaranteed to be called
* before retro_init().
*
* The rest of the set_* functions are guaranteed to have been called
* before the first call to retro_run() is made. */
void retro_set_environment(retro_environment_t);
void retro_set_video_refresh(retro_video_refresh_t);
void retro_set_audio_sample(retro_audio_sample_t);
void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
void retro_set_input_poll(retro_input_poll_t);
void retro_set_input_state(retro_input_state_t);
/* Library global initialization/deinitialization. */
void retro_init(void);
void retro_deinit(void);
/* Must return RETRO_API_VERSION. Used to validate ABI compatibility
* when the API is revised. */
unsigned retro_api_version(void);
/* Gets statically known system info. Pointers provided in *info
* must be statically allocated.
* Can be called at any time, even before retro_init(). */
void retro_get_system_info(struct retro_system_info *info);
/* Gets information about system audio/video timings and geometry.
* Can be called only after retro_load_game() has successfully completed.
* NOTE: The implementation of this function might not initialize every
* variable if needed.
* E.g. geom.aspect_ratio might not be initialized if core doesn't
* desire a particular aspect ratio. */
void retro_get_system_av_info(struct retro_system_av_info *info);
/* Sets device to be used for player 'port'.
* By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all
* available ports.
* Setting a particular device type is not a guarantee that libretro cores
* will only poll input based on that particular device type. It is only a
* hint to the libretro core when a core cannot automatically detect the
* appropriate input device type on its own. It is also relevant when a
* core can change its behavior depending on device type. */
void retro_set_controller_port_device(unsigned port, unsigned device);
/* Resets the current game. */
void retro_reset(void);
/* Runs the game for one video frame.
* During retro_run(), input_poll callback must be called at least once.
*
* If a frame is not rendered for reasons where a game "dropped" a frame,
* this still counts as a frame, and retro_run() should explicitly dupe
* a frame if GET_CAN_DUPE returns true.
* In this case, the video callback can take a NULL argument for data.
*/
void retro_run(void);
/* Returns the amount of data the implementation requires to serialize
* internal state (save states).
* Between calls to retro_load_game() and retro_unload_game(), the
* returned size is never allowed to be larger than a previous returned
* value, to ensure that the frontend can allocate a save state buffer once.
*/
size_t retro_serialize_size(void);
/* Serializes internal state. If failed, or size is lower than
* retro_serialize_size(), it should return false, true otherwise. */
bool retro_serialize(void *data, size_t size);
bool retro_unserialize(const void *data, size_t size);
void retro_cheat_reset(void);
void retro_cheat_set(unsigned index, bool enabled, const char *code);
/* Loads a game. */
bool retro_load_game(const struct retro_game_info *game);
/* Loads a "special" kind of game. Should not be used,
* except in extreme cases. */
bool retro_load_game_special(
unsigned game_type,
const struct retro_game_info *info, size_t num_info
);
/* Unloads a currently loaded game. */
void retro_unload_game(void);
/* Gets region of game. */
unsigned retro_get_region(void);
/* Gets region of memory. */
void *retro_get_memory_data(unsigned id);
size_t retro_get_memory_size(unsigned id);
#ifdef __cplusplus
}
#endif
#endif
nestopia-1.47/libretro/link.T 0000664 0000000 0000000 00000000047 12644314416 0016201 0 ustar 00root root 0000000 0000000 {
global: retro_*;
local: *;
};
nestopia-1.47/libretro/msvc/ 0000775 0000000 0000000 00000000000 12644314416 0016066 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/msvc/msvc-2003-xbox1.bat 0000664 0000000 0000000 00000003042 12644314416 0021146 0 ustar 00root root 0000000 0000000 @SET VSINSTALLDIR=C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE
@SET VCINSTALLDIR=C:\Program Files\Microsoft Visual Studio .NET 2003
@SET FrameworkDir=C:\WINDOWS\Microsoft.NET\Framework
@SET FrameworkVersion=v1.1.4322
@SET FrameworkSDKDir=C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1
@rem Root of Visual Studio common files.
@if "%VSINSTALLDIR%"=="" goto Usage
@if "%VCINSTALLDIR%"=="" set VCINSTALLDIR=%VSINSTALLDIR%
@rem
@rem Root of Visual Studio ide installed files.
@rem
@set DevEnvDir=%VSINSTALLDIR%
@rem
@rem Root of Visual C++ installed files.
@rem
@set MSVCDir=%VCINSTALLDIR%\VC7
@rem
@echo Setting environment for using Microsoft Visual Studio .NET 2003 tools.
@echo (If you have another version of Visual Studio or Visual C++ installed and wish
@echo to use its tools from the command line, run vcvars32.bat for that version.)
@rem
@REM %VCINSTALLDIR%\Common7\Tools dir is added only for real setup.
@set PATH=%DevEnvDir%;%MSVCDir%\BIN;%VCINSTALLDIR%\Common7\Tools;%VCINSTALLDIR%\Common7\Tools\bin\prerelease;%VCINSTALLDIR%\Common7\Tools\bin;%FrameworkSDKDir%\bin;%FrameworkDir%\%FrameworkVersion%;%PATH%;
@set INCLUDE=%MSVCDir%\ATLMFC\INCLUDE;%MSVCDir%\INCLUDE;%FrameworkSDKDir%\include;%INCLUDE%;%XDK%\xbox\include
@set LIB=%MSVCDir%\ATLMFC\LIB;%MSVCDir%\LIB;%MSVCDir%\PlatformSDK\lib;%XDK%\lib;%XDK%\xbox\lib;%LIB%
@goto end
:Usage
@echo. VSINSTALLDIR variable is not set.
@echo.
@echo SYNTAX: %0
@goto end
:end
devenv /clean Release_LTCG msvc-2003-xbox1.sln
devenv /build Release_LTCG msvc-2003-xbox1.sln
exit
nestopia-1.47/libretro/msvc/msvc-2003-xbox1.sln 0000664 0000000 0000000 00000002754 12644314416 0021205 0 ustar 00root root 0000000 0000000 Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2003-xbox1", "msvc-2003-xbox1/msvc-2003-xbox1.vcproj", "{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Profile = Profile
Profile_FastCap = Profile_FastCap
Release = Release
Release_LTCG = Release_LTCG
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Debug.ActiveCfg = Debug|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Debug.Build.0 = Debug|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Profile.ActiveCfg = Profile|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Profile.Build.0 = Profile|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Profile_FastCap.ActiveCfg = Profile_FastCap|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Profile_FastCap.Build.0 = Profile_FastCap|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Release.ActiveCfg = Release|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Release.Build.0 = Release|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Release_LTCG.ActiveCfg = Release_LTCG|Xbox
{E3D2A7C9-228F-4706-AFCD-992D7B39ADCF}.Release_LTCG.Build.0 = Release_LTCG|Xbox
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
nestopia-1.47/libretro/msvc/msvc-2003-xbox1/ 0000775 0000000 0000000 00000000000 12644314416 0020457 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/msvc/msvc-2003-xbox1/msvc-2003-xbox1.vcproj 0000664 0000000 0000000 00000102056 12644314416 0024301 0 ustar 00root root 0000000 0000000
nestopia-1.47/libretro/msvc/msvc-2003-xbox1/stdint.h 0000664 0000000 0000000 00000017100 12644314416 0022134 0 ustar 00root root 0000000 0000000 // ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __RARCH_STDINT_H
#define __RARCH_STDINT_H
#if _MSC_VER && (_MSC_VER < 1600)
//pre-MSVC 2010 needs an implementation of stdint.h
#if _MSC_VER > 1000
#pragma once
#endif
#include
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif // __STDC_CONSTANT_MACROS ]
#else
//sanity for everything else
#include
#endif
#endif
nestopia-1.47/libretro/msvc/msvc-2010-360.bat 0000664 0000000 0000000 00000007767 12644314416 0020435 0 ustar 00root root 0000000 0000000 @echo off
@echo Setting environment for using Microsoft Visual Studio 2010 x86 tools.
@call :GetVSCommonToolsDir
@if "%VS100COMNTOOLS%"=="" goto error_no_VS100COMNTOOLSDIR
@call "%VS100COMNTOOLS%VCVarsQueryRegistry.bat" 32bit No64bit
@if "%VSINSTALLDIR%"=="" goto error_no_VSINSTALLDIR
@if "%FrameworkDir32%"=="" goto error_no_FrameworkDIR32
@if "%FrameworkVersion32%"=="" goto error_no_FrameworkVer32
@if "%Framework35Version%"=="" goto error_no_Framework35Version
@set FrameworkDir=%FrameworkDir32%
@set FrameworkVersion=%FrameworkVersion32%
@if not "%WindowsSdkDir%" == "" (
@set "PATH=%WindowsSdkDir%bin\NETFX 4.0 Tools;%WindowsSdkDir%bin;%PATH%"
@set "INCLUDE=%WindowsSdkDir%include;%INCLUDE%"
@set "LIB=%WindowsSdkDir%lib;%LIB%"
)
@rem
@rem Root of Visual Studio IDE installed files.
@rem
@set DevEnvDir=%VSINSTALLDIR%Common7\IDE\
@rem PATH
@rem ----
@if exist "%VSINSTALLDIR%Team Tools\Performance Tools" (
@set "PATH=%VSINSTALLDIR%Team Tools\Performance Tools;%PATH%"
)
@if exist "%ProgramFiles%\HTML Help Workshop" set PATH=%ProgramFiles%\HTML Help Workshop;%PATH%
@if exist "%ProgramFiles(x86)%\HTML Help Workshop" set PATH=%ProgramFiles(x86)%\HTML Help Workshop;%PATH%
@if exist "%VCINSTALLDIR%VCPackages" set PATH=%VCINSTALLDIR%VCPackages;%PATH%
@set PATH=%FrameworkDir%%Framework35Version%;%PATH%
@set PATH=%FrameworkDir%%FrameworkVersion%;%PATH%
@set PATH=%VSINSTALLDIR%Common7\Tools;%PATH%
@if exist "%VCINSTALLDIR%BIN" set PATH=%VCINSTALLDIR%BIN;%PATH%
@set PATH=%DevEnvDir%;%PATH%
@if exist "%VSINSTALLDIR%VSTSDB\Deploy" (
@set "PATH=%VSINSTALLDIR%VSTSDB\Deploy;%PATH%"
)
@if not "%FSHARPINSTALLDIR%" == "" (
@set "PATH=%FSHARPINSTALLDIR%;%PATH%"
)
@rem INCLUDE
@rem -------
@if exist "%VCINSTALLDIR%ATLMFC\INCLUDE" set INCLUDE=%VCINSTALLDIR%ATLMFC\INCLUDE;%INCLUDE%
@if exist "%VCINSTALLDIR%INCLUDE" set INCLUDE=%VCINSTALLDIR%INCLUDE;%INCLUDE%
@rem LIB
@rem ---
@if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIB=%VCINSTALLDIR%ATLMFC\LIB;%LIB%
@if exist "%VCINSTALLDIR%LIB" set LIB=%VCINSTALLDIR%LIB;%LIB%
@rem LIBPATH
@rem -------
@if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIBPATH=%VCINSTALLDIR%ATLMFC\LIB;%LIBPATH%
@if exist "%VCINSTALLDIR%LIB" set LIBPATH=%VCINSTALLDIR%LIB;%LIBPATH%
@set LIBPATH=%FrameworkDir%%Framework35Version%;%LIBPATH%
@set LIBPATH=%FrameworkDir%%FrameworkVersion%;%LIBPATH%
@goto end
@REM -----------------------------------------------------------------------
:GetVSCommonToolsDir
@set VS100COMNTOOLS=
@call :GetVSCommonToolsDirHelper32 HKLM > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper32 HKCU > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKLM > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKCU > nul 2>&1
@exit /B 0
:GetVSCommonToolsDirHelper32
@for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO (
@if "%%i"=="10.0" (
@SET "VS100COMNTOOLS=%%k"
)
)
@if "%VS100COMNTOOLS%"=="" exit /B 1
@SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\"
@exit /B 0
:GetVSCommonToolsDirHelper64
@for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO (
@if "%%i"=="10.0" (
@SET "VS100COMNTOOLS=%%k"
)
)
@if "%VS100COMNTOOLS%"=="" exit /B 1
@SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\"
@exit /B 0
@REM -----------------------------------------------------------------------
:error_no_VS100COMNTOOLSDIR
@echo ERROR: Cannot determine the location of the VS Common Tools folder.
@goto end
:error_no_VSINSTALLDIR
@echo ERROR: Cannot determine the location of the VS installation.
@goto end
:error_no_FrameworkDIR32
@echo ERROR: Cannot determine the location of the .NET Framework 32bit installation.
@goto end
:error_no_FrameworkVer32
@echo ERROR: Cannot determine the version of the .NET Framework 32bit installation.
@goto end
:error_no_Framework35Version
@echo ERROR: Cannot determine the .NET Framework 3.5 version.
@goto end
:end
msbuild msvc-2010-360.sln /p:Configuration=Release_LTCG /target:clean
msbuild msvc-2010-360.sln /p:Configuration=Release_LTCG
exit
nestopia-1.47/libretro/msvc/msvc-2010-360.sln 0000664 0000000 0000000 00000003516 12644314416 0020447 0 ustar 00root root 0000000 0000000
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2010-360", "msvc-2010-360\msvc-2010-360.vcxproj", "{C4D4209C-05D5-404F-8925-BD7ABA58D686}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeAnalysis|Xbox 360 = CodeAnalysis|Xbox 360
Debug|Xbox 360 = Debug|Xbox 360
Profile_FastCap|Xbox 360 = Profile_FastCap|Xbox 360
Profile|Xbox 360 = Profile|Xbox 360
Release_LTCG|Xbox 360 = Release_LTCG|Xbox 360
Release|Xbox 360 = Release|Xbox 360
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.CodeAnalysis|Xbox 360.ActiveCfg = CodeAnalysis|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.CodeAnalysis|Xbox 360.Build.0 = CodeAnalysis|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Debug|Xbox 360.ActiveCfg = Debug|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Debug|Xbox 360.Build.0 = Debug|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Profile_FastCap|Xbox 360.ActiveCfg = Profile_FastCap|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Profile_FastCap|Xbox 360.Build.0 = Profile_FastCap|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Profile|Xbox 360.ActiveCfg = Profile|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Profile|Xbox 360.Build.0 = Profile|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release_LTCG|Xbox 360.ActiveCfg = Release_LTCG|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release_LTCG|Xbox 360.Build.0 = Release_LTCG|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release|Xbox 360.ActiveCfg = Release|Xbox 360
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release|Xbox 360.Build.0 = Release|Xbox 360
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
nestopia-1.47/libretro/msvc/msvc-2010-360/ 0000775 0000000 0000000 00000000000 12644314416 0017724 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj 0000664 0000000 0000000 00000102237 12644314416 0023204 0 ustar 00root root 0000000 0000000
CodeAnalysisXbox 360DebugXbox 360ProfileXbox 360Profile_FastCapXbox 360ReleaseXbox 360Release_LTCGXbox 360{C4D4209C-05D5-404F-8925-BD7ABA58D686}Xbox360ProjStaticLibraryMultiByteStaticLibraryMultiByteStaticLibraryMultiByteStaticLibraryMultiByteStaticLibraryMultiByteStaticLibrarytrueMultiByte$(OutDir)msvc-2010-360.lib$(OutDir)msvc-2010-360.lib$(OutDir)msvc-2010-360.lib$(OutDir)msvc-2010-360.lib$(OutDir)msvc-2010-360.lib$(OutDir)msvc-2010-360.libNotUsingLevel3ProgramDatabaseDisabledfalsetruefalseMultiThreadedDebug_DEBUG;_XBOX;_LIB;%(PreprocessorDefinitions);__LIBRETRO__;NST_NO_ZLIB;_SECURE_SCL=0Callcap$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)trueNotUsingLevel4ProgramDatabaseDisabledfalsetrueAnalyzeOnlyfalseMultiThreadedDebug_DEBUG;_XBOX;_LIB;%(PreprocessorDefinitions);NST_MSVC_OPTIMIZE;__LIBRETRO__;NST_NO_ZLIB;_SECURE_SCL=0CallcaptrueLevel3NotUsingFulltruefalsetrueProgramDatabaseSizefalseMultiThreadedNDEBUG;_XBOX;PROFILE;_LIB;%(PreprocessorDefinitions);__LIBRETRO__;NST_MSVC_OPTIMIZE;NST_NO_ZLIB;_SECURE_SCL=0Callcap$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truefalsexapilib.lib;%(IgnoreSpecificDefaultLibraries)trueLevel3NotUsingFulltruefalsetrueProgramDatabaseFastcapSizefalseMultiThreadedNDEBUG;_XBOX;PROFILE;FASTCAP;_LIB;%(PreprocessorDefinitions);__LIBRETRO__;NST_MSVC_OPTIMIZE;NST_NO_ZLIB;_SECURE_SCL=0$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truefalsetrueLevel3NotUsingFulltruetrueProgramDatabaseSizefalsefalseMultiThreadedNDEBUG;_XBOX;_LIB;%(PreprocessorDefinitions);NST_NO_ZLIB;__LIBRETRO__;_SECURE_SCL=0$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truetruetrueLevel3NotUsingFulltruetrueProgramDatabaseSizefalsefalseMultiThreadedNDEBUG;_XBOX;LTCG;_LIB;%(PreprocessorDefinitions);__LIBRETRO__;NST_NO_ZLIB;_SECURE_SCL=0$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truetruetrue
nestopia-1.47/libretro/msvc/msvc-2010-360/msvc-2010-360.vcxproj.filters 0000664 0000000 0000000 00000116401 12644314416 0024651 0 ustar 00root root 0000000 0000000
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx{93995380-89BD-4b04-88EB-625FBE52EBFB}h;hpp;hxx;hm;inl;inc;xsd{bb2769c3-f85a-46ed-b7fa-9b479cacb927}{cfd4b486-09df-4d1c-8ae5-d39d256c047a}{f3d53a31-83d2-40ac-8c5d-ad9324f3d392}{89661cd6-755f-4ecd-89a3-ac7caf2d908c}{21634da5-491c-4dd3-b53b-cc17f64c07e2}{763265c6-4c2c-4a36-9561-d7bc02c13c07}Source Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\vssystemSource Files\core\vssystemSource Files\core\vssystemSource Files\core\vssystemSource Files\libretroSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\api
nestopia-1.47/libretro/msvc/msvc-2010.bat 0000664 0000000 0000000 00000007745 12644314416 0020123 0 ustar 00root root 0000000 0000000 @echo off
@echo Setting environment for using Microsoft Visual Studio 2010 x86 tools.
@call :GetVSCommonToolsDir
@if "%VS100COMNTOOLS%"=="" goto error_no_VS100COMNTOOLSDIR
@call "%VS100COMNTOOLS%VCVarsQueryRegistry.bat" 32bit No64bit
@if "%VSINSTALLDIR%"=="" goto error_no_VSINSTALLDIR
@if "%FrameworkDir32%"=="" goto error_no_FrameworkDIR32
@if "%FrameworkVersion32%"=="" goto error_no_FrameworkVer32
@if "%Framework35Version%"=="" goto error_no_Framework35Version
@set FrameworkDir=%FrameworkDir32%
@set FrameworkVersion=%FrameworkVersion32%
@if not "%WindowsSdkDir%" == "" (
@set "PATH=%WindowsSdkDir%bin\NETFX 4.0 Tools;%WindowsSdkDir%bin;%PATH%"
@set "INCLUDE=%WindowsSdkDir%include;%INCLUDE%"
@set "LIB=%WindowsSdkDir%lib;%LIB%"
)
@rem
@rem Root of Visual Studio IDE installed files.
@rem
@set DevEnvDir=%VSINSTALLDIR%Common7\IDE\
@rem PATH
@rem ----
@if exist "%VSINSTALLDIR%Team Tools\Performance Tools" (
@set "PATH=%VSINSTALLDIR%Team Tools\Performance Tools;%PATH%"
)
@if exist "%ProgramFiles%\HTML Help Workshop" set PATH=%ProgramFiles%\HTML Help Workshop;%PATH%
@if exist "%ProgramFiles(x86)%\HTML Help Workshop" set PATH=%ProgramFiles(x86)%\HTML Help Workshop;%PATH%
@if exist "%VCINSTALLDIR%VCPackages" set PATH=%VCINSTALLDIR%VCPackages;%PATH%
@set PATH=%FrameworkDir%%Framework35Version%;%PATH%
@set PATH=%FrameworkDir%%FrameworkVersion%;%PATH%
@set PATH=%VSINSTALLDIR%Common7\Tools;%PATH%
@if exist "%VCINSTALLDIR%BIN" set PATH=%VCINSTALLDIR%BIN;%PATH%
@set PATH=%DevEnvDir%;%PATH%
@if exist "%VSINSTALLDIR%VSTSDB\Deploy" (
@set "PATH=%VSINSTALLDIR%VSTSDB\Deploy;%PATH%"
)
@if not "%FSHARPINSTALLDIR%" == "" (
@set "PATH=%FSHARPINSTALLDIR%;%PATH%"
)
@rem INCLUDE
@rem -------
@if exist "%VCINSTALLDIR%ATLMFC\INCLUDE" set INCLUDE=%VCINSTALLDIR%ATLMFC\INCLUDE;%INCLUDE%
@if exist "%VCINSTALLDIR%INCLUDE" set INCLUDE=%VCINSTALLDIR%INCLUDE;%INCLUDE%
@rem LIB
@rem ---
@if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIB=%VCINSTALLDIR%ATLMFC\LIB;%LIB%
@if exist "%VCINSTALLDIR%LIB" set LIB=%VCINSTALLDIR%LIB;%LIB%
@rem LIBPATH
@rem -------
@if exist "%VCINSTALLDIR%ATLMFC\LIB" set LIBPATH=%VCINSTALLDIR%ATLMFC\LIB;%LIBPATH%
@if exist "%VCINSTALLDIR%LIB" set LIBPATH=%VCINSTALLDIR%LIB;%LIBPATH%
@set LIBPATH=%FrameworkDir%%Framework35Version%;%LIBPATH%
@set LIBPATH=%FrameworkDir%%FrameworkVersion%;%LIBPATH%
@goto end
@REM -----------------------------------------------------------------------
:GetVSCommonToolsDir
@set VS100COMNTOOLS=
@call :GetVSCommonToolsDirHelper32 HKLM > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper32 HKCU > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKLM > nul 2>&1
@if errorlevel 1 call :GetVSCommonToolsDirHelper64 HKCU > nul 2>&1
@exit /B 0
:GetVSCommonToolsDirHelper32
@for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO (
@if "%%i"=="10.0" (
@SET "VS100COMNTOOLS=%%k"
)
)
@if "%VS100COMNTOOLS%"=="" exit /B 1
@SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\"
@exit /B 0
:GetVSCommonToolsDirHelper64
@for /F "tokens=1,2*" %%i in ('reg query "%1\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7" /v "10.0"') DO (
@if "%%i"=="10.0" (
@SET "VS100COMNTOOLS=%%k"
)
)
@if "%VS100COMNTOOLS%"=="" exit /B 1
@SET "VS100COMNTOOLS=%VS100COMNTOOLS%Common7\Tools\"
@exit /B 0
@REM -----------------------------------------------------------------------
:error_no_VS100COMNTOOLSDIR
@echo ERROR: Cannot determine the location of the VS Common Tools folder.
@goto end
:error_no_VSINSTALLDIR
@echo ERROR: Cannot determine the location of the VS installation.
@goto end
:error_no_FrameworkDIR32
@echo ERROR: Cannot determine the location of the .NET Framework 32bit installation.
@goto end
:error_no_FrameworkVer32
@echo ERROR: Cannot determine the version of the .NET Framework 32bit installation.
@goto end
:error_no_Framework35Version
@echo ERROR: Cannot determine the .NET Framework 3.5 version.
@goto end
:end
msbuild msvc-2010.sln /p:Configuration=Release /target:clean
msbuild msvc-2010.sln /p:Configuration=Release
exit
nestopia-1.47/libretro/msvc/msvc-2010.sln 0000664 0000000 0000000 00000001552 12644314416 0020137 0 ustar 00root root 0000000 0000000
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2010", "msvc-2010\msvc-2010.vcxproj", "{C4D4209C-05D5-404F-8925-BD7ABA58D686}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Debug|Win32.ActiveCfg = Debug|Win32
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Debug|Win32.Build.0 = Debug|Win32
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release|Win32.ActiveCfg = Release|Win32
{C4D4209C-05D5-404F-8925-BD7ABA58D686}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
nestopia-1.47/libretro/msvc/msvc-2010/ 0000775 0000000 0000000 00000000000 12644314416 0017416 5 ustar 00root root 0000000 0000000 nestopia-1.47/libretro/msvc/msvc-2010/libretro.def 0000664 0000000 0000000 00000001012 12644314416 0021712 0 ustar 00root root 0000000 0000000 LIBRARY "msvc-2010"
EXPORTS
retro_set_environment
retro_set_video_refresh
retro_set_audio_sample
retro_set_audio_sample_batch
retro_set_input_poll
retro_set_input_state
retro_init
retro_deinit
retro_api_version
retro_get_system_info
retro_get_system_av_info
retro_set_controller_port_device
retro_reset
retro_run
retro_serialize_size
retro_serialize
retro_unserialize
retro_cheat_reset
retro_cheat_set
retro_load_game
retro_load_game_special
retro_unload_game
retro_get_region
retro_get_memory_data
retro_get_memory_size
nestopia-1.47/libretro/msvc/msvc-2010/msvc-2010.vcxproj 0000664 0000000 0000000 00000062721 12644314416 0022373 0 ustar 00root root 0000000 0000000
DebugWin32ReleaseWin32{C4D4209C-05D5-404F-8925-BD7ABA58D686}Win32ProjDynamicLibraryUnicodeDynamicLibraryUnicode$(OutDir)msvc-2010$(TargetExt)$(SolutionDir)msvc-2010\$(Configuration)\$(OutDir)msvc-2010$(TargetExt)$(SolutionDir)msvc-2010\$(Configuration)\NotUsingLevel3ProgramDatabaseDisabledfalsetruefalseMultiThreadedDebug_DEBUG;_WIN32;_LIB;%(PreprocessorDefinitions);__LIBRETRO__;NST_NO_ZLIB;_SECURE_SCL=0Callcap$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truelibretro.defLevel3NotUsingFulltruetrueProgramDatabaseSizefalsefalseMultiThreadedNDEBUG;_WIN32;_LIB;%(PreprocessorDefinitions);NST_NO_ZLIB;__LIBRETRO__;_SECURE_SCL=0$(SolutionDir)\..\..\source;%(AdditionalIncludeDirectories)truetruetruelibretro.def
nestopia-1.47/libretro/msvc/msvc-2010/msvc-2010.vcxproj.filters 0000664 0000000 0000000 00000116401 12644314416 0024035 0 ustar 00root root 0000000 0000000
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx{93995380-89BD-4b04-88EB-625FBE52EBFB}h;hpp;hxx;hm;inl;inc;xsd{bb2769c3-f85a-46ed-b7fa-9b479cacb927}{cfd4b486-09df-4d1c-8ae5-d39d256c047a}{f3d53a31-83d2-40ac-8c5d-ad9324f3d392}{89661cd6-755f-4ecd-89a3-ac7caf2d908c}{21634da5-491c-4dd3-b53b-cc17f64c07e2}{763265c6-4c2c-4a36-9561-d7bc02c13c07}Source Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\boardSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\inputSource Files\core\vssystemSource Files\core\vssystemSource Files\core\vssystemSource Files\core\vssystemSource Files\libretroSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\apiSource Files\core\api
nestopia-1.47/projects/ 0000775 0000000 0000000 00000000000 12644314416 0015125 5 ustar 00root root 0000000 0000000 nestopia-1.47/projects/blackberry-qnx/ 0000775 0000000 0000000 00000000000 12644314416 0020051 5 ustar 00root root 0000000 0000000 nestopia-1.47/projects/blackberry-qnx/.cproject 0000664 0000000 0000000 00000027411 12644314416 0021670 0 ustar 00root root 0000000 0000000
nestopia-1.47/projects/blackberry-qnx/.project 0000664 0000000 0000000 00000004773 12644314416 0021533 0 ustar 00root root 0000000 0000000
nestopiaorg.eclipse.cdt.managedbuilder.core.genmakebuilderclean,full,incremental,?name?org.eclipse.cdt.make.core.append_environmenttrueorg.eclipse.cdt.make.core.autoBuildTargetallorg.eclipse.cdt.make.core.buildArguments-C ../../libretro platform=qnxorg.eclipse.cdt.make.core.buildCommandmakeorg.eclipse.cdt.make.core.cleanBuildTargetcleanorg.eclipse.cdt.make.core.contentsorg.eclipse.cdt.make.core.activeConfigSettingsorg.eclipse.cdt.make.core.enableAutoBuildfalseorg.eclipse.cdt.make.core.enableCleanBuildtrueorg.eclipse.cdt.make.core.enableFullBuildtrueorg.eclipse.cdt.make.core.fullBuildTargetallorg.eclipse.cdt.make.core.stopOnErrortrueorg.eclipse.cdt.make.core.useDefaultBuildCmdfalseorg.eclipse.cdt.managedbuilder.core.ScannerConfigBuilderfull,incremental,com.qnx.tools.bbt.xml.core.bbtXMLValidationBuilderorg.eclipse.cdt.core.cnatureorg.eclipse.cdt.managedbuilder.core.managedBuildNatureorg.eclipse.cdt.managedbuilder.core.ScannerConfigNaturecom.qnx.tools.ide.bbt.core.bbtnatureorg.eclipse.cdt.core.ccnature
nestopia-1.47/readme.html 0000664 0000000 0000000 00000107655 12644314416 0015435 0 ustar 00root root 0000000 0000000
Nestopia Documentation
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or (at your
option) any later version. This program is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details. You should have received a copy of the GNU General
Public License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Nestopia is an open source NES/Famicom emulator written in standard C++,
focused on delivering as accurate emulation as possible. Development began in
mid 2002, initially released for the Windows platform a year later.
It has since been ported to other platforms, including Linux and Mac OS X.
See credits section for the list of authors involved.
* only supported if PIN wiring info is available through a database or ROM set.
External Sound Chips:
Konami VRC6
Konami VRC7
MMC5
Namcot 163
RP2C33
Sunsoft 5B
Controllers:
Arkanoid (1)
Crazy Climber Sticks
Doremikko Keyboard
Exciting Boxing Bop Bag
Family BASIC Keyboard
Family Computer Robot / R.O.B.
Family Trainer / Family Fun Fitness / Power Pad
Hori Track (1)
Hyper Shot
Light Gun (1)
Mahjong Controller
Oeka Kids Tablet (1)
Pachinko Controller (2)
Party Tap
Pokkun Moguraa
Power Glove (1)
Standard Pad
Subor Keyboard + Mouse
Top Rider Bike
(1) Using the mouse
(2) Using the mouse wheel
Other Peripherals/Systems:
Bandai Karaoke Studio
Barcode Battler
Data Recorder
Datach Joint ROM System
Famicom Disk System
Game Genie & Pro Action Rocky
Turbo File
VS System
Image File Formats:
ROM images backed by XML descriptor (.zip)
UNIF (.unf)
iNES (.nes)
FDS with/without headers (.fds)
Extras:
Savestates / Saveslots
PNG/JPEG/BMP File Screenshots
Movie/AVI File Recording
WAVE File Recording
ZIP/RAR/7zip Archive Support
On-the-fly IPS Patching
Netplay
NSF Player
Video Filters including NTSC video emulation
Real-time Rewinding
Cheat Searching
Databases of cartridge info
File Launcher
Palette Editor
iNES File Header Editor
Recognized VS System Games:
Name
Dip Switch Info
Battle City
partial
Castlevania
full
Clu Clu Land
partial
Dr. Mario
full
Duck Hunt
full
Excitebike
full
Freedom Force
partial
Golf
full
Goonies
full
Gradius
full
Gumshoe
full
Hogan's Alley
full
Ice Climber
full
Lady Golf
full
Mach Rider
partial
Mach Rider - Fighting Course
partial
Mighty Bomb Jack
partial
Ninja Jajamaru Kun
partial
Pinball
partial
Platoon
partial
Raid on Bungeling Bay
partial
RBI Baseball
full
Sky Kid
full
Slalom
full
Soccer
full
Star Luster
partial
Stroke and Match Golf
full
Super Mario Bros
full
Super Xevious
partial
Tetris
partial
TKO Boxing
partial
Top Gun
full
Games with Sound Sample Support:
Game
File Archive Name
Number of Samples
Family Trainer - Aerobics Studio
ftaerobi
8
Moero!! Pro Yakyuu
moepro
16
Moero!! Pro Yakyuu '88 - Ketteiban
moepro88
20
Moe Pro! '90 - Kandou Hen
Moe Pro! - Saikyou Hen
Shin Moero!! Pro Yakyuu
Moero!! Pro Tennis
mptennis
19
Terao no Dosukoi Oozumou
terao
6
Samples must be in MS Wave format and use indexed naming convention, i.e. 00.wav, 01.wav and so on.
The compression format may be zip, rar or 7zip. The archives must be placed in the directory specified
in the Paths Settings (defaulted to .\samples).
(*) Win98/Me users need to obtain the Unicode Layer DLL (unicows.dll)
from Microsoft's site and place it in the same directory as Nestopia.
It can be downloaded from here.
NES is either a trademark or registered trademark of Nintendo of America Inc.
Famicom is either a trademark or registered trademark of Nintendo Co., LTD.
All other trademarks are property of their respective owners.
Nestopia is not affiliated with or endorsed by any of the companies mentioned.
nestopia-1.47/schemadb.xsd 0000664 0000000 0000000 00000101537 12644314416 0015571 0 ustar 00root root 0000000 0000000
nestopia-1.47/schemaromset.xsd 0000664 0000000 0000000 00000101521 12644314416 0016506 0 ustar 00root root 0000000 0000000
nestopia-1.47/source/ 0000775 0000000 0000000 00000000000 12644314416 0014574 5 ustar 00root root 0000000 0000000 nestopia-1.47/source/core/ 0000775 0000000 0000000 00000000000 12644314416 0015524 5 ustar 00root root 0000000 0000000 nestopia-1.47/source/core/NstApu.cpp 0000664 0000000 0000000 00000157773 12644314416 0017466 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include "NstCpu.hpp"
#include "NstState.hpp"
#include "api/NstApiSound.hpp"
#include "NstSoundRenderer.inl"
namespace Nes
{
namespace Core
{
const dword Apu::Cycles::frameClocks[3][4] =
{
{
CPU_RP2A03_CC * 29830UL,
CPU_RP2A03_CC,
CPU_RP2A03_CC,
CPU_RP2A03_CC * (29830UL - 2),
},
{
CPU_RP2A07_CC * 33254UL,
CPU_RP2A07_CC,
CPU_RP2A07_CC,
CPU_RP2A07_CC * (33254UL - 2)
},
{
CPU_DENDY_CC * 29830UL,
CPU_DENDY_CC,
CPU_DENDY_CC,
CPU_DENDY_CC * (29830UL - 2),
}
};
const dword Apu::Cycles::oscillatorClocks[3][2][4] =
{
{
{
CPU_RP2A03_CC * (7459UL - 1),
CPU_RP2A03_CC * 7456UL,
CPU_RP2A03_CC * 7458UL,
CPU_RP2A03_CC * 7458UL
},
{
CPU_RP2A03_CC * 7458UL,
CPU_RP2A03_CC * 7456UL,
CPU_RP2A03_CC * 7458UL,
CPU_RP2A03_CC * (7458UL + 7452)
}
},
{
{
CPU_RP2A07_CC * (8315UL - 1),
CPU_RP2A07_CC * 8314UL,
CPU_RP2A07_CC * 8312UL,
CPU_RP2A07_CC * 8314UL
},
{
CPU_RP2A07_CC * 8314UL,
CPU_RP2A07_CC * 8314UL,
CPU_RP2A07_CC * 8312UL,
CPU_RP2A07_CC * (8314UL + 8312)
}
},
{
{
CPU_DENDY_CC * (7459UL - 1),
CPU_DENDY_CC * 7456UL,
CPU_DENDY_CC * 7458UL,
CPU_DENDY_CC * 7458UL
},
{
CPU_DENDY_CC * 7458UL,
CPU_DENDY_CC * 7456UL,
CPU_DENDY_CC * 7458UL,
CPU_DENDY_CC * (7458UL + 7452)
}
}
};
const byte Apu::Channel::LengthCounter::lut[32] =
{
0x0A, 0xFE, 0x14, 0x02,
0x28, 0x04, 0x50, 0x06,
0xA0, 0x08, 0x3C, 0x0A,
0x0E, 0x0C, 0x1A, 0x0E,
0x0C, 0x10, 0x18, 0x12,
0x30, 0x14, 0x60, 0x16,
0xC0, 0x18, 0x48, 0x1A,
0x10, 0x1C, 0x20, 0x1E
};
const word Apu::Noise::lut[3][16] =
{
{
0x004, 0x008, 0x010, 0x020,
0x040, 0x060, 0x080, 0x0A0,
0x0CA, 0x0FE, 0x17C, 0x1FC,
0x2FA, 0x3F8, 0x7F2, 0xFE4
},
{
0x004, 0x007, 0x00E, 0x01E,
0x03C, 0x058, 0x076, 0x094,
0x0BC, 0x0EC, 0x162, 0x1D8,
0x2C4, 0x3B0, 0x762, 0xEC2
},
{
0x004, 0x008, 0x010, 0x020,
0x040, 0x060, 0x080, 0x0A0,
0x0CA, 0x0FE, 0x17C, 0x1FC,
0x2FA, 0x3F8, 0x7F2, 0xFE4
}
};
const word Apu::Dmc::lut[3][16] =
{
{
0x1AC * CPU_RP2A03_CC,
0x17C * CPU_RP2A03_CC,
0x154 * CPU_RP2A03_CC,
0x140 * CPU_RP2A03_CC,
0x11E * CPU_RP2A03_CC,
0x0FE * CPU_RP2A03_CC,
0x0E2 * CPU_RP2A03_CC,
0x0D6 * CPU_RP2A03_CC,
0x0BE * CPU_RP2A03_CC,
0x0A0 * CPU_RP2A03_CC,
0x08E * CPU_RP2A03_CC,
0x080 * CPU_RP2A03_CC,
0x06A * CPU_RP2A03_CC,
0x054 * CPU_RP2A03_CC,
0x048 * CPU_RP2A03_CC,
0x036 * CPU_RP2A03_CC
},
{
0x18E * CPU_RP2A07_CC,
0x162 * CPU_RP2A07_CC,
0x13C * CPU_RP2A07_CC,
0x12A * CPU_RP2A07_CC,
0x114 * CPU_RP2A07_CC,
0x0EC * CPU_RP2A07_CC,
0x0D2 * CPU_RP2A07_CC,
0x0C6 * CPU_RP2A07_CC,
0x0B0 * CPU_RP2A07_CC,
0x094 * CPU_RP2A07_CC,
0x084 * CPU_RP2A07_CC,
0x076 * CPU_RP2A07_CC,
0x062 * CPU_RP2A07_CC,
0x04E * CPU_RP2A07_CC,
0x042 * CPU_RP2A07_CC,
0x032 * CPU_RP2A07_CC
},
{
0x1AC * CPU_DENDY_CC,
0x17C * CPU_DENDY_CC,
0x154 * CPU_DENDY_CC,
0x140 * CPU_DENDY_CC,
0x11E * CPU_DENDY_CC,
0x0FE * CPU_DENDY_CC,
0x0E2 * CPU_DENDY_CC,
0x0D6 * CPU_DENDY_CC,
0x0BE * CPU_DENDY_CC,
0x0A0 * CPU_DENDY_CC,
0x08E * CPU_DENDY_CC,
0x080 * CPU_DENDY_CC,
0x06A * CPU_DENDY_CC,
0x054 * CPU_DENDY_CC,
0x048 * CPU_DENDY_CC,
0x036 * CPU_DENDY_CC
}
};
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Apu(Cpu& c)
:
cpu (c),
extChannel (NULL),
buffer (16)
{
NST_COMPILE_ASSERT( CPU_RP2A03 == 0 && CPU_RP2A07 == 1 && CPU_DENDY == 2 );
PowerOff();
}
void Apu::PowerOff()
{
Reset( false, true );
}
void Apu::Reset(bool hard)
{
Reset( true, hard );
}
void Apu::Reset(const bool on,const bool hard)
{
if (on)
UpdateSettings();
updater = &Apu::SyncOff;
cycles.Reset( extChannel, cpu.GetModel() );
synchronizer.Resync( settings.speed, cpu );
for (uint i=0; i < 2; ++i)
square[i].Reset();
triangle.Reset();
noise.Reset( cpu.GetModel() );
dmc.Reset( cpu.GetModel() );
dcBlocker.Reset();
stream = NULL;
buffer.Reset( settings.bits );
if (on)
{
cpu.Map( 0x4000 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4000 );
cpu.Map( 0x4001 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4001 );
cpu.Map( 0x4002 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4002 );
cpu.Map( 0x4003 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4003 );
cpu.Map( 0x4004 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4000 );
cpu.Map( 0x4005 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4001 );
cpu.Map( 0x4006 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4002 );
cpu.Map( 0x4007 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4003 );
cpu.Map( 0x4008 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4008 );
cpu.Map( 0x400A ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400A );
cpu.Map( 0x400B ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400B );
cpu.Map( 0x400C ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400C );
cpu.Map( 0x400E ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400E );
cpu.Map( 0x400F ).Set( this, &Apu::Peek_40xx, &Apu::Poke_400F );
cpu.Map( 0x4010 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4010 );
cpu.Map( 0x4011 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4011 );
cpu.Map( 0x4012 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4012 );
cpu.Map( 0x4013 ).Set( this, &Apu::Peek_40xx, &Apu::Poke_4013 );
cpu.Map( 0x4015 ).Set( this, &Apu::Peek_4015, &Apu::Poke_4015 );
if (cpu.GetApu().IsGenie())
{
NES_DO_POKE(4000,0x4000,0x30);
NES_DO_POKE(4001,0x4001,0xF9);
NES_DO_POKE(400C,0x400C,0x30);
NES_DO_POKE(400E,0x400E,0x0E);
NES_DO_POKE(400F,0x400F,0x04);
NES_DO_POKE(4015,0x4015,0x09);
}
if (cpu.GetModel() == CPU_DENDY)
{
ctrl = STATUS_NO_FRAME_IRQ;
}
else if (hard)
{
ctrl = STATUS_FRAME_IRQ_ENABLE;
}
if (ctrl == STATUS_FRAME_IRQ_ENABLE)
cycles.frameIrqClock = (cycles.frameCounter / cycles.fixed) - cpu.GetClock();
if (extChannel)
extChannel->Reset();
}
else
{
if (cpu.GetModel() == CPU_DENDY)
ctrl = STATUS_NO_FRAME_IRQ;
else
ctrl = STATUS_FRAME_IRQ_ENABLE;
}
}
Result Apu::SetSampleRate(const dword rate)
{
if (settings.rate == rate)
return RESULT_NOP;
if (!rate)
return RESULT_ERR_INVALID_PARAM;
if (rate < 11025 || rate > 96000)
return RESULT_ERR_UNSUPPORTED;
settings.rate = rate;
UpdateSettings();
return RESULT_OK;
}
Result Apu::SetSampleBits(const uint bits)
{
if (settings.bits == bits)
return RESULT_NOP;
if (!bits)
return RESULT_ERR_INVALID_PARAM;
if (bits != 8 && bits != 16)
return RESULT_ERR_UNSUPPORTED;
settings.bits = bits;
UpdateSettings();
return RESULT_OK;
}
Result Apu::SetVolume(const uint channels,const uint volume)
{
if (volume > 100)
return RESULT_ERR_INVALID_PARAM;
bool updated = false;
for (uint i=0; i < MAX_CHANNELS; ++i)
{
if (channels & (1U << i))
{
if (settings.volumes[i] != volume)
{
settings.volumes[i] = volume;
updated = true;
}
}
}
if (!updated)
return RESULT_NOP;
UpdateSettings();
return RESULT_OK;
}
uint Apu::GetVolume(const uint channel) const
{
for (uint i=0; i < MAX_CHANNELS; ++i)
{
if (channel & (1U << i))
return settings.volumes[i];
}
return 0;
}
Result Apu::SetSpeed(const uint speed)
{
if (settings.speed == speed)
return RESULT_NOP;
if ((speed > 0 && speed < 30) || speed > 240)
return RESULT_ERR_UNSUPPORTED;
settings.speed = speed;
UpdateSettings();
return RESULT_OK;
}
void Apu::Mute(const bool mute)
{
if (settings.muted != mute)
{
settings.muted = mute;
UpdateSettings();
}
}
void Apu::SetAutoTranspose(const bool transpose)
{
if (settings.transpose != transpose)
{
settings.transpose = transpose;
UpdateSettings();
}
}
void Apu::SetGenie(const bool genie)
{
if (settings.genie != genie)
{
settings.genie = genie;
UpdateSettings();
}
}
void Apu::EnableStereo(const bool enable)
{
if (settings.stereo != enable)
{
settings.stereo = enable;
UpdateSettings();
}
}
void Apu::UpdateSettings()
{
cycles.Update( settings.rate, settings.speed, cpu );
synchronizer.Reset( settings.speed, settings.rate, cpu );
dcBlocker.Reset();
buffer.Reset( settings.bits );
Cycle rate; uint fixed;
CalculateOscillatorClock( rate, fixed );
square[0].UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_SQUARE1 ], rate, fixed );
square[1].UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_SQUARE2 ], rate, fixed );
triangle.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_TRIANGLE ], rate, fixed, cpu.GetModel() );
noise.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_NOISE ], rate, fixed );
dmc.UpdateSettings ( settings.muted ? 0 : settings.volumes[ Channel::APU_DPCM ] );
UpdateVolumes();
}
void Apu::UpdateVolumes()
{
settings.audible = (extChannel && extChannel->UpdateSettings()) ||
(
uint(settings.volumes[ Channel::APU_SQUARE1 ]) |
uint(settings.volumes[ Channel::APU_SQUARE2 ]) |
uint(settings.volumes[ Channel::APU_TRIANGLE ]) |
uint(settings.volumes[ Channel::APU_NOISE ]) |
uint(settings.volumes[ Channel::APU_DPCM ])
);
}
void Apu::Resync(const dword rate)
{
cycles.Update( rate, settings.speed, cpu );
ClearBuffers( false );
}
void Apu::CalculateOscillatorClock(Cycle& rate,uint& fixed) const
{
dword sampleRate = settings.rate;
if (settings.transpose && settings.speed)
sampleRate = sampleRate * cpu.GetFps() / settings.speed;
uint multiplier = 0;
const qaword clockBase = cpu.GetClockBase();
while (++multiplier < 0x1000 && clockBase * (multiplier+1) / sampleRate <= 0x7FFFF && clockBase * multiplier % sampleRate);
rate = clockBase * multiplier / sampleRate;
fixed = cpu.GetClockDivider() * cpu.GetClock() * multiplier;
}
void Apu::SaveState(State::Saver& state,const dword baseChunk) const
{
state.Begin( baseChunk );
{
Cycle clock = cycles.frameCounter / cycles.fixed;
NST_VERIFY( clock >= cpu.GetCycles() );
if (clock > cpu.GetCycles())
clock = (clock - cpu.GetCycles()) / cpu.GetClock();
else
clock = 0;
NST_VERIFY( cycles.frameCounter == (cpu.GetCycles() + clock * cpu.GetClock()) * cycles.fixed );
const byte data[4] =
{
ctrl,
clock & 0xFF,
clock >> 8,
cycles.frameDivider
};
state.Begin( AsciiId<'F','R','M'>::V ).Write( data ).End();
}
if (cycles.frameIrqClock != Cpu::CYCLE_MAX)
{
Cycle clock = cycles.frameIrqClock;
NST_VERIFY( clock >= cpu.GetCycles() );
if (clock > cpu.GetCycles())
clock = (clock - cpu.GetCycles()) / cpu.GetClock();
else
clock = 0;
NST_VERIFY( cycles.frameIrqClock == cpu.GetCycles() + clock * cpu.GetClock() );
const byte data[3] =
{
clock & 0xFF,
clock >> 8,
cycles.frameIrqRepeat % 3
};
state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End();
}
if (cycles.extCounter != Cpu::CYCLE_MAX)
{
Cycle clock = cycles.extCounter / cycles.fixed;
NST_VERIFY( clock >= cpu.GetCycles() || clock == 0 );
if (clock > cpu.GetCycles())
{
clock = (clock - cpu.GetCycles()) / cpu.GetClock();
NST_VERIFY( cycles.extCounter == (cpu.GetCycles() + clock * cpu.GetClock()) * cycles.fixed );
}
else
{
clock = 0;
}
state.Begin( AsciiId<'E','X','T'>::V ).Write16( clock ).End();
}
square[0].SaveState( state, AsciiId<'S','Q','0'>::V );
square[1].SaveState( state, AsciiId<'S','Q','1'>::V );
triangle.SaveState( state, AsciiId<'T','R','I'>::V );
noise.SaveState( state, AsciiId<'N','O','I'>::V );
dmc.SaveState( state, AsciiId<'D','M','C'>::V, cpu, cycles.dmcClock );
state.End();
}
void Apu::LoadState(State::Loader& state)
{
cycles.frameIrqClock = Cpu::CYCLE_MAX;
cycles.frameIrqRepeat = 0;
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'F','R','M'>::V:
{
State::Loader::Data<4> data( state );
ctrl = data[0] & STATUS_BITS;
cycles.rateCounter = cycles.fixed * cpu.GetCycles();
cycles.frameCounter = cycles.fixed *
(
cpu.GetCycles() + (data[1] | data[2] << 8) * cpu.GetClock()
);
cycles.frameDivider = data[3] & 0x3;
break;
}
case AsciiId<'I','R','Q'>::V:
{
State::Loader::Data<3> data( state );
cycles.frameIrqClock = cpu.GetCycles() +
(
(data[0] | data[1] << 8) * cpu.GetClock()
);
cycles.frameIrqRepeat = (data[2] & 0x3) % 3;
break;
}
case AsciiId<'E','X','T'>::V:
NST_VERIFY( cycles.extCounter != Cpu::CYCLE_MAX );
if (cycles.extCounter != Cpu::CYCLE_MAX)
{
cycles.extCounter = cycles.fixed *
(
cpu.GetCycles() + state.Read16() * cpu.GetClock()
);
}
break;
case AsciiId<'S','Q','0'>::V:
square[0].LoadState( state );
break;
case AsciiId<'S','Q','1'>::V:
square[1].LoadState( state );
break;
case AsciiId<'T','R','I'>::V:
triangle.LoadState( state );
break;
case AsciiId<'N','O','I'>::V:
noise.LoadState( state, cpu.GetModel() );
break;
case AsciiId<'D','M','C'>::V:
dmc.LoadState( state, cpu, cpu.GetModel(), cycles.dmcClock );
break;
}
state.End();
}
if (ctrl != STATUS_FRAME_IRQ_ENABLE)
{
cycles.frameIrqClock = Cpu::CYCLE_MAX;
cycles.frameIrqRepeat = 0;
}
else if (cycles.frameIrqClock == Cpu::CYCLE_MAX)
{
cycles.frameIrqClock = (cycles.frameCounter / cycles.fixed) + (3 - cycles.frameDivider) * (Cycles::frameClocks[cpu.GetModel()][0] / 4);
cycles.frameIrqRepeat = 0;
}
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
void NST_FASTCALL Apu::SyncOn(const Cycle target)
{
NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) && (cycles.extCounter == Cpu::CYCLE_MAX) );
if (cycles.rateCounter < target)
{
Cycle rateCounter = cycles.rateCounter;
const Cycle rate = cycles.rate;
do
{
buffer << GetSample();
if (cycles.frameCounter <= rateCounter)
ClockFrameCounter();
rateCounter += rate;
}
while (rateCounter < target);
cycles.rateCounter = rateCounter;
}
if (cycles.frameCounter < target)
{
ClockFrameCounter();
NST_ASSERT( cycles.frameCounter >= target );
}
}
void NST_FASTCALL Apu::SyncOnExt(const Cycle target)
{
NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) && extChannel );
Cycle extCounter = cycles.extCounter;
if (cycles.rateCounter < target)
{
Cycle rateCounter = cycles.rateCounter;
do
{
buffer << GetSample();
if (extCounter <= rateCounter)
extCounter = extChannel->Clock( extCounter, cycles.fixed, rateCounter );
if (cycles.frameCounter <= rateCounter)
ClockFrameCounter();
rateCounter += cycles.rate;
}
while (rateCounter < target);
cycles.rateCounter = rateCounter;
}
if (extCounter <= target)
{
cycles.extCounter = extChannel->Clock( extCounter, cycles.fixed, target );
NST_ASSERT( cycles.extCounter > target );
}
else
{
cycles.extCounter = extCounter;
}
if (cycles.frameCounter < target)
{
ClockFrameCounter();
NST_ASSERT( cycles.frameCounter >= target );
}
}
void NST_FASTCALL Apu::SyncOff(const Cycle target)
{
NST_ASSERT( !(stream && settings.audible) && cycles.fixed );
cycles.rateCounter = target;
while (cycles.frameCounter < target)
ClockFrameCounter();
NST_ASSERT( cycles.extCounter == Cpu::CYCLE_MAX || extChannel );
if (cycles.extCounter <= target)
{
cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, target );
NST_ASSERT( cycles.extCounter > target );
}
}
void Apu::BeginFrame(Sound::Output* output)
{
stream = output;
updater = (output && settings.audible ? (cycles.extCounter == Cpu::CYCLE_MAX ? &Apu::SyncOn : &Apu::SyncOnExt) : &Apu::SyncOff);
}
inline void Apu::Update(const Cycle target)
{
NST_ASSERT( cycles.fixed );
(*this.*updater)( target * cycles.fixed );
}
void Apu::Update()
{
Update( cpu.Update() );
}
void Apu::UpdateLatency()
{
Update( cpu.Update() + 1 );
}
bool Apu::UpdateDelta()
{
const Cycle elapsed = cpu.Update();
const bool delta = cycles.frameCounter != elapsed * cycles.fixed;
Update( elapsed + 1 );
return delta;
}
template
void Apu::FlushSound()
{
NST_ASSERT( (stream && settings.audible) && (cycles.rate && cycles.fixed) );
for (uint i=0; i < 2; ++i)
{
if (stream->length[i] && stream->samples[i])
{
Sound::Buffer::Block block( stream->length[i] );
buffer >> block;
Sound::Buffer::Renderer output( stream->samples[i], stream->length[i], buffer.history );
if (output << block)
{
const Cycle target = cpu.GetCycles() * cycles.fixed;
if (cycles.rateCounter < target)
{
Cycle rateCounter = cycles.rateCounter;
do
{
output << GetSample();
if (cycles.frameCounter <= rateCounter)
ClockFrameCounter();
if (cycles.extCounter <= rateCounter)
cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, rateCounter );
rateCounter += cycles.rate;
}
while (rateCounter < target && output);
cycles.rateCounter = rateCounter;
}
if (output)
{
if (cycles.frameCounter < target)
ClockFrameCounter();
if (cycles.extCounter <= target)
cycles.extCounter = extChannel->Clock( cycles.extCounter, cycles.fixed, target );
do
{
output << GetSample();
}
while (output);
}
}
}
}
}
void Apu::EndFrame()
{
NST_ASSERT( (stream && settings.audible) == (updater != &Apu::SyncOff) );
if (updater != &Apu::SyncOff)
{
dword streamed = 0;
if (Sound::Output::lockCallback( *stream ))
{
streamed = stream->length[0] + stream->length[1];
if (settings.bits == 16)
{
if (!settings.stereo)
FlushSound();
else
FlushSound();
}
else
{
if (!settings.stereo)
FlushSound();
else
FlushSound();
}
Sound::Output::unlockCallback( *stream );
}
if (const dword rate = synchronizer.Clock( streamed, settings.rate, cpu ))
Resync( rate );
}
Update( cpu.GetCycles() );
Cycle frame = cpu.GetFrameCycles();
NST_ASSERT
(
cycles.dmcClock >= frame &&
cycles.frameIrqClock >= frame
);
cycles.dmcClock -= frame;
if (cycles.frameIrqClock != Cpu::CYCLE_MAX)
cycles.frameIrqClock -= frame;
frame *= cycles.fixed;
NST_ASSERT
(
cycles.rateCounter >= frame &&
cycles.frameCounter >= frame &&
cycles.extCounter >= frame
);
cycles.rateCounter -= frame;
cycles.frameCounter -= frame;
if (cycles.extCounter != Cpu::CYCLE_MAX)
cycles.extCounter -= frame;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Settings::Settings()
: rate(44100), bits(16), speed(0), muted(false), transpose(false), stereo(false), audible(true)
{
for (uint i=0; i < MAX_CHANNELS; ++i)
volumes[i] = Channel::DEFAULT_VOLUME;
}
Apu::Cycles::Cycles()
: fixed(1), rate(1) {}
void Apu::Cycles::Reset(const bool extChannel,const CpuModel model)
{
rateCounter = 0;
frameDivider = 0;
frameIrqClock = Cpu::CYCLE_MAX;
frameIrqRepeat = 0;
dmcClock = Dmc::GetResetFrequency( model );
frameCounter = frameClocks[model][0] * fixed;
extCounter = (extChannel ? 0UL : Cpu::CYCLE_MAX);
}
void Apu::Cycles::Update(dword sampleRate,const uint speed,const Cpu& cpu)
{
frameCounter /= fixed;
rateCounter /= fixed;
if (extCounter != Cpu::CYCLE_MAX)
extCounter /= fixed;
if (speed)
sampleRate = sampleRate * cpu.GetFps() / speed;
uint multiplier = 0;
const qaword clockBase = cpu.GetClockBase();
while (++multiplier < 512 && clockBase * multiplier % sampleRate);
rate = clockBase * multiplier / sampleRate;
fixed = cpu.GetClockDivider() * multiplier;
frameCounter *= fixed;
rateCounter *= fixed;
if (extCounter != Cpu::CYCLE_MAX)
extCounter *= fixed;
}
Apu::Synchronizer::Synchronizer()
: rate(0) {}
void Apu::Synchronizer::Resync(uint speed,const Cpu& cpu)
{
duty = 0;
streamed = 0;
if (speed == 0 || speed == cpu.GetFps())
sync = 4;
else
sync = 0;
}
void Apu::Synchronizer::Reset(uint speed,dword sampleRate,const Cpu& cpu)
{
rate = sampleRate;
Resync( speed, cpu );
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NST_SINGLE_CALL dword Apu::Synchronizer::Clock(const dword output,const dword sampleRate,const Cpu& cpu)
{
/*if (sync)
{
if (duty >= 60*4)
streamed += output;
if (duty < 60*12)
{
duty++;
}
else
{
duty = 60*4;
dword actualRate = streamed / (60*8) * cpu.GetFps();
const dword limit = sampleRate / 21;
if (actualRate <= sampleRate-limit)
{
actualRate = sampleRate-limit;
sync--;
}
else if (actualRate >= sampleRate+limit)
{
actualRate = sampleRate+limit;
sync--;
}
else
{
sync = (sync > 2 ? sync - 2 : 0);
}
actualRate = actualRate * 9999 / 10000;
streamed = 0;
if (rate != actualRate)
{
rate = actualRate;
return actualRate;
}
}
}*/
return 0;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Channel::LengthCounter::LengthCounter()
{
Reset();
}
void Apu::Channel::LengthCounter::Reset()
{
enabled = 0;
count = 0;
}
void Apu::Channel::LengthCounter::LoadState(State::Loader& state)
{
const uint data = state.Read8();
enabled = (data == 0xFF ? 0U : ~0U);
count = data & enabled;
}
void Apu::Channel::LengthCounter::SaveState(State::Saver& state,const dword chunk) const
{
NST_VERIFY( count < 0xFF );
state.Begin( chunk ).Write8( enabled ? count : 0xFF ).End();
}
Apu::Channel::Envelope::Envelope()
: outputVolume(OUTPUT_MUL)
{
Reset();
}
void Apu::Channel::Envelope::Reset()
{
output = 0;
regs[0] = 0x0;
regs[1] = 0x10;
count = 0;
reset = false;
}
void Apu::Channel::Envelope::SetOutputVolume(uint v)
{
outputVolume = v;
UpdateOutput();
}
void Apu::Channel::Envelope::SaveState(State::Saver& state,const dword chunk) const
{
const byte data[3] =
{
count,
regs[0] | (reset ? 0x80U : 0x00U),
regs[1]
};
state.Begin( chunk ).Write( data ).End();
}
void Apu::Channel::Envelope::LoadState(State::Loader& state)
{
State::Loader::Data<3> data( state );
count = data[0] & 0x0F;
reset = data[1] >> 7;
regs[0] = data[1] & 0x0F;
regs[1] = data[2];
UpdateOutput();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
void Apu::Channel::Envelope::UpdateOutput()
{
output = (regs[regs[1] >> 4 & 1U] & 0xFUL) * outputVolume;
}
void Apu::Channel::Envelope::Clock()
{
if (!reset)
{
if (count)
{
count--;
return;
}
if (regs[0] | (regs[1] & 0x20U))
regs[0] = (regs[0] - 1U) & 0xF;
}
else
{
reset = false;
regs[0] = 0xF;
}
count = regs[1] & 0x0FU;
UpdateOutput();
}
void Apu::Channel::Envelope::Write(const uint data)
{
regs[1] = data;
UpdateOutput();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Channel::DcBlocker::DcBlocker()
{
Reset();
}
void Apu::Channel::DcBlocker::Reset()
{
acc = 0;
prev = 0;
next = 0;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
Apu::Channel::Sample Apu::Channel::DcBlocker::Apply(Sample sample)
{
acc -= prev;
prev = signed_shl(sample,15);
acc += prev - next * POLE;
next = signed_shr(acc,15);
return next;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Channel::Channel(Apu& a)
: apu(a) {}
Apu::Channel::~Channel()
{
if (apu.extChannel == this)
{
apu.extChannel = NULL;
apu.UpdateVolumes();
}
}
void Apu::Channel::Connect(bool audible)
{
NST_ASSERT( apu.extChannel == NULL );
if (audible)
apu.settings.audible = true;
else
apu.UpdateVolumes();
apu.extChannel = this;
}
void Apu::Channel::GetOscillatorClock(Cycle& rate,uint& fixed) const
{
apu.CalculateOscillatorClock( rate, fixed );
}
uint Apu::Channel::GetVolume(uint channel) const
{
NST_ASSERT( channel < MAX_CHANNELS );
return apu.settings.volumes[channel];
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
Cycle Apu::Channel::GetCpuClockBase() const
{
return apu.cpu.GetClockBase();
}
uint Apu::Channel::GetCpuClockDivider() const
{
return apu.cpu.GetClockDivider();
}
Cycle Apu::Channel::GetCpuClock(uint clock) const
{
return apu.cpu.GetClock(clock);
}
dword Apu::Channel::GetSampleRate() const
{
return apu.settings.rate;
}
bool Apu::Channel::IsMuted() const
{
return apu.settings.muted;
}
void Apu::Channel::Update() const
{
apu.Update();
}
Cycle Apu::Channel::Clock(Cycle,Cycle,Cycle)
{
return Cpu::CYCLE_MAX;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Oscillator::Oscillator()
: rate(1), fixed(1) {}
void Apu::Oscillator::Reset()
{
active = false;
timer = RESET_CYCLES * fixed;
frequency = fixed;
amp = 0;
}
inline void Apu::Oscillator::ClearAmp()
{
amp = 0;
}
void Apu::Oscillator::UpdateSettings(dword r,uint f)
{
NST_ASSERT( r && f );
frequency = frequency / fixed * f;
timer = timer / fixed * f;
fixed = f;
rate = r;
}
void Apu::Square::Reset()
{
Oscillator::Reset();
frequency = fixed * 2;
step = 0;
duty = 0;
envelope.Reset();
lengthCounter.Reset();
validFrequency = false;
sweepRate = 0;
sweepCount = 1;
sweepReload = false;
sweepIncrease = ~0U;
sweepShift = 0;
waveLength = 0;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
inline bool Apu::Square::CanOutput() const
{
return lengthCounter.GetCount() && envelope.Volume() && validFrequency;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Apu::Square::UpdateSettings(uint v,dword r,uint f)
{
Oscillator::UpdateSettings( r, f );
envelope.SetOutputVolume( (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME );
active = CanOutput();
}
void Apu::Square::SaveState(State::Saver& state,const dword chunk) const
{
state.Begin( chunk );
{
byte data[4];
data[0] = waveLength & 0xFFU;
data[1] = (waveLength >> 8) | (duty ? duty << (2+3) : 2U << 3); // for version compatibility
data[2] = (sweepCount - 1U) << 4;
if (sweepRate)
data[2] |= 0x08U | (sweepRate - 1);
if (sweepReload)
data[2] |= 0x80U;
data[3] = sweepShift;
if (!sweepIncrease)
data[3] |= 0x08U;
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
}
lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V );
envelope.SaveState( state, AsciiId<'E','N','V'>::V );
state.End();
}
void Apu::Square::LoadState(State::Loader& state)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'R','E','G'>::V:
{
State::Loader::Data<4> data( state );
waveLength = data[0] | (data[1] << 8 & 0x0700);
// for version compatibility
switch (data[1] >> 3 & 0xF)
{
case 4: duty = 1; break;
case 8: duty = 2; break;
case 12: duty = 3; break;
default: duty = 0; break;
}
if (data[2] & 0x08)
sweepRate = (data[2] & 0x07) + 1;
else
sweepRate = 0;
sweepCount = (data[2] >> 4 & 0x07) + 1;
sweepReload = data[2] >> 7;
sweepShift = data[3] & 0x07;
sweepIncrease = (data[3] & 0x08) ? 0U : ~0U;
break;
}
case AsciiId<'L','E','N'>::V:
lengthCounter.LoadState( state );
break;
case AsciiId<'E','N','V'>::V:
envelope.LoadState( state );
break;
}
state.End();
}
step = 0;
timer = 0;
UpdateFrequency();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NST_SINGLE_CALL void Apu::Square::Disable(const bool disable)
{
active &= lengthCounter.Disable( disable );
}
void Apu::Square::UpdateFrequency()
{
if (waveLength >= MIN_FRQ && waveLength + (sweepIncrease & waveLength >> sweepShift) <= MAX_FRQ)
{
frequency = (waveLength + 1UL) * 2 * fixed;
validFrequency = true;
active = lengthCounter.GetCount() && envelope.Volume();
}
else
{
validFrequency = false;
active = false;
}
}
NST_SINGLE_CALL void Apu::Square::WriteReg0(const uint data)
{
envelope.Write( data );
duty = data >> REG0_DUTY_SHIFT;
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Square::WriteReg1(const uint data)
{
sweepIncrease = (data & REG1_SWEEP_DECREASE) ? 0U : ~0U;
sweepShift = data & REG1_SWEEP_SHIFT;
sweepRate = 0;
if ((data & (REG1_SWEEP_ENABLED|REG1_SWEEP_SHIFT)) > REG1_SWEEP_ENABLED)
{
sweepRate = ((data & REG1_SWEEP_RATE) >> REG1_SWEEP_RATE_SHIFT) + 1;
sweepReload = true;
}
UpdateFrequency();
}
NST_SINGLE_CALL void Apu::Square::WriteReg2(const uint data)
{
waveLength = (waveLength & uint(REG3_WAVELENGTH_HIGH)) | (data & REG3_WAVELENGTH_LOW);
UpdateFrequency();
}
NST_SINGLE_CALL void Apu::Square::WriteReg3(const uint data,const Cycle frameCounterDelta)
{
step = 0;
envelope.ResetClock();
lengthCounter.Write( data, frameCounterDelta );
waveLength = (data << 8 & REG3_WAVELENGTH_HIGH) | (waveLength & uint(REG3_WAVELENGTH_LOW));
UpdateFrequency();
}
NST_SINGLE_CALL void Apu::Square::ClockEnvelope()
{
envelope.Clock();
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Square::ClockSweep(const uint complement)
{
if (!envelope.Looping() && lengthCounter.Clock())
active = false;
if (sweepRate && !--sweepCount)
{
sweepCount = sweepRate;
if (waveLength >= MIN_FRQ)
{
const uint shifted = waveLength >> sweepShift;
if (!sweepIncrease)
{
waveLength += complement - shifted;
UpdateFrequency();
}
else if (waveLength + shifted <= MAX_FRQ)
{
waveLength += shifted;
UpdateFrequency();
}
}
}
if (sweepReload)
{
sweepReload = false;
sweepCount = sweepRate;
}
}
inline uint Apu::Square::GetLengthCounter() const
{
return lengthCounter.GetCount();
}
dword Apu::Square::GetSample()
{
NST_VERIFY( bool(active) == CanOutput() && timer >= 0 );
dword sum = timer;
timer -= idword(rate);
if (active)
{
static const byte forms[4][8] =
{
{0x1F,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
{0x1F,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F},
{0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F},
{0x00,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00}
};
const byte* const NST_RESTRICT form = forms[duty];
if (timer >= 0)
{
amp = envelope.Volume() >> form[step];
}
else
{
sum >>= form[step];
do
{
sum += NST_MIN(-timer,frequency) >> form[step = (step + 1) & 0x7];
timer += idword(frequency);
}
while (timer < 0);
NST_VERIFY( !envelope.Volume() || sum <= 0xFFFFFFFF / envelope.Volume() + rate/2 );
amp = (sum * envelope.Volume() + rate/2) / rate;
}
}
else
{
if (timer < 0)
{
const uint count = (-timer + frequency - 1) / frequency;
step = (step + count) & 0x7;
timer += idword(count * frequency);
}
if (amp < Channel::OUTPUT_DECAY)
{
return 0;
}
else
{
amp -= Channel::OUTPUT_DECAY;
}
}
return amp;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Triangle::Triangle()
: outputVolume(0) {}
void Apu::Triangle::Reset()
{
Oscillator::Reset();
step = 0x7;
status = STATUS_COUNTING;
waveLength = 0;
linearCtrl = 0;
linearCounter = 0;
lengthCounter.Reset();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
inline bool Apu::Triangle::CanOutput() const
{
return lengthCounter.GetCount() && linearCounter && waveLength >= MIN_FRQ && outputVolume;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Apu::Triangle::UpdateSettings(uint v,dword r,uint f,CpuModel model)
{
Oscillator::UpdateSettings( r, f );
if (model == CPU_DENDY)
v = v * 85 / Channel::DEFAULT_VOLUME;
outputVolume = (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME;
active = CanOutput();
}
void Apu::Triangle::SaveState(State::Saver& state,const dword chunk) const
{
state.Begin( chunk );
{
const byte data[4] =
{
waveLength & 0xFFU,
waveLength >> 8,
linearCounter | (uint(status) << 7),
linearCtrl
};
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
}
lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V );
state.End();
}
void Apu::Triangle::LoadState(State::Loader& state)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'R','E','G'>::V:
{
State::Loader::Data<4> data( state );
waveLength = data[0] | (data[1] << 8 & 0x0700);
linearCounter = data[2] & 0x7F;
status = static_cast(data[2] >> 7);
linearCtrl = data[3];
frequency = (waveLength + 1UL) * fixed;
break;
}
case AsciiId<'L','E','N'>::V:
lengthCounter.LoadState( state );
break;
}
state.End();
}
timer = 0;
step = 0;
active = CanOutput();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NST_SINGLE_CALL void Apu::Triangle::Disable(const bool disable)
{
active &= lengthCounter.Disable( disable );
}
NST_SINGLE_CALL void Apu::Triangle::WriteReg0(const uint data)
{
linearCtrl = data;
}
NST_SINGLE_CALL void Apu::Triangle::WriteReg2(const uint data)
{
waveLength = (waveLength & uint(REG3_WAVE_LENGTH_HIGH)) | (data & REG2_WAVE_LENGTH_LOW);
frequency = (waveLength + 1UL) * fixed;
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Triangle::WriteReg3(const uint data,const Cycle frameCounterDelta)
{
waveLength = (data << 8 & REG3_WAVE_LENGTH_HIGH) | (waveLength & uint(REG2_WAVE_LENGTH_LOW));
frequency = (waveLength + 1UL) * fixed;
status = STATUS_RELOAD;
lengthCounter.Write( data, frameCounterDelta );
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Triangle::ClockLinearCounter()
{
if (status == STATUS_COUNTING)
{
if (linearCounter && !--linearCounter)
active = false;
}
else
{
if (!(linearCtrl & uint(REG0_LINEAR_COUNTER_START)))
status = STATUS_COUNTING;
linearCounter = linearCtrl & uint(REG0_LINEAR_COUNTER_LOAD);
active = CanOutput();
}
}
NST_SINGLE_CALL void Apu::Triangle::ClockLengthCounter()
{
if (!(linearCtrl & uint(REG0_LINEAR_COUNTER_START)) && lengthCounter.Clock())
active = false;
}
NST_SINGLE_CALL dword Apu::Triangle::GetSample()
{
NST_VERIFY( bool(active) == CanOutput() && timer >= 0 );
if (active)
{
static const byte pyramid[32] =
{
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,
0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,
0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,
0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0
};
dword sum = timer;
timer -= idword(rate);
if (timer >= 0)
{
amp = pyramid[step] * outputVolume * 3;
}
else
{
sum *= pyramid[step];
do
{
sum += NST_MIN(-timer,frequency) * pyramid[step = (step + 1) & 0x1F];
timer += idword(frequency);
}
while (timer < 0);
NST_VERIFY( !outputVolume || sum <= 0xFFFFFFFF / outputVolume + rate/2 );
amp = (sum * outputVolume + rate/2) / rate * 3;
}
}
else if (amp < Channel::OUTPUT_DECAY)
{
return 0;
}
else
{
amp -= Channel::OUTPUT_DECAY;
step &= STEP_CHECK;
}
return amp;
}
inline uint Apu::Triangle::GetLengthCounter() const
{
return lengthCounter.GetCount();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Apu::Noise::Reset(const CpuModel model)
{
Oscillator::Reset();
frequency = lut[model][0] * dword(fixed);
bits = 1;
shifter = 13;
envelope.Reset();
lengthCounter.Reset();
}
uint Apu::Noise::GetFrequencyIndex() const
{
for (uint v=frequency/fixed, i=0; i < 16; ++i)
{
if (v == lut[0][i] || v == lut[1][i])
return i;
}
return 0;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
inline bool Apu::Noise::CanOutput() const
{
return lengthCounter.GetCount() && envelope.Volume();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Apu::Noise::UpdateSettings(uint v,dword r,uint f)
{
Oscillator::UpdateSettings( r, f );
envelope.SetOutputVolume( (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME );
active = CanOutput();
}
void Apu::Noise::SaveState(State::Saver& state,const dword chunk) const
{
state.Begin( chunk );
state.Begin( AsciiId<'R','E','G'>::V ).Write8( (shifter == 8 ? 0x10 : 0x00) | GetFrequencyIndex() ).End();
lengthCounter.SaveState( state, AsciiId<'L','E','N'>::V );
envelope.SaveState( state, AsciiId<'E','N','V'>::V );
state.End();
}
void Apu::Noise::LoadState(State::Loader& state,const CpuModel model)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'R','E','G'>::V:
{
const uint data = state.Read8();
frequency = lut[model][data & 0x0F] * dword(fixed);
shifter = (data & 0x10) ? 8 : 13;
break;
}
case AsciiId<'L','E','N'>::V:
lengthCounter.LoadState( state );
break;
case AsciiId<'E','N','V'>::V:
envelope.LoadState( state );
break;
}
state.End();
}
timer = 0;
bits = 1;
active = CanOutput();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NST_SINGLE_CALL void Apu::Noise::Disable(const bool disable)
{
active &= lengthCounter.Disable( disable );
}
NST_SINGLE_CALL void Apu::Noise::WriteReg0(const uint data)
{
envelope.Write( data );
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Noise::WriteReg2(const uint data,const CpuModel model)
{
frequency = lut[model][data & REG2_FREQUENCY] * dword(fixed);
shifter = (data & REG2_93BIT_MODE) ? 8 : 13;
}
NST_SINGLE_CALL void Apu::Noise::WriteReg3(const uint data,const Cycle frameCounterDelta)
{
envelope.ResetClock();
lengthCounter.Write( data, frameCounterDelta );
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Noise::ClockEnvelope()
{
envelope.Clock();
active = CanOutput();
}
NST_SINGLE_CALL void Apu::Noise::ClockLengthCounter()
{
if (!envelope.Looping() && lengthCounter.Clock())
active = false;
}
NST_SINGLE_CALL dword Apu::Noise::GetSample()
{
NST_VERIFY( bool(active) == CanOutput() && timer >= 0 );
dword sum = timer;
timer -= idword(rate);
if (active)
{
if (timer >= 0)
{
if (!(bits & 0x4000))
return envelope.Volume() * 2;
}
else
{
if (bits & 0x4000)
sum = 0;
do
{
bits = (bits << 1) | ((bits >> 14 ^ bits >> shifter) & 0x1);
if (!(bits & 0x4000))
sum += NST_MIN(-timer,frequency);
timer += idword(frequency);
}
while (timer < 0);
NST_VERIFY( !envelope.Volume() || sum <= 0xFFFFFFFF / envelope.Volume() + rate/2 );
return (sum * envelope.Volume() + rate/2) / rate * 2;
}
}
else while (timer < 0)
{
bits = (bits << 1) | ((bits >> 14 ^ bits >> shifter) & 0x1);
timer += idword(frequency);
}
return 0;
}
inline uint Apu::Noise::GetLengthCounter() const
{
return lengthCounter.GetCount();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Apu::Dmc::Dmc()
: outputVolume(0)
{
frequency = GetResetFrequency( CPU_RP2A03 );
}
void Apu::Dmc::Reset(const CpuModel model)
{
curSample = 0;
linSample = 0;
frequency = GetResetFrequency( model );
regs.ctrl = 0;
regs.lengthCounter = 1;
regs.address = 0xC000;
out.active = false;
out.shifter = 0;
out.dac = 0;
out.buffer = 0x00;
dma.lengthCounter = 0;
dma.buffered = false;
dma.address = 0xC000;
dma.buffer = 0x00;
}
Cycle Apu::Dmc::GetResetFrequency(CpuModel model)
{
return lut[model][0];
}
void Apu::Dmc::UpdateSettings(uint v)
{
v = (v * Channel::OUTPUT_MUL + Channel::DEFAULT_VOLUME/2) / Channel::DEFAULT_VOLUME;
if (outputVolume)
linSample /= outputVolume;
if (outputVolume)
curSample /= outputVolume;
linSample *= v;
curSample *= v;
outputVolume = v;
if (!v)
out.active = false;
}
inline void Apu::Dmc::ClearAmp()
{
curSample = 0;
linSample = 0;
}
void Apu::Dmc::SaveState(State::Saver& state,const dword chunk,const Cpu& cpu,const Cycle dmcMcClock) const
{
NST_VERIFY( dmcMcClock >= cpu.GetCycles() );
dword dmcClock = dmcMcClock;
if (dmcClock > cpu.GetCycles())
dmcClock = (dmcClock - cpu.GetCycles()) / cpu.GetClock();
else
dmcClock = 0;
NST_VERIFY( dmcClock <= 0x1FFF && dmcMcClock == cpu.GetCycles() + dmcClock * cpu.GetClock() );
byte data[12] =
{
dmcClock & 0xFF,
dmcClock >> 8,
(
( ( regs.ctrl & REG0_FREQUENCY ) ) |
( ( regs.ctrl & REG0_LOOP ) ? 0x10U : 0U ) |
( ( regs.ctrl & REG0_IRQ_ENABLE ) ? 0x20U : 0U ) |
( ( dma.lengthCounter ) ? 0x40U : 0U )
),
(regs.address - 0xC000U) >> 6,
(regs.lengthCounter - 1U) >> 4,
(dma.address >> 0 & 0xFFU),
(dma.address >> 8 & 0x7FU) | (dma.buffered ? 0x80 : 0x00),
dma.lengthCounter ? (dma.lengthCounter - 1U) >> 4 : 0,
dma.buffer,
7 - out.shifter,
out.buffer,
out.dac
};
state.Begin( chunk ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End();
}
void Apu::Dmc::LoadState(State::Loader& state,const Cpu& cpu,const CpuModel model,Cycle& dmcClock)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'R','E','G'>::V:
{
State::Loader::Data<12> data( state );
dmcClock = cpu.GetCycles() + ((data[0] | data[1] << 8) * cpu.GetClock());
regs.ctrl =
(
( ( data[2] & 0x10 ) ? REG0_LOOP : 0U ) |
( ( data[2] & 0x20 ) ? REG0_IRQ_ENABLE : 0U ) |
( ( data[2] & REG0_FREQUENCY ) )
);
frequency = lut[model][regs.ctrl & REG0_FREQUENCY];
regs.address = 0xC000 | (data[3] << 6);
regs.lengthCounter = (data[4] << 4) + 1;
dma.address = 0x8000 | data[5] | (data[6] << 8 & 0x7F00);
dma.buffered = data[6] >> 7;
dma.lengthCounter = (data[2] & 0x40) ? (data[7] << 4) + 1 : 0;
dma.buffer = data[8];
out.shifter = 7 - (data[9] & 0x7);
out.buffer = data[10];
out.dac = data[11] & 0x7F;
curSample = out.dac * outputVolume;
linSample = curSample;
out.active = dma.buffered && outputVolume;
break;
}
}
state.End();
}
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NST_SINGLE_CALL void Apu::Dmc::Disable(const bool disable,Cpu& cpu)
{
cpu.ClearIRQ( Cpu::IRQ_DMC );
if (disable)
{
dma.lengthCounter = 0;
}
else if (!dma.lengthCounter)
{
dma.lengthCounter = regs.lengthCounter;
dma.address = regs.address;
if (!dma.buffered)
DoDMA( cpu, cpu.GetCycles() );
}
}
NST_SINGLE_CALL dword Apu::Dmc::GetSample()
{
if (curSample != linSample)
{
const uint step = outputVolume * INP_STEP;
if (curSample + step - linSample <= step*2)
{
linSample = curSample;
}
else if (curSample > linSample)
{
linSample += step;
}
else
{
linSample -= step;
}
}
return linSample;
}
void Apu::Dmc::DoDMA(Cpu& cpu,const Cycle clock,const uint readAddress)
{
NST_VERIFY( !dma.buffered && (!readAddress || !cpu.IsWriteCycle(clock)) );
if (!readAddress)
{
cpu.StealCycles( cpu.GetClock(cpu.IsWriteCycle(clock) ? 2 : 3) );
}
else if (cpu.GetCycles() != clock)
{
cpu.StealCycles( cpu.GetClock(3) );
}
else
{
NST_DEBUG_MSG("DMA/Read conflict!");
cpu.StealCycles( cpu.GetClock(1) );
// This is disabled until a real solution is discovered
//if ((readAddress & 0xF000) != 0x4000)
// cpu.Peek( readAddress );
cpu.StealCycles( cpu.GetClock(1) );
cpu.Peek( readAddress );
cpu.StealCycles( cpu.GetClock(1) );
}
dma.buffer = cpu.Peek( dma.address );
cpu.StealCycles( cpu.GetClock() );
dma.address = 0x8000 | ((dma.address + 1U) & 0x7FFF);
dma.buffered = true;
NST_VERIFY( dma.lengthCounter );
if (!--dma.lengthCounter)
{
if (regs.ctrl & REG0_LOOP)
{
dma.address = regs.address;
dma.lengthCounter = regs.lengthCounter;
}
else if (regs.ctrl & REG0_IRQ_ENABLE)
{
cpu.DoIRQ( Cpu::IRQ_DMC );
}
}
}
NST_SINGLE_CALL bool Apu::Dmc::WriteReg0(const uint data,const CpuModel model)
{
regs.ctrl = data;
frequency = lut[model][data & REG0_FREQUENCY];
return data & REG0_IRQ_ENABLE;
}
NST_SINGLE_CALL void Apu::Dmc::WriteReg1(const uint data)
{
out.dac = data & 0x7F;
curSample = out.dac * outputVolume;
}
NST_SINGLE_CALL void Apu::Dmc::WriteReg2(const uint data)
{
regs.address = 0xC000 | (data << 6);
}
NST_SINGLE_CALL void Apu::Dmc::WriteReg3(const uint data)
{
regs.lengthCounter = (data << 4) + 1;
}
NST_SINGLE_CALL bool Apu::Dmc::ClockDAC()
{
if (out.active)
{
const uint next = out.dac + ((out.buffer & 0x1U) << 2) - 2;
out.buffer >>= 1;
if (next <= 0x7F && next != out.dac)
{
out.dac = next;
return true;
}
}
return false;
}
NST_SINGLE_CALL void Apu::Dmc::Update()
{
curSample = out.dac * outputVolume;
}
NST_SINGLE_CALL void Apu::Dmc::ClockDMA(Cpu& cpu,Cycle& clock,const uint readAddress)
{
const Cycle tmp = clock;
clock += frequency;
if (out.shifter)
{
out.shifter--;
}
else
{
out.shifter = 7;
out.active = dma.buffered;
if (out.active)
{
out.active = outputVolume;
dma.buffered = false;
out.buffer = dma.buffer;
if (dma.lengthCounter)
DoDMA( cpu, tmp, readAddress );
}
}
}
inline uint Apu::Dmc::GetLengthCounter() const
{
return dma.lengthCounter;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Apu::ClearBuffers()
{
ClearBuffers( true );
}
NST_NO_INLINE void Apu::ClearBuffers(bool resync)
{
if (resync)
synchronizer.Resync( settings.speed, cpu );
square[0].ClearAmp();
square[1].ClearAmp();
triangle.ClearAmp();
noise.ClearAmp();
dmc.ClearAmp();
dcBlocker.Reset();
buffer.Reset( settings.bits, false );
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
Cycle Apu::Clock()
{
if (cycles.dmcClock <= cpu.GetCycles())
ClockDmc( cpu.GetCycles() );
if (cycles.frameIrqClock <= cpu.GetCycles())
ClockFrameIRQ( cpu.GetCycles() );
return NST_MIN(cycles.dmcClock,cycles.frameIrqClock);
}
void Apu::ClockDMA(uint readAddress)
{
if (cycles.dmcClock <= cpu.GetCycles())
ClockDmc( cpu.GetCycles(), readAddress );
}
NST_NO_INLINE void Apu::ClockOscillators(const bool twoClocks)
{
for (uint i=0; i < 2; ++i)
square[i].ClockEnvelope();
triangle.ClockLinearCounter();
noise.ClockEnvelope();
if (twoClocks)
{
for (uint i=0; i < 2; ++i)
square[i].ClockSweep( i-1 );
triangle.ClockLengthCounter();
noise.ClockLengthCounter();
}
}
NST_NO_INLINE void Apu::ClockDmc(const Cycle target,const uint readAddress)
{
NST_ASSERT( cycles.dmcClock <= target );
do
{
if (dmc.ClockDAC())
{
Update( cycles.dmcClock );
dmc.Update();
}
dmc.ClockDMA( cpu, cycles.dmcClock, readAddress );
}
while (cycles.dmcClock <= target);
}
NST_NO_INLINE void Apu::ClockFrameCounter()
{
NST_COMPILE_ASSERT( STATUS_SEQUENCE_5_STEP == 0x80 );
NST_VERIFY( cycles.frameCounter <= cpu.GetCycles() * cycles.fixed );
ClockOscillators( cycles.frameDivider & 0x1U );
cycles.frameDivider = (cycles.frameDivider + 1) & 0x3U;
cycles.frameCounter += Cycles::oscillatorClocks[cpu.GetModel()][ctrl >> 7][cycles.frameDivider] * cycles.fixed;
}
NST_NO_INLINE void Apu::ClockFrameIRQ(const Cycle target)
{
NST_VERIFY( ctrl == STATUS_FRAME_IRQ_ENABLE );
cpu.DoIRQ( Cpu::IRQ_FRAME, cycles.frameIrqClock );
Cycle clock = cycles.frameIrqClock;
uint repeat = cycles.frameIrqRepeat;
do
{
clock += Cycles::frameClocks[cpu.GetModel()][1 + repeat++ % 3];
}
while (clock <= target);
cycles.frameIrqClock = clock;
cycles.frameIrqRepeat = repeat;
}
NST_NO_INLINE Apu::Channel::Sample Apu::GetSample()
{
dword dac[2];
return Clamp
(
dcBlocker.Apply
(
(0 != (dac[0] = square[0].GetSample() + square[1].GetSample()) ? NLN_SQ_0 / (NLN_SQ_1 / dac[0] + NLN_SQ_2) : 0) +
(0 != (dac[1] = triangle.GetSample() + noise.GetSample() + dmc.GetSample()) ? NLN_TND_0 / (NLN_TND_1 / dac[1] + NLN_TND_2) : 0)
) + (extChannel ? extChannel->GetSample() : 0)
);
}
NES_POKE_AD(Apu,4000)
{
UpdateLatency();
square[address >> 2 & 0x1].WriteReg0( data );
}
NES_POKE_AD(Apu,4001)
{
Update();
square[address >> 2 & 0x1].WriteReg1( data );
}
NES_POKE_AD(Apu,4002)
{
Update();
square[address >> 2 & 0x1].WriteReg2( data );
}
NES_POKE_AD(Apu,4003)
{
square[address >> 2 & 0x1].WriteReg3( data, UpdateDelta() );
}
NES_POKE_D(Apu,4008)
{
Update();
triangle.WriteReg0( data );
}
NES_POKE_D(Apu,400A)
{
Update();
triangle.WriteReg2( data );
}
NES_POKE_D(Apu,400B)
{
triangle.WriteReg3( data, UpdateDelta() );
}
NES_POKE_D(Apu,400C)
{
UpdateLatency();
noise.WriteReg0( data );
}
NES_POKE_D(Apu,400E)
{
Update();
noise.WriteReg2( data, cpu.GetModel() );
}
NES_POKE_D(Apu,400F)
{
noise.WriteReg3( data, UpdateDelta() );
}
NES_POKE_D(Apu,4010)
{
if (!dmc.WriteReg0( data, cpu.GetModel() ))
cpu.ClearIRQ( Cpu::IRQ_DMC );
}
NES_POKE_D(Apu,4011)
{
Update();
dmc.WriteReg1( data );
}
NES_POKE_D(Apu,4012)
{
dmc.WriteReg2( data );
}
NES_POKE_D(Apu,4013)
{
dmc.WriteReg3( data );
}
NES_POKE_D(Apu,4015)
{
Update();
data = ~data;
square[0].Disable ( data >> 0 & 0x1 );
square[1].Disable ( data >> 1 & 0x1 );
triangle.Disable ( data >> 2 & 0x1 );
noise.Disable ( data >> 3 & 0x1 );
dmc.Disable ( data & 0x10, cpu );
}
NES_PEEK_A(Apu,4015)
{
NST_COMPILE_ASSERT( Cpu::IRQ_FRAME == 0x40 && Cpu::IRQ_DMC == 0x80 );
const Cycle elapsed = cpu.Update( address );
if (cycles.frameIrqClock <= elapsed)
ClockFrameIRQ( elapsed );
if (cycles.frameCounter < elapsed * cycles.fixed)
Update( elapsed );
const uint data = cpu.GetIRQ();
cpu.ClearIRQ( Cpu::IRQ_FRAME );
return (data & (Cpu::IRQ_FRAME|Cpu::IRQ_DMC)) |
(
( square[0].GetLengthCounter() ? 0x01U : 0x00U ) |
( square[1].GetLengthCounter() ? 0x02U : 0x00U ) |
( triangle.GetLengthCounter() ? 0x04U : 0x00U ) |
( noise.GetLengthCounter() ? 0x08U : 0x00U ) |
( dmc.GetLengthCounter() ? 0x10U : 0x00U )
);
}
void Apu::WriteFrameCtrl(uint data)
{
Cycle next = cpu.Update();
if (cpu.IsOddCycle())
next += cpu.GetClock();
Update( next );
if (cycles.frameIrqClock <= next)
ClockFrameIRQ( next );
next += cpu.GetClock();
data &= STATUS_BITS;
cycles.frameCounter = (next + Cycles::oscillatorClocks[cpu.GetModel()][data >> 7][0]) * cycles.fixed;
cycles.frameDivider = 0;
cycles.frameIrqRepeat = 0;
ctrl = data;
if (data)
{
cycles.frameIrqClock = Cpu::CYCLE_MAX;
if (data & STATUS_NO_FRAME_IRQ)
cpu.ClearIRQ( Cpu::IRQ_FRAME );
if (data & STATUS_SEQUENCE_5_STEP)
ClockOscillators( true );
}
else
{
cycles.frameIrqClock = next + Cycles::frameClocks[cpu.GetModel()][0];
}
}
NES_PEEK(Apu,40xx)
{
return 0x40;
}
}
}
nestopia-1.47/source/core/NstApu.hpp 0000664 0000000 0000000 00000033407 12644314416 0017456 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CPU_H
#error Do not include NstApu.h directly!
#endif
#include "NstSoundRenderer.hpp"
namespace Nes
{
namespace Core
{
namespace Sound
{
class Output;
}
namespace State
{
class Saver;
class Loader;
}
class Cpu;
class Apu
{
public:
explicit Apu(Cpu&);
void Reset(bool);
void PowerOff();
void ClearBuffers();
void BeginFrame(Sound::Output*);
void EndFrame();
void WriteFrameCtrl(uint);
Cycle Clock();
void ClockDMA(uint=0);
Result SetSampleRate(dword);
Result SetSampleBits(uint);
Result SetSpeed(uint);
Result SetVolume(uint,uint);
uint GetVolume(uint) const;
void Mute(bool);
void SetAutoTranspose(bool);
void SetGenie(bool);
void EnableStereo(bool);
void SaveState(State::Saver&,dword) const;
void LoadState(State::Loader&);
class NST_NO_VTABLE Channel
{
Apu& apu;
protected:
explicit Channel(Apu&);
~Channel();
void Update() const;
void Connect(bool);
dword GetSampleRate() const;
uint GetVolume(uint) const;
void GetOscillatorClock(Cycle&,uint&) const;
Cycle GetCpuClockBase() const;
uint GetCpuClockDivider() const;
Cycle GetCpuClock(uint=1) const;
bool IsMuted() const;
bool IsGenie() const;
public:
typedef Sound::Sample Sample;
enum
{
APU_SQUARE1,
APU_SQUARE2,
APU_TRIANGLE,
APU_NOISE,
APU_DPCM,
EXT_FDS,
EXT_MMC5,
EXT_VRC6,
EXT_VRC7,
EXT_N163,
EXT_S5B
};
enum
{
OUTPUT_MIN = -32767,
OUTPUT_MAX = +32767,
OUTPUT_MUL = 256,
OUTPUT_DECAY = OUTPUT_MUL / 4 - 1,
DEFAULT_VOLUME = 85
};
virtual void Reset() = 0;
virtual Sample GetSample() = 0;
virtual Cycle Clock(Cycle,Cycle,Cycle);
virtual bool UpdateSettings() = 0;
class LengthCounter
{
public:
LengthCounter();
void Reset();
void LoadState(State::Loader&);
void SaveState(State::Saver&,dword) const;
private:
uint enabled;
uint count;
static const byte lut[32];
public:
uint Disable(bool disable)
{
enabled = disable - 1U;
count &= enabled;
return enabled;
}
void Write(uint data)
{
NST_ASSERT( (data >> 3) < sizeof(array(lut)) );
count = lut[data >> 3] & enabled;
}
void Write(uint data,bool frameCounterDelta)
{
NST_VERIFY_MSG( frameCounterDelta, "APU $40xx/framecounter conflict" );
if (frameCounterDelta || !count)
Write( data );
}
uint GetCount() const
{
return count;
}
bool Clock()
{
return count && !--count;
}
};
class Envelope
{
public:
Envelope();
void Reset();
void SetOutputVolume(uint);
void LoadState(State::Loader&);
void SaveState(State::Saver&,dword) const;
void Clock();
void Write(uint);
private:
void UpdateOutput();
dword output;
uint outputVolume;
byte regs[2];
byte count;
bool reset;
public:
bool Looping() const
{
return regs[1] & 0x20U;
}
dword Volume() const
{
return output;
}
void ResetClock()
{
reset = true;
}
};
class DcBlocker
{
public:
DcBlocker();
void Reset();
Sample Apply(Sample);
private:
enum
{
POLE = 3 // ~0.9999
};
idword prev;
idword next;
idword acc;
};
};
private:
typedef void (NST_FASTCALL Apu::*Updater)(Cycle);
inline void Update(Cycle);
void Update();
void UpdateLatency();
bool UpdateDelta();
void Reset(bool,bool);
void CalculateOscillatorClock(Cycle&,uint&) const;
void Resync(dword);
NST_NO_INLINE void ClearBuffers(bool);
enum
{
MAX_CHANNELS = 11,
STATUS_NO_FRAME_IRQ = 0x40,
STATUS_SEQUENCE_5_STEP = 0x80,
STATUS_FRAME_IRQ_ENABLE = 0,
STATUS_BITS = STATUS_NO_FRAME_IRQ|STATUS_SEQUENCE_5_STEP,
NLN_VOL = 192,
NLN_SQ_F = 900,
NLN_SQ_0 = 9552UL * Channel::OUTPUT_MUL * NLN_VOL * (NLN_SQ_F/100),
NLN_SQ_1 = 8128UL * Channel::OUTPUT_MUL * NLN_SQ_F,
NLN_SQ_2 = NLN_SQ_F * 100UL,
NLN_TND_F = 500,
NLN_TND_0 = 16367UL * Channel::OUTPUT_MUL * NLN_VOL * (NLN_TND_F/100),
NLN_TND_1 = 24329UL * Channel::OUTPUT_MUL * NLN_TND_F,
NLN_TND_2 = NLN_TND_F * 100UL
};
NES_DECL_POKE( 4000 );
NES_DECL_POKE( 4001 );
NES_DECL_POKE( 4002 );
NES_DECL_POKE( 4003 );
NES_DECL_POKE( 4004 );
NES_DECL_POKE( 4005 );
NES_DECL_POKE( 4006 );
NES_DECL_POKE( 4007 );
NES_DECL_POKE( 4008 );
NES_DECL_POKE( 400A );
NES_DECL_POKE( 400B );
NES_DECL_POKE( 400C );
NES_DECL_POKE( 400E );
NES_DECL_POKE( 400F );
NES_DECL_POKE( 4010 );
NES_DECL_POKE( 4011 );
NES_DECL_POKE( 4012 );
NES_DECL_POKE( 4013 );
NES_DECL_POKE( 4015 );
NES_DECL_PEEK( 4015 );
NES_DECL_PEEK( 40xx );
NST_NO_INLINE Channel::Sample GetSample();
void NST_FASTCALL SyncOn (Cycle);
void NST_FASTCALL SyncOnExt (Cycle);
void NST_FASTCALL SyncOff (Cycle);
NST_NO_INLINE void ClockFrameIRQ(Cycle);
NST_NO_INLINE void ClockFrameCounter();
NST_NO_INLINE void ClockDmc(Cycle,uint=0);
NST_NO_INLINE void ClockOscillators(bool);
template
void FlushSound();
void UpdateSettings();
void UpdateVolumes();
struct Cycles
{
Cycles();
void Update(dword,uint,const Cpu&);
void Reset(bool,CpuModel);
uint fixed;
Cycle rate;
Cycle rateCounter;
Cycle frameCounter;
Cycle extCounter;
word frameDivider;
word frameIrqRepeat;
Cycle frameIrqClock;
Cycle dmcClock;
static const dword frameClocks[3][4];
static const dword oscillatorClocks[3][2][4];
};
class Synchronizer
{
uint sync;
uint duty;
dword streamed;
dword rate;
public:
Synchronizer();
void Reset(uint,dword,const Cpu&);
void Resync(uint,const Cpu&);
NST_SINGLE_CALL dword Clock(dword,dword,const Cpu&);
};
class Oscillator
{
enum
{
RESET_CYCLES = 2048
};
protected:
Oscillator();
void Reset();
void UpdateSettings(dword,uint);
ibool active;
idword timer;
Cycle rate;
Cycle frequency;
dword amp;
uint fixed;
public:
inline void ClearAmp();
};
class Square : public Oscillator
{
public:
void Reset();
void UpdateSettings(uint,dword,uint);
void LoadState(State::Loader&);
void SaveState(State::Saver&,dword) const;
NST_SINGLE_CALL void WriteReg0(uint);
NST_SINGLE_CALL void WriteReg1(uint);
NST_SINGLE_CALL void WriteReg2(uint);
NST_SINGLE_CALL void WriteReg3(uint,Cycle);
NST_SINGLE_CALL void Disable(bool);
dword GetSample();
NST_SINGLE_CALL void ClockEnvelope();
NST_SINGLE_CALL void ClockSweep(uint);
inline uint GetLengthCounter() const;
private:
inline bool CanOutput() const;
void UpdateFrequency();
enum
{
MIN_FRQ = 0x008,
MAX_FRQ = 0x7FF,
REG0_DUTY_SHIFT = 6,
REG1_SWEEP_SHIFT = 0x07,
REG1_SWEEP_DECREASE = 0x08,
REG1_SWEEP_RATE = 0x70,
REG1_SWEEP_RATE_SHIFT = 4,
REG1_SWEEP_ENABLED = 0x80,
REG3_WAVELENGTH_LOW = 0x00FF,
REG3_WAVELENGTH_HIGH = 0x0700
};
uint step;
uint duty;
Channel::Envelope envelope;
Channel::LengthCounter lengthCounter;
bool validFrequency;
bool sweepReload;
byte sweepCount;
byte sweepRate;
uint sweepIncrease;
word sweepShift;
word waveLength;
};
class Triangle : public Oscillator
{
public:
Triangle();
void Reset();
void UpdateSettings(uint,dword,uint,CpuModel);
void LoadState(State::Loader&);
void SaveState(State::Saver&,dword) const;
NST_SINGLE_CALL void WriteReg0(uint);
NST_SINGLE_CALL void WriteReg2(uint);
NST_SINGLE_CALL void WriteReg3(uint,Cycle);
NST_SINGLE_CALL void Disable(bool);
NST_SINGLE_CALL dword GetSample();
NST_SINGLE_CALL void ClockLinearCounter();
NST_SINGLE_CALL void ClockLengthCounter();
inline uint GetLengthCounter() const;
private:
inline bool CanOutput() const;
enum
{
MIN_FRQ = 2 + 1,
STEP_CHECK = 0x00, // >= 0x1F is technically correct but will produce clicks/pops
REG0_LINEAR_COUNTER_LOAD = 0x7F,
REG0_LINEAR_COUNTER_START = 0x80,
REG2_WAVE_LENGTH_LOW = 0x00FF,
REG3_WAVE_LENGTH_HIGH = 0x0700
};
enum Status
{
STATUS_COUNTING,
STATUS_RELOAD
};
uint step;
uint outputVolume;
Status status;
word waveLength;
byte linearCtrl;
byte linearCounter;
Channel::LengthCounter lengthCounter;
};
class Noise : public Oscillator
{
public:
void Reset(CpuModel);
void UpdateSettings(uint,dword,uint);
void LoadState(State::Loader&,CpuModel);
void SaveState(State::Saver&,dword) const;
NST_SINGLE_CALL void WriteReg0(uint);
NST_SINGLE_CALL void WriteReg2(uint,CpuModel);
NST_SINGLE_CALL void WriteReg3(uint,Cycle);
NST_SINGLE_CALL void Disable(bool);
NST_SINGLE_CALL dword GetSample();
NST_SINGLE_CALL void ClockEnvelope();
NST_SINGLE_CALL void ClockLengthCounter();
inline uint GetLengthCounter() const;
private:
inline bool CanOutput() const;
uint GetFrequencyIndex() const;
enum
{
REG2_FREQUENCY = 0x0F,
REG2_93BIT_MODE = 0x80
};
uint bits;
uint shifter;
Channel::Envelope envelope;
Channel::LengthCounter lengthCounter;
static const word lut[3][16];
};
class Dmc
{
public:
Dmc();
void Reset(CpuModel);
void UpdateSettings(uint);
void LoadState(State::Loader&,const Cpu&,CpuModel,Cycle&);
void SaveState(State::Saver&,dword,const Cpu&,Cycle) const;
NST_SINGLE_CALL bool WriteReg0(uint,CpuModel);
NST_SINGLE_CALL void WriteReg1(uint);
NST_SINGLE_CALL void WriteReg2(uint);
NST_SINGLE_CALL void WriteReg3(uint);
NST_SINGLE_CALL void Disable(bool,Cpu&);
NST_SINGLE_CALL dword GetSample();
NST_SINGLE_CALL bool ClockDAC();
NST_SINGLE_CALL void Update();
NST_SINGLE_CALL void ClockDMA(Cpu&,Cycle&,uint=0);
inline void ClearAmp();
inline uint GetLengthCounter() const;
static Cycle GetResetFrequency(CpuModel);
private:
void DoDMA(Cpu&,Cycle,uint=0);
enum
{
REG0_FREQUENCY = 0x0F,
REG0_LOOP = 0x40,
REG0_IRQ_ENABLE = 0x80,
INP_STEP = 8
};
uint curSample;
uint linSample;
uint outputVolume;
Cycle frequency;
struct
{
uint ctrl;
word lengthCounter;
word address;
} regs;
struct
{
byte shifter;
byte dac;
byte buffer;
bool active;
} out;
struct
{
word lengthCounter;
word address;
word buffered;
word buffer;
} dma;
static const word lut[3][16];
};
struct Settings
{
Settings();
dword rate;
uint bits;
byte speed;
bool muted;
bool transpose;
bool genie;
bool stereo;
bool audible;
byte volumes[MAX_CHANNELS];
};
uint ctrl;
Updater updater;
Cpu& cpu;
Cycles cycles;
Synchronizer synchronizer;
Square square[2];
Triangle triangle;
Noise noise;
Dmc dmc;
Channel* extChannel;
Channel::DcBlocker dcBlocker;
Sound::Output* stream;
Sound::Buffer buffer;
Settings settings;
public:
dword GetSampleRate() const
{
return settings.rate;
}
uint GetSampleBits() const
{
return settings.bits;
}
uint GetSpeed() const
{
return settings.speed;
}
bool IsAutoTransposing() const
{
return settings.transpose;
}
bool IsGenie() const
{
return settings.genie;
}
bool InStereo() const
{
return settings.stereo;
}
bool IsMuted() const
{
return settings.muted;
}
bool IsAudible() const
{
return settings.audible && !settings.muted;
}
};
}
}
nestopia-1.47/source/core/NstAssert.cpp 0000664 0000000 0000000 00000006375 12644314416 0020171 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "NstCore.hpp"
#if defined(NST_DEBUG) && defined(NST_WIN32)
#include
#include
#include
#include
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include
#ifdef _UNICODE
#define NST_MESSAGEBOX MessageBoxA
#else
#define NST_MESSAGEBOX MessageBox
#endif
#if NST_MSVC >= 1200
#ifdef _UNICODE
#define NST_DEBUGSTRING(s_) OutputDebugStringA( s_ );
#else
#define NST_DEBUGSTRING(s_) OutputDebugString( s_ );
#endif
#else
#define NST_DEBUGSTRING(s_)
#endif
namespace Nes
{
namespace Assertion
{
NST_NO_INLINE uint NST_CALL Issue
(
const char* expression,
const char* msg,
const char* file,
const char* function,
int line
)
{
const std::size_t length =
(
(msg ? std::strlen(msg) : 0) +
(expression ? std::strlen(expression) : 16) +
(file ? std::strlen(file) : 16) +
(function ? std::strlen(function) : 16) +
64 + 1
);
if (char* const buffer = new (std::nothrow) char [length])
{
std::sprintf
(
buffer,
msg ? "%s, Expression: %s\n\n File: %s\n Function: %s\n Line: %i\n\n" :
"%sExpression: %s\n\n File: %s\n Function: %s\n Line: %i\n\n",
msg ? msg : "",
expression ? expression : "break point",
file,
function ? function : "unknown",
line
);
NST_DEBUGSTRING( buffer );
int result = NST_MESSAGEBOX
(
::GetActiveWindow(),
buffer,
"Nestopia Debug Assertion!",
MB_ABORTRETRYIGNORE|MB_SETFOREGROUND|MB_TOPMOST
);
delete [] buffer;
if (result != IDABORT)
return result == IDIGNORE ? 1 : 2;
result = NST_MESSAGEBOX
(
::GetActiveWindow(),
"break into the debugger?",
"Nestopia Debug Assertion!",
MB_YESNO|MB_SETFOREGROUND|MB_TOPMOST
);
if (result == IDNO)
::FatalExit( EXIT_FAILURE );
}
else
{
NST_MESSAGEBOX
(
::GetActiveWindow(),
"Out of memory!",
"Nestopia Debug Assertion!",
MB_OK|MB_ICONERROR|MB_SETFOREGROUND|MB_TOPMOST
);
::FatalExit( EXIT_FAILURE );
}
return 0;
}
}
}
#endif
nestopia-1.47/source/core/NstAssert.hpp 0000664 0000000 0000000 00000011421 12644314416 0020162 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_ASSERT_H
#define NST_ASSERT_H
#ifndef NST_CORE_H
#include "NstCore.hpp"
#endif
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
#ifndef NST_DEBUG
#define NST_DEBUG_MSG(msg_) NST_NOP()
#define NST_ASSERT_MSG(expr_,msg_) NST_ASSUME(expr_)
#define NST_VERIFY_MSG(expr_,msg_) NST_NOP()
#elif defined(NST_WIN32)
#if NST_GCC >= 200 || NST_MWERKS >= 0x3000
#define NST_FUNC_NAME __PRETTY_FUNCTION__
#elif NST_MSVC >= 1300
#define NST_FUNC_NAME __FUNCTION__
#elif NST_BCC >= 0x550
#define NST_FUNC_NAME __FUNC__
#else
#define NST_FUNC_NAME 0
#endif
#if NST_MSVC >= 1300
#define NST_HALT() __debugbreak()
#elif NST_MSVC >= 1200 && defined(_M_IX86)
#define NST_HALT() __asm {int 3} NST_NOP()
#else
#include
#define NST_HALT() std::abort()
#endif
namespace Nes
{
namespace Assertion
{
NST_NO_INLINE uint NST_CALL Issue
(
const char*,
const char*,
const char*,
const char*,
int
);
}
}
#define NST_DEBUG_MSG(msg_) \
{ \
static bool ignore_ = false; \
\
if (!ignore_) \
{ \
switch (Nes::Assertion::Issue(0,msg_,__FILE__,NST_FUNC_NAME,__LINE__)) \
{ \
case 0: NST_HALT(); break; \
case 1: ignore_ = true; break; \
} \
} \
} \
NST_NOP()
#define NST_ASSERT_MSG(expr_,msg_) \
{ \
static bool ignore_ = false; \
\
if (!ignore_ && !(expr_)) \
{ \
switch (Nes::Assertion::Issue(#expr_,msg_,__FILE__,NST_FUNC_NAME,__LINE__)) \
{ \
case 0: NST_HALT(); break; \
case 1: ignore_ = true; break; \
} \
} \
} \
NST_NOP()
#define NST_VERIFY_MSG(expr_,msg_) NST_ASSERT_MSG(expr_,msg_)
#else
#include
#define NST_DEBUG_MSG(msg_) NST_NOP()
#define NST_ASSERT_MSG(expr_,msg_) assert( !!(expr_) )
#define NST_VERIFY_MSG(expr_,msg_) NST_NOP()
#endif
#define NST_ASSERT(expr_) NST_ASSERT_MSG(expr_,0)
#define NST_VERIFY(expr_) NST_VERIFY_MSG(expr_,0)
#endif
nestopia-1.47/source/core/NstBarcodeReader.hpp 0000664 0000000 0000000 00000002602 12644314416 0021404 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_BARCODEREADER_H
#define NST_BARCODEREADER_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
class NST_NO_VTABLE BarcodeReader
{
public:
virtual bool Transfer(cstring,uint) = 0;
virtual bool IsDigitsSupported(uint) const = 0;
virtual bool IsTransferring() const = 0;
};
}
}
#endif
nestopia-1.47/source/core/NstBase.hpp 0000664 0000000 0000000 00000025457 12644314416 0017611 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_BASE_H
#define NST_BASE_H
#include
#include "api/NstApiConfig.hpp"
//--------------------------------------------------------------------------------------
// Microsoft Visual C++
//--------------------------------------------------------------------------------------
#ifdef _MSC_VER
#define NST_MSVC _MSC_VER
#else
#define NST_MSVC 0
#endif
//--------------------------------------------------------------------------------------
// Intel C/C++ Compiler
//--------------------------------------------------------------------------------------
#ifdef __INTEL_COMPILER
#define NST_ICC __INTEL_COMPILER
#else
#define NST_ICC 0
#endif
//--------------------------------------------------------------------------------------
// GNU Compiler Collection
//--------------------------------------------------------------------------------------
#ifdef __GNUC__
#define NST_GCC (__GNUC__ * 100 + __GNUC_MINOR__)
#else
#define NST_GCC 0
#endif
//--------------------------------------------------------------------------------------
// Borland C++
//--------------------------------------------------------------------------------------
#ifdef __BORLANDC__
#define NST_BCB __BORLANDC__
#else
#define NST_BCB 0
#endif
//--------------------------------------------------------------------------------------
// Metrowerks CodeWarrior
//--------------------------------------------------------------------------------------
#ifdef __MWERKS__
#define NST_MWERKS __MWERKS__
#else
#define NST_MWERKS 0
#endif
//--------------------------------------------------------------------------------------
#ifdef NST_PRAGMA_ONCE
#pragma once
#elif NST_MSVC >= 1020 || NST_MWERKS >= 0x3000
#pragma once
#define NST_PRAGMA_ONCE
#endif
//--------------------------------------------------------------------------------------
#ifndef NST_CALL
#define NST_CALL
#endif
namespace Nes
{
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
#if UCHAR_MAX >= 0xFF
typedef unsigned char byte;
#else
#error Unsupported plattform!
#endif
#if UCHAR_MAX >= 0xFFFF
typedef unsigned char word;
#elif USHRT_MAX >= 0xFFFF
typedef unsigned short word;
#elif UINT_MAX >= 0xFFFF
typedef unsigned int word;
#else
#error Unsupported plattform!
#endif
#if SCHAR_MAX >= 32767 && SCHAR_MIN <= -32767
typedef signed char iword;
#elif SHRT_MAX >= 32767 && SHRT_MIN <= -32767
typedef signed short iword;
#elif INT_MAX >= 32767 && INT_MIN <= -32767
typedef signed int iword;
#else
#error Unsupported plattform!
#endif
#if UCHAR_MAX >= 0xFFFFFFFF
typedef unsigned char dword;
#elif USHRT_MAX >= 0xFFFFFFFF
typedef unsigned short dword;
#elif UINT_MAX >= 0xFFFFFFFF
typedef unsigned int dword;
#elif ULONG_MAX >= 0xFFFFFFFF
typedef unsigned long dword;
#else
#error Unsupported plattform!
#endif
#if SCHAR_MAX >= 2147483647 && SCHAR_MIN <= -2147483647
typedef signed char idword;
#elif SHRT_MAX >= 2147483647 && SHRT_MIN <= -2147483647
typedef signed short idword;
#elif INT_MAX >= 2147483647 && INT_MIN <= -2147483647
typedef signed int idword;
#elif LONG_MAX >= 2147483647 && LONG_MIN <= -2147483647
typedef signed long idword;
#else
#error Unsupported plattform!
#endif
/**
* General result codes.
*/
enum Result
{
/**
* NTSC/PAL region mismatch.
*/
RESULT_ERR_WRONG_MODE = -13,
/**
* Missing FDS BIOS.
*/
RESULT_ERR_MISSING_BIOS = -12,
/**
* Unsupported or malformed mapper.
*/
RESULT_ERR_UNSUPPORTED_MAPPER = -11,
/**
* Vs DualSystem is unsupported.
*/
RESULT_ERR_UNSUPPORTED_VSSYSTEM = -10,
/**
* File format version is no longer supported.
*/
RESULT_ERR_UNSUPPORTED_FILE_VERSION = -9,
/**
* Unsupported operation.
*/
RESULT_ERR_UNSUPPORTED = -8,
/**
* Invalid CRC checksum.
*/
RESULT_ERR_INVALID_CRC = -7,
/**
* Corrupt file.
*/
RESULT_ERR_CORRUPT_FILE = -6,
/**
* Invalid file.
*/
RESULT_ERR_INVALID_FILE = -5,
/**
* Invalid parameter(s).
*/
RESULT_ERR_INVALID_PARAM = -4,
/**
* System not ready.
*/
RESULT_ERR_NOT_READY = -3,
/**
* Out of memory.
*/
RESULT_ERR_OUT_OF_MEMORY = -2,
/**
* Generic error.
*/
RESULT_ERR_GENERIC = -1,
/**
* Success.
*/
RESULT_OK = 0,
/**
* Success but operation had no effect.
*/
RESULT_NOP = 1,
/**
* Success but image dump may be bad.
*/
RESULT_WARN_BAD_DUMP = 2,
/**
* Success but PRG-ROM may be bad.
*/
RESULT_WARN_BAD_PROM = 3,
/**
* Success but CHR-ROM may be bad.
*/
RESULT_WARN_BAD_CROM = 4,
/**
* Success but file header may have incorrect data.
*/
RESULT_WARN_BAD_FILE_HEADER = 5,
/**
* Success but save data has been lost.
*/
RESULT_WARN_SAVEDATA_LOST = 6,
/**
* Success but data may have been replaced.
*/
RESULT_WARN_DATA_REPLACED = 8
};
namespace Core
{
enum Region
{
REGION_NTSC,
REGION_PAL
};
enum System
{
SYSTEM_NES_NTSC,
SYSTEM_NES_PAL,
SYSTEM_NES_PAL_A,
SYSTEM_NES_PAL_B,
SYSTEM_FAMICOM,
SYSTEM_DENDY,
SYSTEM_VS_UNISYSTEM,
SYSTEM_VS_DUALSYSTEM,
SYSTEM_PLAYCHOICE_10
};
enum FavoredSystem
{
FAVORED_NES_NTSC,
FAVORED_NES_PAL,
FAVORED_FAMICOM,
FAVORED_DENDY
};
enum CpuModel
{
CPU_RP2A03,
CPU_RP2A07,
CPU_DENDY
};
enum PpuModel
{
PPU_RP2C02,
PPU_RP2C03B,
PPU_RP2C03G,
PPU_RP2C04_0001,
PPU_RP2C04_0002,
PPU_RP2C04_0003,
PPU_RP2C04_0004,
PPU_RC2C03B,
PPU_RC2C03C,
PPU_RC2C05_01,
PPU_RC2C05_02,
PPU_RC2C05_03,
PPU_RC2C05_04,
PPU_RC2C05_05,
PPU_RP2C07,
PPU_DENDY
};
enum
{
CLK_M2_MUL = 6,
CLK_NTSC = 39375000UL * CLK_M2_MUL,
CLK_NTSC_DIV = 11,
CLK_NTSC_HVSYNC = 525UL * 455 * CLK_NTSC_DIV * CLK_M2_MUL / 4,
CLK_PAL = 35468950UL * CLK_M2_MUL,
CLK_PAL_DIV = 8,
CLK_PAL_HVSYNC = 625UL * 1418758 / (10000/CLK_PAL_DIV) * CLK_M2_MUL
};
enum
{
CPU_RP2A03_CC = 12,
CPU_RP2A07_CC = 16,
CPU_DENDY_CC = 15
};
enum
{
PPU_RP2C02_CC = 4,
PPU_RP2C02_HACTIVE = PPU_RP2C02_CC * 256,
PPU_RP2C02_HBLANK = PPU_RP2C02_CC * 85,
PPU_RP2C02_HSYNC = PPU_RP2C02_HACTIVE + PPU_RP2C02_HBLANK,
PPU_RP2C02_VACTIVE = 240,
PPU_RP2C02_VSLEEP = 1,
PPU_RP2C02_VINT = 20,
PPU_RP2C02_VDUMMY = 1,
PPU_RP2C02_VBLANK = PPU_RP2C02_VSLEEP + PPU_RP2C02_VINT + PPU_RP2C02_VDUMMY,
PPU_RP2C02_VSYNC = PPU_RP2C02_VACTIVE + PPU_RP2C02_VBLANK,
PPU_RP2C02_HVSYNCBOOT = PPU_RP2C02_VACTIVE * PPU_RP2C02_HSYNC + PPU_RP2C02_CC * 312,
PPU_RP2C02_HVREGBOOT = (PPU_RP2C02_VACTIVE + PPU_RP2C02_VINT) * PPU_RP2C02_HSYNC + PPU_RP2C02_CC * 314,
PPU_RP2C02_HVINT = PPU_RP2C02_VINT * ulong(PPU_RP2C02_HSYNC),
PPU_RP2C02_HVSYNC_0 = PPU_RP2C02_VSYNC * ulong(PPU_RP2C02_HSYNC),
PPU_RP2C02_HVSYNC_1 = PPU_RP2C02_VSYNC * ulong(PPU_RP2C02_HSYNC) - PPU_RP2C02_CC,
PPU_RP2C02_HVSYNC = (PPU_RP2C02_HVSYNC_0 + ulong(PPU_RP2C02_HVSYNC_1)) / 2,
PPU_RP2C02_FPS = (CLK_NTSC + CLK_NTSC_DIV * ulong(PPU_RP2C02_HVSYNC) / 2) / (CLK_NTSC_DIV * ulong(PPU_RP2C02_HVSYNC)),
PPU_RP2C07_CC = 5,
PPU_RP2C07_HACTIVE = PPU_RP2C07_CC * 256,
PPU_RP2C07_HBLANK = PPU_RP2C07_CC * 85,
PPU_RP2C07_HSYNC = PPU_RP2C07_HACTIVE + PPU_RP2C07_HBLANK,
PPU_RP2C07_VACTIVE = 240,
PPU_RP2C07_VSLEEP = 1,
PPU_RP2C07_VINT = 70,
PPU_RP2C07_VDUMMY = 1,
PPU_RP2C07_VBLANK = PPU_RP2C07_VSLEEP + PPU_RP2C07_VINT + PPU_RP2C07_VDUMMY,
PPU_RP2C07_VSYNC = PPU_RP2C07_VACTIVE + PPU_RP2C07_VBLANK,
PPU_RP2C07_HVSYNCBOOT = PPU_RP2C07_VACTIVE * PPU_RP2C07_HSYNC + PPU_RP2C07_CC * 312,
PPU_RP2C07_HVREGBOOT = (PPU_RP2C07_VACTIVE + PPU_RP2C07_VINT) * PPU_RP2C07_HSYNC + PPU_RP2C07_CC * 314,
PPU_RP2C07_HVINT = PPU_RP2C07_VINT * ulong(PPU_RP2C07_HSYNC),
PPU_RP2C07_HVSYNC = PPU_RP2C07_VSYNC * ulong(PPU_RP2C07_HSYNC),
PPU_RP2C07_FPS = (CLK_PAL + CLK_PAL_DIV * ulong(PPU_RP2C07_HVSYNC) / 2) / (CLK_PAL_DIV * ulong(PPU_RP2C07_HVSYNC)),
PPU_DENDY_CC = 5,
PPU_DENDY_HACTIVE = PPU_DENDY_CC * 256,
PPU_DENDY_HBLANK = PPU_DENDY_CC * 85,
PPU_DENDY_HSYNC = PPU_DENDY_HACTIVE + PPU_DENDY_HBLANK,
PPU_DENDY_VACTIVE = 240,
PPU_DENDY_VSLEEP = 51,
PPU_DENDY_VINT = 20,
PPU_DENDY_VDUMMY = 1,
PPU_DENDY_VBLANK = PPU_DENDY_VSLEEP + PPU_DENDY_VINT + PPU_DENDY_VDUMMY,
PPU_DENDY_VSYNC = PPU_DENDY_VACTIVE + PPU_DENDY_VBLANK,
PPU_DENDY_HVSYNCBOOT = PPU_DENDY_VACTIVE * PPU_DENDY_HSYNC + PPU_DENDY_CC * 312,
PPU_DENDY_HVREGBOOT = (PPU_DENDY_VACTIVE + PPU_DENDY_VINT) * PPU_DENDY_HSYNC + PPU_DENDY_CC * 314,
PPU_DENDY_HVINT = PPU_DENDY_VINT * ulong(PPU_DENDY_HSYNC),
PPU_DENDY_HVSYNC = PPU_DENDY_VSYNC * ulong(PPU_DENDY_HSYNC),
PPU_DENDY_FPS = (CLK_PAL + CLK_PAL_DIV * ulong(PPU_DENDY_HVSYNC) / 2) / (CLK_PAL_DIV * ulong(PPU_DENDY_HVSYNC))
};
template
class ImplicitBool;
template<>
class ImplicitBool
{
public:
int type;
typedef int ImplicitBool::*Type;
};
template
class ImplicitBool
{
template void operator == (const ImplicitBool&) const;
template void operator != (const ImplicitBool&) const;
public:
operator ImplicitBool::Type () const
{
return !static_cast(*this) ? 0 : &ImplicitBool::type;
}
};
}
}
#define NES_FAILED(x_) ((x_) < Nes::RESULT_OK)
#define NES_SUCCEEDED(x_) ((x_) >= Nes::RESULT_OK)
#endif
nestopia-1.47/source/core/NstCartridge.cpp 0000664 0000000 0000000 00000030651 12644314416 0020626 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include
#include "NstLog.hpp"
#include "NstChecksum.hpp"
#include "NstImageDatabase.hpp"
#include "board/NstBoard.hpp"
#include "NstCartridge.hpp"
#include "NstCartridgeRomset.hpp"
#include "NstCartridgeInes.hpp"
#include "NstCartridgeUnif.hpp"
#include "vssystem/NstVsSystem.hpp"
#include "api/NstApiUser.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Cartridge::ProfileEx::ProfileEx()
: nmt(NMT_DEFAULT), battery(false), wramAuto(false) {}
Cartridge::Cartridge(Context& context)
: Image(CARTRIDGE), board(NULL), vs(NULL), favoredSystem(context.favoredSystem)
{
try
{
ProfileEx profileEx;
switch (Stream::In(&context.stream).Peek32())
{
case INES_ID:
Ines::Load
(
context.stream,
context.patch,
context.patchBypassChecksum,
context.patchResult,
prg,
chr,
context.favoredSystem,
profile,
profileEx,
context.database
);
break;
case UNIF_ID:
Unif::Load
(
context.stream,
context.patch,
context.patchBypassChecksum,
context.patchResult,
prg,
chr,
context.favoredSystem,
profile,
profileEx,
context.database
);
break;
default:
Romset::Load
(
context.stream,
context.patch,
context.patchBypassChecksum,
context.patchResult,
prg,
chr,
context.favoredSystem,
context.askProfile,
profile
);
break;
}
if (profile.dump.state == Profile::Dump::BAD)
context.result = RESULT_WARN_BAD_DUMP;
else
context.result = RESULT_OK;
const Result result = SetupBoard( prg, chr, &board, &context, profile, profileEx, &prgCrc );
if (NES_FAILED(result))
throw result;
board->Load( savefile );
switch (profile.system.type)
{
case Profile::System::VS_UNISYSTEM:
vs = VsSystem::Create
(
context.cpu,
context.ppu,
static_cast(profile.system.ppu),
prgCrc
);
profile.system.ppu = static_cast(vs->GetPpuModel());
break;
case Profile::System::VS_DUALSYSTEM:
throw RESULT_ERR_UNSUPPORTED_VSSYSTEM;
}
if (Cartridge::QueryExternalDevice( EXT_DIP_SWITCHES ))
Log::Flush( "Cartridge: DIP Switches present" NST_LINEBREAK );
}
catch (...)
{
Destroy();
throw;
}
}
void Cartridge::Destroy()
{
VsSystem::Destroy( vs );
Boards::Board::Destroy( board );
}
Cartridge::~Cartridge()
{
Destroy();
}
void Cartridge::ReadRomset(std::istream& stream,FavoredSystem favoredSystem,bool askSystem,Profile& profile)
{
Log::Suppressor logSupressor;
Ram prg, chr;
ProfileEx profileEx;
Romset::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, askSystem, profile, true );
SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL, true );
}
void Cartridge::ReadInes(std::istream& stream,FavoredSystem favoredSystem,Profile& profile)
{
Log::Suppressor logSupressor;
Ram prg, chr;
ProfileEx profileEx;
Ines::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, profile, profileEx, NULL );
SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL );
}
void Cartridge::ReadUnif(std::istream& stream,FavoredSystem favoredSystem,Profile& profile)
{
Log::Suppressor logSupressor;
Ram prg, chr;
ProfileEx profileEx;
Unif::Load( stream, NULL, false, NULL, prg, chr, favoredSystem, profile, profileEx, NULL );
SetupBoard( prg, chr, NULL, NULL, profile, profileEx, NULL );
}
uint Cartridge::GetDesiredController(uint port) const
{
NST_ASSERT( port < Api::Input::NUM_CONTROLLERS );
return profile.game.controllers[port];
}
uint Cartridge::GetDesiredAdapter() const
{
return profile.game.adapter;
}
Cartridge::ExternalDevice Cartridge::QueryExternalDevice(ExternalDeviceType deviceType)
{
switch (deviceType)
{
case EXT_DIP_SWITCHES:
if (vs)
return &vs->GetDipSwiches();
else
return board->QueryDevice( Boards::Board::DEVICE_DIP_SWITCHES );
case EXT_BARCODE_READER:
return board->QueryDevice( Boards::Board::DEVICE_BARCODE_READER );
default:
return Image::QueryExternalDevice( deviceType );
}
}
Result Cartridge::SetupBoard
(
Ram& prg,
Ram& chr,
Boards::Board** board,
const Context* const context,
Profile& profile,
const ProfileEx& profileEx,
dword* const prgCrc,
const bool readOnly
)
{
NST_ASSERT( bool(board) == bool(context) );
Boards::Board::Type::Nmt nmt;
if (profile.board.solderPads & (Profile::Board::SOLDERPAD_H|Profile::Board::SOLDERPAD_V))
{
if (profile.board.solderPads & Profile::Board::SOLDERPAD_H)
nmt = Boards::Board::Type::NMT_VERTICAL;
else
nmt = Boards::Board::Type::NMT_HORIZONTAL;
}
else switch (profileEx.nmt)
{
case ProfileEx::NMT_HORIZONTAL: nmt = Boards::Board::Type::NMT_HORIZONTAL; break;
case ProfileEx::NMT_VERTICAL: nmt = Boards::Board::Type::NMT_VERTICAL; break;
case ProfileEx::NMT_SINGLESCREEN: nmt = Boards::Board::Type::NMT_SINGLESCREEN; break;
case ProfileEx::NMT_FOURSCREEN: nmt = Boards::Board::Type::NMT_FOURSCREEN; break;
default: nmt = Boards::Board::Type::NMT_CONTROLLED; break;
}
Chips chips;
for (Profile::Board::Chips::const_iterator i(profile.board.chips.begin()), end(profile.board.chips.end()); i != end; ++i)
{
Chips::Type& type = chips.Add( i->type.c_str() );
for (Profile::Board::Pins::const_iterator j(i->pins.begin()), end(i->pins.end()); j != end; ++j)
type.Pin(j->number) = j->function.c_str();
for (Profile::Board::Samples::const_iterator j(i->samples.begin()), end(i->samples.end()); j != end; ++j)
type.Sample(j->id) = j->file.c_str();
}
Boards::Board::Context b
(
context ? &context->cpu : NULL,
context ? &context->apu : NULL,
context ? &context->ppu : NULL,
prg,
chr,
profileEx.trainer,
nmt,
profileEx.battery || profile.board.HasWramBattery(),
profile.board.HasMmcBattery(),
chips
);
if (profile.board.type.empty() || !b.DetectBoard( profile.board.type.c_str(), profile.board.GetWram() ))
{
if (profile.board.mapper == Profile::Board::NO_MAPPER || !b.DetectBoard( profile.board.mapper, profile.board.GetWram(), profileEx.wramAuto, profile.board.subMapper ) && board)
return RESULT_ERR_UNSUPPORTED_MAPPER;
if (profile.board.type.empty())
profile.board.type = std::wstring( b.name, b.name + std::strlen(b.name) );
}
if (profile.board.mapper == Profile::Board::NO_MAPPER && b.type.GetMapper() != Boards::Board::Type::NMPR)
profile.board.mapper = b.type.GetMapper();
for (uint i=0; i < 2; ++i)
{
dword size = (i ? b.chr : b.prg).Size();
if (size != (i ? profile.board.GetChr() : profile.board.GetPrg()))
{
Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg);
roms.clear();
if (size)
{
Profile::Board::Rom rom;
rom.size = size;
roms.push_back( rom );
}
}
size = (i ? b.type.GetVram() : b.type.GetWram());
if (size != (i ? profile.board.GetVram() : profile.board.GetWram()))
{
Profile::Board::Rams& rams = (i ? profile.board.vram : profile.board.wram);
rams.clear();
for (uint j=0; j < 2; ++j)
{
size = i ? (j ? b.type.GetNonSavableVram() : b.type.GetSavableVram()) :
(j ? b.type.GetNonSavableWram() : b.type.GetSavableWram());
if (size)
{
Profile::Board::Ram ram;
ram.size = size;
ram.battery = (i == 0 && j == 0 && b.wramBattery);
rams.push_back( ram );
}
}
}
Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg);
for (dword j=0, k=0, n=roms.size(); j < n; k += roms[j].size, ++j)
roms[j].hash.Compute( (i ? chr : prg).Mem(k), roms[j].size );
}
if (!readOnly)
{
Checksum checksum;
checksum.Compute( prg.Mem(), prg.Size() );
if (prgCrc)
*prgCrc = checksum.GetCrc();
checksum.Compute( chr.Mem(), chr.Size() );
profile.hash.Assign( checksum.GetSha1(), checksum.GetCrc() );
}
if (board)
*board = Boards::Board::Create( b );
return RESULT_OK;
}
void Cartridge::Reset(const bool hard)
{
board->Reset( hard );
if (vs)
vs->Reset( hard );
}
bool Cartridge::PowerOff()
{
try
{
if (board)
{
board->Sync( Boards::Board::EVENT_POWER_OFF, NULL );
board->Save( savefile );
}
return true;
}
catch (...)
{
return false;
}
}
void Cartridge::SaveState(State::Saver& state,const dword baseChunk) const
{
state.Begin( baseChunk );
board->SaveState( state, AsciiId<'M','P','R'>::V );
if (vs)
vs->SaveState( state, AsciiId<'V','S','S'>::V );
state.End();
}
void Cartridge::LoadState(State::Loader& state)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'M','P','R'>::V:
board->LoadState( state );
break;
case AsciiId<'V','S','S'>::V:
NST_VERIFY( vs );
if (vs)
vs->LoadState( state );
break;
}
state.End();
}
}
Region Cartridge::GetDesiredRegion() const
{
switch (profile.system.type)
{
case Profile::System::NES_PAL:
case Profile::System::NES_PAL_A:
case Profile::System::NES_PAL_B:
case Profile::System::DENDY:
return REGION_PAL;
case Profile::System::NES_NTSC:
case Profile::System::FAMICOM:
if (favoredSystem == FAVORED_DENDY)
return REGION_PAL;
default:
return REGION_NTSC;
}
}
System Cartridge::GetDesiredSystem(Region region,CpuModel* cpu,PpuModel* ppu) const
{
if (region == Cartridge::GetDesiredRegion())
{
if (favoredSystem == FAVORED_DENDY && region == REGION_PAL)
{
switch (profile.system.type)
{
case Profile::System::NES_NTSC:
case Profile::System::NES_PAL:
case Profile::System::NES_PAL_A:
case Profile::System::NES_PAL_B:
case Profile::System::FAMICOM:
case Profile::System::DENDY:
if (cpu)
*cpu = CPU_DENDY;
if (ppu)
*ppu = PPU_DENDY;
return SYSTEM_DENDY;
}
}
if (cpu)
*cpu = static_cast(profile.system.cpu);
if (ppu)
*ppu = static_cast(profile.system.ppu);
return static_cast(profile.system.type);
}
else
{
return Image::GetDesiredSystem( region, cpu, ppu );
}
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
void Cartridge::BeginFrame(const Api::Input& input,Input::Controllers* controllers)
{
board->Sync( Boards::Board::EVENT_BEGIN_FRAME, controllers );
if (vs)
vs->BeginFrame( input, controllers );
}
void Cartridge::VSync()
{
board->Sync( Boards::Board::EVENT_END_FRAME, NULL );
if (vs)
vs->VSync();
}
}
}
nestopia-1.47/source/core/NstCartridge.hpp 0000664 0000000 0000000 00000006022 12644314416 0020626 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CARTRIDGE_H
#define NST_CARTRIDGE_H
#include "NstRam.hpp"
#include "NstImage.hpp"
#include "NstFile.hpp"
#include "api/NstApiCartridge.hpp"
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
namespace Boards
{
class Board;
}
class Cartridge : public Image
{
public:
explicit Cartridge(Context&);
void BeginFrame(const Api::Input&,Input::Controllers*);
typedef Api::Cartridge::Profile Profile;
static void ReadRomset(std::istream&,FavoredSystem,bool,Profile&);
static void ReadInes(std::istream&,FavoredSystem,Profile&);
static void ReadUnif(std::istream&,FavoredSystem,Profile&);
class Ines;
class Unif;
class Romset;
private:
~Cartridge();
struct ProfileEx
{
ProfileEx();
enum Nmt
{
NMT_DEFAULT,
NMT_HORIZONTAL,
NMT_VERTICAL,
NMT_SINGLESCREEN,
NMT_FOURSCREEN,
NMT_CONTROLLED
};
Nmt nmt;
bool battery;
bool wramAuto;
Ram trainer;
};
class VsSystem;
static Result SetupBoard
(
Ram&,
Ram&,
Boards::Board**,
const Context*,
Profile&,
const ProfileEx&,
dword*,
bool=false
);
void Reset(bool);
bool PowerOff();
void LoadState(State::Loader&);
void SaveState(State::Saver&,dword) const;
void Destroy();
void VSync();
uint GetDesiredController(uint) const;
uint GetDesiredAdapter() const;
void DetectControllers(uint);
Region GetDesiredRegion() const;
System GetDesiredSystem(Region,CpuModel*,PpuModel*) const;
ExternalDevice QueryExternalDevice(ExternalDeviceType);
Boards::Board* board;
VsSystem* vs;
Ram prg;
Ram chr;
Profile profile;
dword prgCrc;
File savefile;
const FavoredSystem favoredSystem;
public:
const Profile& GetProfile() const
{
return profile;
}
dword GetPrgCrc() const
{
return prgCrc;
}
};
}
}
#endif
nestopia-1.47/source/core/NstCartridgeInes.cpp 0000664 0000000 0000000 00000052167 12644314416 0021453 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include "NstLog.hpp"
#include "NstPatcher.hpp"
#include "NstStream.hpp"
#include "NstChecksum.hpp"
#include "NstImageDatabase.hpp"
#include "NstCartridge.hpp"
#include "NstCartridgeInes.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
class Cartridge::Ines::Loader
{
bool Load(Ram&,dword);
enum TrainerSetup
{
TRAINER_NONE,
TRAINER_IGNORE,
TRAINER_READ
};
enum
{
VS_MAPPER_99 = 99,
VS_MAPPER_151 = 151,
FFE_MAPPER_6 = 6,
FFE_MAPPER_8 = 8,
FFE_MAPPER_17 = 17,
TRAINER_LENGTH = 0x200,
MIN_DB_SEARCH_STRIDE = SIZE_8K,
MAX_DB_SEARCH_LENGTH = SIZE_16K * 0xFFFUL + SIZE_8K * 0xFFFUL
};
Stream::In stream;
const FavoredSystem favoredSystem;
Profile& profile;
ProfileEx& profileEx;
Ram& prg;
Ram& chr;
const ImageDatabase* const database;
Patcher patcher;
public:
Loader
(
std::istream& stdStreamImage,
std::istream* const stdStreamPatch,
const bool patchBypassChecksum,
Result* const patchResult,
Ram& p,
Ram& c,
const FavoredSystem f,
Profile& r,
ProfileEx& x,
const ImageDatabase* const d
)
:
stream (&stdStreamImage),
favoredSystem (f),
profile (r),
profileEx (x),
prg (p),
chr (c),
database (d),
patcher (patchBypassChecksum)
{
NST_ASSERT( prg.Empty() && chr.Empty() );
if (stdStreamPatch)
*patchResult = patcher.Load( *stdStreamPatch, stdStreamImage );
profile = Profile();
profileEx = ProfileEx();
}
void Load()
{
const TrainerSetup trainerSetup = Collect();
if (!profile.patched)
{
if (const ImageDatabase::Entry entry = SearchDatabase( trainerSetup ))
{
entry.Fill( profile, patcher.Empty() );
profileEx.wramAuto = false;
}
}
prg.Set( profile.board.GetPrg() );
chr.Set( profile.board.GetChr() );
if (!profile.board.prg.empty())
{
for (Profile::Board::Pins::const_iterator it(profile.board.prg.front().pins.begin()), end(profile.board.prg.front().pins.end()); it != end; ++it)
prg.Pin(it->number) = it->function.c_str();
}
if (!profile.board.chr.empty())
{
for (Profile::Board::Pins::const_iterator it(profile.board.chr.front().pins.begin()), end(profile.board.chr.front().pins.end()); it != end; ++it)
chr.Pin(it->number) = it->function.c_str();
}
if (trainerSetup == TRAINER_READ)
{
profileEx.trainer.Set( TRAINER_LENGTH );
stream.Read( profileEx.trainer.Mem(), TRAINER_LENGTH );
}
else if (trainerSetup == TRAINER_IGNORE)
{
stream.Seek( TRAINER_LENGTH );
}
if (Load( prg, 16 ))
Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK );
if (Load( chr, 16 + prg.Size() ))
Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK );
}
private:
TrainerSetup Collect()
{
NST_COMPILE_ASSERT
(
Header::PPU_RP2C03B == 1 &&
Header::PPU_RP2C03G == 2 &&
Header::PPU_RP2C04_0001 == 3 &&
Header::PPU_RP2C04_0002 == 4 &&
Header::PPU_RP2C04_0003 == 5 &&
Header::PPU_RP2C04_0004 == 6 &&
Header::PPU_RC2C03B == 7 &&
Header::PPU_RC2C03C == 8 &&
Header::PPU_RC2C05_01 == 9 &&
Header::PPU_RC2C05_02 == 10 &&
Header::PPU_RC2C05_03 == 11 &&
Header::PPU_RC2C05_04 == 12 &&
Header::PPU_RC2C05_05 == 13
);
Header setup;
byte header[16];
stream.Read( header );
if (patcher.Patch( header, header, 16 ))
{
profile.patched = true;
Log::Flush( "Ines: header was patched" NST_LINEBREAK );
}
Result result = ReadHeader( setup, header, 16 );
if (NES_FAILED(result))
throw RESULT_ERR_CORRUPT_FILE;
Log log;
static const char title[] = "Ines: ";
if (setup.version)
{
log << title << "NES 2.0 (extended iNES)" NST_LINEBREAK;
}
if (result == RESULT_WARN_BAD_FILE_HEADER)
log << title << "warning, unknown or invalid header data!" NST_LINEBREAK;
log << title
<< (setup.prgRom / SIZE_1K)
<< "k PRG-ROM set" NST_LINEBREAK;
if (setup.version)
{
if (setup.prgRam)
{
log << title
<< (setup.prgRam % SIZE_1K ? setup.prgRam : setup.prgRam / SIZE_1K)
<< (setup.prgRam % SIZE_1K ? " byte" : "k")
<< " PRG-RAM set" NST_LINEBREAK;
}
if (setup.prgNvRam)
{
log << title
<< (setup.prgNvRam % SIZE_1K ? setup.prgNvRam : setup.prgNvRam / SIZE_1K)
<< (setup.prgNvRam % SIZE_1K ? " bytes" : "k")
<< " non-volatile PRG-RAM set" NST_LINEBREAK;
}
}
if (setup.chrRom)
{
log << title
<< (setup.chrRom / SIZE_1K)
<< "k CHR-ROM set" NST_LINEBREAK;
}
if (setup.version)
{
if (setup.chrRam)
{
log << title
<< (setup.chrRam % SIZE_1K ? setup.chrRam : setup.chrRam / SIZE_1K)
<< (setup.chrRam % SIZE_1K ? " bytes" : "k")
<< " CHR-RAM set" NST_LINEBREAK;
}
if (setup.chrNvRam)
{
log << title
<< (setup.chrNvRam % SIZE_1K ? setup.chrNvRam : setup.chrNvRam / SIZE_1K)
<< (setup.chrNvRam % SIZE_1K ? " bytes" : "k")
<< " non-volatile CHR-RAM set" NST_LINEBREAK;
}
}
else
{
if (header[8])
{
log << title
<< (header[8] * 8U)
<< "k W-RAM set" NST_LINEBREAK;
}
if (header[6] & 0x2U)
{
log << title
<< "battery set" NST_LINEBREAK;
}
}
log << title <<
(
setup.mirroring == Header::MIRRORING_FOURSCREEN ? "four-screen" :
setup.mirroring == Header::MIRRORING_VERTICAL ? "vertical" :
"horizontal"
) << " mirroring set" NST_LINEBREAK;
log << title <<
(
setup.region == Header::REGION_BOTH ? "NTSC/PAL" :
setup.region == Header::REGION_PAL ? "PAL":
"NTSC"
) << " set" NST_LINEBREAK;
if (setup.system == Header::SYSTEM_VS)
{
log << title << "VS System set" NST_LINEBREAK;
if (setup.version)
{
if (setup.ppu)
{
static cstring const names[] =
{
"RP2C03B",
"RP2C03G",
"RP2C04-0001",
"RP2C04-0002",
"RP2C04-0003",
"RP2C04-0004",
"RC2C03B",
"RC2C03C",
"RC2C05-01",
"RC2C05-02",
"RC2C05-03",
"RC2C05-04",
"RC2C05-05"
};
NST_ASSERT( setup.ppu < 1+sizeof(array(names)) );
log << title << names[setup.ppu-1] << " PPU set" NST_LINEBREAK;
}
if (setup.security)
{
static const cstring names[] =
{
"RBI Baseball",
"TKO Boxing",
"Super Xevious"
};
NST_ASSERT( setup.security < 1+sizeof(array(names)) );
log << title << names[setup.security-1] << " VS mode set" NST_LINEBREAK;
}
}
}
else if (setup.system == Header::SYSTEM_PC10)
{
log << title << "PlayChoice-10 set" NST_LINEBREAK;
}
log << title << "mapper " << setup.mapper << " set";
if (setup.system != Header::SYSTEM_VS && (setup.mapper == VS_MAPPER_99 || setup.mapper == VS_MAPPER_151))
{
setup.system = Header::SYSTEM_VS;
setup.ppu = Header::PPU_RP2C03B;
log << ", forcing VS System";
}
log << NST_LINEBREAK;
if (setup.version && setup.subMapper)
log << title << "submapper " << setup.subMapper << " set" NST_LINEBREAK;
TrainerSetup trainerSetup;
if (!setup.trainer)
{
trainerSetup = TRAINER_NONE;
}
else if (setup.mapper == FFE_MAPPER_6 || setup.mapper == FFE_MAPPER_8 || setup.mapper == FFE_MAPPER_17)
{
trainerSetup = TRAINER_READ;
log << title << "trainer set" NST_LINEBREAK;
if (setup.prgRam + setup.prgNvRam < SIZE_8K)
{
setup.prgRam = SIZE_8K - setup.prgNvRam;
log << title << "warning, forcing 8k of W-RAM for trainer" NST_LINEBREAK;
}
}
else
{
trainerSetup = TRAINER_IGNORE;
log << title << "warning, trainer ignored" NST_LINEBREAK;
}
if (setup.prgRom)
{
Profile::Board::Rom rom;
rom.size = setup.prgRom;
profile.board.prg.push_back( rom );
}
if (setup.chrRom)
{
Profile::Board::Rom rom;
rom.size = setup.chrRom;
profile.board.chr.push_back( rom );
}
if (setup.prgNvRam)
{
Profile::Board::Ram ram;
ram.size = setup.prgNvRam;
ram.battery = true;
profile.board.wram.push_back( ram );
}
if (setup.prgRam)
{
Profile::Board::Ram ram;
ram.size = setup.prgRam;
profile.board.wram.push_back( ram );
}
if (setup.chrNvRam)
{
Profile::Board::Ram ram;
ram.size = setup.chrNvRam;
ram.battery = true;
profile.board.vram.push_back( ram );
}
if (setup.chrRam)
{
Profile::Board::Ram ram;
ram.size = setup.chrRam;
profile.board.vram.push_back( ram );
}
profile.board.mapper = setup.mapper;
profile.board.subMapper = setup.subMapper;
profileEx.wramAuto = (setup.version == 0 && profile.board.wram.empty());
switch (setup.mirroring)
{
case Header::MIRRORING_HORIZONTAL:
profile.board.solderPads = Profile::Board::SOLDERPAD_V;
break;
case Header::MIRRORING_VERTICAL:
profile.board.solderPads = Profile::Board::SOLDERPAD_H;
break;
case Header::MIRRORING_FOURSCREEN:
profileEx.nmt = ProfileEx::NMT_FOURSCREEN;
break;
}
profile.system.cpu = Profile::System::CPU_RP2A03;
profile.system.ppu = static_cast(setup.ppu);
switch (setup.system)
{
case Header::SYSTEM_VS:
profile.system.type = Profile::System::VS_UNISYSTEM;
break;
case Header::SYSTEM_PC10:
profile.system.type = Profile::System::PLAYCHOICE_10;
break;
default:
switch (setup.region)
{
case Header::REGION_NTSC:
if (favoredSystem == FAVORED_FAMICOM)
{
profile.system.type = Profile::System::FAMICOM;
}
else if (favoredSystem == FAVORED_DENDY)
{
profile.system.type = Profile::System::DENDY;
profile.system.ppu = Profile::System::PPU_DENDY;
profile.system.cpu = Profile::System::CPU_DENDY;
}
else
{
profile.system.type = Profile::System::NES_NTSC;
}
break;
default:
profile.multiRegion = true;
if (favoredSystem == FAVORED_FAMICOM)
{
profile.system.type = Profile::System::FAMICOM;
break;
}
else if (favoredSystem != FAVORED_NES_PAL && favoredSystem != FAVORED_DENDY)
{
profile.system.type = Profile::System::NES_NTSC;
break;
}
case Header::REGION_PAL:
if (favoredSystem == FAVORED_DENDY)
{
profile.system.type = Profile::System::DENDY;
profile.system.cpu = Profile::System::CPU_DENDY;
profile.system.ppu = Profile::System::PPU_DENDY;
}
else
{
profile.system.type = Profile::System::NES_PAL;
profile.system.cpu = Profile::System::CPU_RP2A07;
profile.system.ppu = Profile::System::PPU_RP2C07;
}
break;
}
break;
}
return trainerSetup;
}
ImageDatabase::Entry SearchDatabase(const TrainerSetup trainerSetup)
{
ImageDatabase::Entry entry;
if (database && database->Enabled())
{
if (trainerSetup != TRAINER_NONE)
stream.Seek( TRAINER_LENGTH );
const dword romLength = profile.board.GetPrg() + profile.board.GetChr();
dword count = 0;
for (Checksum it, checksum;;)
{
const uint data = stream.SafeRead8();
if (data <= 0xFF)
{
const byte in = data;
it.Compute( &in, 1 );
if (++count % MIN_DB_SEARCH_STRIDE == 0)
checksum = it;
}
const bool stop = (data > 0xFF || count == MAX_DB_SEARCH_LENGTH);
if (stop || count == romLength)
{
entry = database->Search( Profile::Hash(checksum.GetSha1(),checksum.GetCrc()), favoredSystem );
if (stop || entry)
break;
}
}
if (count)
stream.Seek( -idword(count) + (trainerSetup == TRAINER_NONE ? 0 : -TRAINER_LENGTH) );
}
return entry;
}
};
bool Cartridge::Ines::Loader::Load(Ram& rom,const dword offset)
{
if (rom.Size())
{
if (patcher.Empty())
{
stream.Read( rom.Mem(), rom.Size() );
}
else
{
dword size = stream.Length();
NST_VERIFY( size >= rom.Size() );
if (size > rom.Size())
size = rom.Size();
if (size)
stream.Read( rom.Mem(), size );
if (patcher.Patch( rom.Mem(), rom.Mem(), rom.Size(), offset ))
{
profile.patched = true;
return true;
}
}
}
return false;
}
void Cartridge::Ines::Load
(
std::istream& stdStreamImage,
std::istream* const stdStreamPatch,
const bool patchBypassChecksum,
Result* const patchResult,
Ram& prg,
Ram& chr,
const FavoredSystem favoredSystem,
Profile& profile,
ProfileEx& profileEx,
const ImageDatabase* const database
)
{
Loader loader
(
stdStreamImage,
stdStreamPatch,
patchBypassChecksum,
patchResult,
prg,
chr,
favoredSystem,
profile,
profileEx,
database
);
loader.Load();
}
Result Cartridge::Ines::ReadHeader(Header& setup,const byte* const file,const ulong length)
{
if (file == NULL)
return RESULT_ERR_INVALID_PARAM;
if
(
length < 4 ||
file[0] != Ascii<'N'>::V ||
file[1] != Ascii<'E'>::V ||
file[2] != Ascii<'S'>::V ||
file[3] != 0x1A
)
return RESULT_ERR_INVALID_FILE;
if (length < 16)
return RESULT_ERR_CORRUPT_FILE;
byte header[16];
std::memcpy( header, file, 16 );
Result result = RESULT_OK;
setup.version = ((header[7] & 0xCU) == 0x8 ? 2 : 0);
if (!setup.version)
{
for (uint i=10; i < 16; ++i)
{
if (header[i])
{
header[7] = 0;
header[8] = 0;
header[9] = 0;
result = RESULT_WARN_BAD_FILE_HEADER;
break;
}
}
}
setup.prgRom = header[4];
setup.chrRom = header[5];
if (setup.version)
{
setup.prgRom |= uint(header[9]) << 8 & 0xF00;
setup.chrRom |= uint(header[9]) << 4 & 0xF00;
}
setup.prgRom *= SIZE_16K;
setup.chrRom *= SIZE_8K;
setup.trainer = bool(header[6] & 0x4U);
setup.mapper = (header[6] >> 4) | (header[7] & 0xF0U);
setup.subMapper = 0;
if (setup.version)
{
setup.mapper |= uint(header[8]) << 8 & 0x100;
setup.subMapper = header[8] >> 4;
}
if (header[6] & 0x8U)
{
setup.mirroring = Header::MIRRORING_FOURSCREEN;
}
else if (header[6] & 0x1U)
{
setup.mirroring = Header::MIRRORING_VERTICAL;
}
else
{
setup.mirroring = Header::MIRRORING_HORIZONTAL;
}
setup.security = 0;
if (header[7] & 0x1U)
{
setup.system = Header::SYSTEM_VS;
setup.ppu = Header::PPU_RP2C03B;
if (setup.version)
{
if ((header[13] & 0xFU) < 13)
setup.ppu = static_cast((header[13] & 0xFU) + 1);
if ((header[13] >> 4) < 4)
setup.security = header[13] >> 4;
}
}
else if (setup.version && (header[7] & 0x2U))
{
setup.system = Header::SYSTEM_PC10;
setup.ppu = Header::PPU_RP2C03B;
}
else
{
setup.system = Header::SYSTEM_CONSOLE;
setup.ppu = Header::PPU_RP2C02;
}
if (setup.version && (header[12] & 0x2U))
{
setup.region = Header::REGION_BOTH;
}
else if (header[setup.version ? 12 : 9] & 0x1U)
{
if (setup.system == Header::SYSTEM_CONSOLE)
{
setup.region = Header::REGION_PAL;
setup.ppu = Header::PPU_RP2C07;
}
else
{
setup.region = Header::REGION_NTSC;
}
}
else
{
setup.region = Header::REGION_NTSC;
}
if (setup.version)
{
setup.prgRam = ((header[10]) & 0xFU) - 1U < 14 ? 64UL << (header[10] & 0xFU) : 0;
setup.prgNvRam = ((header[10]) >> 4) - 1U < 14 ? 64UL << (header[10] >> 4) : 0;
setup.chrRam = ((header[11]) & 0xFU) - 1U < 14 ? 64UL << (header[11] & 0xFU) : 0;
setup.chrNvRam = ((header[11]) >> 4) - 1U < 14 ? 64UL << (header[11] >> 4) : 0;
}
else
{
setup.prgRam = ((header[6] & 0x2U) ? 0 : header[8] * dword(SIZE_8K));
setup.prgNvRam = ((header[6] & 0x2U) ? NST_MAX(header[8],1U) * dword(SIZE_8K) : 0);
setup.chrRam = (setup.chrRom ? 0 : SIZE_8K);
setup.chrNvRam = 0;
}
return result;
}
Result Cartridge::Ines::WriteHeader(const Header& setup,byte* const file,const ulong length)
{
if
(
(file == NULL || length < 16) ||
(setup.prgRom > (setup.version ? 0xFFFUL * SIZE_16K : 0xFFUL * SIZE_16K)) ||
(setup.chrRom > (setup.version ? 0xFFFUL * SIZE_8K : 0xFFUL * SIZE_8K)) ||
(setup.mapper > (setup.version ? 0x1FF : 0xFF)) ||
(setup.version && setup.subMapper > 0xF)
)
return RESULT_ERR_INVALID_PARAM;
byte header[16] =
{
Ascii<'N'>::V,
Ascii<'E'>::V,
Ascii<'S'>::V,
0x1A,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
if (setup.version)
header[7] |= 0x8U;
header[4] = (setup.prgRom / SIZE_16K) & 0xFF;
header[5] = (setup.chrRom / SIZE_8K) & 0xFF;
if (setup.version)
{
header[9] |= (setup.prgRom / SIZE_16K) >> 8;
header[9] |= (setup.chrRom / SIZE_8K) >> 4 & 0xF0;
}
if (setup.mirroring == Header::MIRRORING_FOURSCREEN)
{
header[6] |= 0x8U;
}
else if (setup.mirroring == Header::MIRRORING_VERTICAL)
{
header[6] |= 0x1U;
}
if (setup.prgNvRam)
header[6] |= 0x2U;
if (setup.trainer)
header[6] |= 0x4U;
if (setup.system == Header::SYSTEM_VS)
{
header[7] |= 0x1U;
}
else if (setup.version && setup.system == Header::SYSTEM_PC10)
{
header[7] |= 0x2U;
}
header[6] |= setup.mapper << 4 & 0xF0U;
header[7] |= setup.mapper & 0xF0U;
if (setup.version)
{
header[8] |= setup.mapper >> 8;
header[8] |= setup.subMapper << 4;
uint i, data;
for (i=0, data=setup.prgRam >> 7; data; data >>= 1, ++i)
{
if (i > 0xF)
return RESULT_ERR_INVALID_PARAM;
}
header[10] |= i;
for (i=0, data=setup.prgNvRam >> 7; data; data >>= 1, ++i)
{
if (i > 0xF)
return RESULT_ERR_INVALID_PARAM;
}
header[10] |= i << 4;
for (i=0, data=setup.chrRam >> 7; data; data >>= 1, ++i)
{
if (i > 0xF)
return RESULT_ERR_INVALID_PARAM;
}
header[11] |= i;
for (i=0, data=setup.chrNvRam >> 7; data; data >>= 1, ++i)
{
if (i > 0xF)
return RESULT_ERR_INVALID_PARAM;
}
header[11] |= i << 4;
if (setup.region == Header::REGION_BOTH)
{
header[12] |= 0x2U;
}
else if (setup.region == Header::REGION_PAL)
{
header[12] |= 0x1U;
}
if (setup.system == Header::SYSTEM_VS)
{
if (setup.ppu > 0xF || setup.security > 0xF)
return RESULT_ERR_INVALID_PARAM;
if (setup.ppu)
header[13] = setup.ppu - 1;
header[13] |= setup.security << 4;
}
}
else
{
header[8] = (setup.prgRam + setup.prgNvRam) / SIZE_8K;
header[9] = (setup.region == Header::REGION_PAL ? 0x1 : 0x0);
}
std::memcpy( file, header, 16 );
return RESULT_OK;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}
nestopia-1.47/source/core/NstCartridgeInes.hpp 0000664 0000000 0000000 00000003152 12644314416 0021446 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CARTRIDGE_INES_H
#define NST_CARTRIDGE_INES_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
class Cartridge::Ines
{
class Loader;
public:
typedef Api::Cartridge::NesHeader Header;
static void Load
(
std::istream&,
std::istream*,
bool,
Result*,
Ram&,
Ram&,
FavoredSystem,
Profile&,
ProfileEx&,
const ImageDatabase*
);
static Result ReadHeader(Header&,const byte*,ulong);
static Result WriteHeader(const Header&,byte*,ulong);
};
}
}
#endif
nestopia-1.47/source/core/NstCartridgeRomset.cpp 0000664 0000000 0000000 00000071676 12644314416 0022034 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include "NstLog.hpp"
#include "NstPatcher.hpp"
#include "NstXml.hpp"
#include "NstStream.hpp"
#include "NstChecksum.hpp"
#include "NstCartridge.hpp"
#include "NstCartridgeRomset.hpp"
#include "api/NstApiCartridge.hpp"
#include "api/NstApiUser.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
class Cartridge::Romset::Loader
{
typedef std::vector Profiles;
enum
{
DEFAULT_VERSION = 10,
MIN_PLAYERS = 1,
MAX_PLAYERS = 255,
MIN_CHIP_SIZE = 1,
MAX_CHIP_SIZE = SIZE_16384K,
MIN_IC_PINS = 1,
MAX_IC_PINS = 127,
MAX_CHIP_SAMPLES = 255,
MAX_MAPPER = 255
};
std::istream& imageStream;
std::istream* const patchStream;
const FavoredSystem favoredSystem;
Ram& prg;
Ram& chr;
Profile& profile;
Profiles profiles;
Result* const patchResult;
const bool askProfile;
const bool readOnly;
const bool patchBypassChecksum;
public:
Loader
(
std::istream& i,
std::istream* t,
const bool b,
Result* const e,
Ram& p,
Ram& c,
const FavoredSystem f,
const bool a,
Profile& r,
const bool o
)
:
imageStream (i),
patchStream (t),
favoredSystem (f),
prg (p),
chr (c),
profile (r),
patchResult (e),
askProfile (a),
readOnly (o),
patchBypassChecksum (b)
{
NST_ASSERT( prg.Empty() && chr.Empty() );
}
void Load()
{
Collect();
ChooseProfile();
LoadRoms();
PatchRoms();
}
private:
void Collect()
{
Xml xml;
if (!xml.Read( imageStream ))
throw RESULT_ERR_INVALID_FILE;
const Xml::Node romset( xml.GetRoot() );
if (!romset.IsType( L"romset" ))
throw RESULT_ERR_INVALID_FILE;
uint version = DEFAULT_VERSION;
if (const Xml::Attribute attribute=romset.GetAttribute( L"version" ))
{
wcstring const string = attribute.GetValue();
if
(
(string[0] >= L'1' && string[0] <= L'9') &&
(string[1] == L'.') &&
(string[2] >= L'0' && string[2] <= L'9') &&
(string[3] == L'\0')
)
{
version = (string[0] - L'0') * 10 + (string[2] - L'0');
}
else
{
throw RESULT_ERR_INVALID_FILE;
}
}
bool strict = true;
if (const Xml::Attribute attribute=romset.GetAttribute( L"conformance" ))
{
if (attribute.IsValue( L"loose" ))
{
strict = false;
}
else if (version != DEFAULT_VERSION && !attribute.IsValue( L"strict" ))
{
throw RESULT_ERR_INVALID_FILE;
}
}
profiles.reserve( 4 );
for (Xml::Node game(xml.GetRoot().GetFirstChild()); game; game=game.GetNextSibling())
{
for (Xml::Node image(game.GetFirstChild()); image; image=image.GetNextSibling())
{
Profile p;
p.game.title = game.GetAttribute( L"name" ).GetValue();
p.game.altTitle = game.GetAttribute( L"altname" ).GetValue();
p.game.clss = game.GetAttribute( L"class" ).GetValue();
p.game.subClss = game.GetAttribute( L"subclass" ).GetValue();
p.game.catalog = game.GetAttribute( L"catalog" ).GetValue();
p.game.publisher = game.GetAttribute( L"publisher" ).GetValue();
p.game.developer = game.GetAttribute( L"developer" ).GetValue();
p.game.portDeveloper = game.GetAttribute( L"portdeveloper" ).GetValue();
p.game.region = game.GetAttribute( L"region" ).GetValue();
if (const Xml::Attribute attribute=game.GetAttribute( L"players" ))
{
const ulong players = attribute.GetUnsignedValue();
if (players >= MIN_PLAYERS && players <= MAX_PLAYERS)
{
p.game.players = players;
}
else if (strict)
{
throw RESULT_ERR_INVALID_FILE;
}
}
if (image.IsType( L"cartridge" ))
{
if (const Xml::Attribute attribute=image.GetAttribute( L"system" ))
{
if (attribute.IsValue( L"famicom" ))
{
p.system.type = Profile::System::FAMICOM;
}
else if (attribute.IsValue( L"nes-ntsc" ))
{
p.system.type = Profile::System::NES_NTSC;
}
else if (attribute.IsValue( L"nes-pal" ))
{
p.system.type = Profile::System::NES_PAL;
p.system.cpu = Profile::System::CPU_RP2A07;
p.system.ppu = Profile::System::PPU_RP2C07;
}
else if (attribute.IsValue( L"nes-pal-a" ))
{
p.system.type = Profile::System::NES_PAL_A;
p.system.cpu = Profile::System::CPU_RP2A07;
p.system.ppu = Profile::System::PPU_RP2C07;
}
else if (attribute.IsValue( L"nes-pal-b" ))
{
p.system.type = Profile::System::NES_PAL_B;
p.system.cpu = Profile::System::CPU_RP2A07;
p.system.ppu = Profile::System::PPU_RP2C07;
}
else if (attribute.IsValue( L"dendy" ))
{
p.system.type = Profile::System::DENDY;
p.system.cpu = Profile::System::CPU_DENDY;
p.system.ppu = Profile::System::PPU_DENDY;
}
else if (!strict)
{
if (favoredSystem == FAVORED_NES_PAL)
{
p.system.type = Profile::System::NES_PAL;
p.system.cpu = Profile::System::CPU_RP2A07;
p.system.ppu = Profile::System::PPU_RP2C07;
}
else if (favoredSystem == FAVORED_FAMICOM)
{
p.system.type = Profile::System::FAMICOM;
}
else if (favoredSystem == FAVORED_DENDY)
{
p.system.type = Profile::System::DENDY;
p.system.cpu = Profile::System::CPU_DENDY;
p.system.ppu = Profile::System::PPU_DENDY;
}
else
{
p.system.type = Profile::System::NES_NTSC;
}
}
else
{
throw RESULT_ERR_INVALID_FILE;
}
}
else if (strict)
{
throw RESULT_ERR_INVALID_FILE;
}
}
else if (image.IsType( L"arcade" ))
{
p.system.ppu = Profile::System::PPU_RP2C03B;
if (const Xml::Attribute attribute=image.GetAttribute( L"system" ))
{
if (attribute.IsValue( L"vs-unisystem" ))
{
p.system.type = Profile::System::VS_UNISYSTEM;
}
else if (attribute.IsValue( L"vs-dualsystem" ))
{
p.system.type = Profile::System::VS_DUALSYSTEM;
}
else if (attribute.IsValue( L"playchoice-10" ))
{
p.system.type = Profile::System::PLAYCHOICE_10;
}
else
{
throw RESULT_ERR_INVALID_FILE;
}
}
else
{
throw RESULT_ERR_INVALID_FILE;
}
}
else
{
throw RESULT_ERR_INVALID_FILE;
}
p.dump.by = image.GetAttribute( L"dumper" ).GetValue();
p.dump.date = image.GetAttribute( L"datedumped" ).GetValue();
p.dump.state = Profile::Dump::OK;
if (const Xml::Attribute attribute=image.GetAttribute( L"dump" ))
{
if (attribute.IsValue( L"bad" ))
{
p.dump.state = Profile::Dump::BAD;
}
else if (attribute.IsValue( L"unknown" ))
{
p.dump.state = Profile::Dump::UNKNOWN;
}
else if (strict && !attribute.IsValue( L"ok" ))
{
throw RESULT_ERR_INVALID_FILE;
}
}
if (Xml::Node node=image.GetChild( L"properties" ))
{
for (node=node.GetFirstChild(); node.IsType( L"property" ); node=node.GetNextSibling())
{
Profile::Property property;
property.name = node.GetAttribute( L"name" ).GetValue();
property.value = node.GetAttribute( L"value" ).GetValue();
p.properties.push_back( property );
}
}
if (p.system.type == Profile::System::VS_UNISYSTEM || p.system.type == Profile::System::VS_DUALSYSTEM)
{
if (const Xml::Attribute attribute=image.GetAttribute( L"ppu" ))
{
if (attribute.IsValue( L"rp2c03b" )) p.system.ppu = Profile::System::PPU_RP2C03B;
else if (attribute.IsValue( L"rp2c03g" )) p.system.ppu = Profile::System::PPU_RP2C03G;
else if (attribute.IsValue( L"rp2c04-0001" )) p.system.ppu = Profile::System::PPU_RP2C04_0001;
else if (attribute.IsValue( L"rp2c04-0002" )) p.system.ppu = Profile::System::PPU_RP2C04_0002;
else if (attribute.IsValue( L"rp2c04-0003" )) p.system.ppu = Profile::System::PPU_RP2C04_0003;
else if (attribute.IsValue( L"rp2c04-0004" )) p.system.ppu = Profile::System::PPU_RP2C04_0004;
else if (attribute.IsValue( L"rc2c03b" )) p.system.ppu = Profile::System::PPU_RC2C03B;
else if (attribute.IsValue( L"rc2c03c" )) p.system.ppu = Profile::System::PPU_RC2C03C;
else if (attribute.IsValue( L"rc2c05-01" )) p.system.ppu = Profile::System::PPU_RC2C05_01;
else if (attribute.IsValue( L"rc2c05-02" )) p.system.ppu = Profile::System::PPU_RC2C05_02;
else if (attribute.IsValue( L"rc2c05-03" )) p.system.ppu = Profile::System::PPU_RC2C05_03;
else if (attribute.IsValue( L"rc2c05-04" )) p.system.ppu = Profile::System::PPU_RC2C05_04;
else if (attribute.IsValue( L"rc2c05-05" )) p.system.ppu = Profile::System::PPU_RC2C05_05;
}
}
p.game.revision = image.GetAttribute( L"revision" ).GetValue();
p.hash.Assign
(
image.GetAttribute( L"sha1" ).GetValue(),
image.GetAttribute( L"crc" ).GetValue()
);
if (const Xml::Node board=image.GetChild( L"board" ))
{
p.board.type = board.GetAttribute( L"type" ).GetValue();
p.board.pcb = board.GetAttribute( L"pcb" ).GetValue();
p.board.cic = board.GetChild( L"cic" ).GetAttribute( L"type" ).GetValue();
if (const Xml::Attribute attribute=board.GetAttribute( L"mapper" ))
{
const ulong mapper = attribute.GetUnsignedValue();
if (mapper <= MAX_MAPPER)
{
p.board.mapper = mapper;
}
else if (strict)
{
throw RESULT_ERR_INVALID_FILE;
}
}
if (const Xml::Node pad=board.GetChild( L"pad" ))
{
p.board.solderPads =
(
(pad.GetAttribute( L"h" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_H : 0U) |
(pad.GetAttribute( L"v" ).IsValue( L"1" ) ? Profile::Board::SOLDERPAD_V : 0U)
);
}
for (Xml::Node node=board.GetFirstChild(); node; node=node.GetNextSibling())
{
dword size = 0;
if (const Xml::Attribute attribute=node.GetAttribute( L"size" ))
{
wcstring end;
const ulong value = attribute.GetUnsignedValue( end, 10 );
if (end[0] == L'\0')
{
size = value;
}
else if ((end[0] == L'k' || end[0] == L'K') && end[1] == L'\0' && value <= MAX_CHIP_SIZE/SIZE_1K)
{
size = value * SIZE_1K;
}
}
Profile::Board::Pins pins;
Profile::Board::Samples samples;
for (Xml::Node child(node.GetFirstChild()); child; child=child.GetNextSibling())
{
if (child.IsType(L"pin"))
{
const ulong number = child.GetAttribute(L"number").GetUnsignedValue();
wcstring const function = child.GetAttribute(L"function").GetValue();
if (number >= MIN_IC_PINS && number <= MAX_IC_PINS && *function)
{
Profile::Board::Pin pin;
pin.number = number;
pin.function = function;
pins.push_back( pin );
}
}
else if (child.IsType(L"sample"))
{
const ulong id = child.GetAttribute(L"id").GetUnsignedValue();
wcstring const file = child.GetAttribute(L"file").GetValue();
if (id <= MAX_CHIP_SAMPLES && *file)
{
Profile::Board::Sample sample;
sample.id = id;
sample.file = file;
samples.push_back( sample );
}
}
}
bool first;
if (true == (first=node.IsType( L"prg" )) || node.IsType( L"chr" ))
{
if (size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE)
throw RESULT_ERR_INVALID_FILE;
Profile::Board::Roms& roms = (first ? p.board.prg : p.board.chr);
Profile::Board::Rom rom;
rom.id = node.GetAttribute( L"id" ).GetUnsignedValue();
rom.size = size;
rom.name = node.GetAttribute( L"name" ).GetValue();
rom.pins = pins;
rom.file = node.GetAttribute( L"file" ).GetValue();
rom.package = node.GetAttribute( L"package" ).GetValue();
rom.hash.Assign( node.GetAttribute( L"sha1" ).GetValue(), node.GetAttribute( L"crc" ).GetValue() );
for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); ; ++it)
{
if (it == end || it->id > rom.id)
{
roms.insert( it, rom );
break;
}
}
}
else if (true == (first=node.IsType( L"wram" )) || node.IsType( L"vram" ))
{
if (size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE)
throw RESULT_ERR_INVALID_FILE;
Profile::Board::Rams& rams = (first ? p.board.wram : p.board.vram);
Profile::Board::Ram ram;
ram.id = node.GetAttribute( L"id" ).GetUnsignedValue();
ram.size = size;
ram.file = node.GetAttribute( L"file" ).GetValue();
ram.pins = pins;
ram.package = node.GetAttribute( L"package" ).GetValue();
ram.battery = node.GetAttribute( L"battery" ).IsValue( L"1" );
for (Profile::Board::Rams::iterator it(rams.begin()), end(rams.end()); ; ++it)
{
if (it == end || it->id > ram.id)
{
rams.insert( it, ram );
break;
}
}
}
else if (node.IsType( L"chip" ))
{
Profile::Board::Chip chip;
chip.type = node.GetAttribute( L"type" ).GetValue();
chip.file = node.GetAttribute( L"file" ).GetValue();
chip.pins = pins;
chip.samples = samples;
chip.battery = node.GetAttribute( L"battery" ).IsValue( L"1" );
chip.package = node.GetAttribute( L"package" ).GetValue();
p.board.chips.push_back( chip );
}
}
}
if (Xml::Node device=game.GetChild( L"peripherals" ))
{
for (device=device.GetFirstChild(); device.IsType( L"device" ); device=device.GetNextSibling())
{
if (const Xml::Attribute attribute = device.GetAttribute( L"type" ))
{
if (attribute.IsValue( L"arkanoid" ))
{
if (p.system.type == Profile::System::FAMICOM)
p.game.controllers[4] = Api::Input::PADDLE;
else
p.game.controllers[1] = Api::Input::PADDLE;
}
else if (attribute.IsValue( L"bandaihypershot" ))
{
p.game.controllers[4] = Api::Input::BANDAIHYPERSHOT;
}
else if (attribute.IsValue( L"barcodeworld" ))
{
p.game.controllers[4] = Api::Input::BARCODEWORLD;
}
else if (attribute.IsValue( L"crazyclimber" ))
{
p.game.controllers[4] = Api::Input::CRAZYCLIMBER;
}
else if (attribute.IsValue( L"doremikko" ))
{
p.game.controllers[4] = Api::Input::DOREMIKKOKEYBOARD;
}
else if (attribute.IsValue( L"excitingboxing" ))
{
p.game.controllers[4] = Api::Input::EXCITINGBOXING;
}
else if (attribute.IsValue( L"familykeyboard" ))
{
p.game.controllers[4] = Api::Input::FAMILYKEYBOARD;
}
else if (attribute.IsValue( L"familytrainer" ))
{
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::FAMILYTRAINER;
}
else if (attribute.IsValue( L"fourplayer" ))
{
if (p.system.type == Profile::System::FAMICOM)
p.game.adapter = Api::Input::ADAPTER_FAMICOM;
else
p.game.adapter = Api::Input::ADAPTER_NES;
p.game.controllers[2] = Api::Input::PAD3;
p.game.controllers[3] = Api::Input::PAD4;
}
else if (attribute.IsValue( L"horitrack" ))
{
p.game.controllers[4] = Api::Input::HORITRACK;
}
else if (attribute.IsValue( L"konamihypershot" ))
{
p.game.controllers[0] = Api::Input::UNCONNECTED;
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::KONAMIHYPERSHOT;
}
else if (attribute.IsValue( L"mahjong" ))
{
p.game.controllers[0] = Api::Input::UNCONNECTED;
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::MAHJONG;
}
else if (attribute.IsValue( L"oekakidstablet" ))
{
p.game.controllers[0] = Api::Input::UNCONNECTED;
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::OEKAKIDSTABLET;
}
else if (attribute.IsValue( L"pachinko" ))
{
p.game.controllers[4] = Api::Input::PACHINKO;
}
else if (attribute.IsValue( L"partytap" ))
{
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::PARTYTAP;
}
else if (attribute.IsValue( L"pokkunmoguraa" ))
{
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::POKKUNMOGURAA;
}
else if (attribute.IsValue( L"powerglove" ))
{
p.game.controllers[0] = Api::Input::POWERGLOVE;
}
else if (attribute.IsValue( L"powerpad" ) || attribute.IsValue( L"familyfunfitness" ))
{
if (p.system.type == Profile::System::FAMICOM)
{
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::FAMILYTRAINER;
}
else
{
p.game.controllers[1] = Api::Input::POWERPAD;
}
}
else if (attribute.IsValue( L"rob" ))
{
p.game.controllers[1] = Api::Input::ROB;
}
else if (attribute.IsValue( L"suborkeyboard" ))
{
p.game.controllers[4] = Api::Input::SUBORKEYBOARD;
}
else if (attribute.IsValue( L"subormouse" ))
{
p.game.controllers[1] = Api::Input::MOUSE;
}
else if (attribute.IsValue( L"standard" ))
{
p.game.controllers[0] = Api::Input::PAD1;
p.game.controllers[1] = Api::Input::PAD2;
}
else if (attribute.IsValue( L"topriderbike" ))
{
p.game.controllers[0] = Api::Input::UNCONNECTED;
p.game.controllers[1] = Api::Input::UNCONNECTED;
p.game.controllers[4] = Api::Input::TOPRIDER;
}
else if (attribute.IsValue( L"turbofile" ))
{
p.game.controllers[4] = Api::Input::TURBOFILE;
}
else if (attribute.IsValue( L"zapper" ))
{
if (p.system.type == Profile::System::VS_UNISYSTEM || p.system.type == Profile::System::VS_DUALSYSTEM)
{
p.game.controllers[0] = Api::Input::ZAPPER;
p.game.controllers[1] = Api::Input::UNCONNECTED;
}
else
{
p.game.controllers[1] = Api::Input::ZAPPER;
}
}
}
}
}
profiles.push_back( p );
}
}
}
void ChooseProfile()
{
if (profiles.empty())
throw RESULT_ERR_INVALID_FILE;
Profiles::const_iterator bestMatch( profiles.begin() );
if (profiles.size() > 1)
{
for (Profiles::const_iterator it(profiles.begin()), end(profiles.end()); it != end; ++it)
{
if (it->system.type == Profile::System::NES_NTSC)
{
if (favoredSystem == FAVORED_NES_NTSC)
{
bestMatch = it;
break;
}
}
else if
(
it->system.type == Profile::System::NES_PAL ||
it->system.type == Profile::System::NES_PAL_A ||
it->system.type == Profile::System::NES_PAL_B
)
{
if (favoredSystem == FAVORED_NES_PAL)
{
bestMatch = it;
break;
}
}
else if (it->system.type == Profile::System::FAMICOM)
{
if (favoredSystem == FAVORED_FAMICOM)
{
bestMatch = it;
break;
}
}
else if (it->system.type == Profile::System::DENDY)
{
if (favoredSystem == FAVORED_DENDY)
{
bestMatch = it;
break;
}
}
}
if (askProfile && Api::Cartridge::chooseProfileCallback)
{
std::vector names( profiles.size() );
std::vector::iterator dst( names.begin() );
for (Profiles::const_iterator src(profiles.begin()), end(profiles.end()); src != end; ++src, ++dst)
{
*dst = src->game.title;
if (!src->game.revision.empty())
{
*dst += dst->empty() ? L"(Rev. " : L" (Rev. ";
*dst += src->game.revision;
*dst += L')';
}
if (!src->game.region.empty())
{
*dst += dst->empty() ? L"(" : L" (";
*dst += src->game.region;
*dst += L')';
}
if (!dst->empty())
*dst += L' ';
*dst +=
(
src->system.type == Profile::System::NES_PAL ? L"(NES-PAL)" :
src->system.type == Profile::System::NES_PAL_A ? L"(NES-PAL-A)" :
src->system.type == Profile::System::NES_PAL_B ? L"(NES-PAL-B)" :
src->system.type == Profile::System::FAMICOM ? L"(Famicom)" :
src->system.type == Profile::System::DENDY ? L"(Dendy)" :
src->system.type == Profile::System::VS_UNISYSTEM ? L"(VS)" :
src->system.type == Profile::System::VS_DUALSYSTEM ? L"(VS)" :
src->system.type == Profile::System::PLAYCHOICE_10 ? L"(PC10)" :
L"(NES-NTSC)"
);
}
const uint selected = Api::Cartridge::chooseProfileCallback( &profiles.front(), &names.front(), profiles.size() );
if (selected < profiles.size())
bestMatch = profiles.begin() + selected;
}
}
profile = *bestMatch;
if (profiles.size() > 1)
{
uint regions = 0x0;
for (Profiles::const_iterator it(profiles.begin()), end(profiles.end()); it != end; ++it)
{
if (profile.hash == it->hash)
{
switch (it->system.type)
{
case Profile::System::NES_PAL:
case Profile::System::NES_PAL_A:
case Profile::System::NES_PAL_B:
case Profile::System::DENDY:
regions |= 0x1;
break;
default:
regions |= 0x2;
break;
}
}
if (regions == 0x3)
{
profile.multiRegion = true;
break;
}
}
}
}
void LoadRoms()
{
class Loader : public Api::User::File
{
wcstring const filename;
byte* const rom;
const dword size;
bool loaded;
Action GetAction() const throw()
{
return LOAD_ROM;
}
wcstring GetName() const throw()
{
return filename;
}
ulong GetMaxSize() const throw()
{
return size;
}
Result SetContent(const void* filedata,ulong filesize) throw()
{
if (filesize)
{
if (filedata)
{
std::memcpy( rom, filedata, NST_MIN(size,filesize) );
loaded = true;
}
else
{
return RESULT_ERR_INVALID_PARAM;
}
}
return RESULT_OK;
}
Result SetContent(std::istream& stdStream) throw()
{
try
{
Nes::Core::Stream::In stream( &stdStream );
if (const ulong length = stream.Length())
{
stream.Read( rom, NST_MIN(size,length) );
loaded = true;
}
}
catch (Result result)
{
return result;
}
catch (const std::bad_alloc&)
{
return RESULT_ERR_OUT_OF_MEMORY;
}
catch (...)
{
return RESULT_ERR_GENERIC;
}
return RESULT_OK;
}
public:
Loader(wcstring f,byte* r,dword s)
: filename(f), rom(r), size(s), loaded(false) {}
bool Loaded() const
{
return loaded;
}
};
for (uint i=0; i < 2; ++i)
{
Profile::Board::Roms& roms = (i ? profile.board.chr : profile.board.prg);
if (roms.empty())
continue;
Ram& rom = (i ? chr : prg);
dword size = 0;
for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); it != end; ++it)
{
size += it->size;
if (it->size < MIN_CHIP_SIZE || size > MAX_CHIP_SIZE)
throw RESULT_ERR_INVALID_FILE;
}
rom.Set( size );
for (Profile::Board::Pins::const_iterator pin(roms.begin()->pins.begin()), end(roms.begin()->pins.end()); pin != end; ++pin)
rom.Pin(pin->number) = pin->function.c_str();
if (readOnly)
continue;
if (!Api::User::fileIoCallback)
throw RESULT_ERR_NOT_READY;
size = 0;
for (Profile::Board::Roms::iterator it(roms.begin()), end(roms.end()); it != end; ++it)
{
if (it->file.empty())
throw RESULT_ERR_INVALID_FILE;
Loader loader( it->file.c_str(), rom.Mem(size), it->size );
Api::User::fileIoCallback( loader );
if (!loader.Loaded())
throw RESULT_ERR_INVALID_FILE;
size += it->size;
}
}
}
void PatchRoms()
{
if (patchStream)
{
Patcher patcher( patchBypassChecksum );
*patchResult = patcher.Load( *patchStream );
if (NES_SUCCEEDED(*patchResult))
{
const Patcher::Block blocks[] =
{
{ prg.Mem(), prg.Size() },
{ chr.Mem(), chr.Size() }
};
*patchResult = patcher.Test( blocks );
if (NES_SUCCEEDED(*patchResult))
{
if (patcher.Patch( prg.Mem(), prg.Mem(), prg.Size(), 16 ))
{
profile.patched = true;
Log::Flush( "Romset: PRG-ROM was patched" NST_LINEBREAK );
}
if (patcher.Patch( chr.Mem(), chr.Mem(), chr.Size(), 16 + prg.Size() ))
{
profile.patched = true;
Log::Flush( "Romset: CHR-ROM was patched" NST_LINEBREAK );
}
}
}
}
}
};
void Cartridge::Romset::Load
(
std::istream& stdStreamImage,
std::istream* const stdStreamPatch,
const bool patchBypassChecksum,
Result* const patchResult,
Ram& prg,
Ram& chr,
const FavoredSystem favoredSystem,
const bool askProfile,
Profile& profile,
const bool readOnly
)
{
Loader loader
(
stdStreamImage,
stdStreamPatch,
patchBypassChecksum,
patchResult,
prg,
chr,
favoredSystem,
askProfile,
profile,
readOnly
);
loader.Load();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}
nestopia-1.47/source/core/NstCartridgeRomset.hpp 0000664 0000000 0000000 00000002673 12644314416 0022030 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CARTRIDGE_ROMSET_H
#define NST_CARTRIDGE_ROMSET_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
class Cartridge::Romset
{
class Loader;
public:
static void Load
(
std::istream&,
std::istream*,
bool,
Result*,
Ram&,
Ram&,
FavoredSystem,
bool,
Profile&,
bool=false
);
};
}
}
#endif
nestopia-1.47/source/core/NstCartridgeUnif.cpp 0000664 0000000 0000000 00000045167 12644314416 0021460 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include "NstLog.hpp"
#include "NstPatcher.hpp"
#include "NstStream.hpp"
#include "NstChecksum.hpp"
#include "NstImageDatabase.hpp"
#include "NstCartridge.hpp"
#include "NstCartridgeUnif.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
class Cartridge::Unif::Loader
{
class Context
{
public:
bool operator () (uint,dword);
enum System
{
SYSTEM_NTSC,
SYSTEM_PAL,
SYSTEM_BOTH
};
struct Rom
{
Rom();
Ram data;
dword truncated;
char crc[12];
};
System system;
Rom roms[2][16];
private:
byte chunks[80];
public:
Context()
: system(SYSTEM_NTSC)
{
std::memset( chunks, 0, sizeof(chunks) );
}
};
enum
{
HEADER_RESERVED_LENGTH = 24,
MAX_ROM_SIZE = SIZE_16K * 0x1000UL,
DUMPER_NAME_LENGTH = 100,
DUMPER_AGENT_LENGTH = 100,
DUMPER_LENGTH = DUMPER_NAME_LENGTH + 4 + DUMPER_AGENT_LENGTH
};
dword ReadString(cstring,Vector*);
static cstring ChunkName (char (&)[5],dword);
Stream::In stream;
const FavoredSystem favoredSystem;
Profile& profile;
ProfileEx& profileEx;
Ram& prg;
Ram& chr;
Patcher patcher;
Result* const patchResult;
const ImageDatabase* const database;
public:
Loader
(
std::istream& stdStreamImage,
std::istream* const stdStreamPatch,
const bool patchBypassChecksum,
Result* const e,
Ram& p,
Ram& c,
const FavoredSystem f,
Profile& r,
ProfileEx& x,
const ImageDatabase* const d
)
:
stream (&stdStreamImage),
favoredSystem (f),
profile (r),
profileEx (x),
prg (p),
chr (c),
patcher (patchBypassChecksum),
patchResult (e),
database (d)
{
NST_ASSERT( prg.Empty() && chr.Empty() );
profile = Profile();
profileEx = ProfileEx();
if (stdStreamPatch)
*patchResult = patcher.Load( *stdStreamPatch );
}
void Load()
{
ReadHeader();
ReadChunks();
if (database && database->Enabled())
{
Checksum checksum;
checksum.Compute( prg.Mem(), prg.Size() );
checksum.Compute( chr.Mem(), chr.Size() );
if (const ImageDatabase::Entry entry = database->Search( Profile::Hash(checksum.GetSha1(),checksum.GetCrc()), favoredSystem ))
entry.Fill( profile, patcher.Empty() );
}
if (!patcher.Empty())
{
const Patcher::Block blocks[] =
{
{ prg.Mem(), prg.Size() },
{ chr.Mem(), chr.Size() }
};
*patchResult = patcher.Test( blocks );
if (NES_SUCCEEDED(*patchResult))
{
if (patcher.Patch( prg.Mem(), prg.Mem(), prg.Size(), 16 ))
{
profile.patched = true;
Log::Flush( "Unif: PRG-ROM was patched" NST_LINEBREAK );
}
if (patcher.Patch( chr.Mem(), chr.Mem(), chr.Size(), 16 + prg.Size() ))
{
profile.patched = true;
Log::Flush( "Unif: CHR-ROM was patched" NST_LINEBREAK );
}
}
}
}
private:
void ReadHeader()
{
if (stream.Read32() != AsciiId<'U','N','I','F'>::V)
throw RESULT_ERR_INVALID_FILE;
dword version = stream.Read32();
Log() << "Unif: revision " << version << NST_LINEBREAK;
byte reserved[HEADER_RESERVED_LENGTH];
stream.Read( reserved );
for (uint i=0; i < HEADER_RESERVED_LENGTH; ++i)
{
NST_VERIFY( !reserved[i] );
if (reserved[i])
{
Log() << "Unif: warning, unknown header data" NST_LINEBREAK;
break;
}
}
}
void ReadChunks()
{
Context context;
while (!stream.Eof())
{
dword id = stream.Read32();
const dword length = stream.Read32();
NST_VERIFY( length <= SIZE_1K * 4096UL );
switch (id)
{
case AsciiId<'N','A','M','E'>::V: id = (context( 0, id ) ? ReadName ( ) : 0); break;
case AsciiId<'R','E','A','D'>::V: id = (context( 1, id ) ? ReadComment ( ) : 0); break;
case AsciiId<'D','I','N','F'>::V: id = (context( 2, id ) ? ReadDumper ( ) : 0); break;
case AsciiId<'T','V','C','I'>::V: id = (context( 3, id ) ? ReadSystem ( context ) : 0); break;
case AsciiId<'B','A','T','R'>::V: id = (context( 4, id ) ? ReadBattery ( ) : 0); break;
case AsciiId<'M','A','P','R'>::V: id = (context( 5, id ) ? ReadBoard ( ) : 0); break;
case AsciiId<'M','I','R','R'>::V: id = (context( 6, id ) ? ReadMirroring ( ) : 0); break;
case AsciiId<'C','T','R','L'>::V: id = (context( 7, id ) ? ReadController ( ) : 0); break;
case AsciiId<'V','R','O','R'>::V: id = (context( 8, id ) ? ReadChrRam ( ) : 0); break;
default: switch (id & 0x00FFFFFF)
{
case AsciiId<'P','C','K'>::V:
case AsciiId<'C','C','K'>::V:
case AsciiId<'P','R','G'>::V:
case AsciiId<'C','H','R'>::V:
{
uint index = id >> 24 & 0xFF;
if (index >= Ascii<'0'>::V && index <= Ascii<'9'>::V)
{
index -= Ascii<'0'>::V;
}
else if (index >= Ascii<'A'>::V && index <= Ascii<'F'>::V)
{
index = index - Ascii<'A'>::V + 10;
}
else
{
index = ~0U;
}
if (index < 16)
{
switch (dword part = (id & 0x00FFFFFF))
{
case AsciiId<'P','C','K'>::V:
case AsciiId<'C','C','K'>::V:
part = (part == AsciiId<'C','C','K'>::V);
id = (context( 9 + (part << 4) + index, id) ? ReadChecksum( part, index, context.roms[part][index] ) : 0);
break;
case AsciiId<'P','R','G'>::V:
case AsciiId<'C','H','R'>::V:
part = (part == AsciiId<'C','H','R'>::V);
id = (context( 9 + 32 + (part << 4) + index, id ) ? ReadRom( part, index, length, context.roms[part] ) : 0);
break;
}
break;
}
}
default:
id = ReadUnknown( id );
break;
}
}
if (id < length)
{
for (id = length - id; id > 0x7FFFFFFF; id -= 0x7FFFFFFF)
stream.Seek( 0x7FFFFFFF );
if (id)
stream.Seek( id );
}
else if (id > length)
{
throw RESULT_ERR_CORRUPT_FILE;
}
}
for (uint i=0; i < 2; ++i)
{
uint count = 0;
dword size = 0;
for (uint j=0; j < 16; ++j)
{
if (const dword n=context.roms[i][j].data.Size())
{
count++;
size += n;
}
}
if (count)
{
Profile::Board::Roms& rom = (i ? profile.board.chr : profile.board.prg);
rom.resize( count );
Ram& dst = (i ? chr : prg);
dst.Set( size );
if (!rom.empty())
{
for (Profile::Board::Pins::const_iterator it(rom.front().pins.begin()), end(rom.front().pins.end()); it != end; ++it)
dst.Pin(it->number) = it->function.c_str();
}
size = 0;
for (uint j=0, k=0; j < 16; ++j)
{
const Context::Rom& src = context.roms[i][j];
if (src.data.Size())
{
rom[k].id = k;
rom[k].size = src.data.Size();
rom[k].hash.Assign( NULL, src.crc );
k++;
std::memcpy( dst.Mem(size), src.data.Mem(), src.data.Size() );
size += src.data.Size();
}
}
}
}
if (profileEx.nmt == ProfileEx::NMT_HORIZONTAL)
{
profile.board.solderPads = Profile::Board::SOLDERPAD_V;
}
else if (profileEx.nmt == ProfileEx::NMT_VERTICAL)
{
profile.board.solderPads = Profile::Board::SOLDERPAD_H;
}
switch (context.system)
{
case Context::SYSTEM_NTSC:
if (favoredSystem == FAVORED_FAMICOM)
{
profile.system.type = Profile::System::FAMICOM;
}
if (favoredSystem == FAVORED_DENDY)
{
profile.system.type = Profile::System::DENDY;
profile.system.cpu = Profile::System::CPU_DENDY;
profile.system.ppu = Profile::System::PPU_DENDY;
}
else
{
profile.system.type = Profile::System::NES_NTSC;
}
break;
default:
profile.multiRegion = true;
if (favoredSystem == FAVORED_FAMICOM)
{
profile.system.type = Profile::System::FAMICOM;
break;
}
else if (favoredSystem != FAVORED_NES_PAL && favoredSystem != FAVORED_DENDY)
{
profile.system.type = Profile::System::NES_NTSC;
break;
}
case Context::SYSTEM_PAL:
if (favoredSystem == FAVORED_DENDY)
{
profile.system.type = Profile::System::DENDY;
profile.system.cpu = Profile::System::CPU_DENDY;
profile.system.ppu = Profile::System::PPU_DENDY;
}
else
{
profile.system.type = Profile::System::NES_PAL;
profile.system.cpu = Profile::System::CPU_RP2A07;
profile.system.ppu = Profile::System::PPU_RP2C07;
}
break;
}
}
dword ReadName()
{
Vector buffer;
const dword length = ReadString( "Unif: name: ", &buffer );
if (length && *buffer.Begin())
profile.game.title.assign( buffer.Begin(), buffer.End() );
return length;
}
dword ReadComment()
{
return ReadString( "Unif: comment: ", NULL );
}
dword ReadDumper()
{
struct
{
char name[DUMPER_NAME_LENGTH];
byte day;
byte month;
word year;
char agent[DUMPER_AGENT_LENGTH];
} dumper;
stream.Read( dumper.name, DUMPER_NAME_LENGTH );
dumper.name[DUMPER_NAME_LENGTH-1] = '\0';
dumper.day = stream.Read8();
dumper.month = stream.Read8();
dumper.year = stream.Read16();
stream.Read( dumper.agent, DUMPER_AGENT_LENGTH );
dumper.agent[DUMPER_AGENT_LENGTH-1] = '\0';
Log log;
if (*dumper.name)
log << "Unif: dumped by: " << dumper.name << NST_LINEBREAK;
log << "Unif: dump year: " << dumper.year << NST_LINEBREAK
"Unif: dump month: " << dumper.month << NST_LINEBREAK
"Unif: dump day: " << dumper.day << NST_LINEBREAK;
if (*dumper.agent)
log << "Unif: dumper agent: " << dumper.agent << NST_LINEBREAK;
return DUMPER_LENGTH;
}
dword ReadSystem(Context& context)
{
switch (stream.Read8())
{
case 0:
context.system = Context::SYSTEM_NTSC;
Log::Flush( "Unif: NTSC system" NST_LINEBREAK );
break;
case 1:
context.system = Context::SYSTEM_PAL;
Log::Flush( "Unif: PAL system" NST_LINEBREAK );
break;
default:
context.system = Context::SYSTEM_BOTH;
Log::Flush( "Unif: dual system" NST_LINEBREAK );
break;
}
return 1;
}
dword ReadBattery()
{
profileEx.battery = true;
Log::Flush( "Unif: battery present" NST_LINEBREAK );
return 0;
}
dword ReadBoard()
{
Vector buffer;
const dword length = ReadString( "Unif: board: ", &buffer );
if (length && *buffer.Begin())
profile.board.type.assign( buffer.Begin(), buffer.End() );
return length;
}
dword ReadMirroring()
{
switch (stream.Read8())
{
case 0: profileEx.nmt = ProfileEx::NMT_HORIZONTAL; Log::Flush( "Unif: horizontal mirroring" NST_LINEBREAK ); break;
case 1: profileEx.nmt = ProfileEx::NMT_VERTICAL; Log::Flush( "Unif: vertical mirroring" NST_LINEBREAK ); break;
case 2:
case 3: profileEx.nmt = ProfileEx::NMT_SINGLESCREEN; Log::Flush( "Unif: single-screen mirroring" NST_LINEBREAK ); break;
case 4: profileEx.nmt = ProfileEx::NMT_FOURSCREEN; Log::Flush( "Unif: four-screen mirroring" NST_LINEBREAK ); break;
case 5: profileEx.nmt = ProfileEx::NMT_CONTROLLED; Log::Flush( "Unif: mapper controlled mirroring" NST_LINEBREAK ); break;
}
return 1;
}
dword ReadChecksum(const uint type,const uint index,Context::Rom& rom)
{
NST_ASSERT( type < 2 && index < 16 );
for (dword crc=stream.Read32(), i=0; i < 8; ++i)
{
uint c = crc >> (i*4) & 0xF;
rom.crc[i] = (c < 0xA ? '0' + c : 'A' + (c - 0xA) );
}
Log() << "Unif: "
<< (type ? "CHR-ROM " : "PRG-ROM ")
<< char(index < 10 ? index + '0' : index-10 + 'A')
<< " CRC: "
<< rom.crc
<< NST_LINEBREAK;
return 4;
}
dword ReadRom(const uint type,const uint index,dword length,Context::Rom* const roms)
{
NST_ASSERT( type < 2 && index < 16 );
Log() << "Unif: "
<< (type ? "CHR-ROM " : "PRG-ROM ")
<< char(index < 10 ? index + '0' : index-10 + 'A')
<< " size: "
<< (length / SIZE_1K)
<< "k" NST_LINEBREAK;
dword available = 0;
for (uint i=0; i < 16; ++i)
available += roms[i].data.Size();
available = MAX_ROM_SIZE - available;
NST_VERIFY( length <= available );
if (length > available)
{
roms[index].truncated = length - available;
length = available;
Log() << "Unif: warning, "
<< (type ? "CHR-ROM " : "PRG-ROM ")
<< char(index < 10 ? index + '0' : index-10 + 'A')
<< " truncated to: "
<< (length / SIZE_1K)
<< "k" NST_LINEBREAK;
}
if (length)
{
roms[index].data.Set( length );
stream.Read( roms[index].data.Mem(), length );
}
return length;
}
dword ReadController()
{
Log log;
log << "Unif: controllers: ";
const uint controller = stream.Read8();
NST_VERIFY( !(controller & (0x40|0x80)) );
if (controller & (0x1|0x2|0x4|0x8|0x10|0x20))
{
if (controller & 0x01)
{
profile.game.controllers[0] = Api::Input::PAD1;
profile.game.controllers[1] = Api::Input::PAD2;
log << "standard joypad";
}
if (controller & 0x02)
{
profile.game.controllers[1] = Api::Input::ZAPPER;
cstring const zapper = ", zapper";
log << (zapper + ((controller & 0x1) ? 0 : 2));
}
if (controller & 0x04)
{
profile.game.controllers[1] = Api::Input::ROB;
cstring const rob = ", R.O.B.";
log << (rob + ((controller & (0x1|0x2)) ? 0 : 2));
}
if (controller & 0x08)
{
profile.game.controllers[0] = Api::Input::PADDLE;
cstring const paddle = ", paddle";
log << (paddle + ((controller & (0x1|0x2|0x4)) ? 0 : 2));
}
if (controller & 0x10)
{
profile.game.controllers[1] = Api::Input::POWERPAD;
cstring const powerpad = ", power pad";
log << (powerpad + ((controller & (0x1|0x2|0x4|0x8)) ? 0 : 2));
}
if (controller & 0x20)
{
profile.game.controllers[2] = Api::Input::PAD3;
profile.game.controllers[3] = Api::Input::PAD4;
cstring const fourplayer = ", four player adapter";
log << (fourplayer + ((controller & (0x1|0x2|0x4|0x8|0x10)) ? 0 : 2));
}
log << NST_LINEBREAK;
}
else
{
log << ((controller & (0x40|0x80)) ? "unknown" NST_LINEBREAK : "unspecified" NST_LINEBREAK);
}
return 1;
}
static dword ReadChrRam()
{
Log::Flush( "Unif: CHR is writable" NST_LINEBREAK );
return 0;
}
static dword ReadUnknown(dword id)
{
NST_DEBUG_MSG("unknown unif chunk");
char name[5];
Log() << "Unif: warning, skipping unknown chunk: \"" << ChunkName(name,id) << "\"" NST_LINEBREAK;
return 0;
}
};
void Cartridge::Unif::Load
(
std::istream& stdStreamImage,
std::istream* const stdStreamPatch,
const bool patchBypassChecksum,
Result* const patchResult,
Ram& prg,
Ram& chr,
const FavoredSystem favoredSystem,
Profile& profile,
ProfileEx& profileEx,
const ImageDatabase* const database
)
{
Loader loader
(
stdStreamImage,
stdStreamPatch,
patchBypassChecksum,
patchResult,
prg,
chr,
favoredSystem,
profile,
profileEx,
database
);
loader.Load();
}
Cartridge::Unif::Loader::Context::Rom::Rom()
: truncated(0)
{
for (uint i=0; i < sizeof(crc); ++i)
crc[i] = '\0';
}
bool Cartridge::Unif::Loader::Context::operator () (const uint id,const dword chunk)
{
NST_VERIFY( chunks[id] == 0 );
if (chunks[id] == 0)
{
chunks[id] = 1;
return true;
}
else
{
char name[5];
Log() << "Unif: warning, duplicate chunk: \"" << ChunkName(name,chunk) << "\" ignored" NST_LINEBREAK;
return false;
}
}
dword Cartridge::Unif::Loader::ReadString(cstring const logtext,Vector* string)
{
Vector tmp;
if (string == NULL)
string = &tmp;
const dword count = stream.Read( *string );
if (string->Size() > 1)
Log() << logtext << string->Begin() << NST_LINEBREAK;
return count;
}
cstring Cartridge::Unif::Loader::ChunkName(char (&name)[5],const dword id)
{
const byte bytes[] =
{
id >> 0 & 0xFF,
id >> 8 & 0xFF,
id >> 16 & 0xFF,
id >> 24 & 0xFF,
0
};
Stream::In::AsciiToC( name, bytes, 5 );
return name;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}
nestopia-1.47/source/core/NstCartridgeUnif.hpp 0000664 0000000 0000000 00000002705 12644314416 0021454 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CARTRIDGE_UNIF_H
#define NST_CARTRIDGE_UNIF_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
class Cartridge::Unif
{
class Loader;
public:
static void Load
(
std::istream&,
std::istream*,
bool,
Result*,
Ram&,
Ram&,
FavoredSystem,
Profile&,
ProfileEx&,
const ImageDatabase*
);
};
}
}
#endif
nestopia-1.47/source/core/NstCheats.cpp 0000664 0000000 0000000 00000014250 12644314416 0020126 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include "NstCpu.hpp"
#include "NstCheats.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Cheats::Cheats(Cpu& c)
: cpu(c), frameLocked(false) {}
Cheats::~Cheats()
{
ClearCodes();
}
Result Cheats::SetCode
(
const word address,
const byte data,
const byte compare,
const bool useCompare,
const bool activate
)
{
if (address < 0x2000)
{
const LoCode code = {address,data,compare,useCompare};
for (LoCode *it=loCodes.Begin(), *const end=loCodes.End(); ; ++it)
{
if (it == end || it->address > address)
{
loCodes.Insert( it, code );
break;
}
else if (it->address == address)
{
if (it->data == code.data && it->useCompare == code.useCompare && (!code.useCompare || it->compare == code.compare))
{
return RESULT_NOP;
}
else
{
*it = code;
return RESULT_WARN_DATA_REPLACED;
}
}
}
}
else
{
const HiCode code = {address,data,compare,useCompare,NULL};
HiCode* it = hiCodes.Begin();
for (const HiCode* const end=hiCodes.End(); ; ++it)
{
if (it == end || it->address > address)
{
it = hiCodes.Insert( it, code );
break;
}
else if (it->address == address)
{
if (it->data == code.data && it->useCompare == code.useCompare && (!code.useCompare || it->compare == code.compare))
{
return RESULT_NOP;
}
else
{
it->data = code.data;
it->compare = code.compare;
it->useCompare = code.useCompare;
return RESULT_WARN_DATA_REPLACED;
}
}
}
if (activate)
Map( *it );
}
return RESULT_OK;
}
Result Cheats::DeleteCode(dword index)
{
if (loCodes.Size() > index)
{
loCodes.Erase( loCodes.Begin() + index );
return RESULT_OK;
}
else if (hiCodes.Size() > (index -= loCodes.Size()))
{
HiCode* const it = hiCodes.Begin() + index;
cpu.Unlink( it->address, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard );
hiCodes.Erase( it );
return RESULT_OK;
}
else
{
return RESULT_ERR_INVALID_PARAM;
}
}
void Cheats::Reset()
{
loCodes.Defrag();
hiCodes.Defrag();
for (HiCode *it=hiCodes.Begin(), *const end=hiCodes.End(); it != end; ++it)
Map( *it );
}
void Cheats::Map(HiCode& code)
{
code.port = cpu.Link( code.address, Cpu::LEVEL_HIGH, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard );
}
void Cheats::ClearCodes()
{
loCodes.Destroy();
for (const HiCode *it=hiCodes.Begin(), *const end=hiCodes.End(); it != end; ++it)
cpu.Unlink( it->address, this, &Cheats::Peek_Wizard, &Cheats::Poke_Wizard );
hiCodes.Destroy();
}
Result Cheats::GetCode
(
dword index,
ushort* const address,
uchar* const data,
uchar* const compare,
bool* const useCompare
) const
{
if (loCodes.Size() > index)
{
const LoCode* NST_RESTRICT code = loCodes.Begin() + index;
if (address)
*address = code->address;
if (data)
*data = code->data;
if (compare)
*compare = code->compare;
if (useCompare)
*useCompare = code->useCompare;
}
else if (hiCodes.Size() > (index -= loCodes.Size()))
{
const HiCode* NST_RESTRICT code = hiCodes.Begin() + index;
if (address)
*address = code->address;
if (data)
*data = code->data;
if (compare)
*compare = code->compare;
if (useCompare)
*useCompare = code->useCompare;
}
else
{
return RESULT_ERR_INVALID_PARAM;
}
return RESULT_OK;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
void Cheats::BeginFrame(bool frameLock)
{
frameLocked = frameLock;
if (!frameLock)
{
for (const LoCode* NST_RESTRICT it=loCodes.Begin(), *const end=loCodes.End(); it != end; ++it)
{
const uint address = it->address & (Cpu::RAM_SIZE-1);
if (!it->useCompare || cpu.GetRam()[address] == it->compare)
cpu.GetRam()[address] = it->data;
}
}
}
inline bool Cheats::HiCode::operator < (const Cheats::HiCode& c) const
{
return address < c.address;
}
inline bool Cheats::HiCode::operator < (Address a) const
{
return address < a;
}
inline bool operator < (Address a,const Cheats::HiCode& c)
{
return a < c.address;
}
NES_PEEK_A(Cheats,Wizard)
{
NST_ASSERT( address >= 0x2000 );
const HiCode* const NST_RESTRICT code = std::lower_bound( hiCodes.Begin(), hiCodes.End(), address );
if (!frameLocked)
{
if (code->useCompare)
{
const uint data = code->port->Peek( address );
if (code->compare != data)
return data;
}
return code->data;
}
else
{
return code->port->Peek( address );
}
}
NES_POKE_AD(Cheats,Wizard)
{
NST_ASSERT( address >= 0x2000 );
return std::lower_bound( hiCodes.Begin(), hiCodes.End(), address )->port->Poke( address, data );
}
}
}
nestopia-1.47/source/core/NstCheats.hpp 0000664 0000000 0000000 00000004400 12644314416 0020127 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CHEATS_H
#define NST_CHEATS_H
#ifndef NST_VECTOR_H
#include "NstVector.hpp"
#endif
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
class Cheats
{
public:
explicit Cheats(Cpu&);
~Cheats();
void Reset();
void BeginFrame(bool);
void ClearCodes();
Result GetCode (dword,ushort*,uchar*,uchar*,bool*) const;
Result SetCode (word,byte,byte,bool,bool);
Result DeleteCode (dword);
private:
NES_DECL_PEEK( Wizard );
NES_DECL_POKE( Wizard );
struct LoCode
{
word address;
byte data;
byte compare;
ibool useCompare;
};
struct HiCode
{
inline bool operator < (const HiCode&) const;
inline bool operator < (Address) const;
word address;
byte data;
byte compare;
ibool useCompare;
const Io::Port* port;
};
inline friend bool operator < (Address,const HiCode&);
typedef Vector LoCodes;
typedef Vector HiCodes;
void Map(HiCode&);
Cpu& cpu;
ibool frameLocked;
LoCodes loCodes;
HiCodes hiCodes;
public:
dword NumCodes() const
{
return loCodes.Size() + hiCodes.Size();
}
};
}
}
#endif
nestopia-1.47/source/core/NstChecksum.cpp 0000664 0000000 0000000 00000004074 12644314416 0020464 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include "NstAssert.hpp"
#include "NstChecksum.hpp"
#include "NstCrc32.hpp"
namespace Nes
{
namespace Core
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
Checksum::Checksum()
: crc32(0) {}
Checksum::Checksum(const byte* data,dword size)
: crc32(0)
{
Compute( data, size );
}
void Checksum::Clear()
{
crc32 = 0;
sha1.Clear();
}
void Checksum::Compute(const byte* data,dword size)
{
crc32 = Crc32::Compute( data, size, crc32 );
Sha1::Compute( sha1, data, size );
}
void Checksum::Recompute(const byte* data,dword size)
{
Clear();
Compute( data, size );
}
bool Checksum::operator == (const Checksum& checksum) const
{
NST_VERIFY( (crc32 == checksum.crc32) == (sha1 == checksum.sha1) );
return crc32 == checksum.crc32 && sha1 == checksum.sha1;
}
bool Checksum::operator ! () const
{
NST_VERIFY( !crc32 == !sha1 );
return !crc32 && !sha1;
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
}
}
nestopia-1.47/source/core/NstChecksum.hpp 0000664 0000000 0000000 00000003474 12644314416 0020474 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CHECKSUM_H
#define NST_CHECKSUM_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
#include "NstCore.hpp"
#include "NstSha1.hpp"
namespace Nes
{
namespace Core
{
class Checksum : public ImplicitBool
{
public:
Checksum();
Checksum(const byte*,dword);
void Clear();
void Compute(const byte*,dword);
void Recompute(const byte*,dword);
bool operator == (const Checksum&) const;
bool operator ! () const;
private:
Sha1::Key sha1;
dword crc32;
public:
bool operator != (const Checksum& checksum) const
{
return !(*this == checksum);
}
Sha1::Key::Digest GetSha1() const
{
return sha1.GetDigest();
}
dword GetCrc() const
{
return crc32;
}
};
}
}
#endif
nestopia-1.47/source/core/NstChips.cpp 0000664 0000000 0000000 00000005454 12644314416 0017773 0 ustar 00root root 0000000 0000000 ////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#include
#include