mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-24 13:01:42 +02:00
Compare commits
90 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b55783c322 | ||
|
3ec08cebbe | ||
|
8d7d452534 | ||
|
56cb9c01a5 | ||
|
e9d2d56df9 | ||
|
6d487925d0 | ||
|
7aad868adb | ||
|
dd06dd0fed | ||
|
3c26736d4b | ||
|
f53cb33eb9 | ||
|
426de198b7 | ||
|
9e06857e4d | ||
|
e28aa32324 | ||
|
a9571ff5b8 | ||
|
3d21e9afe0 | ||
|
1cb37fc974 | ||
|
f92fc276af | ||
|
18afd41a80 | ||
|
3507c522f4 | ||
|
7a4bfca106 | ||
|
0db886f91d | ||
|
904d11a3f7 | ||
|
214b921388 | ||
|
b8b5aef165 | ||
|
f8e71b50d0 | ||
|
9a13863adb | ||
|
5dbaec85a7 | ||
|
92d86aef16 | ||
|
6524a7181d | ||
|
fbc58c70ae | ||
|
c63e6f2953 | ||
|
b899ee9a9c | ||
|
28fc75737e | ||
|
1ff315838e | ||
|
2e4cd09800 | ||
|
4fb8ce2821 | ||
|
3dce3aa3c8 | ||
|
28060d3a69 | ||
|
9dcbd12159 | ||
|
5352c5ab27 | ||
|
b47488ab09 | ||
|
96c45420d1 | ||
|
fd9194e4c2 | ||
|
593d32b885 | ||
|
fb31df6eb8 | ||
|
a81802422f | ||
|
a1eaec493a | ||
|
2956930d1c | ||
|
c557d68ec4 | ||
|
6b8c003ff8 | ||
|
25bda4f159 | ||
|
d8a8f06c35 | ||
|
fab830f84b | ||
|
f669c424c4 | ||
|
9c25f128f9 | ||
|
c273297577 | ||
|
afa8ea61c5 | ||
|
ea3c2dafda | ||
|
b38a657192 | ||
|
a8f2bfc533 | ||
|
d060904b8d | ||
|
56293c585b | ||
|
15b3dc8b0b | ||
|
d621136d69 | ||
|
c0934b826c | ||
|
86f3a8e670 | ||
|
b308661fa3 | ||
|
a4483339e5 | ||
|
1c13f0ad42 | ||
|
d416bb7231 | ||
|
4ba37e6cbe | ||
|
6c7a9adaad | ||
|
bafdb09e1b | ||
|
53c0002274 | ||
|
15c467b482 | ||
|
bfcd4e376b | ||
|
d13f1dd9ea | ||
|
8976438118 | ||
|
11357169a5 | ||
|
9be4e59a05 | ||
|
281b22e1c0 | ||
|
c9c931ecab | ||
|
366e9cebff | ||
|
58d70c7c9a | ||
|
d0b90d0b5c | ||
|
e0512b9100 | ||
|
08e1f93f71 | ||
|
6caad914ad | ||
|
c39ef91307 | ||
|
f0cf1df4af |
@@ -5,22 +5,21 @@ image: debian:stable
|
||||
|
||||
linux-x86_64-binaries:
|
||||
script:
|
||||
- apt-get update && apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl1.2-dev libxv-dev libao-dev libopenal-dev libudev-dev
|
||||
- apt-get update && apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl1.2-dev libxv-dev libao-dev libopenal-dev libudev-dev mkdocs
|
||||
- make -C icarus compiler=g++
|
||||
- make -C higan compiler=g++
|
||||
- LC_ALL=C.UTF-8 mkdocs build
|
||||
- mkdir higan-nightly
|
||||
- cp -a icarus/out/icarus higan-nightly/icarus
|
||||
- cp -a icarus/Database higan-nightly/
|
||||
- cp -a higan/out/higan higan-nightly/higan
|
||||
- cp -a higan/systems/* higan-nightly/
|
||||
- cp -a shaders "higan-nightly/Video Shaders"
|
||||
- cp -a docs_build higan-nightly/docs
|
||||
- cp -a GPLv3.txt higan-nightly/
|
||||
artifacts:
|
||||
paths:
|
||||
- higan-nightly/*
|
||||
cache:
|
||||
paths:
|
||||
- icarus/obj/*.o
|
||||
- higan/obj/*.o
|
||||
|
||||
windows-x86_64-binaries:
|
||||
# This is a normal Windows cross-compile process, except that
|
||||
@@ -28,20 +27,33 @@ windows-x86_64-binaries:
|
||||
# though it's a POSIX function, and for some weird reason mingw has
|
||||
# clock_gettime() in the pthread library.
|
||||
script:
|
||||
- apt-get update && apt-get -y install build-essential mingw-w64
|
||||
- apt-get update && apt-get -y install build-essential mingw-w64 mkdocs
|
||||
- sed -i -e 's/-lole32/& -static -lpthread/' nall/GNUmakefile
|
||||
- make -C icarus platform=windows compiler="x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++" windres="x86_64-w64-mingw32-windres"
|
||||
- make -C higan platform=windows compiler="x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++" windres="x86_64-w64-mingw32-windres"
|
||||
- LC_ALL=C.UTF-8 mkdocs build
|
||||
- mkdir higan-nightly
|
||||
- cp -a icarus/out/icarus higan-nightly/icarus.exe
|
||||
- cp -a icarus/Database higan-nightly/
|
||||
- cp -a higan/out/higan higan-nightly/higan.exe
|
||||
- cp -a higan/systems/* higan-nightly/
|
||||
- cp -a shaders "higan-nightly/Video Shaders"
|
||||
- cp -a docs_build higan-nightly/docs
|
||||
- cp -a GPLv3.txt higan-nightly/
|
||||
artifacts:
|
||||
paths:
|
||||
- higan-nightly/*
|
||||
cache:
|
||||
|
||||
libretro-test:
|
||||
script:
|
||||
- apt-get update && apt-get -y install build-essential git
|
||||
# git refuses to even attempt a merge if you haven't told it who you are,
|
||||
# even if you use --no-commit. *sigh*
|
||||
- EMAIL=fake-email@example.com git merge origin/libretro
|
||||
- make -C higan compiler=g++ binary=library target=libretro
|
||||
- mkdir libretro-nightly
|
||||
- cp -a higan/out/higan_sfc_libretro.so libretro-nightly/
|
||||
- cp -a GPLv3.txt libretro-nightly/
|
||||
artifacts:
|
||||
paths:
|
||||
- icarus/obj/*.o
|
||||
- higan/obj/*.o
|
||||
- libretro-nightly/*
|
||||
|
@@ -3,7 +3,7 @@ Contributing to higan
|
||||
|
||||
If you would like to propose a change to higan,
|
||||
you should create an account on the [official forums][f],
|
||||
go to the "Projects" forum and the "higan" subforum,
|
||||
go to the "Projects" forum and the "higan" sub-forum,
|
||||
and post your idea in a new topic there.
|
||||
|
||||
[f]: https://board.byuu.org/
|
||||
|
674
GPLv3.txt
Normal file
674
GPLv3.txt
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
44
LICENSE.txt
Normal file
44
LICENSE.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
----------------------------------------------------------------------
|
||||
higan - Suite of videogame console emulators
|
||||
icarus - Game library importer for higan
|
||||
|
||||
Copyright © 2004-2017 byuu
|
||||
|
||||
https://byuu.org/
|
||||
|
||||
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, specifically version 3 of the License
|
||||
and no other 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, see <https://www.gnu.org/licenses/>.
|
||||
----------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------
|
||||
hiro - User interface toolkit
|
||||
libco - C cooperative threading library
|
||||
nall - C++ template library
|
||||
ruby - Hardware abstraction layer
|
||||
|
||||
Copyright © 2006-2017 byuu
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted, provided that the
|
||||
above copyright notice and this permission notice appear in all
|
||||
copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
----------------------------------------------------------------------
|
@@ -1,7 +1,7 @@
|
||||
The unofficial higan repository
|
||||
===============================
|
||||
|
||||
higan emulates a number of classic videogame consoles of the 1980s and 1990s,
|
||||
higan emulates a number of classic video-game consoles of the 1980s and 1990s,
|
||||
allowing you to play classic games on a modern general-purpose computer.
|
||||
|
||||
This repository includes
|
||||
|
294
README.txt
Normal file
294
README.txt
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
higan - "Now you're playing with fire!"
|
||||
=======================================
|
||||
|
||||
higan is a multi-system emulator that began development on October 14th, 2004.
|
||||
It currently plays games for the following systems:
|
||||
|
||||
* Nintendo Famicom (NES), Super Famicom (SNES)
|
||||
* Nintendo Game Boy, Game Boy Color + Game Boy Advance
|
||||
* Sega Master System, Game Gear + Mega Drive (Genesis)
|
||||
* NEC PC Engine (TurboGrafx) + SuperGrafx
|
||||
* Bandai WonderSwan + WonderSwan Color
|
||||
|
||||
|
||||
Supported Systems
|
||||
-----------------
|
||||
|
||||
* FreeBSD 10+
|
||||
* Windows 7, 8, 10
|
||||
* Linux 3.2+
|
||||
* OS X 10.7 Lion or above
|
||||
|
||||
You'll need a fast CPU, with clock speed being vastly more important.
|
||||
Dual-core is perfectly adequate, since higan doesn't make significant use
|
||||
of more than one core.
|
||||
|
||||
For Intel, you're looking at a 3.5 GHz Haswell architecture or better,
|
||||
whilst AMD users will want a similarly specced Ryzen build.
|
||||
|
||||
|
||||
Controller Setup
|
||||
----------------
|
||||
|
||||
First, you'll want to configure your controllers. Choose Settings -> Input and
|
||||
pick the system you'd like to configure. If you have two players, or a special
|
||||
game (eg. Mario Paint), you can pick the controller port and device here.
|
||||
|
||||
To assign inputs, double click the name and press the stick or button on your
|
||||
controller. You can have multiple assignments, for example both keyboard and
|
||||
joypad. The Erase button clears the assignments for one input; Reset clears
|
||||
them all in one go.
|
||||
|
||||
(Normally you only need to do this once. But because of how USB works,
|
||||
it's impossible to tell identical controllers apart. This means if you move
|
||||
one to another port, it counts as a new device, and you'll have to reassign
|
||||
the buttons or move it back.)
|
||||
|
||||
|
||||
Loading Games
|
||||
-------------
|
||||
|
||||
After this you can go to Library -> Load ROM File and select a game. higan
|
||||
adds it to your library, and it should start immediately. (Game Boy Advance
|
||||
titles need one more step; please see the FAQ below.)
|
||||
|
||||
To add games en masse, you can use Library -> Import ROM Files. This opens
|
||||
icarus, where you can choose a folder of ROMs, then select the ones you want
|
||||
to import.
|
||||
|
||||
In both cases, if you choose a system under the Library submenus, all games
|
||||
added will show up in a file browser under the Emulation folder in your user
|
||||
profile. The path can be changed under Settings -> Advanced if desired.
|
||||
|
||||
|
||||
Controller Ports
|
||||
----------------
|
||||
|
||||
If you're emulating a console, you need to plug the controllers in, since
|
||||
there's no connection by default.
|
||||
|
||||
Usually this means selecting eg. Super Famicom -> Controller Port 1 -> Gamepad,
|
||||
for example. However, some games require other peripherals like the SNES Mouse.
|
||||
|
||||
|
||||
Troubleshooting & FAQ
|
||||
---------------------
|
||||
|
||||
Q: What's the Library?
|
||||
|
||||
A: higan loads folders containing all the files needed to run the game.
|
||||
Odds are you have PC games and music albums organised the same way.
|
||||
This does mean that to play the games, you have to import them first.
|
||||
|
||||
If you're familiar with iTunes or Steam, you already know how this works!
|
||||
|
||||
|
||||
Q: Importing vs. loading? What's the difference?
|
||||
|
||||
A: The "Library -> Load ROM File" menu is a shortcut. It adds the game to your
|
||||
library, then opens it without the manual import process.
|
||||
|
||||
However, if you have lots of games to add at once, you'll want
|
||||
"Import ROM Files" instead.
|
||||
|
||||
|
||||
Q: Why's higan say I'm missing a file ("Game Boy Advance.sys/bios.rom")?
|
||||
|
||||
A: This is the ROM for the startup screen you see when you switch on the
|
||||
Game Boy Advance. Games require it to run, but like other ROMs, it's
|
||||
copyrighted and therefore not provided with higan.
|
||||
|
||||
Having acquired a copy, you'll have to drop it in the requested folder,
|
||||
then rename it to bios.rom.
|
||||
|
||||
|
||||
Q: Where are the games imported? Where did all my save files go?
|
||||
|
||||
A: Check the path under Settings -> Advanced. On Windows it'll probably be
|
||||
something like C:\Users\<name>\Emulation, organised by system. The saves
|
||||
are typically named save.ram.
|
||||
|
||||
|
||||
Q: Where can I find the settings?
|
||||
|
||||
A: There's a few possible locations for settings.bml.
|
||||
|
||||
1) In the same folder as the higan executable.
|
||||
|
||||
2) In the older location if you previously installed higan:
|
||||
|
||||
C:\Users\<name>\AppData\Roaming\higan (Windows)
|
||||
/home/<name>/.config/higan (BSD, Linux)
|
||||
|
||||
3) In the new location (created if the others aren't found):
|
||||
|
||||
C:\Users\<name>\AppData\Local\higan (Windows)
|
||||
/home/<name>/.local/share/higan (BSD, Linux)
|
||||
/Users/<name>/Library/Application Support/higan (Mac)
|
||||
|
||||
higan checks these in order, so you can make a portable install if you like.
|
||||
|
||||
(macOS normally hides the Library folder. To open it, switch to Finder,
|
||||
hold the Option key and select Go -> Library from the menu.)
|
||||
|
||||
|
||||
Q: I set up my gamepads, but they don't work!
|
||||
|
||||
A: Try configuring the ports found in the system menu (eg.
|
||||
Super Famicom -> Controller Port 1 -> Gamepad). Like a real console,
|
||||
fresh higan installs come without any controllers plugged in.
|
||||
|
||||
|
||||
Q: I upgraded higan, why do I get a black screen? What's "Ignore Manifests?"
|
||||
|
||||
A: higan looks at a file called "manifest.bml" to get the information needed
|
||||
to run each game. However, the format has changed over time, making older
|
||||
manifests incompatible with newer higan releases.
|
||||
|
||||
If you tick "Settings -> Advanced -> Ignore Manifests," you might find this
|
||||
resolves the problem. This can be useful for developers and testers.
|
||||
However, it breaks a few titles that require manifests to work!
|
||||
|
||||
Should you find yourself in this situation, consider removing manifest.bml.
|
||||
|
||||
(By default, no manifests are created; higan looks at the files in the
|
||||
game folder, and with the help of a database, tries to regenerate the
|
||||
correct one each time you load the game.)
|
||||
|
||||
|
||||
Q: I have "Ignore Manifests" ticked, but the game won't run?
|
||||
|
||||
A: A few games have especially quirky setups that require manifests for
|
||||
the time being, so you'll need to untick this option:
|
||||
|
||||
* Far East of Eden: Tengai Makyou Zero (English translation only)
|
||||
* Campus Challenge '92
|
||||
* PowerFest '94
|
||||
|
||||
|
||||
Q: Why's the audio lag, stutter, distort, or sound robotic?
|
||||
|
||||
A: If you have an Atom, certain Celeron models, or an older AMD processor
|
||||
(or even an especially old Intel such as a Core 2 Duo)... then these aren't
|
||||
fast enough, sorry. :(
|
||||
|
||||
Try going into the Settings -> Advanced menu, then pick a different audio
|
||||
driver and restart higan. WASAPI can be fussy on some devices.
|
||||
|
||||
Select Settings -> Audio and experiment with the latency. Larger values
|
||||
should be more reliable, with the downside of laggier game controls.
|
||||
|
||||
Occasionally software that hooks into the system or other apps, for example
|
||||
mouse settings panels, can cause lag and other problems.
|
||||
|
||||
Because higan is CPU-intensive and single-threaded, it can interact badly
|
||||
with video capture which is yet another burden on the system. If you're
|
||||
trying to stream or broadcast, and you have Windows 7, consider disabling
|
||||
DWM. Also, look up how to configure hardware encoding (eg. QuickSync).
|
||||
|
||||
|
||||
Q: Can I get smoother video?
|
||||
|
||||
A: Try Settings -> Video -> Exclusive mode, then switch to fullscreen. This
|
||||
currently requires the Direct3D video driver under Settings -> Advanced
|
||||
in order to work.
|
||||
|
||||
(Exclusive fullscreen is pretty experimental at the moment.
|
||||
There are cases where it fails badly, so save your work!)
|
||||
|
||||
Exclusive mode will normally yield what's known as "tearing." If this
|
||||
bothers you, there's an alternative... albeit one with serious gotchas,
|
||||
which is why it's hidden away.
|
||||
|
||||
Close higan, then open up settings.bml and look for the following:
|
||||
|
||||
Video
|
||||
Driver:Direct3D
|
||||
Synchronize:false
|
||||
...
|
||||
|
||||
Change false to true, save the file, then start higan and untick
|
||||
Settings -> Synchronize Audio.
|
||||
|
||||
Keep in mind that this setting can and will reduce sound quality, as GPUs
|
||||
and sound cards in modern PCs generally are not synchronised with each
|
||||
other. The second big consideration is that your refresh rate needs to
|
||||
match the game.
|
||||
|
||||
PAL and NTSC titles run at 50 Hz and 60 Hz, respectively. This applies to
|
||||
all console systems. Of the handhelds: Game Boy, Game Boy Color and
|
||||
Game Boy Advance run at 60 Hz, while WonderSwan runs at 75 Hz.
|
||||
|
||||
This means you'll need a monitor that supports these frequencies, set to
|
||||
the appropriate display mode. Not all of them do. If your refresh rate
|
||||
doesn't match, games will run at the wrong speed.
|
||||
|
||||
|
||||
Online Resources
|
||||
----------------
|
||||
|
||||
Official homepage + forum:
|
||||
|
||||
https://byuu.org/emulation/higan
|
||||
https://board.byuu.org/viewforum.php?f=4
|
||||
|
||||
Unoffical source code repository + documentation:
|
||||
|
||||
https://gitlab.com/higan/higan
|
||||
https://higan.readthedocs.io
|
||||
|
||||
Info on game folders and firmware:
|
||||
|
||||
https://byuu.org/emulation/higan/game-paks
|
||||
https://byuu.org/emulation/higan/firmware
|
||||
|
||||
Donations:
|
||||
|
||||
https://patreon.com/byuu
|
||||
|
||||
Commercial use:
|
||||
|
||||
https://byuu.org/emulation/higan/licensing
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
Original author:
|
||||
|
||||
byuu
|
||||
|
||||
We'd like to acknowledge many invaluable contributions made to higan
|
||||
by the following individuals:
|
||||
|
||||
Andreas Naive Hendricks266 Overload
|
||||
Ange Albertini hex_usr p4plus2
|
||||
anomie jchadwick quequotion
|
||||
AWJ Jonas Quinn RedDwarf
|
||||
Bisqwit kode54 Richard Bannister
|
||||
blargg krom Ryphecha
|
||||
Łukasz Krawczyk Lioncash segher
|
||||
Cydrak Lord Nightmare Sintendo
|
||||
Danish lowkey SuperMikeMan
|
||||
DMV27 MerryMage tetsuo55
|
||||
Dr. Decapitator Matthew Callis TmEE
|
||||
endrift mightymo TRAC
|
||||
Fatbag Nach wareya
|
||||
FitzRoy ncbncb zones
|
||||
gekkio neviksti
|
||||
GIGO OV2
|
||||
|
||||
It's been a long, wild ride... apologies to anyone we've missed!
|
||||
|
||||
For more information, please see:
|
||||
|
||||
https://board.byuu.org/viewtopic.php?f=4&t=1631&p=41575#p41575
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
higan is provided under the GNU General Public License, version 3.
|
||||
However, certain libraries may be used under the more permissive ISC license.
|
||||
Please see LICENSE.txt for details.
|
@@ -1,89 +1,99 @@
|
||||
What is a game folder?
|
||||
----------------------
|
||||
A game folder
|
||||
is higan's way of grouping all
|
||||
the information and resources required
|
||||
to properly emulate a particular game.
|
||||
For example,
|
||||
to represent a Super Famicom game named `dkc3`,
|
||||
higan would create a game folder named `dkc3.sfc`,
|
||||
and inside it store the game data as `program.rom`
|
||||
and the save data as `save.ram`:
|
||||
|
||||
TODO
|
||||
```python
|
||||
+- Super Famicom
|
||||
|
|
||||
+- dkc3.sfc
|
||||
|
|
||||
+- program.rom
|
||||
|
|
||||
+- save.ram
|
||||
```
|
||||
|
||||
In contrast,
|
||||
other emulators typically
|
||||
group resources related to a game
|
||||
by requiring that every file has the same base name
|
||||
but different file extensions.
|
||||
For example,
|
||||
if another emulator loaded the game `dkc3.sfc`
|
||||
it might store the save data in `dkc3.srm`:
|
||||
|
||||
```python
|
||||
+- Super Famicom
|
||||
|
|
||||
+- dkc3.sfc
|
||||
|
|
||||
+- dkc3.srm
|
||||
```
|
||||
|
||||
Why game folders?
|
||||
-----------------
|
||||
|
||||
A game is more than just
|
||||
the raw data originally encased in a game's ROM chip.
|
||||
If a game allows you to save your progress,
|
||||
that information needs to be stored somewhere.
|
||||
If you use an emulator's [save states](#save-states),
|
||||
those save states need to be stored somewhere.
|
||||
If you use Game Genie or Pro Action Replay codes,
|
||||
information about what codes exist,
|
||||
what codes are enabled,
|
||||
and what they do
|
||||
needs to be stored somewhere.
|
||||
A file extension doesn't offer
|
||||
much room for description,
|
||||
so the traditional name-based-grouping system
|
||||
only really works when games use a small number of files,
|
||||
Also,
|
||||
since file extensions traditionally describe
|
||||
the format of the file in question,
|
||||
it also means a game can't use
|
||||
two or more files in the same format.
|
||||
|
||||
On the technical side,
|
||||
a physical game cartridge contains a circuit board
|
||||
that makes the game data available to the console,
|
||||
and different games used circuit boards that work differently.
|
||||
That circuit-layout information needs to be stored somewhere.
|
||||
Some games included custom processors
|
||||
to do calculations the base console could not do quickly enough
|
||||
(like the SuperFX chip used in _StarFox_ for the Super Famicom)
|
||||
and information about extra chips needs to be stored somewhere.
|
||||
Some of those custom processors require extra data to work
|
||||
that's not part of the main game data
|
||||
(like the DSP chip used in Super Mario Kart for the Super Famicom)
|
||||
and that data needs to be stored somewhere too.
|
||||
Compared to other emulators,
|
||||
higan can use a larger number of files per game.
|
||||
For example,
|
||||
higan's low-level emulation of Super Famicom co-processors
|
||||
often requires [separate firmware files][firmware].
|
||||
higan's [MSU-1 feature][msu1]
|
||||
supports up to 99 audio tracks per game,
|
||||
and higan supports up to 133 save-states per game.
|
||||
Thus,
|
||||
higan suffers from the limitations of name-based-grouping
|
||||
more than most.
|
||||
|
||||
higan keeps all this game-related information together
|
||||
in a single place:
|
||||
a game folder in the higan library.
|
||||
higan's game folders allow a game
|
||||
to have unique, descriptive filenames
|
||||
for all its resources,
|
||||
and for each file to use the extension
|
||||
that's most appropriate.
|
||||
They also allow emulator-specific extras
|
||||
like save-states and the cheat database
|
||||
to be kept separate from the game's actual data,
|
||||
by putting it in a sub-folder.
|
||||
|
||||
[msu1]: ../guides/import.md#msu-1-games
|
||||
[firmware]: ../guides/import.md#games-with-co-processor-firmware
|
||||
|
||||
For a more detailed motivation for game folders,
|
||||
see [Game Paks on the higan website][gp]
|
||||
see [Game Paks on the higan website][gp].
|
||||
|
||||
[gp]: https://byuu.org/emulation/higan/game-paks
|
||||
|
||||
What is a manifest?
|
||||
-------------------
|
||||
|
||||
TODO
|
||||
|
||||
The most important file in a game folder is `manifest.bml`,
|
||||
which describes how all the other files should be wired together
|
||||
to create a runnable game cartridge.
|
||||
However,
|
||||
the manifest format has occasionally changed
|
||||
as new emulation details were uncovered
|
||||
that could not be represented in the old format.
|
||||
Therefore,
|
||||
icarus [defaults](#the-icarus-settings-dialog)
|
||||
to not writing out manifests when it imports games,
|
||||
and higan [defaults](#the-configuration-dialog)
|
||||
to ignoring manifests that are present.
|
||||
Instead,
|
||||
when higan loads a game,
|
||||
it will ask icarus to generate a temporary manifest in the latest format,
|
||||
based on the files present in the game folder
|
||||
and how they are likely to go together.
|
||||
You can view this temporary manifest
|
||||
in [the Manifest Viewer](#the-manifest-viewer).
|
||||
|
||||
What's in a game folder?
|
||||
------------------------
|
||||
|
||||
As mentioned [above](#why-game-folders),
|
||||
a game folder collects all the information relevant
|
||||
A game folder collects all the information relevant
|
||||
to emulating a particular game.
|
||||
Not all of the following files
|
||||
are relevant to every emulated console,
|
||||
or to every game on a given console,
|
||||
but they may be relevantunder particular circumstances.
|
||||
are relevant for every console,
|
||||
or even for every game on a console,
|
||||
but they may be present under particular circumstances.
|
||||
|
||||
All the files directly in the game folder
|
||||
are expected to be useful
|
||||
to all emulators that support them:
|
||||
|
||||
- `manifest.bml`:
|
||||
The [manifest](#what-is-a-manifest)
|
||||
for this game folder.
|
||||
The [manifest](manifests.md) for this game folder.
|
||||
- `program.rom`:
|
||||
For most consoles,
|
||||
this contains
|
||||
@@ -97,7 +107,7 @@ to all emulators that support them:
|
||||
from the cartridge's ROM chips.
|
||||
- `ines.rom`:
|
||||
While other consoles typically include enough hints
|
||||
in `program.rom` for icarus to generate a manifest,
|
||||
in `program.rom` for icarus to guess a working manifest,
|
||||
the Famicom does not.
|
||||
Famicom games not stored in game folders
|
||||
typically include an "iNES header" to store that information,
|
||||
@@ -106,36 +116,31 @@ to all emulators that support them:
|
||||
Games that include a save feature
|
||||
will create this file.
|
||||
Note that it is only written to disk
|
||||
when higan exits gracefully,
|
||||
when higan exits gracefully;
|
||||
if higan crashes or is forced to quit,
|
||||
in-game saves may be lost.
|
||||
Other emulators sometimes call this an "SRAM file",
|
||||
even though the same filename is used
|
||||
for cartridges that use EEPROM or Flash storage,
|
||||
with games that included EEPROM or Flash storage,
|
||||
not just battery-backed Static RAM.
|
||||
- `rtc.ram`:
|
||||
Games that include a calendar or real-time clock
|
||||
will create this file.
|
||||
- `*.data.rom`, `*.program.rom`:
|
||||
Files named like this are usually
|
||||
[co-processor firmware](#importing-and-playing-games-with-co-processor-firmware).
|
||||
Files named like this are usually [co-processor firmware][firmware].
|
||||
- `msu1.rom`:
|
||||
Holds streamable data for
|
||||
[the MSU-1](#importing-and-playing-MSU-1-games).
|
||||
Holds streamable data for [the MSU-1][msu1].
|
||||
- `track-*.pcm`:
|
||||
Holds streamable audio for
|
||||
[the MSU-1](#importing-and-playing-MSU-1-games).
|
||||
Holds streamable audio for [the MSU-1][msu1].
|
||||
|
||||
Files that are only useful to higan specifically
|
||||
are placed in a `higan` subdirectory:
|
||||
are placed in a `higan` sub-folder:
|
||||
|
||||
- `cheats.bml`:
|
||||
All information present in
|
||||
[the Cheat Editor](#the-cheat-editor)
|
||||
[the Cheat Editor](../interface/higan-tools.md#the-cheat-editor)
|
||||
is stored here.
|
||||
- `states/quick/slot-*.bst`:
|
||||
All the save states made to
|
||||
[Quick state slots](#quick-states).
|
||||
All [Quick States](save-states.md#quick-states) are stored here.
|
||||
- `states/managed/slot-*.bst`:
|
||||
All the save states made with
|
||||
[the State Manager](#the-state-manager).
|
||||
All [Manager States](save-states.md#manager-states) are stored here.
|
||||
|
@@ -1,56 +1,87 @@
|
||||
higan maintains a "game library"
|
||||
containing all the games you've played.
|
||||
The game library
|
||||
is the folder where all the
|
||||
[game folders](game-folders.md) go.
|
||||
When [icarus](../interface/icarus.md) imports a game,
|
||||
it creates or updates
|
||||
the corresponding game folder in the game library.
|
||||
When you use the console sub-menu items
|
||||
in [higan's Library menu](../interface/higan.md#the-library-menu),
|
||||
higan shows you the games for that console
|
||||
that are already in the library.
|
||||
|
||||
- In Windows,
|
||||
the default location of
|
||||
the game library is the `Emulation` folder
|
||||
inside your profile folder
|
||||
(To find your profile folder,
|
||||
press `Win+R` to open the Run dialog,
|
||||
then type `%USERPROFILE%` and press Enter).
|
||||
- In Linux,
|
||||
the default location of
|
||||
the game library is the `Emulation` directory
|
||||
inside your home directory.
|
||||
- On all platforms,
|
||||
the game library location can be configured.
|
||||
See [Moving the Game Library](#moving-the-game-library)
|
||||
below.
|
||||
|
||||
Inside the library directory there is a subdirectory for each system,
|
||||
and inside each system directory are the game folders
|
||||
Inside the game library folder
|
||||
there is a sub-folder for each system.
|
||||
Inside each system folder
|
||||
are the game folders
|
||||
for each imported game.
|
||||
|
||||
For more information about game folders,
|
||||
see [Why game folders?](#why-game-folders)
|
||||
and [What's in a game folder?](#whats-in-a-game-folder)
|
||||
Why a game library?
|
||||
-------------------
|
||||
|
||||
higan [requires game folders](game-folders.md#why-game-folders),
|
||||
but it also invented game folders,
|
||||
so existing games need
|
||||
to be converted to game folder format
|
||||
before higan can play them.
|
||||
The converted copy of a game needs to go *somewhere*.
|
||||
|
||||
Also,
|
||||
for people who have a huge collection of games,
|
||||
the game library only lists the games they actually play,
|
||||
rather than every possible game,
|
||||
making it easier to find the games they like.
|
||||
|
||||
|
||||
Where is the game library?
|
||||
--------------------------
|
||||
|
||||
In Windows,
|
||||
the default location of
|
||||
the game library is the `Emulation` folder
|
||||
inside your profile folder
|
||||
(To find your profile folder,
|
||||
press `Win+R` to open the Run dialog,
|
||||
then type `%USERPROFILE%` and press Enter).
|
||||
|
||||
In Linux,
|
||||
the default location of
|
||||
the game library is the `Emulation` directory
|
||||
inside your home directory.
|
||||
|
||||
On all platforms,
|
||||
the game library location can be configured.
|
||||
See [Moving the Game Library](#moving-the-game-library)
|
||||
below.
|
||||
|
||||
Moving the game library
|
||||
-----------------------
|
||||
|
||||
Moving the game library is a little complicated,
|
||||
because there's two parts to it:
|
||||
because there are two parts to it:
|
||||
telling icarus where to put imported games,
|
||||
and telling higan where to find them.
|
||||
|
||||
1. If necessary,
|
||||
create the folder you want higan to use
|
||||
1. Move your existing game library folder
|
||||
to the new location,
|
||||
or otherwise create the folder you want higan to use
|
||||
as its game library.
|
||||
1. Launch icarus,
|
||||
then click the "Settings ..." button in the lower-right,
|
||||
to open the Settings dialog.
|
||||
to open
|
||||
[the Settings dialog][icsettings].
|
||||
1. Click the "Change ..." button on the right.
|
||||
A [filesystem browser](#the-filesystem-browser) window will appear,
|
||||
A [filesystem browser][fsbrowser] window will appear,
|
||||
allowing you to choose
|
||||
where imported games will be stored.
|
||||
1. Launch higan,
|
||||
then from the Settings menu,
|
||||
choose "Configuration ..."
|
||||
to open [the Configuration dialog](#the-configuration-dialog).
|
||||
1. Click the Advanced tab
|
||||
then click the "Change ..." button.
|
||||
A [filesystem browser](#the-filesystem-browser) will appear,
|
||||
allowing you to choose the same directory again.
|
||||
|
||||
then from [the Settings menu][settingsmenu],
|
||||
choose "Advanced ..."
|
||||
to open [higan's Advanced settings][advsettings].
|
||||
1. Click the "Change ..." button on the right.
|
||||
A [filesystem browser][fsbrowser] will appear,
|
||||
allowing you to choose the same folder again.
|
||||
|
||||
[icsettings]: ../interface/icarus.md#the-icarus-settings-dialog
|
||||
[fsbrowser]: ../interface/common.md#the-filesystem-browser
|
||||
[settingsmenu]: ../interface/higan.md#the-settings-menu
|
||||
[advsettings]: ../interface/higan-settings.md#advanced
|
||||
|
142
docs/concepts/manifests.md
Normal file
142
docs/concepts/manifests.md
Normal file
@@ -0,0 +1,142 @@
|
||||
If a [game folder](game-folders.md) is
|
||||
the emulation equivalent of
|
||||
a physical game cartridge,
|
||||
a manifest is like
|
||||
the circuit board inside the cartridge:
|
||||
it connects all the other parts together
|
||||
and to the console itself.
|
||||
|
||||
If you load a game into higan,
|
||||
you can look at the game's manifest
|
||||
by opening [the Tools menu](../interface/higan.md#the-tools-menu)
|
||||
and choosing [Manifest Viewer](../interface/higan-tools.md#the-manifest-viewer).
|
||||
|
||||
Why manifests?
|
||||
--------------
|
||||
|
||||
For most consoles,
|
||||
a manifest isn't strictly necessary:
|
||||
the raw game data provides enough clues
|
||||
for emulators to guess the circuit board configuration,
|
||||
or at least
|
||||
to guess a *reasonable* configuration.
|
||||
However,
|
||||
relying on such heuristics often leads to problems:
|
||||
|
||||
- Inventing heuristics
|
||||
that correctly guess the configuration
|
||||
for a particular game is very difficult.
|
||||
- If you change the rules,
|
||||
you really need to re-test
|
||||
the console's entire game library
|
||||
to check you haven't broken anything.
|
||||
- Some games accidentally do the wrong thing.
|
||||
- The Mega Drive game *Warrior of Rome II*
|
||||
follows the rule for a European game running at 50fps,
|
||||
when it's really an American game designed for 60fps.
|
||||
- Some games deliberately do the wrong thing.
|
||||
- The Game Boy Advance game *Top Gun - Combat Zones*
|
||||
follows the rule for
|
||||
(several kinds of)
|
||||
save-game storage.
|
||||
If it detects any save-game storage,
|
||||
it assumes it's running in an emulator
|
||||
and disables all the main menu options.
|
||||
- Heuristics are difficult to reason about.
|
||||
- If a homebrew developer
|
||||
takes a game that almost does what they want
|
||||
and changes it slightly,
|
||||
it may cause the emulator
|
||||
to do something completely different
|
||||
because the modified game
|
||||
is now a closer match to some other game.
|
||||
- Heuristics can make sensible configurations impossible.
|
||||
- If a homebrew developer wants
|
||||
a particular hardware configuration
|
||||
that no official games happened to use,
|
||||
it may not be possible
|
||||
to trigger it heuristically.
|
||||
- It's not hardware accurate.
|
||||
- The original console did not use heuristics
|
||||
to guess a hardware configuration,
|
||||
it just used the actual configuration
|
||||
of the actual hardware.
|
||||
|
||||
Manifests provide a way to describe
|
||||
*exactly* what hardware configuration to use,
|
||||
no guessing required,
|
||||
avoiding all these problems entirely.
|
||||
|
||||
Where do manifests come from?
|
||||
-----------------------------
|
||||
|
||||
Ideally,
|
||||
everybody who extracts the data from a game cartridge would
|
||||
also record the board configuration in a manifest file.
|
||||
Unfortunately,
|
||||
manifests were invented long after cartridge extracting,
|
||||
so there are a lot of previously extracted games
|
||||
with no manifest attached.
|
||||
|
||||
If a game doesn't come with a manifest,
|
||||
it may be possible to look up the correct manifest.
|
||||
The
|
||||
[SNES Preservation Project](https://preservation.byuu.org/)
|
||||
intends to re-dump every Super Famicom game
|
||||
and record its board configuration at the same time.
|
||||
Given a game's data,
|
||||
you can take the SHA256 fingerprint
|
||||
and look it up in the Project's database
|
||||
to find the correct manifest to use.
|
||||
|
||||
Unfortunately,
|
||||
this doesn't help for any other console.
|
||||
Even for the Super Famicom,
|
||||
there will always be games
|
||||
too rare to acquire for re-dumping,
|
||||
and homebrew that was never on a physical cartridge to begin with.
|
||||
For these games,
|
||||
heuristics will always be needed as a fallback,
|
||||
but at least if the heuristics are wrong
|
||||
they can be overridden.
|
||||
|
||||
Ignoring manifests
|
||||
------------------
|
||||
|
||||
Occasionally,
|
||||
a newly-dumped game will turn out to have
|
||||
a configuration that can't be expressed
|
||||
in the existing manifest file format,
|
||||
and a new format must be designed.
|
||||
If manifests were always written inside game folders,
|
||||
games with old-format manifests
|
||||
would break when played in emulators that supported the new format.
|
||||
|
||||
Therefore,
|
||||
icarus [defaults](../interface/icarus.md#the-icarus-settings-dialog)
|
||||
to not writing out manifests when it imports games,
|
||||
and higan [defaults](../interface/higan-settings.md#advanced)
|
||||
to ignoring manifests that are present.
|
||||
Instead,
|
||||
when higan loads a game,
|
||||
it will ask icarus to generate a temporary manifest in the latest format,
|
||||
based on the files present in the game folder
|
||||
and how they are likely to go together.
|
||||
|
||||
If the manifest that icarus generates
|
||||
for some particular game
|
||||
is broken or buggy,
|
||||
you'll need to switch the manifest machinery back on
|
||||
so you can fix it:
|
||||
|
||||
- Turn on "Create manifests" in icarus' settings
|
||||
- Re-import the game in question
|
||||
to store the broken manifest
|
||||
as `manifest.bml` in the game folder.
|
||||
- Edit `manifest.bml` as you see fit
|
||||
- Turn off "Ignore manifests" in higan's settings
|
||||
- Load the game in higan to check that your changes fixed the problem
|
||||
|
||||
If the manifest format changes in the future,
|
||||
you'll have to repeat this process
|
||||
to create a fixed manifest in the new format.
|
@@ -105,12 +105,12 @@ higan has five Quick State slots,
|
||||
which can be used from
|
||||
[the Tools menu](../interface/higan.md#the-tools-menu),
|
||||
or with the appropriate
|
||||
[hotkeys](../interface/higan-config.md#hotkeys).
|
||||
[hotkeys](../interface/higan-settings.md#hotkeys).
|
||||
|
||||
Quick states are useful
|
||||
as extra checkpoints
|
||||
in games that don't have them,
|
||||
or where they aren't close enough together.
|
||||
in games whose checkpoints are too far apart,
|
||||
or in games that don't have checkpoints at all.
|
||||
Map the "Save Quick State" and "Load Quick State" hotkeys
|
||||
to your controller,
|
||||
and you can cheese your way through just about anything.
|
||||
|
62
docs/credits.md
Normal file
62
docs/credits.md
Normal file
@@ -0,0 +1,62 @@
|
||||
higan's original author:
|
||||
|
||||
- byuu
|
||||
|
||||
We'd like to acknowledge
|
||||
many invaluable contributions made to higan
|
||||
by the following individuals:
|
||||
|
||||
- Andreas Naive
|
||||
- Ange Albertini
|
||||
- anomie
|
||||
- AWJ
|
||||
- Bisqwit
|
||||
- blargg
|
||||
- Łukasz Krawczyk
|
||||
- Cydrak
|
||||
- Danish
|
||||
- DMV27
|
||||
- Dr. Decapitator
|
||||
- endrift
|
||||
- Fatbag
|
||||
- FitzRoy
|
||||
- gekkio
|
||||
- GIGO
|
||||
- Hendricks266
|
||||
- hex_usr
|
||||
- jchadwick
|
||||
- Jonas Quinn
|
||||
- kode54
|
||||
- krom
|
||||
- Lioncash
|
||||
- Lord Nightmare
|
||||
- lowkey
|
||||
- MerryMage
|
||||
- Matthew Callis
|
||||
- mightymo
|
||||
- Nach
|
||||
- ncbncb
|
||||
- neviksti
|
||||
- OV2
|
||||
- Overload
|
||||
- p4plus2
|
||||
- quequotion
|
||||
- RedDwarf
|
||||
- Richard Bannister
|
||||
- Ryphecha
|
||||
- segher
|
||||
- Sintendo
|
||||
- SuperMikeMan
|
||||
- tetsuo55
|
||||
- TmEE
|
||||
- TRAC
|
||||
- wareya
|
||||
- zones
|
||||
|
||||
It's been a long, wild ride...
|
||||
apologies to anyone we've missed!
|
||||
|
||||
For more information,
|
||||
see the [credits thread](
|
||||
https://board.byuu.org/viewtopic.php?f=4&t=1631&p=41575#p41575)
|
||||
on the official forums.
|
88
docs/faq.md
88
docs/faq.md
@@ -1,15 +1,14 @@
|
||||
I see "tearing" when a game scrolls. How can I enable vsync?
|
||||
------------------------------------------------------------
|
||||
|
||||
higan supports synchronizing video output
|
||||
to the display's vertical-synchronization (or "vsync") signal,
|
||||
higan supports synchronising video output
|
||||
to the display's vertical-synchronisation (or "vsync") signal,
|
||||
but the option is hidden
|
||||
because it often causes more problems than it solves
|
||||
(see the next question).
|
||||
To enable video synchronisation:
|
||||
|
||||
To enable video synchronization:
|
||||
|
||||
- Open the higan's configuration file, `settings.bml`
|
||||
- Open higan's configuration file, `settings.bml`
|
||||
- On Windows, look in `%LOCALAPPDATA%\higan`
|
||||
or beside `higan.exe`
|
||||
- On Linux, look in `~/.local/share/higan`
|
||||
@@ -23,19 +22,19 @@ To enable video synchronization:
|
||||
- Save your changes to `settings.bml`
|
||||
and restart higan
|
||||
|
||||
Why is video synchronization a problem for higan?
|
||||
Why is video synchronisation a problem for higan?
|
||||
-------------------------------------------------
|
||||
|
||||
**The short version:**
|
||||
Turning on video synchronization
|
||||
Turning on video synchronisation
|
||||
cleans up video tearing,
|
||||
turning on audio synchronization
|
||||
turning on audio synchronisation
|
||||
cleans up audio glitches,
|
||||
but turning on both
|
||||
makes audio glitches worse.
|
||||
|
||||
**The long version:**
|
||||
Enabling video synchronization
|
||||
Enabling video synchronisation
|
||||
locks the frame-rate of the emulated console
|
||||
to the frame-rate of your computer's display.
|
||||
If your display's refresh rate exactly matches
|
||||
@@ -50,20 +49,20 @@ the emulated console's refresh rate:
|
||||
- The Super Famicom usually runs a little faster than 60Hz
|
||||
- the PAL variants of most consoles run at 50Hz
|
||||
- the WonderSwan runs at 75Hz
|
||||
- While the Game Boy does run its LCD at 60Hz
|
||||
it can turn it off and on at any time,
|
||||
- While the Game Boy does run its LCD at 60Hz,
|
||||
games can turn the LCD off and on at any time,
|
||||
requiring emulation to pause
|
||||
until it can get back in sync
|
||||
with the computer display.
|
||||
|
||||
Because of these frame-rate differences,
|
||||
enabling video synchronization
|
||||
enabling video synchronisation
|
||||
can force games to run
|
||||
faster or slower than intended.
|
||||
|
||||
The consoles that higan emulates
|
||||
produce video frames and audio samples at a particular rate.
|
||||
If video synchronization causes
|
||||
If video synchronisation causes
|
||||
the emulated console to run, say, 5% faster than intended,
|
||||
that means audio samples are also being produced 5% faster.
|
||||
You might not notice the changed game speed,
|
||||
@@ -72,9 +71,9 @@ the game's audio glitching constantly
|
||||
as your sound card tries to keep up.
|
||||
|
||||
Enabling
|
||||
[audio synchronization](interface/higan.md#the-settings-menu)
|
||||
[audio synchronisation](interface/higan.md#the-settings-menu)
|
||||
normally fixes this kind of audio glitching,
|
||||
but with video synchronization it makes things worse:
|
||||
but with video synchronisation it makes things worse:
|
||||
audio is likely to glitch
|
||||
while higan waits for a video frame to be shown,
|
||||
and video is likely to stutter
|
||||
@@ -86,21 +85,24 @@ Games run too fast
|
||||
higan runs as fast as it can,
|
||||
but it will pause and wait
|
||||
for the audio and video drivers to catch up
|
||||
if [Synchronize Audio](interface/higan.md#the-settings-menu)
|
||||
and [video synchronization][vsync]
|
||||
if [audio synchronisation](interface/higan.md#the-settings-menu)
|
||||
and [video synchronisation][vsync]
|
||||
are enabled, respectively.
|
||||
If games are running way too fast, here's some things to check:
|
||||
If games are running way too fast, here are some things to check:
|
||||
|
||||
- Make sure "Synchronize Audio" is ticked in
|
||||
[the Settings menu](interface/higan.md#the-settings-menu)
|
||||
- Make sure the Audio driver is not set to "None"
|
||||
in [the Advanced settings](interface/higan-config.md#advanced)
|
||||
in [the Advanced settings](interface/higan-settings.md#advanced)
|
||||
(remember to restart higan if you change driver settings)
|
||||
- Make sure your computer has speakers or headphones connected
|
||||
(some computers disable all audio if no ouputs are available)
|
||||
(some computers disable all audio if no outputs are available)
|
||||
- If you want the game to be silent,
|
||||
tick "Mute Audio" in
|
||||
[the Settings menu](interface/higan.md#the-settings-menu)
|
||||
- If you can't connect speakers or headphones to your computer,
|
||||
or you did but it didn't help,
|
||||
try enabling the secret [video synchronisation][vsync] option.
|
||||
|
||||
[vsync]: #i-see-tearing-when-a-game-scrolls-how-can-i-enable-vsync
|
||||
|
||||
@@ -114,17 +116,17 @@ Full-speed emulation for the Super Famicom base unit
|
||||
requires an Intel Core 2 Duo (or AMD equivalent),
|
||||
full-speed for games with the SuperFX chip
|
||||
requires an Intel Ivy Bridge (or equivalent),
|
||||
full-speed for the wireframe animations in Mega Man X2
|
||||
full-speed for the wire-frame animations in *Mega Man X2*
|
||||
requires an even faster computer.
|
||||
Low-power CPUs like ARM chips,
|
||||
or Intel Atom and Celeron CPUS
|
||||
or Intel Atom and Celeron CPUs
|
||||
generally aren't fast enough to emulate the Super Famicom with higan,
|
||||
although other emulated consoles may work.
|
||||
|
||||
If your computer meets the general speed requirements
|
||||
but games run too slowly,
|
||||
try choosing a different
|
||||
[audio driver](interface/higan-config.md#advanced),
|
||||
[audio driver](interface/higan-settings.md#advanced),
|
||||
since that's usually what drives higan's timing.
|
||||
|
||||
On some computers,
|
||||
@@ -134,7 +136,7 @@ may be confused by higan's unusual pattern of CPU usage
|
||||
and the next few milliseconds of audio,
|
||||
then stops dead as it waits for output to complete).
|
||||
If holding down
|
||||
the [fast forward hotkey](interface/higan-config.md#hotkeys)
|
||||
the [fast forward hotkey](interface/higan-settings.md#hotkeys)
|
||||
runs too fast but the game normally runs too slow,
|
||||
try disabling "power saver" mode
|
||||
or enabling "performance" mode.
|
||||
@@ -165,11 +167,11 @@ Games can and do depend on timing details like
|
||||
it will interrupt the CPU at exactly the right time
|
||||
for the CPU to fiddle with the video chip".
|
||||
higan is therefore very cautious about timing:
|
||||
while it's emulating the audio chip (for example),
|
||||
at every point the emulated CPU *might* interrupt
|
||||
the emulated audio chip,
|
||||
higan switches to emulating the CPU up to the same point
|
||||
to find out whether the CPU *will* interrupt it.
|
||||
while it's emulating the CPU (for example),
|
||||
at every point the emulated audio chip *might* interrupt
|
||||
the emulated CPU,
|
||||
higan switches to emulating the audio chip up to the same point
|
||||
to find out whether it *will* interrupt the CPU.
|
||||
|
||||
In this way,
|
||||
higan is a little bit like
|
||||
@@ -177,8 +179,8 @@ an office-worker trying to do the jobs of three other people
|
||||
by running from desk to desk,
|
||||
sending the same emails
|
||||
that those three people would send to each other,
|
||||
leaving themselves a note at each desk to remind themselves
|
||||
where they were up to when they come back.
|
||||
leaving itself a note at each desk to remind it
|
||||
where it was up to when it comes back.
|
||||
Although this constant switching
|
||||
is slow and inefficient,
|
||||
higan does it
|
||||
@@ -221,8 +223,8 @@ Why can't higan use multiple CPU cores?
|
||||
|
||||
These days,
|
||||
most computers contain multiple CPU cores,
|
||||
allowing them to run different programs,
|
||||
or different parts of the same program
|
||||
allowing them to run different programs
|
||||
(or different parts of the same program)
|
||||
at the same time.
|
||||
Since higan requires high CPU performance,
|
||||
sometimes people suggest that it should split its work
|
||||
@@ -246,7 +248,7 @@ device B will have finished operation Y
|
||||
and be ready to do something new.
|
||||
Meanwhile, higan's emulated components
|
||||
take an unpredictable amount of time to do their work,
|
||||
so without deliberate synchronization
|
||||
so without deliberate synchronisation
|
||||
things would break almost immediately.
|
||||
|
||||
It's not practical to make higan's emulated devices
|
||||
@@ -254,26 +256,28 @@ do their work in exactly the same amount of time
|
||||
as their hardware counterparts.
|
||||
The problem is forty years of technology
|
||||
designed to make programs run as fast as possible:
|
||||
optimizing compilers and superscalar, out-of-order CPU architectures
|
||||
optimising compilers
|
||||
and super-scalar, out-of-order CPU architectures
|
||||
change programs to make them faster,
|
||||
speeding up some programs more than others
|
||||
in ways that are very difficult to understand and predict.
|
||||
Even if higan's emulated devices
|
||||
ran at the exact, correct speed
|
||||
on one particular computer,
|
||||
they'd still run differently on any other computer,
|
||||
or with a smarter compiler,
|
||||
or with a smarter CPU.
|
||||
they'd still run differently on
|
||||
a computer with a smarter CPU,
|
||||
or when compiled with a smarter compiler.
|
||||
|
||||
Since higan needs its emulated components
|
||||
to run at particular speeds,
|
||||
and they won't run at those speeds naturally,
|
||||
and it's not practical
|
||||
to make them run at those speeds naturally,
|
||||
it must force them manually.
|
||||
An emulated device runs for a little while,
|
||||
then all the others are run until they catch up.
|
||||
It's this careful management,
|
||||
regular stopping and starting,
|
||||
that makes higan slow,
|
||||
not the actual emulation of each device,
|
||||
and so it doesn't make sense
|
||||
for higan to be multi-threaded.
|
||||
not the actual emulation of each device.
|
||||
Having multiple CPU cores waiting on each other
|
||||
would not help them wait any faster.
|
||||
|
@@ -1,11 +1,10 @@
|
||||
Unfortunately,
|
||||
there's no standard for
|
||||
there's no cross-platform standard for
|
||||
displaying video,
|
||||
playing audio,
|
||||
and accepting input from game controllers
|
||||
that works on every operating system.
|
||||
and accepting input from game controllers.
|
||||
Or rather,
|
||||
there's many standards,
|
||||
there are many standards,
|
||||
and different ones work best
|
||||
on different computers.
|
||||
Therefore,
|
||||
@@ -15,12 +14,12 @@ so you can find the one that works best for you.
|
||||
To see what drivers you're currently using,
|
||||
or to choose different ones,
|
||||
go to
|
||||
[the Advanced tab](../interface/higan-config.md#Advanced)
|
||||
[the Advanced tab](../interface/higan-settings.md#advanced)
|
||||
of the Settings window.
|
||||
|
||||
Here are the most notable drivers
|
||||
for each platform
|
||||
for each category.
|
||||
in each category.
|
||||
If your copy of higan
|
||||
includes a driver not listed here,
|
||||
it's probably a reasonable choice,
|
||||
@@ -44,15 +43,15 @@ Video
|
||||
|
||||
On Windows:
|
||||
|
||||
- **OpenGL** is usually the best choice,
|
||||
since it supports [custom shaders](shaders.md),
|
||||
however it does require support for OpenGL 3.2
|
||||
which excludes some integrated graphics chipsets
|
||||
and old graphics cards.
|
||||
- **OpenGL** is the best choice,
|
||||
since it's fast
|
||||
and it supports [custom shaders](shaders.md),
|
||||
but requires support for OpenGL 3.2.
|
||||
This excludes some older and weaker hardware.
|
||||
- **Direct3D** is a good choice
|
||||
if OpenGL is unavailable.
|
||||
It also allows
|
||||
[Exclusive fullscreen](../interface/higan-config.md#video),
|
||||
[Exclusive fullscreen](../interface/higan-settings.md#video),
|
||||
bypassing Windows' desktop compositor.
|
||||
- **GDI** is the safest choice,
|
||||
but performs very poorly at large sizes.
|
||||
@@ -62,7 +61,7 @@ On Linux:
|
||||
- **OpenGL** is the best choice,
|
||||
since it's fast
|
||||
and it supports [custom shaders](shaders.md),
|
||||
but requires OpenGL 3.2.
|
||||
but requires support for OpenGL 3.2.
|
||||
You can check what version of OpenGL
|
||||
your system supports by running
|
||||
`glxinfo | grep 'core profile version'`
|
||||
@@ -82,9 +81,9 @@ On Windows:
|
||||
- **ASIO** offers the lowest possible latency,
|
||||
but is the least likely to work on any given computer.
|
||||
- **WASAPI** offers low latency,
|
||||
but is only slightly more likely to work.
|
||||
but is only slightly more likely to work than ASIO.
|
||||
It also offers
|
||||
[Exclusive Mode](../interface/higan-config.md#audio),
|
||||
[Exclusive Mode](../interface/higan-settings.md#audio),
|
||||
which can improve audio quality and lower latency,
|
||||
but may be better or worse than shared mode
|
||||
in practice.
|
||||
@@ -121,12 +120,11 @@ On Linux:
|
||||
PulseAudio's OSS emulation,
|
||||
or not work at all.
|
||||
|
||||
TODO: If the audio driver is set to None,
|
||||
or you have no audio device,
|
||||
Sync Audio does not work
|
||||
and games will run in fast-forward
|
||||
unless you enable Sync Video.
|
||||
https://board.byuu.org/viewtopic.php?p=44138#p44138
|
||||
**Note:**
|
||||
By default,
|
||||
higan uses the audio driver to regulate its emulation speed.
|
||||
If games run too fast on your computer,
|
||||
see [Games run too fast](../faq.md#games-run-too-fast) in the FAQ.
|
||||
|
||||
Input
|
||||
-----
|
||||
|
@@ -5,33 +5,62 @@ be stored correctly in
|
||||
For [regular games](#regular-games)
|
||||
this is simple,
|
||||
but some games require special treatment,
|
||||
especially games that make use of
|
||||
especially those that make use of
|
||||
unusual hardware.
|
||||
|
||||
Regular games
|
||||
-------------
|
||||
|
||||
icarus supports importing games
|
||||
higan's importing tool, icarus, can import games
|
||||
in the most commonly-used formats
|
||||
for each supported console,
|
||||
and also those same formats inside `.zip` files.
|
||||
and also those same formats inside `.zip` files
|
||||
(as long as the `.zip` file contains only one game).
|
||||
More advanced compression formats
|
||||
like RAR or 7-zip are not supported.
|
||||
|
||||
For most games
|
||||
that do not use special chips or co-processors,
|
||||
importing a game is straight-forward.
|
||||
From [the Library menu](#the-library-menu)
|
||||
To import a game,
|
||||
open [the Library menu](../interface/higan.md#the-library-menu),
|
||||
choose "Load ROM File ..."
|
||||
to open [a filesystem browser](#the-filesystem-browser),
|
||||
choose the game you want to play,
|
||||
and it will be imported into the library and loaded.
|
||||
to open [a filesystem browser](../interface/common.md#the-filesystem-browser),
|
||||
choose the ROM file of the game you want to play,
|
||||
and it will be imported into the library and start playing.
|
||||
|
||||
To play the game again
|
||||
select the console the game runs on from
|
||||
[the Library menu](#the-library-menu)
|
||||
to open another [filesystem browser](#the-filesystem-browser)
|
||||
that lists all the previously-imported games for that platform.
|
||||
**Note:**
|
||||
If you want to import many games,
|
||||
run icarus directly,
|
||||
or choose "Import ROM Files ..."
|
||||
from the Library menu
|
||||
(which just runs icarus anyway).
|
||||
See [the icarus documentation](../interface/icarus.md) for details.
|
||||
|
||||
To play a game for a particular console from your library,
|
||||
open the Library menu,
|
||||
pick the console manufacturer sub-menu
|
||||
(Nintendo for the Super Famicom,
|
||||
Bandai for the WonderSwan,
|
||||
etc.)
|
||||
then choose the appropriate console menu item.
|
||||
A filesystem browser will appear
|
||||
listing all the games in the library
|
||||
for that particular console.
|
||||
Select the game you want to play
|
||||
and click the Open button,
|
||||
or just double-click the game,
|
||||
and it will begin playing.
|
||||
|
||||
**Note:**
|
||||
Sometimes
|
||||
the NTSC and PAL variants of a particular console
|
||||
behave differently,
|
||||
or the Japanese and American variants.
|
||||
When choosing a game from the Game Library,
|
||||
a drop-down list in the bottom-right of the filesystem browser
|
||||
allows you to choose which regional variant
|
||||
of the console higan should emulate.
|
||||
For most consoles,
|
||||
higan can reliably guess which variant to use,
|
||||
and the list defaults to "Auto".
|
||||
|
||||
Games with co-processor firmware
|
||||
--------------------------------
|
||||
@@ -43,7 +72,7 @@ those extra chips were separate CPUs
|
||||
running their own separate firmware,
|
||||
and for those cases
|
||||
higan requires a copy of the co-processor firmware
|
||||
as well as the actual game.
|
||||
as well as the actual game data.
|
||||
Unfortunately,
|
||||
like games themselves,
|
||||
co-processor firmware cannot legally be distributed,
|
||||
@@ -52,14 +81,31 @@ copies of the relevant firmware data
|
||||
yourself.
|
||||
|
||||
To import a game that requires co-processor firmware,
|
||||
you must copy the required firmware files
|
||||
beside the game you want to import.
|
||||
you must first combine the game data and the firmware into a single file.
|
||||
For example,
|
||||
if you want to import Megaman X2,
|
||||
which is stored in the file `mmx2.sfc`,
|
||||
the file `cx4.data.rom`
|
||||
must be placed in the same folder
|
||||
for the import to succeed.
|
||||
let's say you want to import *Super Bases Loaded 2* for the Super Famicom,
|
||||
which is stored in the file `sbl2.sfc`
|
||||
and requires firmware for the DSP1 co-processor
|
||||
stored in `dsp1.program.rom` and `dsp1.data.rom`.
|
||||
On Windows,
|
||||
you can combine them from the command-line like this:
|
||||
|
||||
```dos
|
||||
copy /b sbl2.sfc + dsp1.program.rom + dsp1.data.rom
|
||||
```
|
||||
|
||||
On Linux,
|
||||
the equivalent command-line syntax is:
|
||||
|
||||
```bash
|
||||
cat dsp1.program.rom dsp1.data.rom >> sbl2.sfc
|
||||
```
|
||||
|
||||
(note the use of `>>` to append rather than `>` to overwrite)
|
||||
|
||||
**Note:**
|
||||
For co-processor chips with multiple firmware files,
|
||||
you must put the "program" file before the "data" file.
|
||||
|
||||
Wikipedia [lists which Super Famicom games use which co-processors][wpec],
|
||||
although not all co-processors require separate firmware.
|
||||
@@ -183,42 +229,41 @@ but the firmware inside is identical.
|
||||
|
||||
**Note 2:**
|
||||
The DSP1B is very similar to the DSP1A,
|
||||
but has some bugs fixed.
|
||||
but fixes some bugs.
|
||||
Note that icarus' heuristics cannot distinguish between
|
||||
a game that uses DSP1
|
||||
and one that uses DSP1B,
|
||||
a game that uses the DSP1
|
||||
and one that uses the DSP1B,
|
||||
so if it cannot find your game in its manifest database,
|
||||
it will assume it uses DSP1B.
|
||||
Many games work just as well with either DSP1 or DSP1B,
|
||||
but Pilotwings is a notable exception.
|
||||
Many games work just as well with either variant,
|
||||
but *Pilotwings* requires the DSP1 firmware,
|
||||
while *Ballz 3D* requires the DSP1B.
|
||||
|
||||
If you try to import a game
|
||||
using the "Import ROM Files ..." option
|
||||
in [the Library menu](#the-library-menu)
|
||||
in [the Library menu](../interface/higan.md#the-library-menu)
|
||||
(or using icarus directly)
|
||||
but do not have the required firmware files
|
||||
in the correct place,
|
||||
but it does not include the correct firmware data,
|
||||
a window will appear saying
|
||||
"Import completed, but with 1 errors. View log?"
|
||||
(or howevery many games were lacking the correct firmware).
|
||||
(or however many games were lacking the correct firmware).
|
||||
If you press "Yes",
|
||||
a new window will appear listing the games that couldn't be imported,
|
||||
and at least one firmware file that was missing or incorrect, like this:
|
||||
and what problem was detected:
|
||||
|
||||
> [smk.zip] firmware (dsp1b.program.rom) missing or invalid
|
||||
> [sbl2.sfc] ROM image is missing DSP1 firmware data
|
||||
|
||||
If you try to import a game
|
||||
using the "Load ROM File ..." option
|
||||
in [the Library menu](#the-library-menu)
|
||||
but do not have the required firmware files
|
||||
in the correct place,
|
||||
in [the Library menu](../interface/higan.md#the-library-menu)
|
||||
but it does not include the correct firmware data,
|
||||
nothing will happen,
|
||||
and higan will just sit there
|
||||
with "No cartridge loaded" in
|
||||
[the status bar](#the-status-bar).
|
||||
[the status bar](../interface/higan.md#the-status-bar).
|
||||
|
||||
Once a game with co-processor firmware is imported,
|
||||
you can play it just like any [regular game](#importing-and-playing-regular-games).
|
||||
you can play it just like any [regular game](#regular-games).
|
||||
|
||||
Satellaview games
|
||||
-----------------
|
||||
@@ -234,13 +279,13 @@ browse online services,
|
||||
and download games and data.
|
||||
This control cartridge was called
|
||||
*BS-X Sore wa Namae o Nusumareta Machi no Monogatari*,
|
||||
which translates as
|
||||
which in English is
|
||||
*BS-X The Story of The Town Whose Name Was Stolen*.
|
||||
|
||||
[wpbsx]: https://en.wikipedia.org/wiki/Satellaview
|
||||
|
||||
The control cartridge had a slot that accepted
|
||||
rewritable "memory paks",
|
||||
re-writable "memory paks",
|
||||
so that people could store the games and data they downloaded.
|
||||
A small number of games that did not use the Satellaview modem
|
||||
also had a memory pak slot,
|
||||
@@ -254,7 +299,7 @@ were sold in retail stores
|
||||
containing extra content for specific games.
|
||||
|
||||
Importing a game that has a slot for a memory pak
|
||||
is just like [importing a regular game](#importing-and-playing-regular-games).
|
||||
is just like [importing a regular game](#regular-games).
|
||||
|
||||
Importing a memory pak is like importing a regular game,
|
||||
but the name of the memory pak file *must* end in `.bs`
|
||||
@@ -263,17 +308,17 @@ that's OK,
|
||||
but the name *inside* the `.zip` file
|
||||
must end in `.bs`)
|
||||
in order for it to be successfully imported.
|
||||
Sometimes memory pak filenames end in `(BSROM).sfc`,
|
||||
Sometimes memory pak filenames end in `.sfc`,
|
||||
which will make higan try to import them as
|
||||
regular Super Famicom games,
|
||||
and fail miserably.
|
||||
regular Super Famicom games
|
||||
and fail.
|
||||
Rename the file and it should work beautifully.
|
||||
|
||||
Playing a game that has a slot for a memory pak
|
||||
is just like playing a regular game,
|
||||
but after you have selected which game you want to play
|
||||
higan will open another
|
||||
[filesystem browser](#the-filesystem-browser)
|
||||
[filesystem browser](../interface/common.md#the-filesystem-browser)
|
||||
to let you pick which previously-imported memory pak
|
||||
you want to insert into the game.
|
||||
If you press "Cancel" at this point,
|
||||
@@ -282,7 +327,7 @@ the game will load without any cartridge in its memory pak slot.
|
||||
If you load the control cartridge into higan,
|
||||
make sure the emulated Satellaview
|
||||
is connected to the emulated Super Famicom's expansion port
|
||||
by going to the "Super Famicom" menu,
|
||||
by opening the "Super Famicom" menu,
|
||||
selecting the "Expansion Port" sub-menu,
|
||||
and choosing "Satellaview".
|
||||
If the expansion port was previously
|
||||
@@ -318,16 +363,16 @@ but some games can make use of additional data
|
||||
from a game in slot B.
|
||||
|
||||
Importing the Sufami Turbo cartridge
|
||||
is just like [importing a regular game](#importing-and-playing-regular-games).
|
||||
is just like [importing a regular game](#regular-games).
|
||||
|
||||
Importing a mini-cartridge is like importing a regular game,
|
||||
but the name of the memory pak file *must* end in `.st`
|
||||
but the name of the mini-cartridge file *must* end in `.st`
|
||||
(if it's in a `.zip` file,
|
||||
that's OK,
|
||||
but the name *inside* the `.zip` file
|
||||
must end in `.st`)
|
||||
in order for it to be successfully imported.
|
||||
Sometimes memory pak filenames end in `(ST).sfc`,
|
||||
Sometimes mini-cartridge filenames end in `.sfc`,
|
||||
which will make higan try to import them as
|
||||
regular Super Famicom games,
|
||||
and fail miserably.
|
||||
@@ -336,7 +381,7 @@ Rename the file and it should work beautifully.
|
||||
To play a Sufami Turbo game,
|
||||
load the Sufami Turbo cartridge like any other game.
|
||||
higan will open another
|
||||
[filesystem browser](#the-filesystem-browser)
|
||||
[filesystem browser](../interface/common.md#the-filesystem-browser)
|
||||
to let you pick which previously-imported mini-cartridge
|
||||
you want to insert into slot A.
|
||||
If you press "Cancel" at this point,
|
||||
@@ -346,7 +391,7 @@ to turn off your Super Famicom,
|
||||
insert a game into slot A,
|
||||
and try again.
|
||||
If you chose a cartridge for slot A,
|
||||
higan will yet open another
|
||||
higan will open yet another
|
||||
filesystem browser
|
||||
to let you choose a mini-cartridge for slot B.
|
||||
If you press "Cancel" at this point,
|
||||
@@ -362,17 +407,24 @@ released for the Super Famicom
|
||||
(and all its regional variants around the world)
|
||||
that allowed Game Boy games to be played
|
||||
via the Super Famicom's controllers and video output.
|
||||
The Super Game Boy 2 was released in Japan,
|
||||
and had some minor extra features
|
||||
beyond the original Super Game Boy,
|
||||
but importing and playing games
|
||||
works the same way in higan.
|
||||
The Super Game Boy does not emulate the Game Boy hardware,
|
||||
it physically includes all the Game Boy components
|
||||
so compatibility with Game Boy games is high.
|
||||
However, the Super Game Boy drives the Game Boy hardware
|
||||
from the Super Famicom's timing signals, which means
|
||||
games play 2.4% faster than on a real Game Boy.
|
||||
|
||||
The Super Game Boy cartrige includes
|
||||
the complete hardware of an original
|
||||
(black-and-white)
|
||||
Game Boy,
|
||||
so it needs a boot ROM:
|
||||
The Super Game Boy 2 was a Japan-only release
|
||||
that fixed the timing problem of the original Super Game Boy,
|
||||
and included a different set of default borders.
|
||||
higan supports the Super Game Boy 2 base cartridge,
|
||||
so you can use the extra borders,
|
||||
but does not yet emulate the timing change
|
||||
so games still play slightly too fast.
|
||||
|
||||
Because the Super Game Boy cartridge includes
|
||||
the original Game Boy hardware,
|
||||
it needs a boot ROM:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
@@ -386,55 +438,53 @@ so it needs a boot ROM:
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">SGB</th>
|
||||
<td><code>sgb.boot.rom</code></td>
|
||||
<td><code>sgb1.boot.rom</code></td>
|
||||
<td>256</td>
|
||||
<td><code>0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">SGB2</th>
|
||||
<td><code>sgb.boot.rom</code></td>
|
||||
<td><code>sgb2.boot.rom</code></td>
|
||||
<td>256</td>
|
||||
<td><code>fd243c4fb27008986316ce3df29e9cfbcdc0cd52704970555a8bb76edbec3988</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Yes,
|
||||
the SGB and SGB2 have different firmware,
|
||||
but higan expects the same filename for both.
|
||||
|
||||
To import the SGB base cartridge,
|
||||
you must copy the required firmware file
|
||||
into the same directory.
|
||||
Then you may import it just like
|
||||
[a regular game](#importing-and-playing-regular-games).
|
||||
you must first combine the base cartridge data
|
||||
and the boot ROM into a single file,
|
||||
just like
|
||||
[games with co-processor firmware](#games-with-co-processor-firmware).
|
||||
Then you may import it like [a regular game](#regular-games).
|
||||
|
||||
To play a Game Boy game in Super Game Boy mode,
|
||||
load the Super Game Boy cartridge like any other game.
|
||||
higan will open another
|
||||
[filesystem browser](#the-filesystem-browser)
|
||||
[filesystem browser](../interface/common.md#the-filesystem-browser)
|
||||
to let you pick which previously-imported Game Boy game
|
||||
you want to insert into the Super Game Boy.
|
||||
If you press "Cancel" at this point,
|
||||
higan will crash, so don't do that.
|
||||
|
||||
Note that only games for the original, black-and-white Game Boy
|
||||
**Note:**
|
||||
Only games for the original, black-and-white Game Boy
|
||||
can be used with the Super Game Boy.
|
||||
Some games designed for the Game Boy Color
|
||||
were backward compatible with the original Game Boy
|
||||
and hence the Super Game Boy;
|
||||
see [Playing Game Boy Colour games in Game Boy mode][blackcarts]
|
||||
see [Playing Game Boy Color games in Game Boy mode][blackcarts]
|
||||
for details.
|
||||
|
||||
[blackcarts]: #playing-game-boy-color-games-in-game-boy-mode
|
||||
[blackcarts]: ../notes.md#playing-game-boy-color-games-in-game-boy-mode
|
||||
|
||||
MSU-1 games
|
||||
-----------
|
||||
|
||||
The MSU-1 is a fictional expansion chip
|
||||
invented by higan's author byuu
|
||||
for use with Super Famicom games,
|
||||
designed to allow streaming data and audio.
|
||||
invented by higan's author byuu,
|
||||
designed to allow the Super Famicom
|
||||
to stream data and audio.
|
||||
Although the MSU-1 is not specific
|
||||
to any particular storage medium,
|
||||
it gives the Super Famicom similar capabilities
|
||||
@@ -443,10 +493,18 @@ like the Mega Drive's Mega CD
|
||||
and the PC Engine's CD-ROM²,
|
||||
such as CD-quality music and full-motion video.
|
||||
|
||||
Although the MSU-1 was invented for higan,
|
||||
it is now supported by other Super Famicom emulators too.
|
||||
The [SD2SNES][sd2snes] programmable cartridge
|
||||
even allows you to play MSU-1 games on a real console.
|
||||
There are a number of homebrew games
|
||||
that make use of the MSU-1,
|
||||
and also mods for commercial Super Famicom games
|
||||
that add higher-quality music and sometimes video.
|
||||
|
||||
One thing to be aware of
|
||||
when importing an MSU-1 game
|
||||
is that early firmware versions
|
||||
of the [SD2SNES][sd2snes] programmable cartridge
|
||||
is that early firmware versions of the SD2SNES
|
||||
had a bug that caused MSU-1 music to play too quietly.
|
||||
Skipping over [the full details][msu1vol],
|
||||
the short version is this:
|
||||
@@ -456,20 +514,20 @@ the short version is this:
|
||||
- If an MSU-1 mod for a commercial game offers
|
||||
"emulator" and "hardware" versions of the patch file,
|
||||
it means the audio tracks are already boosted.
|
||||
- Some
|
||||
[third](https://www.zeldix.net/t1265-#18320)
|
||||
[parties](https://www.zeldix.net/t1339-#19818)
|
||||
have created replacement, non-boosted audio tracks
|
||||
for the most popular MSU-1 mods.
|
||||
If the mod you want to play has a replacement pack,
|
||||
use it with the "hardware" version of the patch.
|
||||
- Even without access to non-boosted audio tracks,
|
||||
it may be that the existing audio is only slightly boosted,
|
||||
so try the "hardware" version first, for best quality.
|
||||
- If the audio tracks are heavily boosted,
|
||||
the "hardware" patch may sound terrible,
|
||||
distorting and clipping,
|
||||
in which case try the "emulator" patch.
|
||||
- Some
|
||||
[third](https://www.zeldix.net/t1265-#18320)
|
||||
[parties](https://www.zeldix.net/t1339-#19818)
|
||||
have created replacement, non-boosted audio tracks
|
||||
for the most popular MSU-1 mods.
|
||||
If the mod you want to play has a replacement pack,
|
||||
use it with the "hardware" version of the patch.
|
||||
- Even without access to non-boosted audio tracks,
|
||||
it may be that the existing audio is only slightly boosted,
|
||||
so try the "hardware" version first, for best quality.
|
||||
- If the audio tracks are heavily boosted,
|
||||
the "hardware" patch may sound terrible,
|
||||
distorting and clipping,
|
||||
in which case try the "emulator" patch.
|
||||
|
||||
To import an MSU-1 game:
|
||||
|
||||
@@ -482,7 +540,7 @@ To import an MSU-1 game:
|
||||
instead of these instructions.
|
||||
2. Otherwise,
|
||||
import the Super Famicom ROM with icarus,
|
||||
[like a regular game](#importing-and-playing-regular-games).
|
||||
[like a regular game](#regular-games).
|
||||
- If this is a homebrew game with MSU-1 support,
|
||||
there will probably be an ordinary ROM
|
||||
whose name ends in `.sfc`,
|
||||
@@ -495,7 +553,8 @@ To import an MSU-1 game:
|
||||
then import the patched file.
|
||||
- If there's "hardware" and "emulator" versions of the patch,
|
||||
see "One thing to be aware of..." above.
|
||||
3. Find the game folder in [the game library](#the-game-library)
|
||||
3. Find the game folder in
|
||||
[the game library](../concepts/game-library.md)
|
||||
that icarus created when it imported the game.
|
||||
4. Copy the MSU-1 data file into the game folder.
|
||||
- This should be named `msu1.rom`
|
||||
@@ -525,7 +584,7 @@ To import an MSU-1 game:
|
||||
|
||||
Once the game folder is set up,
|
||||
playing an MSU-1 game is just like
|
||||
[a regular game](#importing-and-playing-regular-games).
|
||||
[a regular game](#regular-games).
|
||||
|
||||
[sd2snes]: https://sd2snes.de/
|
||||
[flips]: http://www.romhacking.net/utilities/1040/
|
||||
@@ -554,7 +613,118 @@ you will need to use a patcher to apply it yourself,
|
||||
creating a new, patched copy of the game.
|
||||
|
||||
Then you can import and play the patched game just like
|
||||
[a regular game](#importing-and-playing-regular-games).
|
||||
[a regular game](#regular-games).
|
||||
|
||||
[rhdn]: http://www.romhacking.net/
|
||||
|
||||
Game Boy Advance games
|
||||
----------------------
|
||||
|
||||
Before you can play Game Boy Advance games,
|
||||
you must provide a copy of the Game Boy Advance BIOS.
|
||||
Unlike game-specific firmware,
|
||||
the GBA BIOS was part of the console,
|
||||
not the cartridge,
|
||||
so it must be installed
|
||||
[into higan](../install/general.md).
|
||||
|
||||
Once the GBA BIOS is installed,
|
||||
GBA games can be imported and played just like
|
||||
[any other games](#regular-games).
|
||||
|
||||
Note that some GBA games
|
||||
have trouble with
|
||||
[in-game saves](../notes#in-game-saves-and-the-game-boy-advance).
|
||||
|
||||
PowerFest '94
|
||||
-------------
|
||||
|
||||
[PowerFest '94](https://en.wikipedia.org/wiki/Nintendo_PowerFest_%2794)
|
||||
was a video game competition
|
||||
organised by Nintendo,
|
||||
in which contestants had six minutes
|
||||
to complete a challenge based on three Super Famicom games.
|
||||
The PowerFest '94 cartridge
|
||||
was custom-built for the competition,
|
||||
and included the three base games
|
||||
as well as software to run each game,
|
||||
switch between them after a specific time,
|
||||
extract a score,
|
||||
and display the combined total at the end.
|
||||
|
||||
icarus cannot automatically import
|
||||
dumps of the PowerFest '94 ROMs,
|
||||
but if you have the files,
|
||||
you can import them manually.
|
||||
|
||||
You will need the following files:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Part</th>
|
||||
<th>Filename</th>
|
||||
<th>Size (bytes)</th>
|
||||
<th>SHA256</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Scoring</th>
|
||||
<td><code>program.rom</code></td>
|
||||
<td>262144</td>
|
||||
<td><code>2fc9dca305ce3fb2f1a476567de500d50c174fbfbabd32b1b91c3ea6a731b4a1</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Super Mario Bros. - The Lost Levels</th>
|
||||
<td><code>slot-1.rom</code></td>
|
||||
<td>524288</td>
|
||||
<td><code>7fd86113c5f95f794d65807bb75ab91c93c914670c27fc813ffa2ca20a48705e</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Super Mario Kart</th>
|
||||
<td><code>slot-2.rom</code></td>
|
||||
<td>524288</td>
|
||||
<td><code>19eb77affbf8dd068f5d79a3cf80a2084fd73237cd1ae4e47192b4422449e64a</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Ken Griffey Jr. Presents Major League Baseball</th>
|
||||
<td><code>slot-3.rom</code></td>
|
||||
<td>1048576</td>
|
||||
<td><code>d47bc9f9a6289c4f2e7f6bf74095f6ed36b1043a761e3e729ac9af2fc39ae062</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
You will also need
|
||||
the usual `dsp1.program.rom` and `dsp1.data.rom`
|
||||
[co-processor firmware](#games-with-co-processor-firmware) files.
|
||||
|
||||
**Note:** the versions of
|
||||
*Super Mario Kart*
|
||||
and *Ken Griffey Jr...*
|
||||
in *PowerFest '94*
|
||||
are not the same as the stand-alone versions of those games.
|
||||
|
||||
To "import" *PowerFest '94*,
|
||||
collect all the files mentioned above, then:
|
||||
|
||||
1. Inside [the game library](../concepts/game-library.md),
|
||||
create the `Super Famicom` folder
|
||||
(if it does not already exist).
|
||||
2. Inside the `Super Famicom` folder,
|
||||
create a `PowerFest '94.sfc` folder
|
||||
(the `.sfc` extension is important,
|
||||
but you can choose a different base name if you want).
|
||||
3. Copy the various ROM files into the `PowerFest '94.sfc` folder.
|
||||
|
||||
To play *PowerFest '94*,
|
||||
open the Library menu,
|
||||
pick the Nintendo sub-menu,
|
||||
then choose the Super Famicom sub-menu item
|
||||
to open a filesystem browser listing
|
||||
all the Super Famicom games in the library.
|
||||
Select *PowerFest '94* from the list
|
||||
and click the Open button,
|
||||
or just double-click the game,
|
||||
and it will begin playing.
|
||||
|
@@ -1,29 +1,40 @@
|
||||
Most of the consoles higan emulates
|
||||
were designed for the low resolution of NTSC televisions,
|
||||
and their video output is often chunky and blocky
|
||||
were designed for low resolution NTSC televisions,
|
||||
and their video output is chunky and blocky
|
||||
by today's standards.
|
||||
Shaders customise how a console's video output
|
||||
Video shaders customise how a console's video output
|
||||
is drawn to the computer screen,
|
||||
and can apply just about any effect you can imagine.
|
||||
and can clean up and smooth out the original video,
|
||||
reproduce the scanlines and blurring of the original display,
|
||||
or any other visual effect.
|
||||
|
||||
Most [drivers](drivers.md)
|
||||
only support these shaders
|
||||
(some only support one or the other):
|
||||
The available video shaders are listed in
|
||||
the "Video Shaders" sub-menu of
|
||||
[the Settings menu](../interface/higan.md#the-settings-menu).
|
||||
Which shaders are available depends on
|
||||
the [video driver](drivers.md#video) higan is configured to use.
|
||||
Most drivers only support these shaders:
|
||||
|
||||
- **None** draws each computer pixel
|
||||
in the same colour as the nearest console pixel.
|
||||
This is sometimes called "nearest neighbour scaling",
|
||||
and produces crisp, blocky output.
|
||||
- **Blur** draws each computer pixel
|
||||
as the weighted average colour
|
||||
of the four nearest console pixels.
|
||||
This is sometimes called "bilinear scaling",
|
||||
and hides some of the blockiness
|
||||
at the expense of blurring edges.
|
||||
- **None**
|
||||
draws each computer pixel according to
|
||||
the colour of the single nearest console pixel,
|
||||
sometimes called "nearest neighbour" scaling.
|
||||
This produces unnaturally crisp and blocky images.
|
||||
- If you use [aspect correction or non-integral scaling][ac],
|
||||
neighbouring console pixels may be drawn
|
||||
with a different number of computer pixels due to rounding errors,
|
||||
causing a distracting rippling effect.
|
||||
- **Blur**
|
||||
draws each computer pixel according to
|
||||
the weighted average colour
|
||||
of the four nearest console pixels,
|
||||
sometimes called "bilinear" scaling.
|
||||
This produces unnaturally blurry images.
|
||||
|
||||
However,
|
||||
the OpenGL driver supports custom shaders,
|
||||
in addition to the above.
|
||||
[ac]: ../interface/higan-settings.md#video
|
||||
|
||||
In addition to those,
|
||||
the OpenGL driver also supports custom shaders.
|
||||
|
||||
**Note:**
|
||||
For technical reasons,
|
||||
@@ -31,10 +42,13 @@ higan's emulation of certain consoles
|
||||
can produce surprising behaviour
|
||||
in certain shaders,
|
||||
particularly shaders that compare each console pixel
|
||||
with its neigbours.
|
||||
See [Console-specific Notes](../notes.md) for details.
|
||||
with its neighbours.
|
||||
See [Video Shaders and TV-based consoles][vstv] for details.
|
||||
|
||||
# Where to get shaders
|
||||
[vstv]: #video-shaders-and-tv-based-consoles
|
||||
|
||||
Where to get custom shaders
|
||||
---------------------------
|
||||
|
||||
- higan includes some simple example shaders.
|
||||
If your copy of higan did not come with shaders,
|
||||
@@ -44,7 +58,8 @@ See [Console-specific Notes](../notes.md) for details.
|
||||
contains many high-quality shaders for use with higan.
|
||||
- You can write your own.
|
||||
|
||||
# How to install shaders
|
||||
How to install custom shaders
|
||||
-----------------------------
|
||||
|
||||
Make sure the shader you want to install
|
||||
is in the correct format:
|
||||
@@ -53,59 +68,55 @@ it should contain a file named `manifest.bml`,
|
||||
and probably some `*.fs` or `*.vs` files.
|
||||
|
||||
Place the shader folder inside
|
||||
the `Video Shaders` directory
|
||||
the `Video Shaders` folder
|
||||
of your higan installation.
|
||||
If you don't have a `Video Shaders` directory,
|
||||
create it beside the `*.sys` directories
|
||||
If you don't have a `Video Shaders` folder,
|
||||
create it beside the `*.sys` folders
|
||||
like `Game Boy Advance.sys` and `Super Famicom.sys`.
|
||||
|
||||
- On Windows,
|
||||
this is probably the directory containing `higan.exe`
|
||||
this is probably the folder containing `higan.exe`
|
||||
- On Linux,
|
||||
this is probably `~/.local/share/higan`
|
||||
|
||||
Launch higan,
|
||||
open the Settings menu,
|
||||
and choose "Advanced ..."
|
||||
to open [the Advanced tab](../interface/higan-config.md#advanced)
|
||||
of the Settings dialog.
|
||||
to open [the Advanced tab](../interface/higan-settings.md#advanced)
|
||||
of the Settings window.
|
||||
Under "Driver Selection",
|
||||
make sure "Video" is set to "OpenGL".
|
||||
If you changed the video driver,
|
||||
If it wasn't already set that way,
|
||||
you'll need to restart higan
|
||||
for the change to take effect.
|
||||
|
||||
Open the Settings menu again,
|
||||
choose the "Video Shader" submenu,
|
||||
choose the "Video Shader" sub-menu,
|
||||
and now the shaders you installed
|
||||
should be listed at the bottom of the menu.
|
||||
|
||||
Load a game
|
||||
(so you can see the results)
|
||||
and switch between shaders
|
||||
to see what they do
|
||||
(so you can see the results),
|
||||
switch between shaders
|
||||
to see what they do,
|
||||
and pick your favourite!
|
||||
|
||||
# Notable examples
|
||||
Notable examples
|
||||
----------------
|
||||
|
||||
The quark-shaders repository
|
||||
The quark-shaders repository mentioned above
|
||||
contains lots of carefully-crafted shaders,
|
||||
but some are particularly noteworthy:
|
||||
|
||||
- **AANN** implements "anti-aliased nearest neighbour" scaling.
|
||||
If the console's video is not displayed
|
||||
at an exact multple of the console's native resolution,
|
||||
rounding errors cause normal nearest-neighbour scaling
|
||||
to draw some rows and columns wider than others,
|
||||
which many people find ugly and distracting.
|
||||
This is very common when
|
||||
higan's aspect-ratio correction mode
|
||||
is enabled.
|
||||
AANN uses very slight anti-aliasing
|
||||
to hide the rounding errors,
|
||||
leaving the overall image as crisp as nearest-neighbour.
|
||||
- **Gameboy** emulates the squarish aspect-ratio
|
||||
greenish-colours
|
||||
This uses anti-aliasing to hide
|
||||
the rounding errors often introduced by
|
||||
aspect ratio correction
|
||||
and non-integral scaling,
|
||||
producing an image nearly as crisp as the "None" shader,
|
||||
but without the distracting ripple effect.
|
||||
- **Gameboy** emulates the squarish aspect-ratio,
|
||||
greenish-colours,
|
||||
and limited palette
|
||||
of the original Game Boy.
|
||||
At larger scales,
|
||||
@@ -120,7 +131,85 @@ but some are particularly noteworthy:
|
||||
and shimmer
|
||||
that most game players would have seen
|
||||
on real televisions.
|
||||
This is important because
|
||||
some games depended on NTSC artifacts
|
||||
Some games depend on NTSC artefacts
|
||||
to display colours outside the console's official palette
|
||||
or to create effects like transparency.
|
||||
|
||||
Video Shaders and TV-based consoles
|
||||
-----------------------------------
|
||||
|
||||
Simple shaders
|
||||
(like "None"
|
||||
and the third-party "AANN" shader)
|
||||
just blindly scale up the images they're given,
|
||||
but sophisticated shaders
|
||||
(such as the third-party "xBR" shader)
|
||||
try to produce higher-quality output
|
||||
by recognising particular patterns,
|
||||
like taking three diagonal pixels
|
||||
and turning that into a smooth diagonal line.
|
||||
|
||||
These shaders assume that
|
||||
each pixel drawn by the game's artists
|
||||
becomes a single pixel in the video output they analyze.
|
||||
The hand-held consoles that higan emulates
|
||||
(and also the Famicom)
|
||||
can only output video at one specific resolution,
|
||||
so this "one pixel equals one pixel" rule holds true,
|
||||
and pattern-based shaders like "xBR" work just fine.
|
||||
Unfortunately,
|
||||
this is not true for most of the TV-based consoles
|
||||
that higan supports.
|
||||
|
||||
The Super Famicom's "normal" video mode
|
||||
draws 256 pixels across the width of the screen,
|
||||
but the "high resolution" mode draws 512.
|
||||
Since Super Famicom games can enable hi-res mode at any time
|
||||
(even halfway through a frame),
|
||||
higan always renders Super Famicom video output 512 pixels wide,
|
||||
just in case.
|
||||
This means that in "normal" mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes two pixels in the video output,
|
||||
breaking the assumption
|
||||
that pattern-based shaders are based on.
|
||||
|
||||
The Super Famicom has a similar issue in the vertical direction:
|
||||
normally,
|
||||
an NTSC-based Super Famicom draws about 240 rows of output every frame,
|
||||
sometimes referred to as "240p" video.
|
||||
When a game turns on "interlaced" mode,
|
||||
it draws the 240 odd-numbered lines of one frame,
|
||||
then the 240 even-numbered lines of the next,
|
||||
and so forth.
|
||||
This is sometimes referred to as "480i" video.
|
||||
Although interlaced mode cannot be enabled mid-frame
|
||||
like high-resolution mode,
|
||||
resolution switching is still complex,
|
||||
so higan always draws all 480 lines of video output.
|
||||
This means for a normal, non-interlaced game,
|
||||
each pixel drawn by the game's artists
|
||||
becomes four pixels in the video output
|
||||
(two horizontally and two vertically)
|
||||
making pattern-based shaders even less useful.
|
||||
It also breaks most scanline-emulation shaders,
|
||||
since they typically draw a scanline
|
||||
for each row of pixels in the video output.
|
||||
|
||||
The Mega Drive has similar problems
|
||||
to the Super Famicom.
|
||||
It has the same behaviour with interlacing,
|
||||
but its high-resolution mode switches
|
||||
from 256 pixels across to 320 pixels across.
|
||||
Therefore in normal mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes five pixels in the video output,
|
||||
while in high-resolution mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes four pixels in the video output
|
||||
(or 10 and 8 pixels in non-interlaced mode).
|
||||
|
||||
The PC Engine does not support an interlaced mode,
|
||||
but its horizontal resolution is much more flexible
|
||||
than the Super Famicom or Mega Drive,
|
||||
and so it has the same problems with shaders as those consoles.
|
||||
|
@@ -1,34 +1,38 @@
|
||||
higan, the multi-system emulator
|
||||
================================
|
||||
|
||||
higan emulates a number of classic videogame consoles of the 1980s and 1990s,
|
||||
higan emulates a number of classic video-game consoles of the 1980s and 1990s,
|
||||
allowing you to play classic games on a modern general-purpose computer.
|
||||
|
||||
To get started with higan right away,
|
||||
see the [Quick Start](qs.md) section of the documentation.
|
||||
|
||||
|
||||
About higan
|
||||
-----------
|
||||
|
||||
As of v102,
|
||||
As of v104,
|
||||
higan has top-tier support for the following consoles:
|
||||
|
||||
- Nintendo Super Famicom/Super Nintendo Entertainment System,
|
||||
including addon hardware:
|
||||
including add-on hardware:
|
||||
- Super Game Boy
|
||||
- Sufami Turbo
|
||||
- Nintendo Game Boy Advance
|
||||
|
||||
It also includes some level of support for these consoles:
|
||||
|
||||
- Satellaview addon for the Super Famicom
|
||||
- Satellaview add-on for the Super Famicom
|
||||
- Nintendo Famicom/Nintendo Entertainment System
|
||||
- Nintendo Game Boy
|
||||
- Nintendo Game Boy Color
|
||||
- Sega Master System
|
||||
- Sega Game Gear
|
||||
- Sega Megadrive/Genesis
|
||||
- Sega Mega Drive/Genesis
|
||||
- NEC PC Engine/TurboGrafx 16 (but not the CD-ROM² System/TurboGrafx-CD)
|
||||
- NEC SuperGrafx
|
||||
- Bandai Wonderswan
|
||||
- Bandai Wonderswan Color
|
||||
- Bandai WonderSwan
|
||||
- Bandai WonderSwan Color
|
||||
|
||||
**Note:** Some consoles were released under different names
|
||||
in different geographic regions.
|
||||
@@ -37,7 +41,7 @@ every time such a console is mentioned,
|
||||
higan uses the name from the console's region of origin.
|
||||
In practice,
|
||||
that means Japanese names:
|
||||
"Famicom" and "Super Famicom" instead of NES and SNES,
|
||||
"Famicom" and "Super Famicom" instead of "NES" and "SNES",
|
||||
"Mega Drive" instead of "Genesis",
|
||||
"PC Engine" instead of "TurboGrafx-16".
|
||||
|
||||
@@ -47,22 +51,19 @@ Microsoft Windows 7 and above.
|
||||
It also includes some level of support
|
||||
for GNU/Linux and macOS.
|
||||
|
||||
If you want to install higan and try it out,
|
||||
see the [Quick Start](#quick-start) section below.
|
||||
|
||||
higan is officially spelled with a lowercase "h", not a capital.
|
||||
|
||||
About this document
|
||||
-------------------
|
||||
|
||||
This is the unofficial higan README,
|
||||
This is the semi-official higan manual,
|
||||
a community-maintained introduction and reference.
|
||||
It may be out of date
|
||||
by the time you read this,
|
||||
and it may contain errors or omissions.
|
||||
If you find something that's wrong,
|
||||
or you have a suggestion,
|
||||
see "Unofficial higan resources" below.
|
||||
post a message on the official higan forum.
|
||||
|
||||
Official higan resources
|
||||
------------------------
|
||||
@@ -81,14 +82,14 @@ Unofficial higan resources
|
||||
collects shaders that higan can use
|
||||
to add special effects like TV scanlines to its video output,
|
||||
or smarter algorithms for scaling up to modern PC resolutions.
|
||||
See [Installing custom shaders][shaders] below for details.
|
||||
See [Using video shaders][shaders] below for details.
|
||||
- [Mercurial Magic](https://github.com/hex-usr/Mercurial-Magic/)
|
||||
is a tool for converting MSU-1 games and mods into a format
|
||||
higan can use.
|
||||
See [Importing MSU-1 games][msu1] below for details.
|
||||
See [Importing MSU-1 games][msu1] for details.
|
||||
|
||||
[shaders]: #installing-custom-shaders
|
||||
[msu1]: #importing-msu-1-games
|
||||
[shaders]: guides/shaders.md
|
||||
[msu1]: guides/import.md#msu-1-games
|
||||
|
||||
There are also other projects
|
||||
based on current or older versions of higan,
|
||||
@@ -102,8 +103,15 @@ that you might want to check out.
|
||||
- [BizHawk](http://tasvideos.org/BizHawk.html)
|
||||
is another multi-system emulator,
|
||||
specialising in the creation of
|
||||
tool-assisted speedruns.
|
||||
tool-assisted speed-runs.
|
||||
Its Super Famicom emulation is based on bsnes v087.
|
||||
- [bsnes-plus](https://github.com/devinacker/bsnes-plus)
|
||||
is a fork of bsnes v073
|
||||
that adds improved support for debugging Super Famicom software.
|
||||
- [bsnes-mercury](https://github.com/libretro/bsnes-mercury/)
|
||||
is a fork of bsnes v094
|
||||
adapted to work as a
|
||||
[libretro](https://www.libretro.com/) emulation core.
|
||||
- [nSide](https://github.com/hex-usr/nSide)
|
||||
is a fork of higan that greatly enhances
|
||||
its NES emulation support,
|
||||
@@ -111,7 +119,4 @@ that you might want to check out.
|
||||
It also restores the "balanced" Super Famicom emulation core
|
||||
that was removed from higan in v099,
|
||||
which is less CPU intensive
|
||||
than the current accuracy-focussed core.
|
||||
- [bsnes-plus](https://github.com/devinacker/bsnes-plus)
|
||||
is a fork of bsnes v073
|
||||
that adds improved support for debugging Super Famicom software.
|
||||
than the current accuracy-focused core.
|
||||
|
@@ -12,19 +12,20 @@ for [common functions games require][bios],
|
||||
often called a "BIOS"
|
||||
by analogy with the Basic Input/Output System
|
||||
used in IBM PC compatibles.
|
||||
Although the GBA BIOS is required
|
||||
in order to emulate GBA games,
|
||||
it cannot be distributed with higan
|
||||
for the same legal reasons that commercial games
|
||||
cannot be distributed with higan,
|
||||
so you'll need to obtain a copy of the BIOS for yourself.
|
||||
|
||||
For the same legal reasons that commercial games
|
||||
cannot be distributed with emulators,
|
||||
the GBA BIOS cannot be distributed with higan,
|
||||
but is required for GBA software to run.
|
||||
|
||||
If you have a real GBA and a flashcart,
|
||||
If you have a real GBA and a flash-cart,
|
||||
the Internet contains many tools
|
||||
that will extract the BIOS image so it can be copied
|
||||
to your desktop computer.
|
||||
The correct GBA BIOS file is exactly 16384 bytes long,
|
||||
and has the SHA-256 hash
|
||||
fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570.
|
||||
and has the SHA256 hash
|
||||
`fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570`.
|
||||
|
||||
Once you have the correct BIOS file:
|
||||
|
||||
@@ -34,7 +35,7 @@ Once you have the correct BIOS file:
|
||||
so you don't wind up with a file called
|
||||
`bios.rom.dat`
|
||||
or whatever the file's original extension was.
|
||||
2. Copy the file into higan's `Game Boy Advance.sys` directory,
|
||||
2. Copy the file into higan's `Game Boy Advance.sys` folder,
|
||||
alongside the `manifest.bml` file that is already there.
|
||||
- In Windows,
|
||||
find `Game Boy Advance.sys` in the same folder
|
||||
@@ -46,7 +47,7 @@ Once you have the correct BIOS file:
|
||||
**Note:**
|
||||
If you upgrade this version of higan to a newer version,
|
||||
make sure the `bios.rom` file
|
||||
winds up in the `Game Boy Advance.sys` directory
|
||||
winds up in the `Game Boy Advance.sys` folder
|
||||
of the new version.
|
||||
|
||||
[bios]: http://problemkaputt.de/gbatek.htm#biosfunctions
|
||||
|
@@ -3,7 +3,8 @@ Compiling from source on Linux
|
||||
|
||||
You will need a copy of the higan source-code.
|
||||
If you download an official release from the higan homepage,
|
||||
you will need [7-zip][7z] or a compatible tool to extract it.
|
||||
you will need [7-zip](http://www.7-zip.org)
|
||||
or a compatible tool to extract it.
|
||||
Alternatively,
|
||||
you may obtain higan source code from
|
||||
[the unofficial git repo](https://gitlab.com/higan/higan/)
|
||||
@@ -29,7 +30,8 @@ for the following libraries:
|
||||
- OpenAL
|
||||
- udev
|
||||
|
||||
On a Debian-derived Linux distribution,
|
||||
On a Debian-derived Linux distribution
|
||||
(including Ubuntu and Mint),
|
||||
you can install everything you need with a command like:
|
||||
|
||||
sudo apt-get install build-essential libgtk2.0-dev libpulse-dev \
|
||||
@@ -51,10 +53,10 @@ being installed system-wide.
|
||||
3. Type `cd ~/higan-src`
|
||||
(or wherever you put the higan source)
|
||||
and press Enter
|
||||
4. Type `make -C icarus compiler=g++` and press Enter
|
||||
to build the icarus import tool
|
||||
5. Type `make -C higan compiler=g++` and press Enter
|
||||
4. Type `make -C higan` and press Enter
|
||||
to build the main higan executable
|
||||
5. Type `make -C icarus` and press Enter
|
||||
to build the icarus import tool
|
||||
|
||||
Installing a compiled build on Linux
|
||||
------------------------------------
|
||||
@@ -66,10 +68,14 @@ as described in the previous section:
|
||||
2. Type `cd ~/higan-src`
|
||||
(or wherever you put the higan source)
|
||||
and press Enter
|
||||
3. Type `make -C icarus install` and press Enter
|
||||
to install icarus and its game database
|
||||
4. Type `make -C higan install` and press Enter
|
||||
3. Type `make -C higan install` and press Enter
|
||||
to install higan and its supporting files
|
||||
4. Type `make -C icarus install` and press Enter
|
||||
to install icarus and its game database
|
||||
5. If the higan source includes a `shaders` subdirectory,
|
||||
type `make -C shaders install`
|
||||
to install the example
|
||||
[video shaders](../guides/shaders.md).
|
||||
|
||||
This installs higan and its associated data files
|
||||
into the `~/.local` directory hierarchy.
|
||||
@@ -107,12 +113,6 @@ You will need to log out and log back in
|
||||
for changes to `~/.profile` or `~/.bash_profile`
|
||||
to take effect.
|
||||
|
||||
Before you can actually play games,
|
||||
you'll need to [import them](#the-game-library)
|
||||
and [configure higan](#configuring-higan).
|
||||
If you want to play Game Boy Advance games,
|
||||
you will need [a GBA BIOS](#installing-the-gba-bios).
|
||||
|
||||
Uninstalling a compiled build on Linux
|
||||
--------------------------------------
|
||||
|
||||
@@ -123,11 +123,17 @@ as installed by the above instructions:
|
||||
2. Type `cd ~/higan-src`
|
||||
(or wherever you put the higan source)
|
||||
and press Enter
|
||||
3. Type `make -C icarus uninstall` and press Enter
|
||||
4. Type `make -C higan uninstall` and press Enter
|
||||
3. Type `make -C higan uninstall` and press Enter
|
||||
4. Type `make -C icarus uninstall` and press Enter
|
||||
|
||||
To remove higan's configuration,
|
||||
delete the directory `~/.config/higan` as well.
|
||||
you should also delete the following directories
|
||||
if they exist:
|
||||
|
||||
- `~/.config/higan/`
|
||||
- `~/.config/hiro/`
|
||||
- `~/.local/share/higan/`
|
||||
- `~/.local/share/hiro/`
|
||||
|
||||
To remove the games imported into higan's library
|
||||
(including in-game saves and save-states),
|
||||
|
@@ -1,31 +1,23 @@
|
||||
Installing an official release on Windows
|
||||
-----------------------------------------
|
||||
|
||||
Official higan releases are distributed in [7-zip][7z] archives.
|
||||
You will need to install 7-zip,
|
||||
or another compatible archiving tool,
|
||||
Official higan releases are distributed in
|
||||
[7-zip](http://www.7-zip.org/)
|
||||
archives.
|
||||
You will need to install 7-zip
|
||||
(or another compatible archiving tool)
|
||||
to install higan.
|
||||
|
||||
[7z]: http://www.7-zip.org/
|
||||
|
||||
Once you have a suitable archiving tool,
|
||||
extract the contents of the higan archive into a new folder.
|
||||
|
||||
When you're done,
|
||||
the new folder should contain `higan.exe` and `icarus.exe`
|
||||
along with other assorted files and directories
|
||||
along with other assorted files and folders
|
||||
that describe the systems higan emulates.
|
||||
|
||||
You may put that folder wherever you like.
|
||||
You may put that new folder wherever you like.
|
||||
|
||||
To run higan, open the `higan.exe` file.
|
||||
|
||||
Before you can actually play games,
|
||||
you'll need to [import them](#the-game-library)
|
||||
and [configure higan](#configuring-higan).
|
||||
If you want to play Game Boy Advance games,
|
||||
you will need [a GBA BIOS](#installing-the-gba-bios).
|
||||
|
||||
Uninstalling an official release on Windows
|
||||
-------------------------------------------
|
||||
|
||||
@@ -37,23 +29,20 @@ To remove higan's configuration:
|
||||
1. Press Win+R to open the Run dialog
|
||||
2. Type `%LOCALAPPDATA%` and press Enter
|
||||
to open the folder where higan's configuration data lives
|
||||
3. Delete the subdirectories named `icarus` and `higan`
|
||||
3. Delete the sub-folders named `icarus` and `higan`
|
||||
if they exist.
|
||||
|
||||
You might also want to remove the games imported into higan's library
|
||||
(including in-game saves and save-states):
|
||||
|
||||
1. Press Win+R to open the Run dialog
|
||||
2. Type `%USERPROFILE%` and press Enter
|
||||
to open the folder where higan keeps its game library
|
||||
3. Delete the folder named `Emulation` if it exists
|
||||
You might also want to remove
|
||||
[higan's game library](../concepts/game-library.md#where-is-the-game-library)
|
||||
(including in-game saves and save-states).
|
||||
|
||||
Compiling from source on Windows
|
||||
--------------------------------
|
||||
|
||||
You will need a copy of the higan source-code.
|
||||
If you download an official release from the higan homepage,
|
||||
you will need [7-zip][7z] or a compatible tool to extract it.
|
||||
you will need [7-zip](http://www.7-zip.org/)
|
||||
or a compatible tool to extract it.
|
||||
Alternatively,
|
||||
you may obtain higan source code from
|
||||
[the unofficial git repo](https://gitlab.com/higan/higan/)
|
||||
@@ -83,25 +72,28 @@ See the higan forum
|
||||
[for](https://board.byuu.org/viewtopic.php?p=41977#p41977)
|
||||
[details](https://board.byuu.org/viewtopic.php?p=42253#p42253).
|
||||
|
||||
Once you've installed mingw-w64,
|
||||
Once you've installed the compiler,
|
||||
open a command-prompt window,
|
||||
type `g++ --version`
|
||||
then press Enter
|
||||
to check it's installed correctly.
|
||||
You should see a message like
|
||||
|
||||
g++ 1.2.3 20010101
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
```text
|
||||
g++ 1.2.3 20010101
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
```
|
||||
|
||||
...except it should mention the version of mingw that you installed
|
||||
...except it should mention the compiler version that you installed
|
||||
and the corresponding dates.
|
||||
If you see an error message like "command not found"
|
||||
or "bad command or filename",
|
||||
you may need to add mingw's "bin" folder
|
||||
If you see an error message like
|
||||
"'g++' is not recognized as an internal or external command,
|
||||
operable program or batch file",
|
||||
you may need to add the compiler's "bin" folder
|
||||
to your computer's `%PATH%`.
|
||||
See the mingw documentation for help with that.
|
||||
See the compiler's documentation for help with that.
|
||||
|
||||
Once mingw is installed and available from the command prompt:
|
||||
|
||||
@@ -111,9 +103,9 @@ Once mingw is installed and available from the command prompt:
|
||||
3. Type `cd C:\higan-src`
|
||||
(or wherever you put the higan source)
|
||||
and press Enter
|
||||
4. Type `mingw32-make -C icarus compiler=g++` and press Enter
|
||||
4. Type `mingw32-make -C icarus` and press Enter
|
||||
to build the icarus import tool
|
||||
5. Type `mingw32-make -C higan compiler=g++` and press Enter
|
||||
5. Type `mingw32-make -C higan` and press Enter
|
||||
to build the main higan executable
|
||||
|
||||
[tdm]: http://tdm-gcc.tdragon.net/download
|
||||
@@ -130,9 +122,15 @@ Installing a compiled build on Windows
|
||||
into the new folder
|
||||
4. Copy `C:\higan-src\higan\out\higan.exe`
|
||||
into the new folder
|
||||
5. Copy all the `*.sys` directories
|
||||
5. Copy all the `*.sys` folders
|
||||
in `C:\higan-src\higan\systems`
|
||||
into the new folder
|
||||
6. If the higan source includes a `shaders` folder,
|
||||
make another new folder named `Video Shaders`
|
||||
inside the new folder,
|
||||
and copy all the `*.shader` folders
|
||||
from `C:\higan-src\shaders\`
|
||||
into the `Video Shaders` folder.
|
||||
|
||||
The new folder should now contain
|
||||
`icarus.exe`,
|
||||
@@ -147,12 +145,6 @@ above.
|
||||
|
||||
[instwin]: #installing-an-official-release-on-windows
|
||||
|
||||
Before you can actually play games,
|
||||
you'll need to [import them](#the-game-library)
|
||||
and [configure higan](#configuring-higan).
|
||||
If you want to play Game Boy Advance games,
|
||||
you will need [a GBA BIOS](#installing-the-gba-bios).
|
||||
|
||||
Uninstalling a compiled build on Windows
|
||||
----------------------------------------
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
The Filesystem Browser
|
||||
----------------------
|
||||
|
||||
Sometimes higan will need
|
||||
to ask you to choose a file or folder.
|
||||
Sometimes higan will need you
|
||||
to choose a file or folder.
|
||||
For this, it uses a special Filesystem Browser dialog.
|
||||
Although many operating systems provide a native filesystem browser,
|
||||
they do not all allow the same customizations.
|
||||
they do not all allow the same customisations.
|
||||
Therefore,
|
||||
higan provides its own filesystem browser
|
||||
that works the same way on every platform.
|
||||
@@ -19,25 +19,25 @@ If you want to browse a specific path,
|
||||
you may edit the contents of this box
|
||||
and press Enter to switch to the new location.
|
||||
|
||||
The button with two blue arrows at the top-right is "Refresh".
|
||||
Pressing this button will check for
|
||||
added (or removed) items in the current folder,
|
||||
and add (or remove) them to (or from) the list.
|
||||
The  button is "Refresh".
|
||||
Pressing this button will check
|
||||
if anything has been added to or removed from the current folder
|
||||
and update the list to match.
|
||||
|
||||
The button with the house at the top-right is "Home".
|
||||
The  button is "Home".
|
||||
Pressing this button will switch to your home folder.
|
||||
|
||||
The button with the green up-arrow at the top right is "Parent".
|
||||
The  button is "Parent".
|
||||
Pressing this button will
|
||||
switch to the parent of the current folder.
|
||||
|
||||
Most of the filesystem browser lists the contents
|
||||
of the current directory.
|
||||
of the current folder.
|
||||
Double-clicking a folder,
|
||||
or selecting it and pressing Enter,
|
||||
will switch to showing the contents of that directory.
|
||||
will switch to showing the contents of that folder.
|
||||
If the list has keyboard focus,
|
||||
typing any text will jump to the first inem in the list
|
||||
typing any text will jump to the first item in the list
|
||||
whose name begins with the text you typed.
|
||||
|
||||
If a drop-down list appears in the bottom-left,
|
||||
@@ -50,12 +50,12 @@ by double-clicking it,
|
||||
by selecting it and pressing Enter,
|
||||
or by selecting it and clicking the "Select" button in the bottom-right.
|
||||
|
||||
If this filesystem browser is asking for a directory,
|
||||
If this filesystem browser is asking for a folder,
|
||||
you can choose one
|
||||
by selecting it and clicking the "Select" button in the bottom-right.
|
||||
Double-clicking
|
||||
or selecting and pressing Enter don't work,
|
||||
they just switch to viewing that directory.
|
||||
they just switch to viewing the contents of that folder.
|
||||
|
||||
The "Cancel" button in the bottom-right
|
||||
closes the filesystem browser without selecting anything.
|
||||
|
@@ -1,40 +1,95 @@
|
||||
|
||||
# Synopsis
|
||||
|
||||
> higan [*\-\-fullscreen*] [*PATH*]
|
||||
> higan [*\-\-fullscreen*] [*GAME* [*SUBGAME1* [*SUBGAME2*]]]
|
||||
|
||||
# Description
|
||||
|
||||
TODO: Put `NTSC-J|`, `NTSC-U|` or `PAL|`
|
||||
at the beginning of the path
|
||||
to force a region
|
||||
for consoles where it can't be detected.
|
||||
|
||||
When launched with `--fullscreen`,
|
||||
higan will automatically enter full-screen mode
|
||||
when it starts.
|
||||
This is not much use unless you also specify `PATH`,
|
||||
higan will automatically enter fullscreen mode
|
||||
when it starts,
|
||||
otherwise it starts in windowed mode.
|
||||
This is not much use unless you also specify `GAME`,
|
||||
because you won't be able to load a game
|
||||
until you exit full-screen mode
|
||||
until you exit fullscreen mode
|
||||
by pressing the "Toggle Fullscreen"
|
||||
[hotkey](higan-config.md#hotkeys).
|
||||
[hotkey](higan-settings.md#hotkeys).
|
||||
|
||||
When `PATH` is the path to an existing
|
||||
When `GAME` is not given,
|
||||
higan starts with no game loaded.
|
||||
|
||||
When `GAME` is the path to an existing
|
||||
[game folder](../concepts/game-folders.md)
|
||||
for any supported console,
|
||||
that game will be loaded when higan starts.
|
||||
that game will automatically be loaded
|
||||
after higan starts.
|
||||
|
||||
When `PATH` is the path to a ROM file
|
||||
When `GAME` is the path to a ROM file
|
||||
for any supported console,
|
||||
it will be imported into a game folder in
|
||||
[the Game Library](../concepts/game-library.md),
|
||||
and then loaded from there when higan starts.
|
||||
and loaded from there after higan starts.
|
||||
|
||||
When `GAME` is of the form `REGION|PATH`
|
||||
(that is,
|
||||
a region code,
|
||||
a vertical bar (`|`),
|
||||
and a path to a game folder or ROM file)
|
||||
higan will load the game at `PATH`
|
||||
into the `REGION` variant of the appropriate console,
|
||||
rather than detecting which variant the game expects.
|
||||
This is the command-line equivalent
|
||||
of choosing a region from
|
||||
the drop-down in the bottom-right of the filesystem browser window
|
||||
when you [load a game from the game library](../guides/import.md#regular-games).
|
||||
The list of region codes differs from console to console,
|
||||
so load a game from the library
|
||||
and check the list
|
||||
before loading it from the command-line.
|
||||
|
||||
When `GAME` refers to a game with
|
||||
a [Satellaview](../guides/import.md#satellaview-games) memory pak slot,
|
||||
`SUBGAME1` should be
|
||||
the path to a game folder or ROM file
|
||||
representing the memory pak to insert into the slot.
|
||||
If `SUBGAME1` is not supplied,
|
||||
higan will prompt for one.
|
||||
`SUBGAME2` is ignored.
|
||||
|
||||
When `GAME` refers to
|
||||
the [Super Game Boy](../guides/import.md#super-game-boy-games),
|
||||
`SUBGAME1` should be
|
||||
the path to a game folder or ROM file
|
||||
representing a Game Boy game to insert into the slot.
|
||||
If `SUBGAME1` is not supplied,
|
||||
higan will prompt for one.
|
||||
`SUBGAME2` is ignored.
|
||||
|
||||
When `GAME` refers to
|
||||
the [Sufami Turbo](../guides/import.md#sufami-turbo-games),
|
||||
then `SUBGAME1` should be
|
||||
the path to a game folder or ROM file
|
||||
representing the mini-cartridge to be inserted into
|
||||
slot A of the Sufami Turbo base cartridge,
|
||||
and `SUBGAME2` is the same thing for slot B.
|
||||
higan will prompt for
|
||||
any mini-cartridges not supplied on the command-line.
|
||||
|
||||
When `GAME` refers to any other game,
|
||||
both `SUBGAME1` and `SUBGAME2` are ignored.
|
||||
|
||||
# Examples
|
||||
|
||||
Play a previously-imported copy of Super Mario World
|
||||
in full-screen (assuming Linux defaults):
|
||||
in fullscreen (assuming Linux defaults):
|
||||
|
||||
```sh
|
||||
higan --fullscreen ~/Emulation/"Super Famicom"/"Super Mario World.sfc"
|
||||
higan --fullscreen "$HOME/Emulation/Super Famicom/Super Mario World.sfc"
|
||||
```
|
||||
|
||||
Play a previously-imported copy of Sonic the Hedgehog 3,
|
||||
forcing higan to emulate a Japanese Mega Drive:
|
||||
|
||||
```sh
|
||||
higan "NTSC-J|$HOME/Emulation/Mega Drive/Sonic the Hedgehog 3.md"
|
||||
```
|
||||
|
@@ -1,298 +0,0 @@
|
||||
TODO: Rename this file to "higan-settings.md"
|
||||
|
||||
The Settings window
|
||||
appears when you choose
|
||||
one of the items at the bottom of
|
||||
[the Settings menu](higan.md#the-settings-menu).
|
||||
It contains less-frequently-modified configuration options.
|
||||
Most of these can be safely ignored,
|
||||
or set once and never changed again.
|
||||
|
||||
This window has a tab for each main category of options:
|
||||
|
||||
Video
|
||||
=====
|
||||
|
||||
This tab contains options that affect
|
||||
how higan displays
|
||||
the emulated console's video output.
|
||||
|
||||
- **Saturation**: adjusts the vibrancy of colours displayed,
|
||||
where 0% makes things pure grey,
|
||||
100% is normal,
|
||||
and 200% is garishly brightly coloured.
|
||||
- **Gamma**: adjusts how bright mid-range colours are
|
||||
compared to the brightest colours,
|
||||
where 100% is normal,
|
||||
and 200% makes mid-range colours much darker.
|
||||
- **Luminance**: adjusts the overall brightness,
|
||||
where 100% is normal,
|
||||
and 0% is totally black.
|
||||
- **Overscan Mask**: hides parts of
|
||||
the video output that would have been hidden
|
||||
by the bezel around the edge of
|
||||
a standard-definition television screen.
|
||||
Some games (particularly on the Famicom)
|
||||
displayed random glitchy output in this area,
|
||||
which can be distracting.
|
||||
The units are "pixels in the emulated console's standard video-mode".
|
||||
For example, setting "Horizontal" to 8
|
||||
will clip 8/256ths from the left and right sides
|
||||
of the Super Famicom's video output,
|
||||
whether the Super Famicom is in
|
||||
lo-res (256px) or hi-res (512px)
|
||||
mode.
|
||||
- **Aspect Correction**:
|
||||
(in both Windowed Mode and Fullscreen Mode)
|
||||
stretches the image to match the aspect ratio
|
||||
produced by the original console hardware,
|
||||
but can cause a "ripple" effect,
|
||||
due to rounding errors.
|
||||
- **Resize Window to Viewport**:
|
||||
(under "Windowed mode")
|
||||
causes higan to resize its window
|
||||
to fit snugly around the emulated console's video
|
||||
whenever it changes size:
|
||||
because a game was loaded for a different console
|
||||
with a different display size or aspect ratio,
|
||||
because the "Overscan Mask" controls were adjusted,
|
||||
because the game switched to a different video mode,
|
||||
because the user pressed the "Rotate Display" hotkey,
|
||||
etc.
|
||||
When this option is disabled,
|
||||
the higan window stays at a fixed size,
|
||||
large enough to contain the video for any supported console,
|
||||
padded with black borders for all smaller video modes.
|
||||
- **Resize Viewport to Window**:
|
||||
(under "Fullscreen mode")
|
||||
causes higan to stretch the emulated console's video output
|
||||
to touch the edges of the screen.
|
||||
Since most screens are not an exact multiple
|
||||
of the size of all emulated consoles,
|
||||
this may cause a "ripple" effect,
|
||||
due to rounding errors.
|
||||
When this option is disabled,
|
||||
higan stretches the emulated console's video output
|
||||
to the largest exact multiple
|
||||
of the emulated console's video output
|
||||
that is smaller than or equal to the screen size.
|
||||
- TODO: Update this to match 103r11, or whatever the latest version is.
|
||||
|
||||
Audio
|
||||
=====
|
||||
|
||||
This tab contains options that affect
|
||||
how higan reproduces
|
||||
the emulated console's audio output.
|
||||
|
||||
- **Device**: allows you to choose
|
||||
which audio device higan sends
|
||||
the emulated game's audio to.
|
||||
- **Frequency**: controls the sample-rate that higan will use
|
||||
when generating audio.
|
||||
If your PC's audio hardware has a "native" sample-rate
|
||||
and you know what it is,
|
||||
pick that.
|
||||
Otherwise,
|
||||
44.1kHz or 48kHz should be fine.
|
||||
- **Latency**: controls how much audio output higan calculates in advance.
|
||||
Higher values reduce the chance of
|
||||
"popping" or "glitching" noises,
|
||||
but increase the delay between an action occurring on-screen
|
||||
and the corresponding sound-effect being played.
|
||||
- **Exclusive Mode**: appears
|
||||
if the current audio driver
|
||||
allows higan to take exclusive control of your PC's audio output,
|
||||
so no other applications can play sounds.
|
||||
This can improve audio quality,
|
||||
and lower the effective audio latency.
|
||||
- **Volume**: controls the overall loudness of
|
||||
the emulated console's audio,
|
||||
where 100% is normal volume,
|
||||
and 0% is complete silence.
|
||||
- **Balance**: controls the relative loudness of
|
||||
the left and right speakers,
|
||||
where 0% means only the left speaker produces sound,
|
||||
50% means both speakers produce sound equally,
|
||||
and 100% means only the right speaker produces sound.
|
||||
- **Reverb**: adds a slight reverberation effect
|
||||
to the emulated console's audio output,
|
||||
as though the console were in a tunnel or small room.
|
||||
|
||||
Input
|
||||
=====
|
||||
|
||||
This tab controls which PC inputs
|
||||
are used for which emulated controllers.
|
||||
The exact PC inputs that can be mapped
|
||||
depend on [the input driver](#drivers).
|
||||
|
||||
- **Pause Emulation**: automatically pauses emulation
|
||||
when the main higan window
|
||||
is not the current foreground window.
|
||||
- **Allow Input**: can be ticked
|
||||
when "Pause Emulation" is *not* ticked,
|
||||
and allows configured inputs to keep affecting higan
|
||||
even when higan is running in the background.
|
||||
This is particularly relevant if
|
||||
you configure your PC keyboard to control higan:
|
||||
if you tick this box,
|
||||
and switch to a different application
|
||||
leaving higan running in the background,
|
||||
typing in that other application may affect
|
||||
the emulated game running in higan
|
||||
even though you can't see it!
|
||||
- The console selector chooses which console's inputs
|
||||
to display in the mapping list below.
|
||||
- The port selector chooses which port of the selected console
|
||||
to display in the mapping list below.
|
||||
- The controller selector chooses which controller
|
||||
associated with the given console and port
|
||||
to display in the mapping list below.
|
||||
- The mapping list includes
|
||||
every button and axis on the selected controller,
|
||||
and the PC inputs that are mapped to it
|
||||
when it is connected to the selected port of the selected console.
|
||||
- **Erase**: removes the mapping
|
||||
for the selected button or axis.
|
||||
- **Reset**: removes all the mappings currently in the list.
|
||||
- TODO: Mention that controllers must be connected
|
||||
in the console menu
|
||||
before they can be used.
|
||||
|
||||
To map
|
||||
a keyboard or gamepad button on your PC to
|
||||
a controller button,
|
||||
double-click the controller button in the list,
|
||||
or select it and press Enter.
|
||||
The window will grey out,
|
||||
and a message will appear in the bottom left:
|
||||
"Press a key or button to map [the button]".
|
||||
Press the key or button you want to map,
|
||||
and it should appear in the list
|
||||
next to the controller button it is mapped to.
|
||||
|
||||
To map
|
||||
a mouse button on your PC to
|
||||
a controller button,
|
||||
select the controller button in the list,
|
||||
then click one of the "Mouse Left",
|
||||
"Mouse Middle",
|
||||
or "Mouse Right" buttons in the bottom-left of the window.
|
||||
|
||||
To map
|
||||
a joystick axis on your PC to
|
||||
a controller axis,
|
||||
double-click the axis in the list,
|
||||
or select it and press Enter.
|
||||
The window will grey out,
|
||||
and a message will appear in the bottom left:
|
||||
"Press a key or button to map [the axis]".
|
||||
Press the joystick in the direction you want to map,
|
||||
and it should appear in the list
|
||||
next to the controller button it is mapped to.
|
||||
|
||||
To map
|
||||
a mouse axis on your PC to
|
||||
a controller axis,
|
||||
select the axis in the list,
|
||||
then click one of the
|
||||
"Mouse X-axis",
|
||||
or "Mouse Y-axis"
|
||||
buttons in the bottom-left of the window.
|
||||
|
||||
If you start mapping a button or axis,
|
||||
but decide you don't want to,
|
||||
you can press Escape
|
||||
to exit the "Press a key or button to map..." mode
|
||||
without actually mapping anything.
|
||||
|
||||
The "Rumble" setting
|
||||
for the Game Boy Advance is treated like a button,
|
||||
and can be mapped to a PC gamepad.
|
||||
When the emulated Game Boy Advance
|
||||
tries to use the rumble feature
|
||||
of the Game Boy Player,
|
||||
higan will turn on the force-feedback
|
||||
of whatever gamepad the mapped button is part of.
|
||||
|
||||
|
||||
Hotkeys
|
||||
=======
|
||||
|
||||
This tab is like "Inputs" above,
|
||||
except it contains controls for higan itself,
|
||||
instead of for the emulated console.
|
||||
|
||||
- **Toggle Fullscreen**: puts higan into fullscreen mode,
|
||||
where the menu and status bar are hidden,
|
||||
and the emulated console's video output
|
||||
is enlarged to cover the entire screen.
|
||||
Toggling fullscreen also automatically captures the mouse.
|
||||
- **Toggle Mouse Capture**: hides the usual mouse-cursor,
|
||||
and captures the mouse so it cannot leave the higan window.
|
||||
This is useful when the mouse is being used to emulate
|
||||
a light-gun controller like the Super Scope.
|
||||
- **Save Quick State**: saves the current state of the emulated console
|
||||
to the currently-selected Quick State slot.
|
||||
- **Load Quick State**: restores the emulated console
|
||||
to the state saved in the currently-selected Quick State slot.
|
||||
- **Decrement Quick State**: selects the previous Quick State slot.
|
||||
The status bar will briefly display the new current slot number.
|
||||
- **Increment Quick State**: selects the next Quick State slot.
|
||||
The status bar will briefly display the new current slot number.
|
||||
- **Pause Emulation**: pauses the emulated console
|
||||
until the Pause Emulation hotkey is pressed a second time.
|
||||
- **Fast Forward**: disables audio and video synchronisation
|
||||
for as long as it's held down,
|
||||
so emulation proceeds as quickly as possible.
|
||||
If your PC struggles to hit "real time"
|
||||
(60fps for most emulated consoles),
|
||||
this likely won't have any effect.
|
||||
- **Power Cycle**: turns the emulated console off and back on,
|
||||
(a "hard reset"),
|
||||
just like the "Power Cycle" menu item
|
||||
in [the console menu](#the-console-menu).
|
||||
- **Rotate Display**: will toggle the display
|
||||
of the Game Boy Advance
|
||||
and WonderSwan (Color)
|
||||
between the usual landscape orientation
|
||||
and a portrait orientation (90° counter-clockwise).
|
||||
These consoles have games
|
||||
that expect the player to hold the console
|
||||
in a different way.
|
||||
|
||||
Advanced
|
||||
========
|
||||
|
||||
This tab contains all the settings
|
||||
that didn't fit into one of the other categories.
|
||||
|
||||
- **Video**: controls how higan will draw
|
||||
the emulated console's video output
|
||||
to the PC screen.
|
||||
"None" means no video will be drawn.
|
||||
See [Drivers](#drivers) for details.
|
||||
- **Audio**: controls how higan will present
|
||||
the emulated console's audio output.
|
||||
"None" means no audio will be played.
|
||||
See [Drivers](#drivers) for details.
|
||||
- **Input**: controls how higan checks for input
|
||||
from the PC's input devices.
|
||||
"None" means the emulated console cannot be controlled.
|
||||
See [Drivers](#drivers) for details.
|
||||
- **Location**: selects where the [Game Library](#the-game-library)
|
||||
looks for games to load.
|
||||
See [Moving the Game Library](#moving-the-game-library)
|
||||
for more information.
|
||||
- **Ignore Manifests**: makes higan ignore the manifest file
|
||||
in the a loaded game's [game folder](#why-game-folders)
|
||||
in favour of asking icarus
|
||||
to guess a manifest on the fly.
|
||||
This means that incompatible or incorrect manifests
|
||||
generated by old versions of icarus
|
||||
won't cause problems,
|
||||
but means you can't fix incorrect manifests
|
||||
generated by the current version of icarus.
|
||||
See also the "Create Manifests" option in
|
||||
[the icarus Settings dialog](#the-icarus-settings-dialog).
|
373
docs/interface/higan-settings.md
Normal file
373
docs/interface/higan-settings.md
Normal file
@@ -0,0 +1,373 @@
|
||||
The Settings window
|
||||
appears when you choose
|
||||
one of the items at the bottom of
|
||||
[the Settings menu](higan.md#the-settings-menu),
|
||||
and contains less-frequently-modified settings.
|
||||
Most of these can be safely ignored,
|
||||
or set once and never changed again.
|
||||
|
||||
This window has a tab for each main category of options:
|
||||
|
||||
Video
|
||||
=====
|
||||
|
||||
This tab contains options that affect
|
||||
how higan displays
|
||||
the emulated console's video output.
|
||||
|
||||
**Color Adjustment**
|
||||
settings adjust the colour and brightness
|
||||
of the emulated console's video output:
|
||||
|
||||
- **Saturation** adjusts the vibrancy of colours displayed,
|
||||
where 0% makes things pure grey,
|
||||
100% is normal,
|
||||
and 200% is garishly brightly coloured.
|
||||
- **Gamma** adjusts how bright mid-range colours are
|
||||
compared to the brightest colours,
|
||||
where 100% is normal,
|
||||
and 200% makes mid-range colours much darker.
|
||||
This is in addition to
|
||||
any adjustment applied by
|
||||
the "Colors" option
|
||||
in the "Video Emulation" sub-menu
|
||||
of the [Settings menu](higan.md#the-settings-menu).
|
||||
- **Luminance** adjusts the overall brightness,
|
||||
where 100% is normal,
|
||||
and 0% is totally black.
|
||||
|
||||
**Overscan Mask**
|
||||
removes parts of
|
||||
the video output that would have been hidden
|
||||
by the bezel around the edge of
|
||||
a standard-definition television screen.
|
||||
Some games (particularly on the Famicom)
|
||||
displayed random glitchy output in this area,
|
||||
which can be distracting.
|
||||
|
||||
- **Horizontal**
|
||||
removes pixels from the left and right of the video output.
|
||||
- **Vertical**
|
||||
removes pixels from the top and bottom of the video output.
|
||||
|
||||
The units are "pixels in the emulated console's standard video-mode".
|
||||
For example, setting "Horizontal" to 8
|
||||
will clip 8/256ths from the left and right sides
|
||||
of the Super Famicom's video output,
|
||||
whether the Super Famicom is in
|
||||
lo-res (256px) or hi-res (512px)
|
||||
mode.
|
||||
|
||||
**Windowed Mode**
|
||||
settings apply when higan is running
|
||||
in a normal window.
|
||||
|
||||
- **Aspect Correction**
|
||||
stretches the image to match the aspect ratio
|
||||
produced by the original console hardware,
|
||||
but can cause a "ripple" effect
|
||||
during horizontal scrolling
|
||||
due to rounding errors.
|
||||
[Video shaders](../guides/shaders.md)
|
||||
can reduce this effect.
|
||||
- **Integral Scaling**
|
||||
makes higan draw the emulated video output
|
||||
at a whole-number multiple of the original size,
|
||||
rather than completely filling the available space.
|
||||
This means that every game pixel
|
||||
uses the same number of computer pixels,
|
||||
and avoids graphics looking chunky and uneven.
|
||||
Note that Aspect Correction
|
||||
is applied after integral scaling,
|
||||
so some unevenness may be visible
|
||||
even with this option enabled.
|
||||
- **Adaptive Sizing**
|
||||
automatically resizes the higan window
|
||||
to fit snugly around the emulated video output
|
||||
whenever it changes size
|
||||
(because the user loaded a game for a different console,
|
||||
chose a different option from
|
||||
the [Video Scale sub-menu](higan.md#the-settings-menu),
|
||||
toggled Aspect Correction, etc.)
|
||||
When disabled,
|
||||
higan generally respects manual resizing.
|
||||
|
||||
**Fullscreen Mode**
|
||||
settings apply
|
||||
when higan is running fullscreen,
|
||||
because it was started with the `--fullscreen`
|
||||
[command-line option](higan-cli.md)
|
||||
or because the user pressed
|
||||
the Toggle Fullscreen [hotkey](higan-settings.md#hotkeys).
|
||||
|
||||
- **Aspect Correction**
|
||||
behaves the same way as in Windowed mode above.
|
||||
- **Integral Scaling**
|
||||
behaves the same way as in Windowed mode above.
|
||||
- **Exclusive Mode**
|
||||
requests exclusive access
|
||||
to the computer's video output
|
||||
when higan enters fullscreen mode.
|
||||
This prevents other applications
|
||||
or the operating system itself
|
||||
from drawing anything,
|
||||
and may also temporarily disable any kind of compositing,
|
||||
reducing video latency.
|
||||
As of v104,
|
||||
only the Direct3D video driver is capable of exclusive mode;
|
||||
with other drivers this option does nothing.
|
||||
|
||||
Audio
|
||||
=====
|
||||
|
||||
This tab contains options that affect
|
||||
how higan reproduces
|
||||
the emulated console's audio output.
|
||||
|
||||
**Driver**
|
||||
settings affect
|
||||
the current [Audio driver](../guides/drivers.md).
|
||||
|
||||
- **Device** allows you to choose
|
||||
which audio device higan sends
|
||||
the emulated game's audio to,
|
||||
if you have more than one.
|
||||
- **Frequency** controls the sample-rate that higan will use
|
||||
when generating audio.
|
||||
If your PC's audio hardware has a "native" sample-rate
|
||||
and you know what it is,
|
||||
pick that.
|
||||
Otherwise,
|
||||
44.1kHz or 48kHz should be fine.
|
||||
- **Latency** controls how much audio output higan calculates in advance.
|
||||
Higher values reduce the chance of
|
||||
"popping" or "glitching" noises,
|
||||
but increase the delay between an action occurring on-screen
|
||||
and the corresponding sound-effect being played.
|
||||
- **Exclusive Mode** appears
|
||||
if the current audio driver
|
||||
allows higan to take exclusive control of your PC's audio output,
|
||||
so no other applications can play sounds.
|
||||
This can improve audio quality,
|
||||
and lower the effective audio latency.
|
||||
|
||||
**Effects**
|
||||
are applied to the emulated audio output
|
||||
before it is sent to your computer's speakers.
|
||||
|
||||
- **Volume** controls the overall loudness of
|
||||
the emulated console's audio,
|
||||
where 100% is normal volume,
|
||||
and 0% is complete silence.
|
||||
- **Balance** controls the relative loudness of
|
||||
the left and right speakers,
|
||||
where 0% means only the left speaker produces sound,
|
||||
50% means both speakers produce sound equally,
|
||||
and 100% means only the right speaker produces sound.
|
||||
- **Reverb** adds a slight reverberation effect
|
||||
to the emulated console's audio output,
|
||||
as though you were playing the game in a tunnel or small room.
|
||||
|
||||
Input
|
||||
=====
|
||||
|
||||
This tab controls which PC inputs
|
||||
are mapped to which emulated controllers.
|
||||
The exact PC inputs that can be mapped
|
||||
depend on [the input driver](../guides/drivers.md#input).
|
||||
|
||||
General input settings:
|
||||
|
||||
- **Pause Emulation** automatically pauses emulation
|
||||
when the main higan window
|
||||
is not the current foreground window.
|
||||
- **Allow Input** can be ticked
|
||||
when "Pause Emulation" is *not* ticked,
|
||||
and allows configured inputs to keep affecting higan
|
||||
even when higan is running in the background.
|
||||
This is particularly relevant if
|
||||
you configure your PC keyboard to control higan:
|
||||
if you tick this box,
|
||||
and switch to a different application
|
||||
leaving higan running in the background,
|
||||
typing in that other application may affect
|
||||
the emulated game running in higan
|
||||
even though you can't see it!
|
||||
|
||||
Choosing which of the possible controllers to configure:
|
||||
|
||||
- The console selector chooses which console's inputs
|
||||
to display in the mapping list below.
|
||||
- The port selector chooses which port of the selected console
|
||||
to display in the mapping list below.
|
||||
- The controller selector chooses which controller
|
||||
associated with the given console and port
|
||||
to display in the mapping list below.
|
||||
Note that some consoles only allow particular controllers
|
||||
to be used in a particular port.
|
||||
For example,
|
||||
the Super Scope controller for the Super Famicom
|
||||
only works in Controller Port 2.
|
||||
|
||||
Configuring the selected controller:
|
||||
|
||||
- The mapping list includes
|
||||
every button and axis on the selected controller,
|
||||
and the PC inputs that will be mapped to it
|
||||
when it is connected to the selected port of the selected console.
|
||||
- **Erase** removes the mapping
|
||||
for the selected button or axis.
|
||||
- **Reset** removes all the mappings currently in the list.
|
||||
|
||||
To map
|
||||
a keyboard or gamepad button on your PC to
|
||||
a controller button,
|
||||
double-click the controller button in the list,
|
||||
or select it and press Enter.
|
||||
The Settings window will grey out,
|
||||
and a message will appear in the bottom left:
|
||||
"Press a key or button to map [the button]".
|
||||
Press the key or button you want to map,
|
||||
and it should appear in the list
|
||||
next to the controller button it is mapped to.
|
||||
|
||||
To map
|
||||
a mouse button on your PC to
|
||||
a controller button,
|
||||
select the controller button in the list,
|
||||
then click one of the "Mouse Left",
|
||||
"Mouse Middle",
|
||||
or "Mouse Right" buttons in the bottom-left of the Settings window.
|
||||
|
||||
To map
|
||||
a joystick axis on your PC to
|
||||
a controller axis,
|
||||
double-click the axis in the list,
|
||||
or select it and press Enter.
|
||||
The Settings window will grey out,
|
||||
and a message will appear in the bottom left:
|
||||
"Press a key or button to map [the axis]".
|
||||
Press the joystick in the direction you want to map,
|
||||
and it should appear in the list
|
||||
next to the controller axis it is mapped to.
|
||||
|
||||
To map
|
||||
a mouse axis on your PC to
|
||||
a controller axis,
|
||||
select the axis in the list,
|
||||
then click one of the
|
||||
"Mouse X-axis",
|
||||
or "Mouse Y-axis"
|
||||
buttons in the bottom-left of the window.
|
||||
|
||||
If you start mapping a button or axis,
|
||||
but decide you don't want to,
|
||||
you can press Escape
|
||||
to exit the "Press a key or button to map..." mode
|
||||
without actually mapping anything.
|
||||
|
||||
**Note:**
|
||||
Consoles in the Game Boy family include
|
||||
a Rumble "input" which is really more of an output.
|
||||
See [Rumble Compatibility for Game Boy (Color)][gbcrumble]
|
||||
and [Rumble Compatibility for Game Boy Advance][gbarumble]
|
||||
for details.
|
||||
|
||||
[gbcrumble]: ../notes.md#rumble-compatibility-for-game-boy-color
|
||||
[gbarumble]: ../notes.md#rumble-compatibility-for-game-boy-advance
|
||||
|
||||
**Note:**
|
||||
Once you've configured which computer inputs
|
||||
higan should route to which controllers,
|
||||
make sure the controller in question
|
||||
is actually connected to the correct controller port
|
||||
in [the console menu](higan.md#the-console-menu).
|
||||
|
||||
Hotkeys
|
||||
=======
|
||||
|
||||
This tab is like "Inputs" above,
|
||||
except it contains controls for higan itself
|
||||
instead of the emulated console.
|
||||
|
||||
- **Toggle Fullscreen** puts higan into fullscreen mode,
|
||||
where the menu and status bar are hidden,
|
||||
and the emulated console's video output
|
||||
is enlarged to cover the entire screen.
|
||||
Toggling fullscreen also automatically captures the mouse.
|
||||
- **Toggle Mouse Capture** hides the usual mouse-cursor,
|
||||
and captures the mouse so it cannot leave the higan window.
|
||||
This is useful when the mouse is being used to emulate
|
||||
a light-gun controller like the Super Scope.
|
||||
- **Save Quick State** saves the current state of the emulated console
|
||||
to the currently-selected [Quick State][qstates] slot.
|
||||
- **Load Quick State** restores the emulated console
|
||||
to the state saved in the currently-selected [Quick State][qstates] slot.
|
||||
- **Decrement Quick State** selects the previous [Quick State][qstates] slot.
|
||||
The status bar will briefly display the new current slot number.
|
||||
- **Increment Quick State** selects the next [Quick State][qstates] slot.
|
||||
The status bar will briefly display the new current slot number.
|
||||
- **Pause Emulation** pauses the emulated console
|
||||
until the Pause Emulation hotkey is pressed a second time.
|
||||
- **Fast Forward** disables audio and video synchronisation
|
||||
for as long as it's held down,
|
||||
so emulation proceeds as quickly as possible.
|
||||
If your PC struggles to hit "real time"
|
||||
(60fps for most emulated consoles),
|
||||
this likely won't have any effect.
|
||||
- **Power Cycle** turns the emulated console off and back on
|
||||
(a "hard reset"),
|
||||
just like the "Power Cycle" menu item
|
||||
in [the console menu](higan.md#the-console-menu).
|
||||
- **Rotate Display** will rotate the display
|
||||
of the Game Boy Advance
|
||||
and WonderSwan (Color).
|
||||
See [Game Boy Advance rotation](../notes.md#game-boy-advance-rotation)
|
||||
and [WonderSwan rotation](../notes.md#wonderswan-rotation)
|
||||
for details.
|
||||
|
||||
[qstates]: ../concepts/save-states.md#quick-states
|
||||
|
||||
Advanced
|
||||
========
|
||||
|
||||
This tab contains all the settings
|
||||
that didn't fit into one of the other categories.
|
||||
|
||||
**Driver Selection**
|
||||
tells higan how to
|
||||
accept input,
|
||||
display video,
|
||||
and play sound
|
||||
on this computer.
|
||||
|
||||
- **Video** controls how higan will draw
|
||||
the emulated console's video output
|
||||
to the PC screen.
|
||||
"None" means no video will be drawn.
|
||||
- **Audio** controls how higan will present
|
||||
the emulated console's audio output.
|
||||
"None" means no audio will be played.
|
||||
- **Input** controls how higan checks for input
|
||||
from the PC's input devices.
|
||||
"None" means the emulated console cannot be controlled.
|
||||
|
||||
See [Choosing drivers](../guides/drivers.md)
|
||||
for help choosing which drivers you should use.
|
||||
|
||||
**Game Library**
|
||||
configures how higan interacts
|
||||
with the [Game Library](../concepts/game-library.md).
|
||||
|
||||
- **Location** selects where higan
|
||||
looks for games to load.
|
||||
See [Moving the Game Library](../concepts/game-library.md#moving-the-game-library)
|
||||
for more information.
|
||||
- **Ignore Manifests** makes higan ignore
|
||||
the [manifest](../concepts/manifests.md) file
|
||||
in the loaded game's
|
||||
[game folder](../concepts/game-folders.md)
|
||||
in favour of asking icarus
|
||||
to guess a manifest on the fly.
|
||||
See [Ignoring manifests](../concepts/manifests.md#ignoring-manifests)
|
||||
for details.
|
@@ -11,7 +11,7 @@ The Cheat Editor
|
||||
For some consoles,
|
||||
higan supports applying temporary changes to the code of a running game.
|
||||
For example,
|
||||
you could disable the code that registers when the player takes damage,
|
||||
you could disable the code that detects when the player takes damage,
|
||||
resulting in an "invulnerability" mode.
|
||||
Currently,
|
||||
higan supports cheats for the following consoles:
|
||||
@@ -23,6 +23,43 @@ higan supports cheats for the following consoles:
|
||||
- PC Engine
|
||||
- Wonder Swan
|
||||
|
||||
To add a new cheat,
|
||||
select an unused row in the list,
|
||||
then type the relevant codes in the "Code(s)" field at the bottom,
|
||||
and a description in the "Description" field.
|
||||
See [Cheat code formats](#cheat-code-formats)
|
||||
for a description of the codes higan understands.
|
||||
|
||||
To enable or disable an existing cheat,
|
||||
tick the checkbox in the first column of the list.
|
||||
The change should take effect immediately.
|
||||
|
||||
To clear out an existing cheat,
|
||||
select it from the list
|
||||
and click the "Erase" button in the bottom right,
|
||||
or just manually delete
|
||||
the contents of the "Code(s)" and "Description" fields.
|
||||
|
||||
To clear out all existing cheats,
|
||||
click the "Reset" button in the bottom right.
|
||||
|
||||
Changes made in the Cheat Editor are saved to disk
|
||||
when the game is unloaded,
|
||||
or when higan exits.
|
||||
higan stores the known cheats for a particular game
|
||||
in `higan/cheats.bml`
|
||||
inside the game's [game folder](../concepts/game-folders.md).
|
||||
|
||||
If your copy of higan includes a cheat database
|
||||
(a file named `cheats.bml`
|
||||
in the same folder as `Super Famicom.sys`
|
||||
and the other `*.sys` folders),
|
||||
you can click the "Find Codes ..." button in the bottom left
|
||||
to load all known cheats for the currently-running game.
|
||||
|
||||
Cheat code formats
|
||||
------------------
|
||||
|
||||
A cheat code of the format `addr=data`
|
||||
will cause the emulated console to obtain `data`
|
||||
whenever it reads from memory address `addr`.
|
||||
@@ -52,39 +89,6 @@ in Super Mario World,
|
||||
you can lock the time to 999 with these codes:
|
||||
`7e0f31=09+7e0f32=09+7e0f33=09`.
|
||||
|
||||
Changes made in the Cheat Editor are saved to disk
|
||||
when the game is unloaded,
|
||||
or when higan exits.
|
||||
higan stores the known cheats for a particular game
|
||||
in `higan/cheats.bml`
|
||||
inside the corresponding game folder
|
||||
in [the Game Library](#the-game-library).
|
||||
|
||||
If your copy of higan includes a cheat database
|
||||
(a file named `cheats.bml`
|
||||
in the same directory as `Super Famicom.sys`
|
||||
and the other `*.sys` directories),
|
||||
you can click the "Find Codes ..." button in the bottom left
|
||||
to load all known cheats for the currently-running game.
|
||||
|
||||
To add a new cheat,
|
||||
select an unused row in the list,
|
||||
then type the relevant codes in the "Code(s)" field at the bottom,
|
||||
and a description in the "Description" field.
|
||||
|
||||
To enable or disable an existing cheat,
|
||||
tick the checkbox in the first column of the list.
|
||||
The code should take effect immediately.
|
||||
|
||||
To clear out an existing cheat,
|
||||
select it from the list
|
||||
and click the "Erase" button in the bottom right,
|
||||
or just manually delete
|
||||
the contents of the "Code(s)" and "Description" fields.
|
||||
|
||||
To clear out all existing cheats,
|
||||
click the "Reset" button in the bottom right.
|
||||
|
||||
The State Manager
|
||||
-----------------
|
||||
|
||||
@@ -95,10 +99,11 @@ For more information on Manager states,
|
||||
quick states,
|
||||
saved games
|
||||
and how they compare,
|
||||
see [Save States](#save-states).
|
||||
see [Save States](../concepts/save-states.md).
|
||||
|
||||
To create a new manager state,
|
||||
or to replace an existing one,
|
||||
To save the current state of the loaded game
|
||||
in a new slot,
|
||||
or to replace the contents of an existing slot,
|
||||
select the slot in the list
|
||||
then click "Save" in the bottom-left corner.
|
||||
You can then type a description in the "Description" field,
|
||||
@@ -111,7 +116,7 @@ and edit the "Description" field.
|
||||
To load a state,
|
||||
select the slot in the list
|
||||
and click "Load" in the bottom-left corner,
|
||||
or just double-click it.
|
||||
or just double-click the slot.
|
||||
|
||||
To clear the state out of a slot,
|
||||
select the slot in the list
|
||||
@@ -123,23 +128,10 @@ click "Reset" in the bottom-right corner.
|
||||
The Manifest Viewer
|
||||
-------------------
|
||||
|
||||
As mentioned in
|
||||
[Why game folders?](#why-game-folders),
|
||||
a game cartridge contains
|
||||
more than just the raw data of the game.
|
||||
|
||||
As described in
|
||||
[Game Manifests](../concepts/manifests.md),
|
||||
higan uses a "manifest" to
|
||||
describe how the various parts of a game cartridge
|
||||
are wired up together,
|
||||
and the Manifest Viewer lets you examine
|
||||
the configuration higan is using for the currently-running game.
|
||||
|
||||
For some games,
|
||||
an actual cartridge has been taken apart and carefully examined
|
||||
and its configuration has been recorded in icarus' database,
|
||||
so the manifest icarus produces
|
||||
is guaranteed accurate.
|
||||
For games that do not exist in icarus' database,
|
||||
icarus will make a reasonable guess.
|
||||
This is enough to get the game running,
|
||||
but does not necessarily reflect the original cartridge.
|
||||
are wired up together.
|
||||
The Manifest Viewer lets you examine
|
||||
the configuration higan is using for the loaded game.
|
||||
|
@@ -1,54 +1,31 @@
|
||||
When you launch higan,
|
||||
When you launch higan
|
||||
the main window appears,
|
||||
with a menu-bar across the top,
|
||||
a status-bar across the bottom,
|
||||
and a large area in the middle where the game's video output appears.
|
||||
and a large area in the middle that shows
|
||||
the running game's video output.
|
||||
|
||||
The Library menu
|
||||
----------------
|
||||
|
||||
The Library menu allows you
|
||||
to import games into higan's game library,
|
||||
and to load games from the library.
|
||||
higan organises the games in your library
|
||||
according to which console they were intended to run on.
|
||||
|
||||
To play a game for a particular console from your library,
|
||||
click on the Library menu,
|
||||
click on the console manufacturer submenu
|
||||
(Nintendo for the Super Famicom,
|
||||
Bandai for the WonderSwan,
|
||||
etc.)
|
||||
then click on the console menu item.
|
||||
A window will appear listing all the games in your library
|
||||
for that particular console.
|
||||
Select the game you want to play
|
||||
and click the Open button,
|
||||
or just double-click the game,
|
||||
and it will begin playing as though you'd just turned on the console.
|
||||
|
||||
To add a new game to your library,
|
||||
choose "Load ROM File ..." from the Library menu.
|
||||
A [filesystem browser](#the-filesystem-browser) will appear,
|
||||
allowing you to pick any ROM image for any supported system,
|
||||
with any of the most common file extensions.
|
||||
It also allows loading ROM images from `.zip` archives,
|
||||
if the archive contains a single ROM image.
|
||||
|
||||
**Note:** Some games require extra steps to import correctly;
|
||||
see [the Game Library](#the-game-library) for details.
|
||||
|
||||
TODO: Mention the region-picker.
|
||||
|
||||
To add many games at once,
|
||||
run icarus,
|
||||
or choose "Import ROM Files ..." from the Library menu
|
||||
(which just runs icarus anyway).
|
||||
See [the icarus interface](#the-icarus-interface)
|
||||
for more information about bulk-importing.
|
||||
|
||||
For more information about the higan game library,
|
||||
see [The Game Library](#the-game-library) below.
|
||||
Manufacturer sub-menus
|
||||
allow you to play
|
||||
games you've already imported
|
||||
into higan's
|
||||
[game library](../concepts/game-library.md).
|
||||
See [Importing and playing games](../guides/import.md).
|
||||
|
||||
**Load ROM File ...**
|
||||
opens a [filesystem browser](common.md#the-filesystem-browser)
|
||||
allowing you to choose a single ROM file.
|
||||
It will be imported and immediately start playing.
|
||||
See [Importing and playing games](../guides/import.md).
|
||||
|
||||
**Import ROM Files ...**
|
||||
launches the icarus importing tool,
|
||||
allowing you to bulk-import many ROM files at once.
|
||||
See [the icarus documentation](icarus.md).
|
||||
|
||||
|
||||
The console menu
|
||||
---------------
|
||||
@@ -69,52 +46,60 @@ to the particular console being emulated.
|
||||
All consoles will have some of the following items,
|
||||
but few consoles have all of them.
|
||||
|
||||
- **Controller Port 1**
|
||||
allows you
|
||||
to connect different emulated controllers
|
||||
to the first controller port,
|
||||
if there is one.
|
||||
- See [the Configuration dialog](#the-configuration-dialog)
|
||||
for information about configuring
|
||||
which host controller inputs are used
|
||||
for the emulated controllers.
|
||||
- This menu appears for the Famicom,
|
||||
even though the Famicom did not support alternate controllers,
|
||||
because the Famicom emulation core also emulates the NES,
|
||||
which did.
|
||||
- **Controller Port 2**
|
||||
allows you
|
||||
to connect different emulated controllers
|
||||
to the second controller port,
|
||||
if there is one.
|
||||
- See [the Configuration dialog](#the-configuration-dialog)
|
||||
for information about configuring
|
||||
which host controller inputs are used
|
||||
for the emulated controllers.
|
||||
- This menu appears for the Famicom,
|
||||
even though the Famicom did not support alternate controllers,
|
||||
because the Famicom emulation core also emulates the NES,
|
||||
which did.
|
||||
- **Expansion Port**
|
||||
allows you
|
||||
to connect different emulated devices
|
||||
to the console's expansion port,
|
||||
if there is one.
|
||||
- For the Super Famicom,
|
||||
the [21fx][21fx] is a homebrew device
|
||||
that allows a program running on a PC
|
||||
to control a physical Super Famicom (or SNES).
|
||||
This option allows the same program
|
||||
to control the emulated SNES,
|
||||
for development or testing.
|
||||
- **Power Cycle**
|
||||
restarts the loaded game
|
||||
as though the emulated console were switched off and on again.
|
||||
- **Unload**
|
||||
stops the current game,
|
||||
as though the emulated console were switched off.
|
||||
You can load the same or a different game
|
||||
from [the Library menu](#the-library-menu).
|
||||
|
||||
**Controller Port 1**
|
||||
allows you
|
||||
to connect different emulated controllers
|
||||
to the first controller port,
|
||||
if there is one.
|
||||
See [higan's Input settings](higan-settings.md#input)
|
||||
for information about configuring
|
||||
which PC controller inputs are used
|
||||
for the emulated controllers.
|
||||
|
||||
This menu appears for the Famicom,
|
||||
even though the Famicom did not support alternate controllers,
|
||||
because the Famicom emulation core also emulates the NES,
|
||||
which did.
|
||||
|
||||
**Controller Port 2**
|
||||
allows you
|
||||
to connect different emulated controllers
|
||||
to the second controller port,
|
||||
if there is one.
|
||||
See [higan's Input settings](higan-settings.md#input)
|
||||
for information about configuring
|
||||
which PC controller inputs are used
|
||||
for the emulated controllers.
|
||||
|
||||
This menu appears for the Famicom,
|
||||
even though the Famicom did not support alternate controllers,
|
||||
because the Famicom emulation core also emulates the NES,
|
||||
which did.
|
||||
|
||||
**Expansion Port**
|
||||
allows you
|
||||
to connect different emulated devices
|
||||
to the console's expansion port,
|
||||
if there is one.
|
||||
|
||||
For the Super Famicom,
|
||||
the [21fx][21fx] is a homebrew device
|
||||
that allows a program running on a PC
|
||||
to control a physical Super Famicom (or SNES).
|
||||
This option allows the same program
|
||||
to control the emulated SNES,
|
||||
for development or testing.
|
||||
|
||||
**Power Cycle**
|
||||
restarts the loaded game
|
||||
as though the emulated console were switched off and on again.
|
||||
|
||||
**Unload**
|
||||
stops the current game,
|
||||
as though the emulated console were switched off.
|
||||
You can load a new game
|
||||
from [the Library menu](#the-library-menu).
|
||||
|
||||
[21fx]: https://github.com/defparam/21FX
|
||||
|
||||
@@ -124,78 +109,79 @@ The Settings menu
|
||||
The Settings menu allows you to configure things
|
||||
that aren't specific to any particular console.
|
||||
|
||||
- **Video Scale** determines the size and shape
|
||||
of the emulated console's video output
|
||||
in windowed mode
|
||||
(as opposed to fullscreen).
|
||||
- **Video Emulation** applies various effects
|
||||
to the emulated console's video output
|
||||
to reproduce some behaviours
|
||||
that aren't technically part of the console itself.
|
||||
- "Blurring" simulates the limited horizontal resolution
|
||||
of standard-definition TVs
|
||||
by blurring together horizontally-adjacent pixels.
|
||||
Games like Jurassic Park for the Super Famicom
|
||||
|
||||
**Video Scale** determines the size
|
||||
of the emulated console's video output
|
||||
when higan is running in windowed mode
|
||||
(as opposed to fullscreen).
|
||||
|
||||
**Video Emulation** applies various effects
|
||||
to the emulated console's video output
|
||||
to reproduce some behaviours
|
||||
that aren't technically part of the console itself:
|
||||
|
||||
- **Blurring**
|
||||
simulates the limited horizontal resolution
|
||||
of standard-definition TVs
|
||||
by blurring together horizontally-adjacent pixels.
|
||||
For hand-held consoles,
|
||||
this simulates the slow response time
|
||||
of the cheap LCD screens these consoles used
|
||||
by blending each output frame with the previous one.
|
||||
- Games like
|
||||
*Jurassic Park* for the Super Famicom
|
||||
or *Chikyuu Kaihou Gun ZAS* for the Game Boy
|
||||
depend on this to emulate a transparency effect.
|
||||
For hand-held consoles like the Game Boy Advance,
|
||||
this simulates the slow response time
|
||||
of the cheap LCD screens these consoles used
|
||||
by blurring each output frame with the previous one.
|
||||
- "Colors" simulates the way a console's display device
|
||||
differs from modern computer monitor's colour reproduction.
|
||||
In particular,
|
||||
it simulates the slightly-different gamma correction
|
||||
used by the Super Famicom,
|
||||
the dim, washed out colours of the original Game Boy Advance,
|
||||
and the pea-green display of the original Game Boy.
|
||||
- **Video Shader** controls
|
||||
how the low-resolution video output of the emulated console
|
||||
is scaled up to suit modern high-resolution displays.
|
||||
The availability of items in this submenu depends on
|
||||
which video driver higan is using,
|
||||
so see [Drivers](#drivers) for more information.
|
||||
- "None" draws each output pixel according to
|
||||
the colour of the single nearest input pixel,
|
||||
sometimes called "nearest neighbour" scaling.
|
||||
This produces unnaturally crisp and blocky images.
|
||||
- "Blur" draws each output pixel by
|
||||
averaging the colours of the four nearest input pixels,
|
||||
sometimes called "bilinear" scaling.
|
||||
This produces unnaturally blurry images.
|
||||
- When using the OpenGL [driver](#drivers),
|
||||
an additional item appears in this menu for
|
||||
each installed Quark shader.
|
||||
See [Installing custom shaders](#installing-custom-shaders)
|
||||
for details.
|
||||
- **Synchronize Audio**
|
||||
causes higan to wait for audio playback to complete
|
||||
before resuming emulation.
|
||||
This should reduce popping and glitching noises,
|
||||
and slows the emulation down to approximately the correct speed.
|
||||
If your PC cannot emulate at full-speed,
|
||||
(60fps for most consoles, 75fps for WonderSwan)
|
||||
this has no noticable effect.
|
||||
- **Mute Audio**
|
||||
causes higan to not output sound from the emulated console.
|
||||
The sound hardware is still emulated.
|
||||
- **Show Status Bar**
|
||||
causes higan to show or hide the status bar
|
||||
at the bottom of the window.
|
||||
This option has no effect in full-screen mode.
|
||||
See [The status bar](#the-status-bar) for more information.
|
||||
- **Video ...**
|
||||
opens the Video tab of [the Configuration dialog][cfgdlg].
|
||||
- **Audio ...**
|
||||
opens the Audio tab of [the Configuration dialog][cfgdlg].
|
||||
- **Input ...**
|
||||
opens the Input tab of [the Configuration dialog][cfgdlg].
|
||||
- **Hotkey ...**
|
||||
opens the Hotkeys tab of [the Configuration dialog][cfgdlg].
|
||||
- **Advanced ...**
|
||||
opens the Advanced tab of [the Configuration dialog][cfgdlg].
|
||||
- **Colors**
|
||||
simulates the way a console's display device
|
||||
differs from modern computer monitor's colour reproduction.
|
||||
In particular,
|
||||
it simulates the slightly-different gamma correction
|
||||
used by the Super Famicom,
|
||||
the dim, washed out colours of the original Game Boy Advance,
|
||||
and the pea-green display of the original Game Boy.
|
||||
|
||||
**Video Shader** controls
|
||||
how the low-resolution video output of the emulated console
|
||||
is scaled up to suit modern high-resolution displays.
|
||||
[Using video shaders](../guides/shaders.md)
|
||||
describes all the options in this sub-menu.
|
||||
|
||||
**Synchronize Audio**
|
||||
causes higan to wait for audio playback to complete
|
||||
before resuming emulation.
|
||||
This should reduce popping and glitching noises,
|
||||
and slows the emulation down to approximately the correct speed.
|
||||
If your PC cannot emulate at full-speed,
|
||||
(60fps for most consoles, 75fps for WonderSwan)
|
||||
this has no noticeable effect.
|
||||
|
||||
**Mute Audio**
|
||||
causes higan to not output sound from the emulated console.
|
||||
The sound hardware is still emulated.
|
||||
|
||||
**Show Status Bar**
|
||||
causes higan to show or hide the status bar
|
||||
at the bottom of the window.
|
||||
This option has no effect in fullscreen mode.
|
||||
See [The status bar](#the-status-bar) for more information.
|
||||
|
||||
**Video ...**
|
||||
opens [higan's Video settings](higan-settings.md#video).
|
||||
|
||||
**Audio ...**
|
||||
opens [higan's Audio settings](higan-settings.md#audio).
|
||||
|
||||
**Input ...**
|
||||
opens [higan's Input settings](higan-settings.md#input).
|
||||
|
||||
**Hotkeys ...**
|
||||
opens [higan's Hotkeys settings](higan-settings.md#hotkeys).
|
||||
|
||||
**Advanced ...**
|
||||
opens [higan's Advanced settings](higan-settings.md#advanced).
|
||||
|
||||
[svsa]: #why-do-synchronize-video-and-synchronize-audio-conflict
|
||||
[cfgdlg]: #the-configuration-dialog
|
||||
|
||||
The Tools menu
|
||||
--------------
|
||||
@@ -203,33 +189,45 @@ The Tools menu
|
||||
The Tools menu
|
||||
contains features for manipulating the emulated console.
|
||||
|
||||
- **Save Quick State**
|
||||
stores the current state of the emulated console
|
||||
into one of the quick state slots.
|
||||
See [Save States](#save-states) for more information.
|
||||
- **Load Quick State**
|
||||
restores the emulated console to
|
||||
a state previously saved to one of the quick state slots.
|
||||
See [Save States](#save-states) for more information.
|
||||
- **Cheat Editor**
|
||||
opens [the Cheat Editor window](#the-cheat-editor)
|
||||
- **State Manager**
|
||||
opens [the State Manager window](#the-state-manager)
|
||||
- **Manifest Viewer**
|
||||
opens [the Manifest Viewer window](#the-manifest-viewer)
|
||||
**Save Quick State**
|
||||
stores the current state of the emulated console
|
||||
into one of the quick state slots.
|
||||
See [Save States](../concepts/save-states.md) for more information.
|
||||
|
||||
**Load Quick State**
|
||||
restores the emulated console to
|
||||
a state previously saved to one of the quick state slots.
|
||||
See [Save States](../concepts/save-states.md) for more information.
|
||||
|
||||
**Cheat Editor**
|
||||
opens [the Cheat Editor tab](higan-tools.md#the-cheat-editor)
|
||||
of the Tools window.
|
||||
|
||||
**State Manager**
|
||||
opens [the State Manager tab](higan-tools.md#the-state-manager)
|
||||
of the Tools window.
|
||||
|
||||
**Manifest Viewer**
|
||||
opens [the Manifest Viewer tab](higan-tools.md#the-manifest-viewer)
|
||||
of the Tools window.
|
||||
|
||||
The Help menu
|
||||
-------------
|
||||
|
||||
The Help menu contains information about higan itself.
|
||||
|
||||
- **Documentation**
|
||||
loads the official higan documentation
|
||||
in your web-browser.
|
||||
- **About**
|
||||
opens the About dialog,
|
||||
which displays basic information about higan,
|
||||
including the version number.
|
||||
**Documentation**
|
||||
loads the official higan documentation
|
||||
in your web-browser.
|
||||
|
||||
**Credits**
|
||||
loads a list of people who have contributed to higan
|
||||
in your web-browser.
|
||||
|
||||
**About**
|
||||
opens the About dialog,
|
||||
which displays basic information about higan,
|
||||
including the version number.
|
||||
|
||||
The status bar
|
||||
--------------
|
||||
@@ -242,7 +240,7 @@ Before any game is loaded,
|
||||
the status bar displays "No cartridge loaded".
|
||||
|
||||
When a game is loaded and running,
|
||||
the status bar displays the current emulation speeed
|
||||
the status bar displays the current emulation speed
|
||||
in frames-per-second.
|
||||
For PAL-based consoles,
|
||||
this should be around 50 FPS for "full speed" emulation,
|
||||
@@ -250,15 +248,15 @@ for NTSC and most portable consoles the ideal speed is 60 FPS,
|
||||
but the WonderSwan runs at 75 FPS.
|
||||
If the number is too low,
|
||||
you may need a faster computer,
|
||||
or a faster [video driver](#drivers).
|
||||
or a faster [video driver](../guides/drivers.md#video).
|
||||
If the number is too high,
|
||||
you may need to [Synchronize Audio](#the-settings-menu),
|
||||
or you may have pressed the "turbo" [hotkey](#the-configuration-dialog).
|
||||
or you may have pressed the "turbo" [hotkey](higan-settings.md#hotkeys).
|
||||
|
||||
The status bar displays "Paused"
|
||||
if you have pressed the "pause" [hotkey](#the-configuration-dialog),
|
||||
if you have pressed the "pause" [hotkey](higan-settings.md#hotkeys),
|
||||
or if "When focus is lost: Pause Emulation" is ticked
|
||||
in [the Input tab of the Configuration dialog](#the-configuration-dialog)
|
||||
in [higan's Input settings](higan-settings.md#input)
|
||||
and the main higan window is not the foreground window.
|
||||
To resume emulation,
|
||||
make sure the main higan window is in the foreground,
|
||||
@@ -282,7 +280,7 @@ or when you press the "Load Quick State" hotkey
|
||||
while the current Quick State slot has not had a save-state saved to it,
|
||||
|
||||
The status bar briefly displays "Power cycled"
|
||||
when you choose "Power Cycle" from [the console menu](#the-console menu),
|
||||
when you choose "Power Cycle" from [the console menu](#the-console-menu),
|
||||
or press the "Power Cycle" hotkey.
|
||||
|
||||
The status bar briefly displays "Display rotation not supported"
|
||||
|
1
docs/interface/home.png
Symbolic link
1
docs/interface/home.png
Symbolic link
@@ -0,0 +1 @@
|
||||
../../hiro/resource/icon/go/home.png
|
@@ -1,8 +1,16 @@
|
||||
When launching icarus,
|
||||
directly or by picking "Import ROM Files ..."
|
||||
from higan's [Library menu](#the-library-menu),
|
||||
from higan's [Library menu](higan.md#the-library-menu),
|
||||
the main icarus window appears.
|
||||
This is [a filesystem browser](#the-filesystem-browser),
|
||||
This window allows you to bulk-import ROM files
|
||||
into [higan's game library][gamelib],
|
||||
and also to access icarus' settings.
|
||||
|
||||
Bulk importing ROM files
|
||||
------------------------
|
||||
|
||||
icarus' main window
|
||||
is [a filesystem browser](common.md#the-filesystem-browser),
|
||||
with customisations:
|
||||
|
||||
- The filesystem browser only lists
|
||||
@@ -15,46 +23,47 @@ with customisations:
|
||||
- You can un-tick all the check-boxes
|
||||
by pressing "Unselect All" in the bottom-left.
|
||||
|
||||
Pressing "Settings ..." in the bottom-right
|
||||
opens [the icarus Settings dialog](#the-icarus-settings-dialog).
|
||||
|
||||
Pressing "Import ..." in the bottom-right
|
||||
will close the filesystem browser
|
||||
then try to import all the files
|
||||
whose check-boxes are ticked
|
||||
into [the Game Library](#the-game-library).
|
||||
icarus displays a progress dialog during the import process.
|
||||
into [the Game Library][gamelib].
|
||||
icarus displays a progress dialog during the import process,
|
||||
and a result window if any errors occurred.
|
||||
|
||||
**Note:** Some games require extra steps to import correctly;
|
||||
see [the Game Library](#the-game-library) for details.
|
||||
see [Importing and playing games](../guides/import.md) for details.
|
||||
|
||||
The icarus Settings dialog
|
||||
--------------------------
|
||||
|
||||
Pressing "Settings ..."
|
||||
in the bottom-right corner of the main icarus window
|
||||
opens the settings dialog.
|
||||
|
||||
The icarus Settings dialog contains the following settings:
|
||||
|
||||
- **Library Location** determines
|
||||
where icarus puts the games it imports.
|
||||
See [Moving the Game Library](#moving-the-game-library)
|
||||
See [Moving the Game Library][movgamelib]
|
||||
for details.
|
||||
- **Create Manifests** causes icarus
|
||||
to write out a manifest file describing
|
||||
each imported game
|
||||
to that game's [game folder](#whats-in-a-game-folder).
|
||||
This means that higan doesn't have to regenerate
|
||||
the manifest each time an imported game is loaded,
|
||||
but it means that a future version of higan
|
||||
with an incompatible manifest format
|
||||
may be unable to play these games.
|
||||
Note that higan also has an "Ignore Manifests" option
|
||||
in the Advanced tab of
|
||||
[its Configuration dialog](#the-configuration-dialog).
|
||||
to include
|
||||
[a manifest file](../concepts/manifests.md)
|
||||
inside
|
||||
[the game folder](../concepts/game-folders.md)
|
||||
for each imported game.
|
||||
See [Ignoring manifests](../concepts/manifests.md#ignoring-manifests)
|
||||
for details.
|
||||
- **Use Database** causes icarus to use manifest information
|
||||
from its database of known-good manifests,
|
||||
if it's importing a game it recognises.
|
||||
For unrecognised games,
|
||||
and for all games if this box is unticked,
|
||||
icarus gueses the manifest data.
|
||||
icarus guesses the manifest data.
|
||||
This option is still relevant when "Create Manifests" is unticked:
|
||||
higan uses icarus to generate a manifest when a game is loaded,
|
||||
not just at import-time.
|
||||
|
||||
[gamelib]: ../concepts/game-library.md
|
||||
[movgamelib]: ../concepts/game-library.md#moving-the-game-library
|
||||
|
1
docs/interface/refresh.png
Symbolic link
1
docs/interface/refresh.png
Symbolic link
@@ -0,0 +1 @@
|
||||
../../hiro/resource/icon/action/refresh.png
|
1
docs/interface/up.png
Symbolic link
1
docs/interface/up.png
Symbolic link
@@ -0,0 +1 @@
|
||||
../../hiro/resource/icon/go/up.png
|
134
docs/notes.md
134
docs/notes.md
@@ -1,105 +1,21 @@
|
||||
The consoles that higan emulates
|
||||
are similar in many ways,
|
||||
but some of them do have particular quirks
|
||||
that you should be aware of.
|
||||
|
||||
Video Shaders and TV-based consoles
|
||||
-----------------------------------
|
||||
|
||||
[Video Shaders](guides/shaders.md)
|
||||
customize how higan scales
|
||||
the low-resolution video of the emulated console
|
||||
up to the high-resolution of the computer display.
|
||||
Simple shaders
|
||||
(like "None"
|
||||
and the third-party "AANN" shader)
|
||||
just blindly scale up the images they're given,
|
||||
but sophisticated shaders
|
||||
(such as the third-party "xBR" shader)
|
||||
try to produce higher-quality output
|
||||
by recognising particular patterns of pixel,
|
||||
like taking three diagonal pixels
|
||||
and turning that into a smooth diagonal line.
|
||||
|
||||
These shaders assume that
|
||||
each pixel drawn by the game's artists
|
||||
becomes a single pixel in the video output they analyze.
|
||||
Many of the consoles higan emulates
|
||||
can only output video at one specific resolution,
|
||||
so this "one pixel equals one pixel" rule holds true,
|
||||
and pattern-based shaders like "xBR" work just fine.
|
||||
|
||||
Unfortunately,
|
||||
this is not the case for the Super Famicom.
|
||||
The "normal" video mode
|
||||
draws 256 pixels across the width of the screen,
|
||||
but the "high resolution" mode draws 512.
|
||||
Since Super Famicom games can enable hi-res mode at any time
|
||||
(even halfway through a frame),
|
||||
higan always renders Super Famicom video output 512 pixels wide,
|
||||
just in case.
|
||||
This means that in "normal" mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes two pixels in the video output,
|
||||
breaking the assumption
|
||||
that pattern-based shaders are based on.
|
||||
|
||||
The Super Famicom has a similar issue in the vertical direction:
|
||||
normally,
|
||||
an NTSC-based Super Famicom draws about 240 rows of output every frame,
|
||||
sometimes referred to as "240p" video.
|
||||
When a game turns on "interlaced" mode,
|
||||
it draws the 240 odd-numbered lines of one frame,
|
||||
then the 240 even-numbered lines of the next,
|
||||
and so forth.
|
||||
This is sometimes referred to as "480i" video.
|
||||
Although interlaced mode cannot be enabled mid-frame
|
||||
like high-resolution mode,
|
||||
resolution switching is still complex,
|
||||
so higan always draws all 480 lines of video output.
|
||||
This means for a normal, non-interlaced game,
|
||||
each pixel drawn by the game's artists
|
||||
becomes four pixels in the video output
|
||||
(two horizontally and two vertically)
|
||||
making pattern-based shaders even less useful.
|
||||
It also breaks most scanline-emulation shaders,
|
||||
since they typically draw a scanline
|
||||
for each row of pixels in the video output.
|
||||
|
||||
The Mega Drive has similar problems
|
||||
to the Super Famicom.
|
||||
It has the same behaviour with interlacing,
|
||||
but its high-resolution mode switches
|
||||
from 256 pixels across to 320 pixels across.
|
||||
Therefore in normal mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes five pixels in the video output,
|
||||
while in high-resolution mode,
|
||||
each pixel drawn by the game's artists
|
||||
becomes four pixels in the video output
|
||||
(or 10 and 8 pixels in non-interlaced mode).
|
||||
|
||||
The PC Engine does not support an interlaced mode,
|
||||
but its horizontal resolution is much more flexible
|
||||
than the Super Famicom or Mega Drive,
|
||||
and so it has the same problems with shaders.
|
||||
but some of them do have particular quirks of their own.
|
||||
|
||||
Music and Sound Effect Volume on the Mega Drive
|
||||
-----------------------------------------------
|
||||
|
||||
The Mega Drive has two different audio-generating chips:
|
||||
|
||||
- the SN76489 or "PSG" chip,
|
||||
- the SN76489 or "PSG" chip
|
||||
inherited from the Master System,
|
||||
mostly used for sound-effects
|
||||
like Sonic picking up rings
|
||||
- the YM2612 or "FM" chip,
|
||||
mostly used for music
|
||||
|
||||
With two different sound sources,
|
||||
it's important that they have similar volumes,
|
||||
or the sound-effects will drown out the music,
|
||||
or vice-versa.
|
||||
it's important that they have similar volumes
|
||||
or one kind of sound will drown out the other.
|
||||
Sega did *not* do this,
|
||||
and different hardware revisions
|
||||
used different relative volumes.
|
||||
@@ -107,8 +23,8 @@ used different relative volumes.
|
||||
higan currently
|
||||
sets the PSG volume to [125% of the FM volume][vol],
|
||||
based on [a Sega Genesis model 1 VA6][va6] that byuu owns.
|
||||
If you feel sound-effects in higan's Mega Drive core
|
||||
are too loud or too quiet,
|
||||
If you feel sound-effects in higan's Mega Drive emulation
|
||||
are too loud or too quiet compared to the music,
|
||||
you may be comparing it
|
||||
to a Mega Drive calibrated to a different scale
|
||||
(or to an emulator tweaked to match such a Mega Drive).
|
||||
@@ -116,12 +32,12 @@ to a Mega Drive calibrated to a different scale
|
||||
[vol]: https://board.byuu.org/viewtopic.php?p=42482#p42482
|
||||
[va6]: https://board.byuu.org/viewtopic.php?p=42195#p42195
|
||||
|
||||
Playing Game Boy Colour games in Game Boy mode
|
||||
----------------------------------------------
|
||||
Playing Game Boy Color games in Game Boy mode
|
||||
---------------------------------------------
|
||||
|
||||
Games for the original Game Boy
|
||||
came in solid grey cartridges,
|
||||
and only supported four-shade greyscale graphics.
|
||||
and only supported four-shade grey-scale graphics.
|
||||
ROM files for these games
|
||||
typically have filenames ending in `.gb`.
|
||||
|
||||
@@ -131,14 +47,14 @@ Games that required
|
||||
the extra hardware in the Game Boy Color
|
||||
came in transparent cartridges,
|
||||
and had a slightly different shape
|
||||
to prevent them from being used in original Game Boys..
|
||||
to prevent them from being used in original Game Boys.
|
||||
ROM files for these games
|
||||
typically have filenames ending in `.gbc`.
|
||||
|
||||
However,
|
||||
there were also some games
|
||||
that could use colour if it was available,
|
||||
but would stick to greyscale if it wasn't.
|
||||
but would stick to grey-scale if it wasn't.
|
||||
These games came in black cartridges.
|
||||
ROM files for these games
|
||||
typically have filenames ending in `.gbc`
|
||||
@@ -198,17 +114,9 @@ higan must guess which storage type to use
|
||||
and sometimes it guesses incorrectly.
|
||||
|
||||
If higan guesses incorrectly for a game you want to play,
|
||||
you will need to turn on
|
||||
"Create manifests" in
|
||||
[the Icarus settings dialog](interface/icarus.md#the-icarus-settings-dialog),
|
||||
turn off
|
||||
"Ignore manifests" in
|
||||
[higan's Advanced settings](interface/higan-config.md#advanced),
|
||||
re-import the game,
|
||||
and edit `manifest.bml` in
|
||||
[the game folder](concepts/game-folders.md)
|
||||
to describe the correct storage type.
|
||||
Try importing other GBA games to see what save types they use.
|
||||
you will need to override the automatically-generated manifest.
|
||||
See [Ignoring manifests](concepts/manifests.md#ignoring-manifests)
|
||||
for details.
|
||||
|
||||
For more discussion of the GBA save type mess,
|
||||
see [What's the deal with... GBA save files?][gbasaves]
|
||||
@@ -226,10 +134,10 @@ included a rumble motor within the cartridge itself.
|
||||
Because higan does not currently support
|
||||
game-specific controller features,
|
||||
to experience the rumble effect in higan
|
||||
you'll need to configure the console itself:
|
||||
you'll need to configure the console:
|
||||
|
||||
- Open
|
||||
[higan's Input settings](interface/higan-config.md#input)
|
||||
[higan's Input settings](interface/higan-settings.md#input)
|
||||
- In the list of consoles,
|
||||
select Game Boy, or Game Boy Color
|
||||
depending on which console you want to use to play the game
|
||||
@@ -245,16 +153,16 @@ Rumble compatibility for Game Boy Advance
|
||||
The original Game Boy Advance
|
||||
and the Game Boy Advance SP
|
||||
did not support any kind of rumble or force-feedback system,
|
||||
but the Game Boy Player addon for the Gamecube
|
||||
but the Game Boy Player add-on for the GameCube
|
||||
allowed Game Boy Advance games
|
||||
to use the rumble feature in Gamecube controllers.
|
||||
to use the rumble feature in GameCube controllers.
|
||||
|
||||
Because rumble is a feature of the Game Boy Player,
|
||||
to experience the rumble effect in higan
|
||||
you'll need to configure the console itself:
|
||||
|
||||
- Open
|
||||
[higan's Input settings](interface/higan-config.md#input)
|
||||
[higan's Input settings](interface/higan-settings.md#input)
|
||||
- In the list of consoles,
|
||||
select Game Boy Advance
|
||||
- In the list of inputs,
|
||||
@@ -283,7 +191,7 @@ as well as a bonus mode in *Dr Mario + Puzzle League*,
|
||||
expect the player to physically rotate the device
|
||||
so the screen is tall rather than wide.
|
||||
higan supports this feature with
|
||||
a Rotate [hotkey](interface/higan-config.md#hotkeys).
|
||||
a Rotate [hotkey](interface/higan-settings.md#hotkeys).
|
||||
|
||||
When the user presses the Rotate hotkey,
|
||||
the console's video output is rotated 90° anti-clockwise,
|
||||
@@ -303,7 +211,7 @@ vertically or horizontally.
|
||||
that requires the player to repeatedly rotate
|
||||
the device as they play.
|
||||
higan supports this feature with
|
||||
a Rotate [hotkey](interface/higan-config.md#hotkeys).
|
||||
a Rotate [hotkey](interface/higan-settings.md#hotkeys).
|
||||
|
||||
When the user presses the Rotate hotkey,
|
||||
the console's video output is rotated 90° anti-clockwise,
|
||||
|
16
docs/qs.md
16
docs/qs.md
@@ -1,4 +1,4 @@
|
||||
If this is you're first time using higan,
|
||||
If this is your first time using higan,
|
||||
welcome!
|
||||
Here's a brief guide to getting started:
|
||||
|
||||
@@ -13,7 +13,7 @@ and extracting it.
|
||||
[More information...](install/windows.md)
|
||||
|
||||
On Linux,
|
||||
if your distribution doesn't include the latest version,
|
||||
if your distribution doesn't already include the latest version,
|
||||
you'll need to compile it yourself — but don't worry,
|
||||
it's not too complex.
|
||||
[More information...](install/linux.md)
|
||||
@@ -25,7 +25,7 @@ Once higan's installed,
|
||||
start it up.
|
||||
Open the "Settings" menu,
|
||||
and choose "Input ..."
|
||||
to open [the Input settings](interface/higan-config.md#input).
|
||||
to open [the Input settings](interface/higan-settings.md#input).
|
||||
|
||||
higan supports a *lot* of different controllers
|
||||
for a lot of different consoles,
|
||||
@@ -63,7 +63,7 @@ In the future,
|
||||
if you want to play this game again,
|
||||
you can choose "Load ROM File ..." as you did before,
|
||||
or you can choose the appropriate console name
|
||||
from [the Library menu](interface/higan.md#the-library-menu),
|
||||
from the Library menu,
|
||||
which will list all the games for that console
|
||||
in the Game Library.
|
||||
|
||||
@@ -79,11 +79,11 @@ that's a Super Famicom game
|
||||
so there will be a Super Famicom menu.
|
||||
|
||||
Open [the console menu](interface/higan.md#the-console-menu),
|
||||
and if there is a submenu for a controller port,
|
||||
and if there is a sub-menu for a controller port,
|
||||
make sure the port is using
|
||||
the controller you [set up previously](#configuring-inputs).
|
||||
If you configured inputs for a Gamepad in Controller Port 1,
|
||||
the Controller Port 1 submenu
|
||||
the Controller Port 1 sub-menu
|
||||
should be set to Gamepad.
|
||||
Like a real console,
|
||||
higan's controller ports
|
||||
@@ -96,7 +96,7 @@ like the Game Boy and WonderSwan,
|
||||
since the "controller" is always connected.
|
||||
This *does* apply to the Famicom,
|
||||
even though the Famicom's controllers are hard-wired,
|
||||
because higan uses "Famicom"
|
||||
to mean Nintendo's 8-bit home console
|
||||
because higan uses the name "Famicom"
|
||||
to refer to Nintendo's 8-bit home console
|
||||
in all territories,
|
||||
including the Nintendo Entertainment System.
|
||||
|
14
docs/release.md
Normal file
14
docs/release.md
Normal file
@@ -0,0 +1,14 @@
|
||||
Release checklist
|
||||
=================
|
||||
|
||||
1. Commit the new release
|
||||
2. Tag the commit
|
||||
3. `git push --tags origin master` to push the commit and tag at the
|
||||
same time.
|
||||
4. Go to [the docs admin][rtd] and verify that it's building the new
|
||||
version as 'stable' and under its tag name.
|
||||
5. Check out the `libretro` branch.
|
||||
6. Merge changes from master.
|
||||
7. `git push` to make the new changes available.
|
||||
|
||||
[rtd]: https://readthedocs.org/projects/higan/builds/
|
@@ -1,28 +1,38 @@
|
||||
build := release
|
||||
build := optimize
|
||||
include ../nall/GNUmakefile
|
||||
|
||||
binary := application
|
||||
target := tomoko
|
||||
objects := libco emulator audio video resource
|
||||
# console := true
|
||||
|
||||
flags += -I. -I..
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
ifeq ($(console),true)
|
||||
link += -mconsole
|
||||
else
|
||||
link += -mwindows
|
||||
link += $(if $(call streq,$(console),true),-mconsole,-mwindows)
|
||||
ifeq ($(binary),application)
|
||||
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||
link += -Wl,-enable-auto-import
|
||||
link += -Wl,-enable-runtime-pseudo-reloc
|
||||
else ifeq ($(binary),library)
|
||||
link += -shared
|
||||
endif
|
||||
else ifeq ($(platform),macos)
|
||||
ifeq ($(binary),application)
|
||||
else ifeq ($(binary),library)
|
||||
flags += -fPIC
|
||||
link += -dynamiclib
|
||||
endif
|
||||
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||
link += -Wl,-enable-auto-import
|
||||
link += -Wl,-enable-runtime-pseudo-reloc
|
||||
else ifeq ($(platform),macosx)
|
||||
flags += -march=native
|
||||
else ifneq ($(filter $(platform),linux bsd),)
|
||||
flags += -march=native -fopenmp
|
||||
flags += -fopenmp
|
||||
link += -fopenmp
|
||||
link += -Wl,-export-dynamic
|
||||
link += -lX11 -lXext
|
||||
ifeq ($(binary),application)
|
||||
flags += -march=native
|
||||
link += -Wl,-export-dynamic
|
||||
link += -lX11 -lXext
|
||||
else ifeq ($(binary),library)
|
||||
flags += -fPIC
|
||||
link += -shared
|
||||
endif
|
||||
else
|
||||
$(error "unsupported platform")
|
||||
endif
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 13 KiB |
84
higan/data/higan.svg
Normal file
84
higan/data/higan.svg
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256mm"
|
||||
height="256mm"
|
||||
viewBox="0 0 256 256"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||
sodipodi:docname="higan.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.5"
|
||||
inkscape:cx="-264.38189"
|
||||
inkscape:cy="632.78774"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-41)">
|
||||
<circle
|
||||
id="path10"
|
||||
cx="128.0"
|
||||
cy="169.0"
|
||||
r="120.0"
|
||||
style="stroke-width:0.25;fill:#ffc0c0;fill-opacity:1" />
|
||||
<g
|
||||
aria-label="火"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:254.9591217px;line-height:1.25;font-family:KaiTi;-inkscape-font-specification:KaiTi;letter-spacing:0px;word-spacing:0px;fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="text818"
|
||||
transform="translate(318.55834,64.029166)">
|
||||
<path
|
||||
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -194.12628,101.7548 q 15.93495,23.90242 34.85769,43.8211 19.91869,19.91868 37.8455,30.87396 18.92275,9.95934 40.833295,16.93088 21.91055,5.9756 -2.987802,7.96747 -24.898353,1.99187 -37.845493,0 -11.95121,-0.99594 -27.88616,-21.91055 -14.93901,-20.91462 -46.8089,-66.72758 -5.9756,25.89428 -13.94307,41.82923 -7.96748,14.93901 -26.89022,30.87395 -18.92275,14.93901 -39.83737,17.92682 -19.91868,3.98373 -3.98373,-3.98374 16.93088,-6.97154 33.86176,-21.91055 17.92681,-14.93901 26.89022,-34.85769 8.9634,-20.91462 10.95527,-50.79264 2.9878,-29.878022 1.99187,-50.792637 0,-20.914616 -4.97967,-28.882088 -4.97967,-8.963407 2.9878,-5.9756048 8.96341,1.9918681 16.93088,5.9756048 8.96341,2.987802 5.9756,8.963406 -2.9878,4.979671 -5.9756,33.861759 -1.99187,27.886153 -1.99187,46.8089 z"
|
||||
id="path827"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -110.28062,50.929737 q 7.96747,6.971538 0,8.963407 -6.97154,0.995934 -22.90648,10.955274 -14.93901,8.963407 -28.88209,15.934945 -12.94714,5.975604 -1.99187,-3.983736 11.95121,-10.955275 21.91055,-21.910549 10.95528,-10.955275 10.95528,-17.926814 0,-7.967472 6.97153,-3.983736 6.97154,3.983736 13.94308,11.951209 z"
|
||||
id="path825"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m -261.66505,69.757659 q -15.93494,-24.898352 0,-15.934945 15.93495,7.967472 20.91462,14.939011 4.97967,5.975604 0.99593,16.930876 -3.98373,10.95528 -21.91055,-15.934942 z"
|
||||
id="path820"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
@@ -12,10 +12,10 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "104";
|
||||
static const string Version = "106";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "104";
|
||||
|
@@ -6,7 +6,8 @@ struct Interface {
|
||||
struct Information {
|
||||
string manufacturer;
|
||||
string name;
|
||||
bool overscan;
|
||||
bool overscan = false;
|
||||
bool resettable = false;
|
||||
} information;
|
||||
|
||||
struct Medium {
|
||||
@@ -37,15 +38,15 @@ struct Interface {
|
||||
virtual auto manifest() -> string = 0;
|
||||
virtual auto title() -> string = 0;
|
||||
|
||||
//video information
|
||||
struct VideoResolution {
|
||||
uint width;
|
||||
uint height;
|
||||
uint internalWidth;
|
||||
uint internalHeight;
|
||||
double aspectCorrection;
|
||||
struct VideoInformation {
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
uint internalWidth = 0;
|
||||
uint internalHeight = 0;
|
||||
double aspectCorrection = 0;
|
||||
double refreshRate = 0;
|
||||
};
|
||||
virtual auto videoResolution() -> VideoResolution = 0;
|
||||
virtual auto videoInformation() -> VideoInformation = 0;
|
||||
virtual auto videoColors() -> uint32 = 0;
|
||||
virtual auto videoColor(uint32 color) -> uint64 = 0;
|
||||
|
||||
@@ -59,6 +60,7 @@ struct Interface {
|
||||
//system interface
|
||||
virtual auto connect(uint port, uint device) -> void {}
|
||||
virtual auto power() -> void {}
|
||||
virtual auto reset() -> void {}
|
||||
virtual auto run() -> void {}
|
||||
|
||||
//time functions
|
||||
|
96
higan/emulator/random.hpp
Normal file
96
higan/emulator/random.hpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Random {
|
||||
enum class Entropy : uint { None, Low, High };
|
||||
|
||||
auto operator()() -> uint64 {
|
||||
return random();
|
||||
}
|
||||
|
||||
auto entropy(Entropy entropy) -> void {
|
||||
_entropy = entropy;
|
||||
seed();
|
||||
}
|
||||
|
||||
auto seed(maybe<uint32> seed = nothing, maybe<uint32> sequence = nothing) -> void {
|
||||
if(!seed) seed = (uint32)clock();
|
||||
if(!sequence) sequence = 0;
|
||||
|
||||
_state = 0;
|
||||
_increment = sequence() << 1 | 1;
|
||||
step();
|
||||
_state += seed();
|
||||
step();
|
||||
}
|
||||
|
||||
auto random() -> uint64 {
|
||||
if(_entropy == Entropy::None) return 0;
|
||||
return (uint64)step() << 32 | (uint64)step() << 0;
|
||||
}
|
||||
|
||||
auto bias(uint64 bias) -> uint64 {
|
||||
if(_entropy == Entropy::None) return bias;
|
||||
return random();
|
||||
}
|
||||
|
||||
auto bound(uint64 bound) -> uint64 {
|
||||
uint64 threshold = -bound % bound;
|
||||
while(true) {
|
||||
uint64 result = random();
|
||||
if(result >= threshold) return result % bound;
|
||||
}
|
||||
}
|
||||
|
||||
auto array(uint8* data, uint32 size) -> void {
|
||||
if(_entropy == Entropy::None) {
|
||||
memory::fill(data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if(_entropy == Entropy::High) {
|
||||
for(uint32 address : range(size)) {
|
||||
data[address] = random();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Entropy::Low
|
||||
uint lobit = random() & 3;
|
||||
uint hibit = (lobit + 8 + (random() & 3)) & 15;
|
||||
uint lovalue = random() & 255;
|
||||
uint hivalue = random() & 255;
|
||||
if((random() & 3) == 0) lovalue = 0;
|
||||
if((random() & 1) == 0) hivalue = ~lovalue;
|
||||
|
||||
for(uint32 address : range(size)) {
|
||||
uint8 value = address.bit(lobit) ? lovalue : hivalue;
|
||||
if(address.bit(hibit)) value = ~value;
|
||||
if((random() & 511) == 0) value.bit(random() & 7) ^= 1;
|
||||
if((random() & 2047) == 0) value.bit(random() & 7) ^= 1;
|
||||
data[address] = value;
|
||||
}
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer((uint&)_entropy);
|
||||
s.integer(_state);
|
||||
s.integer(_increment);
|
||||
}
|
||||
|
||||
private:
|
||||
auto step() -> uint32 {
|
||||
uint64 state = _state;
|
||||
_state = state * 6364136223846793005ull + _increment;
|
||||
uint32 xorshift = (state >> 18 ^ state) >> 27;
|
||||
uint32 rotate = state >> 59;
|
||||
return xorshift >> rotate | xorshift << (-rotate & 31);
|
||||
}
|
||||
|
||||
Entropy _entropy = Entropy::High;
|
||||
uint64 _state;
|
||||
uint64 _increment;
|
||||
};
|
||||
|
||||
}
|
@@ -71,7 +71,7 @@ auto APU::setSample(int16 sample) -> void {
|
||||
cartridgeSample = sample;
|
||||
}
|
||||
|
||||
auto APU::power() -> void {
|
||||
auto APU::power(bool reset) -> void {
|
||||
create(APU::Enter, system.frequency());
|
||||
stream = Emulator::audio.createStream(1, frequency() / rate());
|
||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 90.0);
|
||||
|
@@ -12,7 +12,7 @@ struct APU : Thread {
|
||||
auto setIRQ() -> void;
|
||||
auto setSample(int16 sample) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
auto readIO(uint16 addr) -> uint8;
|
||||
auto writeIO(uint16 addr, uint8 data) -> void;
|
||||
|
@@ -24,16 +24,16 @@ auto CPU::step(uint clocks) -> void {
|
||||
for(auto peripheral : peripherals) synchronize(*peripheral);
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
auto CPU::power(bool reset) -> void {
|
||||
MOS6502::BCD = 0;
|
||||
MOS6502::power();
|
||||
create(CPU::Enter, system.frequency());
|
||||
|
||||
for(auto addr : range(0x0800)) ram[addr] = 0xff;
|
||||
ram[0x0008] = 0xf7;
|
||||
ram[0x0009] = 0xef;
|
||||
ram[0x000a] = 0xdf;
|
||||
ram[0x000f] = 0xbf;
|
||||
if(!reset) for(auto& data : ram) data = 0xff;
|
||||
ram[0x008] = 0xf7; //todo: what is this about?
|
||||
ram[0x009] = 0xef;
|
||||
ram[0x00a] = 0xdf;
|
||||
ram[0x00f] = 0xbf;
|
||||
|
||||
r.pc.byte(0) = bus.read(0xfffc);
|
||||
r.pc.byte(1) = bus.read(0xfffd);
|
||||
|
@@ -6,7 +6,7 @@ struct CPU : Processor::MOS6502, Thread {
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto readRAM(uint11 addr) -> uint8;
|
||||
@@ -37,7 +37,7 @@ struct CPU : Processor::MOS6502, Thread {
|
||||
//protected:
|
||||
vector<Thread*> peripherals;
|
||||
|
||||
uint8 ram[0x0800];
|
||||
uint8 ram[0x800];
|
||||
|
||||
struct IO {
|
||||
bool interruptPending;
|
||||
|
@@ -8,6 +8,7 @@ Interface::Interface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Famicom";
|
||||
information.overscan = true;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::Famicom, "Famicom", "fc"});
|
||||
|
||||
@@ -44,8 +45,15 @@ auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoResolution() -> VideoResolution {
|
||||
return {256, 240, 256, 240, 8.0 / 7.0};
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 256;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 256;
|
||||
vi.internalHeight = 240;
|
||||
vi.aspectCorrection = 8.0 / 7.0;
|
||||
vi.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
@@ -130,7 +138,11 @@ auto Interface::connect(uint port, uint device) -> void {
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
system.power(/* reset = */ false);
|
||||
}
|
||||
|
||||
auto Interface::reset() -> void {
|
||||
system.power(/* reset = */ true);
|
||||
}
|
||||
|
||||
auto Interface::run() -> void {
|
||||
|
@@ -26,7 +26,7 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
@@ -38,6 +38,7 @@ struct Interface : Emulator::Interface {
|
||||
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
auto reset() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
auto serialize() -> serializer override;
|
||||
|
@@ -54,18 +54,20 @@ auto PPU::refresh() -> void {
|
||||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
auto PPU::power(bool reset) -> void {
|
||||
create(PPU::Enter, system.frequency());
|
||||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
memory::fill(&latch, sizeof(Latches));
|
||||
io.vramIncrement = 1;
|
||||
|
||||
for(auto& n : ciram ) n = 0;
|
||||
for(auto& n : cgram ) n = 0;
|
||||
for(auto& n : oam ) n = 0;
|
||||
if(!reset) {
|
||||
for(auto& data : ciram ) data = 0;
|
||||
for(auto& data : cgram ) data = 0;
|
||||
for(auto& data : oam ) data = 0;
|
||||
}
|
||||
|
||||
for(auto& n : buffer) n = 0;
|
||||
for(auto& data : buffer) data = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ struct PPU : Thread {
|
||||
auto frame() -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto readCIRAM(uint11 addr) -> uint8;
|
||||
|
@@ -31,7 +31,7 @@ auto System::unserialize(serializer& s) -> bool {
|
||||
if(signature != 0x31545342) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
power(/* reset = */ false);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ auto System::unload() -> void {
|
||||
information.loaded = false;
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
auto System::power(bool reset) -> void {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
configureVideoPalette();
|
||||
@@ -73,9 +73,9 @@ auto System::power() -> void {
|
||||
|
||||
scheduler.reset();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
apu.power();
|
||||
ppu.power();
|
||||
cpu.power(reset);
|
||||
apu.power(reset);
|
||||
ppu.power(reset);
|
||||
scheduler.primary(cpu);
|
||||
|
||||
controllerPort1.power(ID::Port::Controller1);
|
||||
|
@@ -11,7 +11,7 @@ struct System {
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
|
@@ -36,8 +36,15 @@ auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoResolution() -> VideoResolution {
|
||||
return {160, 144, 160, 144, 1.0};
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 160;
|
||||
vi.height = 144;
|
||||
vi.internalWidth = 160;
|
||||
vi.internalHeight = 144;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
|
@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto sha256() -> string override;
|
||||
|
@@ -24,6 +24,7 @@ auto CPU::main() -> void {
|
||||
Thread::step(16);
|
||||
synchronize(ppu);
|
||||
synchronize(apu);
|
||||
synchronize(player);
|
||||
}
|
||||
context.stopped = false;
|
||||
}
|
||||
@@ -61,6 +62,7 @@ auto CPU::step(uint clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
synchronize(ppu);
|
||||
synchronize(apu);
|
||||
synchronize(player);
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
|
@@ -36,10 +36,6 @@ namespace GameBoyAdvance {
|
||||
inline auto synchronize(Thread& thread) -> void {
|
||||
if(clock() >= thread.clock()) scheduler.resume(thread);
|
||||
}
|
||||
|
||||
inline auto step(uint clocks) -> void {
|
||||
_clock += clocks;
|
||||
}
|
||||
};
|
||||
|
||||
#include <gba/memory/memory.hpp>
|
||||
|
@@ -39,12 +39,19 @@ auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoResolution() -> VideoResolution {
|
||||
if(!settings.rotateLeft) {
|
||||
return {240, 160, 240, 160, 1.0};
|
||||
} else {
|
||||
return {160, 240, 160, 240, 1.0};
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 240;
|
||||
vi.height = 160;
|
||||
vi.internalWidth = 240;
|
||||
vi.internalHeight = 160;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = system.frequency() / (228.0 * 1232.0);
|
||||
if(settings.rotateLeft) {
|
||||
swap(vi.width, vi.height);
|
||||
swap(vi.internalWidth, vi.internalHeight);
|
||||
}
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
|
@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
|
@@ -7,7 +7,26 @@ namespace GameBoyAdvance {
|
||||
Player player;
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto Player::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), player.main();
|
||||
}
|
||||
|
||||
auto Player::main() -> void {
|
||||
if(status.timeout && !--status.timeout) {
|
||||
platform->inputRumble(0, 0, 10, false);
|
||||
}
|
||||
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto Player::step(uint clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
synchronize(cpu);
|
||||
}
|
||||
|
||||
auto Player::power() -> void {
|
||||
create(Player::Enter, 1'000.0);
|
||||
|
||||
status.enable = false;
|
||||
status.rumble = false;
|
||||
|
||||
@@ -17,9 +36,12 @@ auto Player::power() -> void {
|
||||
status.packet = 0;
|
||||
status.send = 0;
|
||||
status.recv = 0;
|
||||
|
||||
status.timeout = 0;
|
||||
}
|
||||
|
||||
auto Player::frame() -> void {
|
||||
//todo: this is not a very performant way of detecting the GBP logo ...
|
||||
uint32 hash = Hash::CRC32(ppu.output, 240 * 160 * sizeof(uint32)).value();
|
||||
status.logoDetected = (hash == 0x7776eb55);
|
||||
|
||||
@@ -101,6 +123,7 @@ auto Player::write(uint2 addr, uint8 byte) -> void {
|
||||
if(addr == 3 && status.packet == 15) {
|
||||
status.rumble = (status.recv & 0xff) == 0x26; //on = 0x26, off = 0x04
|
||||
platform->inputRumble(0, 0, 10, status.rumble);
|
||||
if(status.rumble) status.timeout = 500; //stop rumble manually after 500ms
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,18 @@
|
||||
struct Player {
|
||||
struct Player : Thread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto frame() -> void;
|
||||
|
||||
auto keyinput() -> maybe<uint16>;
|
||||
auto read() -> maybe<uint32>;
|
||||
auto write(uint2 addr, uint8 byte) -> void;
|
||||
|
||||
auto serialize(serializer& s) -> void;
|
||||
|
||||
private:
|
||||
struct Status {
|
||||
bool enable;
|
||||
bool rumble;
|
||||
@@ -9,16 +23,9 @@ struct Player {
|
||||
uint packet;
|
||||
uint32 send;
|
||||
uint32 recv;
|
||||
|
||||
uint timeout;
|
||||
} status;
|
||||
|
||||
auto power() -> void;
|
||||
auto frame() -> void;
|
||||
|
||||
auto keyinput() -> maybe<uint16>;
|
||||
auto read() -> maybe<uint32>;
|
||||
auto write(uint2 addr, uint8 byte) -> void;
|
||||
|
||||
auto serialize(serializer& s) -> void;
|
||||
};
|
||||
|
||||
extern Player player;
|
||||
|
@@ -8,4 +8,6 @@ auto Player::serialize(serializer& s) -> void {
|
||||
s.integer(status.packet);
|
||||
s.integer(status.send);
|
||||
s.integer(status.recv);
|
||||
|
||||
s.integer(status.timeout);
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ auto System::runToSave() -> void {
|
||||
scheduler.synchronize(cpu);
|
||||
scheduler.synchronize(ppu);
|
||||
scheduler.synchronize(apu);
|
||||
scheduler.synchronize(player);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -52,11 +52,13 @@ auto APU::enable(bool value) -> void {
|
||||
state.enabled = value;
|
||||
}
|
||||
|
||||
auto APU::power() -> void {
|
||||
auto APU::power(bool reset) -> void {
|
||||
Z80::bus = this;
|
||||
Z80::power();
|
||||
bus->grant(false);
|
||||
create(APU::Enter, system.frequency() / 15.0);
|
||||
|
||||
if(!reset) memory::fill(ram, sizeof ram);
|
||||
state = {};
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@ struct APU : Processor::Z80, Processor::Z80::Bus, Thread {
|
||||
auto synchronizing() const -> bool override;
|
||||
|
||||
auto enable(bool) -> void;
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto setNMI(bool value) -> void;
|
||||
|
@@ -80,11 +80,13 @@ auto CPU::load(Markup::Node node) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
auto CPU::power(bool reset) -> void {
|
||||
M68K::bus = this;
|
||||
M68K::power();
|
||||
create(CPU::Enter, system.frequency() / 7.0);
|
||||
|
||||
if(!reset) memory::fill(ram, sizeof ram);
|
||||
|
||||
io = {};
|
||||
io.version = tmssEnable;
|
||||
io.romEnable = !tmssEnable;
|
||||
|
@@ -19,7 +19,7 @@ struct CPU : Processor::M68K, Processor::M68K::Bus, Thread {
|
||||
auto lower(Interrupt) -> void;
|
||||
|
||||
auto load(Markup::Node) -> bool;
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//bus.cpp
|
||||
auto readByte(uint24 address) -> uint16 override;
|
||||
|
@@ -8,6 +8,7 @@ Interface::Interface() {
|
||||
information.manufacturer = "Sega";
|
||||
information.name = "Mega Drive";
|
||||
information.overscan = true;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::MegaDrive, "Mega Drive", "md"});
|
||||
|
||||
@@ -64,22 +65,36 @@ auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoResolution() -> VideoResolution {
|
||||
return {320, 240, 1280, 480, 1.0};
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 320;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 1280;
|
||||
vi.internalHeight = 480;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 9;
|
||||
return 3 * (1 << 9);
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
uint R = color.bits(0,2);
|
||||
uint G = color.bits(3,5);
|
||||
uint B = color.bits(6,8);
|
||||
uint R = color.bits(0, 2);
|
||||
uint G = color.bits(3, 5);
|
||||
uint B = color.bits(6, 8);
|
||||
uint M = color.bits(9,10);
|
||||
|
||||
uint64 r = image::normalize(R, 3, 16);
|
||||
uint64 g = image::normalize(G, 3, 16);
|
||||
uint64 b = image::normalize(B, 3, 16);
|
||||
uint lookup[3][8] = {
|
||||
{ 0, 29, 52, 70, 87, 101, 116, 130}, //shadow
|
||||
{ 0, 52, 87, 116, 144, 172, 206, 255}, //normal
|
||||
{130, 144, 158, 172, 187, 206, 228, 255}, //highlight
|
||||
};
|
||||
|
||||
uint64 r = image::normalize(lookup[M][R], 8, 16);
|
||||
uint64 g = image::normalize(lookup[M][G], 8, 16);
|
||||
uint64 b = image::normalize(lookup[M][B], 8, 16);
|
||||
|
||||
return r << 32 | g << 16 | b << 0;
|
||||
}
|
||||
@@ -108,7 +123,11 @@ auto Interface::connect(uint port, uint device) -> void {
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
system.power(/* reset = */ false);
|
||||
}
|
||||
|
||||
auto Interface::reset() -> void {
|
||||
system.power(/* reset = */ true);
|
||||
}
|
||||
|
||||
auto Interface::run() -> void {
|
||||
|
@@ -27,7 +27,7 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
@@ -38,6 +38,7 @@ struct Interface : Emulator::Interface {
|
||||
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
auto reset() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
auto serialize() -> serializer override;
|
||||
|
@@ -34,7 +34,7 @@ auto PSG::step(uint clocks) -> void {
|
||||
synchronize(apu);
|
||||
}
|
||||
|
||||
auto PSG::power() -> void {
|
||||
auto PSG::power(bool reset) -> void {
|
||||
create(PSG::Enter, system.frequency() / 15.0);
|
||||
stream = Emulator::audio.createStream(1, frequency() / 16.0);
|
||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
||||
|
@@ -7,7 +7,7 @@ struct PSG : Thread {
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto write(uint8 data) -> void;
|
||||
|
@@ -48,7 +48,7 @@ auto System::unserialize(serializer& s) -> bool {
|
||||
if(signature != 0x31545342) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
power(/* reset = */ false);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ auto System::unload() -> void {
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
auto System::power(bool reset) -> void {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
Emulator::video.setPalette();
|
||||
@@ -71,11 +71,11 @@ auto System::power() -> void {
|
||||
|
||||
scheduler.reset();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
apu.power();
|
||||
vdp.power();
|
||||
psg.power();
|
||||
ym2612.power();
|
||||
cpu.power(reset);
|
||||
apu.power(reset);
|
||||
vdp.power(reset);
|
||||
psg.power(reset);
|
||||
ym2612.power(reset);
|
||||
scheduler.primary(cpu);
|
||||
|
||||
controllerPort1.power(ID::Port::Controller1);
|
||||
|
@@ -15,7 +15,7 @@ struct System {
|
||||
auto load(Emulator::Interface*, maybe<Region> = nothing) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serializeInit() -> void;
|
||||
|
@@ -16,7 +16,7 @@ auto VDP::Background::updateHorizontalScroll(uint y) -> void {
|
||||
state.horizontalScroll = vdp.vram.read(address).bits(0,9);
|
||||
}
|
||||
|
||||
auto VDP::Background::updateVerticalScroll(uint x, uint y) -> void {
|
||||
auto VDP::Background::updateVerticalScroll(uint x) -> void {
|
||||
if(id == ID::Window) return;
|
||||
|
||||
auto address = (x >> 4 & 0 - io.verticalScrollMode) << 1;
|
||||
@@ -45,38 +45,36 @@ auto VDP::Background::scanline(uint y) -> void {
|
||||
}
|
||||
|
||||
auto VDP::Background::run(uint x, uint y) -> void {
|
||||
updateVerticalScroll(x, y);
|
||||
updateVerticalScroll(x);
|
||||
|
||||
output.priority = 0;
|
||||
output.color = 0;
|
||||
bool interlace = vdp.io.interlaceMode == 3;
|
||||
if(interlace) y = y << 1 | vdp.state.field;
|
||||
|
||||
x -= state.horizontalScroll;
|
||||
y += state.verticalScroll;
|
||||
|
||||
uint width = nametableWidth();
|
||||
uint height = nametableHeight();
|
||||
|
||||
uint tileX = x >> 3 & width - 1;
|
||||
uint tileY = y >> 3 & height - 1;
|
||||
uint tileX = x >> 3 & nametableWidth() - 1;
|
||||
uint tileY = y >> 3 + interlace & nametableHeight() - 1;
|
||||
|
||||
auto address = nametableAddress();
|
||||
address += (tileY * width + tileX) & 0x0fff;
|
||||
address += (tileY * nametableWidth() + tileX) & 0x0fff;
|
||||
|
||||
uint pixelX = x & 7;
|
||||
uint pixelY = y & 7 + interlace * 8;
|
||||
|
||||
uint16 tileAttributes = vdp.vram.read(address);
|
||||
uint15 tileAddress = tileAttributes.bits(0,10) << 4;
|
||||
uint pixelX = (x & 7) ^ (tileAttributes.bit(11) ? 7 : 0);
|
||||
uint pixelY = (y & 7) ^ (tileAttributes.bit(12) ? 7 : 0);
|
||||
uint15 tileAddress = tileAttributes.bits(0,10) << 4 + interlace;
|
||||
if(tileAttributes.bit(11)) pixelX ^= 7;
|
||||
if(tileAttributes.bit(12)) pixelY ^= 7 + interlace * 8;
|
||||
tileAddress += pixelY << 1 | pixelX >> 2;
|
||||
|
||||
uint16 tileData = vdp.vram.read(tileAddress);
|
||||
uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2);
|
||||
if(color) {
|
||||
output.color = tileAttributes.bits(13,14) << 4 | color;
|
||||
output.priority = tileAttributes.bit(15);
|
||||
}
|
||||
output.color = color ? tileAttributes.bits(13,14) << 4 | color : 0;
|
||||
output.priority = tileAttributes.bit(15);
|
||||
}
|
||||
|
||||
auto VDP::Background::power() -> void {
|
||||
memory::fill(&io, sizeof(IO));
|
||||
memory::fill(&state, sizeof(State));
|
||||
io = {};
|
||||
state = {};
|
||||
}
|
||||
|
@@ -13,7 +13,12 @@ auto VDP::read(uint24 addr) -> uint16 {
|
||||
|
||||
//counter
|
||||
case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: {
|
||||
return state.vcounter << 8 | (state.hdot >> 1) << 0;
|
||||
auto vcounter = state.vcounter;
|
||||
if(io.interlaceMode.bit(0)) {
|
||||
if(io.interlaceMode.bit(1)) vcounter <<= 1;
|
||||
vcounter.bit(0) = vcounter.bit(8);
|
||||
}
|
||||
return vcounter << 8 | (state.hdot >> 1) << 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,12 +118,23 @@ auto VDP::writeDataPort(uint16 data) -> void {
|
||||
auto VDP::readControlPort() -> uint16 {
|
||||
io.commandPending = false;
|
||||
|
||||
uint16 result = 0b0011'0100'0000'0000;
|
||||
result |= 1 << 9; //FIFO empty
|
||||
result |= (state.vcounter >= screenHeight()) << 3; //vertical blank
|
||||
result |= (state.hcounter >= 1280) << 2; //horizontal blank
|
||||
result |= io.command.bit(5) << 1; //DMA active
|
||||
result |= Region::PAL() << 0;
|
||||
uint16 result;
|
||||
result.bit( 0) = Region::PAL();
|
||||
result.bit( 1) = io.command.bit(5); //DMA active
|
||||
result.bit( 2) = state.hcounter >= 1280; //horizontal blank
|
||||
result.bit( 3) = state.vcounter >= screenHeight(); //vertical blank
|
||||
result.bit( 4) = io.interlaceMode.bit(0) && state.field;
|
||||
result.bit( 5) = 0; //SCOL
|
||||
result.bit( 6) = 0; //SOVR
|
||||
result.bit( 7) = io.vblankIRQ;
|
||||
result.bit( 8) = 0; //FIFO full
|
||||
result.bit( 9) = 1; //FIFO empty
|
||||
result.bit(10) = 1; //constants (bits 10-15)
|
||||
result.bit(11) = 0;
|
||||
result.bit(12) = 1;
|
||||
result.bit(13) = 1;
|
||||
result.bit(14) = 0;
|
||||
result.bit(15) = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,4 @@
|
||||
auto VDP::frame() -> void {
|
||||
latch.overscan = io.overscan;
|
||||
}
|
||||
|
||||
auto VDP::scanline() -> void {
|
||||
state.hdot = 0;
|
||||
state.hcounter = 0;
|
||||
if(++state.vcounter >= frameHeight()) state.vcounter = 0;
|
||||
if(state.vcounter == 0) frame();
|
||||
|
||||
latch.displayWidth = io.displayWidth;
|
||||
|
||||
if(state.vcounter < screenHeight()) {
|
||||
planeA.scanline(state.vcounter);
|
||||
window.scanline(state.vcounter);
|
||||
@@ -31,22 +20,45 @@ auto VDP::run() -> void {
|
||||
planeB.run(state.hdot, state.vcounter);
|
||||
sprite.run(state.hdot, state.vcounter);
|
||||
|
||||
auto output = io.backgroundColor;
|
||||
if(auto color = planeB.output.color) output = color;
|
||||
if(auto color = planeA.output.color) output = color;
|
||||
if(auto color = sprite.output.color) output = color;
|
||||
if(planeB.output.priority) if(auto color = planeB.output.color) output = color;
|
||||
if(planeA.output.priority) if(auto color = planeA.output.color) output = color;
|
||||
if(sprite.output.priority) if(auto color = sprite.output.color) output = color;
|
||||
Pixel g = {io.backgroundColor, 0};
|
||||
Pixel a = planeA.output;
|
||||
Pixel b = planeB.output;
|
||||
Pixel s = sprite.output;
|
||||
|
||||
outputPixel(cram.read(output));
|
||||
state.hdot++;
|
||||
auto& bg = a.above() || a.color && !b.above() ? a : b.color ? b : g;
|
||||
auto& fg = s.above() || s.color && !b.above() && !a.above() ? s : bg;
|
||||
|
||||
if(!io.shadowHighlightEnable) {
|
||||
auto color = cram.read(fg.color);
|
||||
outputPixel(1 << 9 | color);
|
||||
} else {
|
||||
uint mode = a.priority || b.priority; //0 = shadow, 1 = normal, 2 = highlight
|
||||
|
||||
if(&fg == &s) switch(s.color) {
|
||||
case 0x0e:
|
||||
case 0x1e:
|
||||
case 0x2e: mode = 1; break;
|
||||
case 0x3e: mode += 1; fg = bg; break;
|
||||
case 0x3f: mode = 0; fg = bg; break;
|
||||
default: mode |= s.priority; break;
|
||||
}
|
||||
|
||||
auto color = cram.read(fg.color);
|
||||
outputPixel(mode << 9 | color);
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::outputPixel(uint9 color) -> void {
|
||||
for(auto n : range(pixelWidth())) {
|
||||
state.output[ 0 + n] = color;
|
||||
state.output[1280 + n] = color;
|
||||
auto VDP::outputPixel(uint32 color) -> void {
|
||||
uint32* field[2] = {&state.output[0], &state.output[1280]};
|
||||
if(!io.interlaceMode.bit(0)) {
|
||||
for(auto n : range(pixelWidth())) {
|
||||
field[0][n] = color;
|
||||
field[1][n] = color;
|
||||
}
|
||||
} else {
|
||||
for(auto n : range(pixelWidth())) {
|
||||
field[state.field][n] = color;
|
||||
}
|
||||
}
|
||||
state.output += pixelWidth();
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ auto VDP::serialize(serializer& s) -> void {
|
||||
vsram.serialize(s);
|
||||
cram.serialize(s);
|
||||
|
||||
s.integer(io.vblankIRQ);
|
||||
s.integer(io.command);
|
||||
s.integer(io.address);
|
||||
s.integer(io.commandPending);
|
||||
@@ -43,6 +44,7 @@ auto VDP::serialize(serializer& s) -> void {
|
||||
s.integer(state.hdot);
|
||||
s.integer(state.hcounter);
|
||||
s.integer(state.vcounter);
|
||||
s.integer(state.field);
|
||||
}
|
||||
|
||||
auto VDP::DMA::serialize(serializer& s) -> void {
|
||||
@@ -73,6 +75,19 @@ auto VDP::Background::serialize(serializer& s) -> void {
|
||||
s.integer(output.priority);
|
||||
}
|
||||
|
||||
auto VDP::Object::serialize(serializer& s) -> void {
|
||||
s.integer(x);
|
||||
s.integer(y);
|
||||
s.integer(tileWidth);
|
||||
s.integer(tileHeight);
|
||||
s.integer(horizontalFlip);
|
||||
s.integer(verticalFlip);
|
||||
s.integer(palette);
|
||||
s.integer(priority);
|
||||
s.integer(address);
|
||||
s.integer(link);
|
||||
}
|
||||
|
||||
auto VDP::Sprite::serialize(serializer& s) -> void {
|
||||
s.integer(io.attributeAddress);
|
||||
s.integer(io.nametableAddressBase);
|
||||
@@ -80,8 +95,8 @@ auto VDP::Sprite::serialize(serializer& s) -> void {
|
||||
s.integer(output.color);
|
||||
s.integer(output.priority);
|
||||
|
||||
//todo: serialize oam
|
||||
//todo: serialize objects
|
||||
for(uint n : range(80)) oam[n].serialize(s);
|
||||
for(uint n : range(20)) objects[n].serialize(s);
|
||||
}
|
||||
|
||||
auto VDP::VRAM::serialize(serializer& s) -> void {
|
||||
|
@@ -1,3 +1,11 @@
|
||||
auto VDP::Object::width() const -> uint {
|
||||
return 1 + tileWidth << 3;
|
||||
}
|
||||
|
||||
auto VDP::Object::height() const -> uint {
|
||||
return 1 + tileHeight << 3 + (vdp.io.interlaceMode == 3);
|
||||
}
|
||||
|
||||
auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
|
||||
if(address > 320) return;
|
||||
|
||||
@@ -5,19 +13,19 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
|
||||
switch(address.bits(0,1)) {
|
||||
|
||||
case 0: {
|
||||
object.y = data.bits(0,8);
|
||||
object.y = data.bits(0,9);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
object.link = data.bits(0,6);
|
||||
object.height = 1 + data.bits(8,9) << 3;
|
||||
object.width = 1 + data.bits(10,11) << 3;
|
||||
object.tileHeight = data.bits(8,9);
|
||||
object.tileWidth = data.bits(10,11);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
object.address = data.bits(0,10) << 4;
|
||||
object.address = data.bits(0,10);
|
||||
object.horizontalFlip = data.bit(11);
|
||||
object.verticalFlip = data.bit(12);
|
||||
object.palette = data.bits(13,14);
|
||||
@@ -34,6 +42,10 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
|
||||
}
|
||||
|
||||
auto VDP::Sprite::scanline(uint y) -> void {
|
||||
bool interlace = vdp.io.interlaceMode == 3;
|
||||
y += 128;
|
||||
if(interlace) y = y << 1 | vdp.state.field;
|
||||
|
||||
objects.reset();
|
||||
|
||||
uint7 link = 0;
|
||||
@@ -43,46 +55,51 @@ auto VDP::Sprite::scanline(uint y) -> void {
|
||||
auto& object = oam[link];
|
||||
link = object.link;
|
||||
|
||||
if(128 + y < object.y) continue;
|
||||
if(128 + y >= object.y + object.height) continue;
|
||||
if(y < object.y) continue;
|
||||
if(y >= object.y + object.height()) continue;
|
||||
if(object.x == 0) break;
|
||||
|
||||
objects.append(object);
|
||||
tiles += object.width >> 3;
|
||||
tiles += object.width() >> 3;
|
||||
} while(link && link < 80 && objects.size() < 20 && tiles < 40 && ++count < 80);
|
||||
}
|
||||
|
||||
auto VDP::Sprite::run(uint x, uint y) -> void {
|
||||
bool interlace = vdp.io.interlaceMode == 3;
|
||||
x += 128;
|
||||
y += 128;
|
||||
if(interlace) y = y << 1 | vdp.state.field;
|
||||
|
||||
output.priority = 0;
|
||||
output.color = 0;
|
||||
|
||||
for(auto& o : objects) {
|
||||
if(128 + x < o.x) continue;
|
||||
if(128 + x >= o.x + o.width) continue;
|
||||
for(auto& object : objects) {
|
||||
if(x < object.x) continue;
|
||||
if(x >= object.x + object.width()) continue;
|
||||
|
||||
uint objectX = 128 + x - o.x;
|
||||
uint objectY = 128 + y - o.y;
|
||||
if(o.horizontalFlip) objectX = (o.width - 1) - objectX;
|
||||
if(o.verticalFlip) objectY = (o.height - 1) - objectY;
|
||||
uint objectX = x - object.x;
|
||||
uint objectY = y - object.y;
|
||||
if(object.horizontalFlip) objectX = (object.width() - 1) - objectX;
|
||||
if(object.verticalFlip) objectY = (object.height() - 1) - objectY;
|
||||
|
||||
uint tileX = objectX >> 3;
|
||||
uint tileY = objectY >> 3;
|
||||
uint tileNumber = tileX * (o.height >> 3) + tileY;
|
||||
uint15 tileAddress = o.address + (tileNumber << 4);
|
||||
uint tileY = objectY >> 3 + interlace;
|
||||
uint tileNumber = tileX * (object.height() >> 3 + interlace) + tileY;
|
||||
uint15 tileAddress = object.address + tileNumber << 4 + interlace;
|
||||
uint pixelX = objectX & 7;
|
||||
uint pixelY = objectY & 7;
|
||||
uint pixelY = objectY & 7 + interlace * 8;
|
||||
tileAddress += pixelY << 1 | pixelX >> 2;
|
||||
|
||||
uint16 tileData = vdp.vram.read(tileAddress);
|
||||
uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2);
|
||||
if(color) {
|
||||
output.color = o.palette << 4 | color;
|
||||
output.priority = o.priority;
|
||||
break;
|
||||
}
|
||||
if(!color) continue;
|
||||
|
||||
output.color = object.palette << 4 | color;
|
||||
output.priority = object.priority;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::Sprite::power() -> void {
|
||||
memory::fill(&io, sizeof(IO));
|
||||
io = {};
|
||||
}
|
||||
|
@@ -23,11 +23,13 @@ auto VDP::main() -> void {
|
||||
|
||||
if(state.vcounter == 0) {
|
||||
latch.horizontalInterruptCounter = io.horizontalInterruptCounter;
|
||||
io.vblankIRQ = false;
|
||||
cpu.lower(CPU::Interrupt::VerticalBlank);
|
||||
}
|
||||
|
||||
if(state.vcounter == screenHeight()) {
|
||||
if(io.verticalBlankInterruptEnable) {
|
||||
io.vblankIRQ = true;
|
||||
cpu.raise(CPU::Interrupt::VerticalBlank);
|
||||
}
|
||||
//todo: should only stay high for ~2573/2 clocks
|
||||
@@ -37,6 +39,7 @@ auto VDP::main() -> void {
|
||||
if(state.vcounter < screenHeight()) {
|
||||
while(state.hcounter < 1280) {
|
||||
run();
|
||||
state.hdot++;
|
||||
step(pixelWidth());
|
||||
}
|
||||
|
||||
@@ -51,6 +54,15 @@ auto VDP::main() -> void {
|
||||
} else {
|
||||
step(1710);
|
||||
}
|
||||
|
||||
state.hdot = 0;
|
||||
state.hcounter = 0;
|
||||
if(++state.vcounter >= frameHeight()) {
|
||||
state.vcounter = 0;
|
||||
state.field ^= 1;
|
||||
latch.overscan = io.overscan;
|
||||
}
|
||||
latch.displayWidth = io.displayWidth;
|
||||
}
|
||||
|
||||
auto VDP::step(uint clocks) -> void {
|
||||
@@ -69,14 +81,20 @@ auto VDP::refresh() -> void {
|
||||
Emulator::video.refresh(data, 1280 * sizeof(uint32), 1280, 480);
|
||||
}
|
||||
|
||||
auto VDP::power() -> void {
|
||||
auto VDP::power(bool reset) -> void {
|
||||
create(VDP::Enter, system.frequency() / 2.0);
|
||||
|
||||
output = buffer + 16 * 1280; //overscan offset
|
||||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
memory::fill(&latch, sizeof(Latch));
|
||||
memory::fill(&state, sizeof(State));
|
||||
if(!reset) {
|
||||
for(auto& data : vram.memory) data = 0;
|
||||
for(auto& data : vsram.memory) data = 0;
|
||||
for(auto& data : cram.memory) data = 0;
|
||||
}
|
||||
|
||||
io = {};
|
||||
latch = {};
|
||||
state = {};
|
||||
|
||||
planeA.power();
|
||||
window.power();
|
||||
|
@@ -6,7 +6,7 @@ struct VDP : Thread {
|
||||
auto step(uint clocks) -> void;
|
||||
auto refresh() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto read(uint24 addr) -> uint16;
|
||||
@@ -41,10 +41,17 @@ struct VDP : Thread {
|
||||
} dma;
|
||||
|
||||
//render.cpp
|
||||
auto frame() -> void;
|
||||
auto scanline() -> void;
|
||||
auto run() -> void;
|
||||
auto outputPixel(uint9 color) -> void;
|
||||
auto outputPixel(uint32 color) -> void;
|
||||
|
||||
struct Pixel {
|
||||
inline auto above() const -> bool { return priority == 1 && color; }
|
||||
inline auto below() const -> bool { return priority == 0 && color; }
|
||||
|
||||
uint6 color;
|
||||
uint1 priority;
|
||||
};
|
||||
|
||||
struct Background {
|
||||
enum class ID : uint { PlaneA, Window, PlaneB } id;
|
||||
@@ -53,7 +60,7 @@ struct VDP : Thread {
|
||||
auto isWindowed(uint x, uint y) -> bool;
|
||||
|
||||
auto updateHorizontalScroll(uint y) -> void;
|
||||
auto updateVerticalScroll(uint x, uint y) -> void;
|
||||
auto updateVerticalScroll(uint x) -> void;
|
||||
|
||||
auto nametableAddress() -> uint15;
|
||||
auto nametableWidth() -> uint;
|
||||
@@ -89,15 +96,32 @@ struct VDP : Thread {
|
||||
uint10 verticalScroll;
|
||||
} state;
|
||||
|
||||
struct Output {
|
||||
uint6 color;
|
||||
uint1 priority;
|
||||
} output;
|
||||
Pixel output;
|
||||
};
|
||||
Background planeA{Background::ID::PlaneA};
|
||||
Background window{Background::ID::Window};
|
||||
Background planeB{Background::ID::PlaneB};
|
||||
|
||||
struct Object {
|
||||
//sprite.cpp
|
||||
inline auto width() const -> uint;
|
||||
inline auto height() const -> uint;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint9 x;
|
||||
uint10 y;
|
||||
uint2 tileWidth;
|
||||
uint2 tileHeight;
|
||||
uint1 horizontalFlip;
|
||||
uint1 verticalFlip;
|
||||
uint2 palette;
|
||||
uint1 priority;
|
||||
uint11 address;
|
||||
uint7 link;
|
||||
};
|
||||
|
||||
struct Sprite {
|
||||
//sprite.cpp
|
||||
auto write(uint9 addr, uint16 data) -> void;
|
||||
@@ -114,23 +138,7 @@ struct VDP : Thread {
|
||||
uint1 nametableAddressBase;
|
||||
} io;
|
||||
|
||||
struct Object {
|
||||
uint9 x;
|
||||
uint9 y;
|
||||
uint width;
|
||||
uint height;
|
||||
bool horizontalFlip;
|
||||
bool verticalFlip;
|
||||
uint2 palette;
|
||||
uint1 priority;
|
||||
uint15 address;
|
||||
uint7 link;
|
||||
};
|
||||
|
||||
struct Output {
|
||||
uint6 color;
|
||||
uint1 priority;
|
||||
} output;
|
||||
Pixel output;
|
||||
|
||||
array<Object, 80> oam;
|
||||
array<Object, 20> objects;
|
||||
@@ -158,7 +166,6 @@ private:
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint16 memory[32768];
|
||||
} vram;
|
||||
|
||||
@@ -171,7 +178,6 @@ private:
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint10 memory[40];
|
||||
} vsram;
|
||||
|
||||
@@ -184,11 +190,13 @@ private:
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint9 memory[64];
|
||||
} cram;
|
||||
|
||||
struct IO {
|
||||
//status
|
||||
uint1 vblankIRQ; //true after VIRQ triggers; cleared at start of next frame
|
||||
|
||||
//command
|
||||
uint6 command;
|
||||
uint16 address;
|
||||
@@ -243,13 +251,16 @@ private:
|
||||
|
||||
struct State {
|
||||
uint32* output = nullptr;
|
||||
uint hdot;
|
||||
uint hcounter;
|
||||
uint vcounter;
|
||||
uint16 hdot;
|
||||
uint16 hcounter;
|
||||
uint16 vcounter;
|
||||
uint1 field;
|
||||
} state;
|
||||
|
||||
uint32 buffer[1280 * 512];
|
||||
uint32* output = nullptr;
|
||||
|
||||
friend class Interface;
|
||||
};
|
||||
|
||||
extern VDP vdp;
|
||||
|
@@ -154,7 +154,7 @@ auto YM2612::step(uint clocks) -> void {
|
||||
synchronize(apu);
|
||||
}
|
||||
|
||||
auto YM2612::power() -> void {
|
||||
auto YM2612::power(bool reset) -> void {
|
||||
create(YM2612::Enter, system.frequency() / 7.0);
|
||||
stream = Emulator::audio.createStream(2, frequency() / 144.0);
|
||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
||||
|
@@ -8,7 +8,7 @@ struct YM2612 : Thread {
|
||||
auto sample() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto power(bool reset) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto readStatus() -> uint8;
|
||||
|
@@ -17,7 +17,7 @@ auto Cartridge::load() -> bool {
|
||||
}
|
||||
|
||||
if(Model::GameGear()) {
|
||||
if(auto loaded = platform->load(ID::GameGear, "Game Gear", "gg")) {
|
||||
if(auto loaded = platform->load(ID::GameGear, "Game Gear", "gg", {"NTSC"})) {
|
||||
information.pathID = loaded.pathID();
|
||||
} else return false;
|
||||
}
|
||||
|
@@ -21,8 +21,15 @@ GameGearInterface::GameGearInterface() {
|
||||
ports.append(move(hardware));
|
||||
}
|
||||
|
||||
auto GameGearInterface::videoResolution() -> VideoResolution {
|
||||
return {160, 144, 160, 144, 1.0};
|
||||
auto GameGearInterface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 160;
|
||||
vi.height = 144;
|
||||
vi.internalWidth = 160;
|
||||
vi.internalHeight = 144;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto GameGearInterface::videoColors() -> uint32 {
|
||||
|
@@ -50,7 +50,7 @@ struct MasterSystemInterface : Interface {
|
||||
|
||||
MasterSystemInterface();
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
@@ -64,7 +64,7 @@ struct GameGearInterface : Interface {
|
||||
|
||||
GameGearInterface();
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
|
@@ -36,8 +36,16 @@ MasterSystemInterface::MasterSystemInterface() {
|
||||
ports.append(move(hardware));
|
||||
}
|
||||
|
||||
auto MasterSystemInterface::videoResolution() -> VideoResolution {
|
||||
return {256, 240, 256, 240, 8.0 / 7.0};
|
||||
auto MasterSystemInterface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 256;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 256;
|
||||
vi.internalHeight = 240;
|
||||
vi.aspectCorrection = 8.0 / 7.0;
|
||||
if(Region::NTSC()) vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
if(Region::PAL()) vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto MasterSystemInterface::videoColors() -> uint32 {
|
||||
|
@@ -48,6 +48,8 @@ auto VDP::Background::run() -> void {
|
||||
output.color.bit(1) = vdp.vram[patternAddress + 1].bit(index);
|
||||
output.color.bit(2) = vdp.vram[patternAddress + 2].bit(index);
|
||||
output.color.bit(3) = vdp.vram[patternAddress + 3].bit(index);
|
||||
|
||||
if(output.color == 0) output.priority = 0;
|
||||
}
|
||||
|
||||
auto VDP::Background::power() -> void {
|
||||
|
@@ -38,13 +38,14 @@ auto VDP::main() -> void {
|
||||
sprite.run();
|
||||
step(2);
|
||||
|
||||
uint12 color = palette(io.backdropColor);
|
||||
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||
color = palette(background.output.palette << 4 | background.output.color);
|
||||
} else if(sprite.output.color) {
|
||||
color = palette(16 | sprite.output.color);
|
||||
uint12 color = palette(16 | io.backdropColor);
|
||||
if(!io.leftClip || x >= 8) {
|
||||
if(background.output.priority || !sprite.output.color) {
|
||||
color = palette(background.output.palette << 4 | background.output.color);
|
||||
} else if(sprite.output.color) {
|
||||
color = palette(16 | sprite.output.color);
|
||||
}
|
||||
}
|
||||
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||
if(!io.displayEnable) color = 0;
|
||||
*screen++ = color;
|
||||
}
|
||||
|
@@ -39,8 +39,15 @@ auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoResolution() -> VideoResolution {
|
||||
return {280, 240, 1120, 240, 8.0 / 7.0};
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 280;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 1120;
|
||||
vi.internalHeight = 240;
|
||||
vi.aspectCorrection = 8.0 / 7.0;
|
||||
vi.refreshRate = (system.colorburst() * 6.0) / (262.0 * 1365.0);
|
||||
return vi;
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
|
@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoResolution() -> VideoResolution override;
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
|
@@ -65,6 +65,13 @@ struct HuC6280 {
|
||||
auto instructionAbsoluteWrite(uint8, uint8 = 0) -> void;
|
||||
auto instructionBlockMove(bp) -> void;
|
||||
auto instructionBranch(bool) -> void;
|
||||
auto instructionBranchIfBitReset(uint3) -> void;
|
||||
auto instructionBranchIfBitSet(uint3) -> void;
|
||||
auto instructionBranchSubroutine() -> void;
|
||||
auto instructionBreak() -> void;
|
||||
auto instructionCallAbsolute() -> void;
|
||||
auto instructionChangeSpeedLow() -> void;
|
||||
auto instructionChangeSpeedHigh() -> void;
|
||||
auto instructionClear(uint8&) -> void;
|
||||
auto instructionClear(bool&) -> void;
|
||||
auto instructionImmediate(fp, uint8&) -> void;
|
||||
@@ -73,38 +80,30 @@ struct HuC6280 {
|
||||
auto instructionIndirectWrite(uint8, uint8 = 0) -> void;
|
||||
auto instructionIndirectYRead(fp, uint8&) -> void;
|
||||
auto instructionIndirectYWrite(uint8) -> void;
|
||||
auto instructionJumpAbsolute() -> void;
|
||||
auto instructionJumpIndirect(uint8 = 0) -> void;
|
||||
auto instructionMemory(fp) -> void;
|
||||
auto instructionNoOperation() -> void;
|
||||
auto instructionPull(uint8&) -> void;
|
||||
auto instructionPullP() -> void;
|
||||
auto instructionPush(uint8) -> void;
|
||||
auto instructionResetMemoryBit(uint3) -> void;
|
||||
auto instructionReturnInterrupt() -> void;
|
||||
auto instructionReturnSubroutine() -> void;
|
||||
auto instructionSet(bool&) -> void;
|
||||
auto instructionSetMemoryBit(uint3) -> void;
|
||||
auto instructionStoreImplied(uint2) -> void;
|
||||
auto instructionSwap(uint8&, uint8&) -> void;
|
||||
auto instructionTestAbsolute(uint8 = 0) -> void;
|
||||
auto instructionTestZeroPage(uint8 = 0) -> void;
|
||||
auto instructionTransfer(uint8&, uint8&) -> void;
|
||||
auto instructionTransferAccumulatorToMPR() -> void;
|
||||
auto instructionTransferMPRToAccumulator() -> void;
|
||||
auto instructionTransferXS() -> void;
|
||||
auto instructionZeroPageModify(fp, uint8 = 0) -> void;
|
||||
auto instructionZeroPageRead(fp, uint8&, uint8 = 0) -> void;
|
||||
auto instructionZeroPageWrite(uint8, uint8 = 0) -> void;
|
||||
|
||||
auto instructionBBR(uint3) -> void;
|
||||
auto instructionBBS(uint3) -> void;
|
||||
auto instructionBRK() -> void;
|
||||
auto instructionBSR() -> void;
|
||||
auto instructionCSL() -> void;
|
||||
auto instructionCSH() -> void;
|
||||
auto instructionJMPAbsolute() -> void;
|
||||
auto instructionJMPIndirect(uint8 = 0) -> void;
|
||||
auto instructionJSR() -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionPLP() -> void;
|
||||
auto instructionRMB(uint3) -> void;
|
||||
auto instructionRTI() -> void;
|
||||
auto instructionRTS() -> void;
|
||||
auto instructionSMB(uint3) -> void;
|
||||
auto instructionST(uint2) -> void;
|
||||
auto instructionTAM() -> void;
|
||||
auto instructionTMA() -> void;
|
||||
auto instructionTSTAbsolute(uint8 = 0) -> void;
|
||||
auto instructionTSTZeroPage(uint8 = 0) -> void;
|
||||
auto instructionTXS() -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
|
||||
|
@@ -28,118 +28,118 @@ auto HuC6280::instruction() -> void {
|
||||
|
||||
#define U
|
||||
switch(code) {
|
||||
op(0x00, BRK)
|
||||
op(0x00, Break)
|
||||
op(0x01, IndirectRead, fp(ORA), A, X)
|
||||
op(0x02, Swap, X, Y)
|
||||
op(0x03, ST, 0)
|
||||
op(0x03, StoreImplied, 0)
|
||||
op(0x04, ZeroPageModify, fp(TSB))
|
||||
op(0x05, ZeroPageRead, fp(ORA), A)
|
||||
op(0x06, ZeroPageModify, fp(ASL))
|
||||
op(0x07, RMB, 0)
|
||||
op(0x07, ResetMemoryBit, 0)
|
||||
op(0x08, Push, P)
|
||||
op(0x09, Immediate, fp(ORA), A)
|
||||
op(0x0a, Implied, fp(ASL), A)
|
||||
U op(0x0b, NOP)
|
||||
U op(0x0b, NoOperation)
|
||||
op(0x0c, AbsoluteModify, fp(TSB))
|
||||
op(0x0d, AbsoluteRead, fp(ORA), A)
|
||||
op(0x0e, AbsoluteModify, fp(ASL))
|
||||
op(0x0f, BBR, 0)
|
||||
op(0x0f, BranchIfBitReset, 0)
|
||||
op(0x10, Branch, N == 0)
|
||||
op(0x11, IndirectYRead, fp(ORA), A)
|
||||
op(0x12, IndirectRead, fp(ORA), A)
|
||||
op(0x13, ST, 1)
|
||||
op(0x13, StoreImplied, 1)
|
||||
op(0x14, ZeroPageModify, fp(TRB))
|
||||
op(0x15, ZeroPageRead, fp(ORA), A, X)
|
||||
op(0x16, ZeroPageModify, fp(ASL), X)
|
||||
op(0x17, RMB, 1)
|
||||
op(0x17, ResetMemoryBit, 1)
|
||||
op(0x18, Clear, C)
|
||||
op(0x19, AbsoluteRead, fp(ORA), A, Y)
|
||||
op(0x1a, Implied, fp(INC), A)
|
||||
U op(0x1b, NOP)
|
||||
U op(0x1b, NoOperation)
|
||||
op(0x1c, AbsoluteModify, fp(TRB))
|
||||
op(0x1d, AbsoluteRead, fp(ORA), A, X)
|
||||
op(0x1e, AbsoluteModify, fp(ASL), X)
|
||||
op(0x1f, BBR, 1)
|
||||
op(0x20, JSR)
|
||||
op(0x1f, BranchIfBitReset, 1)
|
||||
op(0x20, CallAbsolute)
|
||||
op(0x21, IndirectRead, fp(AND), A, X)
|
||||
op(0x22, Swap, A, X)
|
||||
op(0x23, ST, 2)
|
||||
op(0x23, StoreImplied, 2)
|
||||
op(0x24, ZeroPageRead, fp(BIT), A)
|
||||
op(0x25, ZeroPageRead, fp(AND), A)
|
||||
op(0x26, ZeroPageModify, fp(ROL))
|
||||
op(0x27, RMB, 2)
|
||||
op(0x28, PLP)
|
||||
op(0x27, ResetMemoryBit, 2)
|
||||
op(0x28, PullP)
|
||||
op(0x29, Immediate, fp(AND), A)
|
||||
op(0x2a, Implied, fp(ROL), A)
|
||||
U op(0x2b, NOP)
|
||||
U op(0x2b, NoOperation)
|
||||
op(0x2c, AbsoluteRead, fp(BIT), A)
|
||||
op(0x2d, AbsoluteRead, fp(AND), A)
|
||||
op(0x2e, AbsoluteModify, fp(ROL))
|
||||
op(0x2f, BBR, 2)
|
||||
op(0x2f, BranchIfBitReset, 2)
|
||||
op(0x30, Branch, N == 1)
|
||||
op(0x31, IndirectYRead, fp(AND), A)
|
||||
op(0x32, IndirectRead, fp(AND), A)
|
||||
U op(0x33, NOP)
|
||||
U op(0x33, NoOperation)
|
||||
op(0x34, ZeroPageRead, fp(BIT), A, X)
|
||||
op(0x35, ZeroPageRead, fp(AND), A, X)
|
||||
op(0x36, ZeroPageModify, fp(ROL), X)
|
||||
op(0x37, RMB, 3)
|
||||
op(0x37, ResetMemoryBit, 3)
|
||||
op(0x38, Set, C)
|
||||
op(0x39, AbsoluteRead, fp(AND), A, Y)
|
||||
op(0x3a, Implied, fp(DEC), A)
|
||||
U op(0x3b, NOP)
|
||||
U op(0x3b, NoOperation)
|
||||
op(0x3c, AbsoluteRead, fp(BIT), A, X)
|
||||
op(0x3d, AbsoluteRead, fp(AND), A, X)
|
||||
op(0x3e, AbsoluteModify, fp(ROL), X)
|
||||
op(0x3f, BBR, 3)
|
||||
op(0x40, RTI)
|
||||
op(0x3f, BranchIfBitReset, 3)
|
||||
op(0x40, ReturnInterrupt)
|
||||
op(0x41, IndirectRead, fp(EOR), A, X)
|
||||
op(0x42, Swap, A, Y)
|
||||
op(0x43, TMA)
|
||||
op(0x44, BSR)
|
||||
op(0x43, TransferMPRToAccumulator)
|
||||
op(0x44, BranchSubroutine)
|
||||
op(0x45, ZeroPageRead, fp(EOR), A)
|
||||
op(0x46, ZeroPageModify, fp(LSR))
|
||||
op(0x47, RMB, 4)
|
||||
op(0x47, ResetMemoryBit, 4)
|
||||
op(0x48, Push, A)
|
||||
op(0x49, Immediate, fp(EOR), A)
|
||||
op(0x4a, Implied, fp(LSR), A)
|
||||
U op(0x4b, NOP)
|
||||
op(0x4c, JMPAbsolute)
|
||||
U op(0x4b, NoOperation)
|
||||
op(0x4c, JumpAbsolute)
|
||||
op(0x4d, AbsoluteRead, fp(EOR), A)
|
||||
op(0x4e, AbsoluteModify, fp(LSR))
|
||||
op(0x4f, BBR, 4)
|
||||
op(0x4f, BranchIfBitReset, 4)
|
||||
op(0x50, Branch, V == 0)
|
||||
op(0x51, IndirectYRead, fp(EOR), A)
|
||||
op(0x52, IndirectRead, fp(EOR), A)
|
||||
op(0x53, TAM)
|
||||
op(0x54, CSL)
|
||||
op(0x53, TransferAccumulatorToMPR)
|
||||
op(0x54, ChangeSpeedLow)
|
||||
op(0x55, ZeroPageRead, fp(EOR), A, X)
|
||||
op(0x56, ZeroPageModify, fp(LSR), X)
|
||||
op(0x57, RMB, 5)
|
||||
op(0x57, ResetMemoryBit, 5)
|
||||
op(0x58, Clear, I)
|
||||
op(0x59, AbsoluteRead, fp(EOR), A, Y)
|
||||
op(0x5a, Push, Y)
|
||||
U op(0x5b, NOP)
|
||||
U op(0x5c, NOP)
|
||||
U op(0x5b, NoOperation)
|
||||
U op(0x5c, NoOperation)
|
||||
op(0x5d, AbsoluteRead, fp(EOR), A, X)
|
||||
op(0x5e, AbsoluteModify, fp(LSR), X)
|
||||
op(0x5f, BBR, 5)
|
||||
op(0x60, RTS)
|
||||
op(0x5f, BranchIfBitReset, 5)
|
||||
op(0x60, ReturnSubroutine)
|
||||
op(0x61, IndirectRead, fp(ADC), A, X)
|
||||
op(0x62, Clear, A)
|
||||
U op(0x63, NOP)
|
||||
U op(0x63, NoOperation)
|
||||
op(0x64, ZeroPageWrite, 0)
|
||||
op(0x65, ZeroPageRead, fp(ADC), A)
|
||||
op(0x66, ZeroPageModify, fp(ROR))
|
||||
op(0x67, RMB, 6)
|
||||
op(0x67, ResetMemoryBit, 6)
|
||||
op(0x68, Pull, A)
|
||||
op(0x69, Immediate, fp(ADC), A)
|
||||
op(0x6a, Implied, fp(ROR), A)
|
||||
U op(0x6b, NOP)
|
||||
op(0x6c, JMPIndirect)
|
||||
U op(0x6b, NoOperation)
|
||||
op(0x6c, JumpIndirect)
|
||||
op(0x6d, AbsoluteRead, fp(ADC), A)
|
||||
op(0x6e, AbsoluteModify, fp(ROR))
|
||||
op(0x6f, BBR, 6)
|
||||
op(0x6f, BranchIfBitReset, 6)
|
||||
op(0x70, Branch, V == 1)
|
||||
op(0x71, IndirectYRead, fp(ADC), A)
|
||||
op(0x72, IndirectRead, fp(ADC), A)
|
||||
@@ -147,79 +147,79 @@ U op(0x6b, NOP)
|
||||
op(0x74, ZeroPageWrite, 0, X)
|
||||
op(0x75, ZeroPageRead, fp(ADC), A, X)
|
||||
op(0x76, ZeroPageModify, fp(ROR), X)
|
||||
op(0x77, RMB, 7)
|
||||
op(0x77, ResetMemoryBit, 7)
|
||||
op(0x78, Set, I)
|
||||
op(0x79, AbsoluteRead, fp(ADC), A, Y)
|
||||
op(0x7a, Pull, Y)
|
||||
U op(0x7b, NOP)
|
||||
op(0x7c, JMPIndirect, X)
|
||||
U op(0x7b, NoOperation)
|
||||
op(0x7c, JumpIndirect, X)
|
||||
op(0x7d, AbsoluteRead, fp(ADC), A, X)
|
||||
op(0x7e, AbsoluteModify, fp(ROR), X)
|
||||
op(0x7f, BBR, 7)
|
||||
op(0x7f, BranchIfBitReset, 7)
|
||||
op(0x80, Branch, 1)
|
||||
op(0x81, IndirectWrite, A, X)
|
||||
op(0x82, Clear, X)
|
||||
op(0x83, TSTZeroPage)
|
||||
op(0x83, TestZeroPage)
|
||||
op(0x84, ZeroPageWrite, Y)
|
||||
op(0x85, ZeroPageWrite, A)
|
||||
op(0x86, ZeroPageWrite, X)
|
||||
op(0x87, SMB, 0)
|
||||
op(0x87, SetMemoryBit, 0)
|
||||
op(0x88, Implied, fp(DEC), Y)
|
||||
op(0x89, Immediate, fp(BIT), A)
|
||||
op(0x8a, Transfer, X, A)
|
||||
U op(0x8b, NOP)
|
||||
U op(0x8b, NoOperation)
|
||||
op(0x8c, AbsoluteWrite, Y)
|
||||
op(0x8d, AbsoluteWrite, A)
|
||||
op(0x8e, AbsoluteWrite, X)
|
||||
op(0x8f, BBS, 0)
|
||||
op(0x8f, BranchIfBitSet, 0)
|
||||
op(0x90, Branch, C == 0)
|
||||
op(0x91, IndirectYWrite, A)
|
||||
op(0x92, IndirectWrite, A)
|
||||
op(0x93, TSTAbsolute)
|
||||
op(0x93, TestAbsolute)
|
||||
op(0x94, ZeroPageWrite, Y, X)
|
||||
op(0x95, ZeroPageWrite, A, X)
|
||||
op(0x96, ZeroPageWrite, X, Y)
|
||||
op(0x97, SMB, 1)
|
||||
op(0x97, SetMemoryBit, 1)
|
||||
op(0x98, Transfer, Y, A)
|
||||
op(0x99, AbsoluteWrite, A, Y)
|
||||
op(0x9a, TXS)
|
||||
U op(0x9b, NOP)
|
||||
op(0x9a, TransferXS)
|
||||
U op(0x9b, NoOperation)
|
||||
op(0x9c, AbsoluteWrite, 0)
|
||||
op(0x9d, AbsoluteWrite, A, X)
|
||||
op(0x9e, AbsoluteWrite, 0, X)
|
||||
op(0x9f, BBS, 1)
|
||||
op(0x9f, BranchIfBitSet, 1)
|
||||
op(0xa0, Immediate, fp(LD), Y)
|
||||
op(0xa1, IndirectRead, fp(LD), A, X)
|
||||
op(0xa2, Immediate, fp(LD), X)
|
||||
op(0xa3, TSTZeroPage, X)
|
||||
op(0xa3, TestZeroPage, X)
|
||||
op(0xa4, ZeroPageRead, fp(LD), Y)
|
||||
op(0xa5, ZeroPageRead, fp(LD), A)
|
||||
op(0xa6, ZeroPageRead, fp(LD), X)
|
||||
op(0xa7, SMB, 2)
|
||||
op(0xa7, SetMemoryBit, 2)
|
||||
op(0xa8, Transfer, A, Y)
|
||||
op(0xa9, Immediate, fp(LD), A)
|
||||
op(0xaa, Transfer, A, X)
|
||||
U op(0xab, NOP)
|
||||
U op(0xab, NoOperation)
|
||||
op(0xac, AbsoluteRead, fp(LD), Y)
|
||||
op(0xad, AbsoluteRead, fp(LD), A)
|
||||
op(0xae, AbsoluteRead, fp(LD), X)
|
||||
op(0xaf, BBS, 2)
|
||||
op(0xaf, BranchIfBitSet, 2)
|
||||
op(0xb0, Branch, C == 1)
|
||||
op(0xb1, IndirectYRead, fp(LD), A)
|
||||
op(0xb2, IndirectRead, fp(LD), A)
|
||||
op(0xb3, TSTAbsolute, X)
|
||||
op(0xb3, TestAbsolute, X)
|
||||
op(0xb4, ZeroPageRead, fp(LD), Y, X)
|
||||
op(0xb5, ZeroPageRead, fp(LD), A, X)
|
||||
op(0xb6, ZeroPageRead, fp(LD), X, Y)
|
||||
op(0xb7, SMB, 3)
|
||||
op(0xb7, SetMemoryBit, 3)
|
||||
op(0xb8, Clear, V)
|
||||
op(0xb9, AbsoluteRead, fp(LD), A, Y)
|
||||
op(0xba, Transfer, S, X)
|
||||
U op(0xbb, NOP)
|
||||
U op(0xbb, NoOperation)
|
||||
op(0xbc, AbsoluteRead, fp(LD), Y, X)
|
||||
op(0xbd, AbsoluteRead, fp(LD), A, X)
|
||||
op(0xbe, AbsoluteRead, fp(LD), X, Y)
|
||||
op(0xbf, BBS, 3)
|
||||
op(0xbf, BranchIfBitSet, 3)
|
||||
op(0xc0, Immediate, fp(CPY), Y)
|
||||
op(0xc1, IndirectRead, fp(CMP), A, X)
|
||||
op(0xc2, Clear, Y)
|
||||
@@ -227,47 +227,47 @@ U op(0xbb, NOP)
|
||||
op(0xc4, ZeroPageRead, fp(CPY), Y)
|
||||
op(0xc5, ZeroPageRead, fp(CMP), A)
|
||||
op(0xc6, ZeroPageModify, fp(DEC))
|
||||
op(0xc7, SMB, 4)
|
||||
op(0xc7, SetMemoryBit, 4)
|
||||
op(0xc8, Implied, fp(INC), Y)
|
||||
op(0xc9, Immediate, fp(CMP), A)
|
||||
op(0xca, Implied, fp(DEC), X)
|
||||
U op(0xcb, NOP)
|
||||
U op(0xcb, NoOperation)
|
||||
op(0xcc, AbsoluteRead, fp(CPY), Y)
|
||||
op(0xcd, AbsoluteRead, fp(CMP), A)
|
||||
op(0xce, AbsoluteModify, fp(DEC))
|
||||
op(0xcf, BBS, 4)
|
||||
op(0xcf, BranchIfBitSet, 4)
|
||||
op(0xd0, Branch, Z == 0)
|
||||
op(0xd1, IndirectYRead, fp(CMP), A)
|
||||
op(0xd2, IndirectRead, fp(CMP), A)
|
||||
op(0xd3, BlockMove, fp(TIN))
|
||||
op(0xd4, CSH)
|
||||
op(0xd4, ChangeSpeedHigh)
|
||||
op(0xd5, ZeroPageRead, fp(CMP), A, X)
|
||||
op(0xd6, ZeroPageModify, fp(DEC), X)
|
||||
op(0xd7, SMB, 5)
|
||||
op(0xd7, SetMemoryBit, 5)
|
||||
op(0xd8, Clear, D)
|
||||
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
|
||||
op(0xda, Push, X)
|
||||
U op(0xdb, NOP)
|
||||
U op(0xdc, NOP)
|
||||
U op(0xdb, NoOperation)
|
||||
U op(0xdc, NoOperation)
|
||||
op(0xdd, AbsoluteRead, fp(CMP), A, X)
|
||||
op(0xde, AbsoluteModify, fp(DEC), X)
|
||||
op(0xdf, BBS, 5)
|
||||
op(0xdf, BranchIfBitSet, 5)
|
||||
op(0xe0, Immediate, fp(CPX), X)
|
||||
op(0xe1, IndirectRead, fp(SBC), A, X)
|
||||
U op(0xe2, NOP)
|
||||
U op(0xe2, NoOperation)
|
||||
op(0xe3, BlockMove, fp(TIA))
|
||||
op(0xe4, ZeroPageRead, fp(CPX), X)
|
||||
op(0xe5, ZeroPageRead, fp(SBC), A)
|
||||
op(0xe6, ZeroPageModify, fp(INC))
|
||||
op(0xe7, SMB, 6)
|
||||
op(0xe7, SetMemoryBit, 6)
|
||||
op(0xe8, Implied, fp(INC), X)
|
||||
op(0xe9, Immediate, fp(SBC), A)
|
||||
op(0xea, NOP)
|
||||
U op(0xeb, NOP)
|
||||
op(0xea, NoOperation)
|
||||
U op(0xeb, NoOperation)
|
||||
op(0xec, AbsoluteRead, fp(CPX), X)
|
||||
op(0xed, AbsoluteRead, fp(SBC), A)
|
||||
op(0xee, AbsoluteModify, fp(INC))
|
||||
op(0xef, BBS, 6)
|
||||
op(0xef, BranchIfBitSet, 6)
|
||||
op(0xf0, Branch, Z == 1)
|
||||
op(0xf1, IndirectYRead, fp(SBC), A)
|
||||
op(0xf2, IndirectRead, fp(SBC), A)
|
||||
@@ -275,15 +275,15 @@ U op(0xeb, NOP)
|
||||
op(0xf4, Set, T)
|
||||
op(0xf5, ZeroPageRead, fp(SBC), A, X)
|
||||
op(0xf6, ZeroPageModify, fp(INC), X)
|
||||
op(0xf7, SMB, 7)
|
||||
op(0xf7, SetMemoryBit, 7)
|
||||
op(0xf8, Set, D)
|
||||
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
|
||||
op(0xfa, Pull, X)
|
||||
U op(0xfb, NOP)
|
||||
U op(0xfc, NOP)
|
||||
U op(0xfb, NoOperation)
|
||||
U op(0xfc, NoOperation)
|
||||
op(0xfd, AbsoluteRead, fp(SBC), A, X)
|
||||
op(0xfe, AbsoluteModify, fp(INC), X)
|
||||
op(0xff, BBS, 7)
|
||||
op(0xff, BranchIfBitSet, 7)
|
||||
}
|
||||
#undef U
|
||||
}
|
||||
|
@@ -62,6 +62,72 @@ auto HuC6280::instructionBranch(bool take) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchIfBitReset(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 0) {
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchIfBitSet(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 1) {
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchSubroutine() -> void {
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
push((PC - 1) >> 8);
|
||||
L push((PC - 1) >> 0);
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBreak() -> void {
|
||||
operand();
|
||||
io();
|
||||
push(PC >> 8);
|
||||
push(PC >> 0);
|
||||
uint8 p = P;
|
||||
push(p | 0x10); //B flag set on push
|
||||
D = 0;
|
||||
I = 1;
|
||||
PC.byte(0) = load16(0xfff6);
|
||||
L PC.byte(1) = load16(0xfff7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionCallAbsolute() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
push((PC - 1) >> 8);
|
||||
L push((PC - 1) >> 0);
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionChangeSpeedLow() -> void {
|
||||
L io();
|
||||
r.cs = 4;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionChangeSpeedHigh() -> void {
|
||||
L io();
|
||||
r.cs = 1;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionClear(uint8& data) -> void {
|
||||
L io();
|
||||
data = 0;
|
||||
@@ -115,6 +181,22 @@ auto HuC6280::instructionIndirectYWrite(uint8 data) -> void {
|
||||
L store16(absolute + Y, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJumpAbsolute() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
L io();
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJumpIndirect(uint8 index) -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
PC.byte(0) = load16(address + index + 0);
|
||||
L PC.byte(1) = load16(address + index + 1);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionMemory(fp alu) -> void {
|
||||
auto a = A;
|
||||
A = ALU(load8(X));
|
||||
@@ -122,6 +204,10 @@ L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionNoOperation() -> void {
|
||||
L io();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPull(uint8& data) -> void {
|
||||
io();
|
||||
io();
|
||||
@@ -130,22 +216,99 @@ L data = pull();
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPullP() -> void {
|
||||
io();
|
||||
io();
|
||||
L P = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPush(uint8 data) -> void {
|
||||
io();
|
||||
L push(data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionResetMemoryBit(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 0;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionReturnInterrupt() -> void {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
P = pull();
|
||||
PC.byte(0) = pull();
|
||||
L PC.byte(1) = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionReturnSubroutine() -> void {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
PC.byte(0) = pull();
|
||||
PC.byte(1) = pull();
|
||||
L io();
|
||||
PC++;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSet(bool& flag) -> void {
|
||||
L io();
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSetMemoryBit(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 1;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionStoreImplied(uint2 index) -> void {
|
||||
auto data = operand();
|
||||
io();
|
||||
io();
|
||||
L store(index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSwap(uint8& lhs, uint8& rhs) -> void {
|
||||
io();
|
||||
L io();
|
||||
swap(lhs, rhs);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTestAbsolute(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
L uint8 data = load16(absolute + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTestZeroPage(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
L uint8 data = load8(zeropage + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransfer(uint8& source, uint8& target) -> void {
|
||||
L io();
|
||||
target = source;
|
||||
@@ -153,6 +316,30 @@ L io();
|
||||
N = target.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferAccumulatorToMPR() -> void {
|
||||
auto mask = operand();
|
||||
io();
|
||||
io();
|
||||
L io();
|
||||
for(uint index : range(8)) {
|
||||
if(mask.bit(index)) r.mpr[index] = A;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferMPRToAccumulator() -> void {
|
||||
auto mask = operand();
|
||||
io();
|
||||
L io();
|
||||
for(uint index : range(8)) {
|
||||
if(mask.bit(index)) { A = r.mpr[index]; break; }
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferXS() -> void {
|
||||
L io();
|
||||
S = X;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionZeroPageModify(fp alu, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
@@ -172,192 +359,3 @@ auto HuC6280::instructionZeroPageWrite(uint8 data, uint8 index) -> void {
|
||||
io();
|
||||
L store8(zeropage + index, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HuC6280::instructionBBR(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 0) {
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBBS(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 1) {
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBRK() -> void {
|
||||
operand();
|
||||
io();
|
||||
push(PC >> 8);
|
||||
push(PC >> 0);
|
||||
uint8 p = P;
|
||||
push(p | 0x10); //B flag set on push
|
||||
D = 0;
|
||||
I = 1;
|
||||
PC.byte(0) = load16(0xfff6);
|
||||
L PC.byte(1) = load16(0xfff7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBSR() -> void {
|
||||
auto displacement = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
push((PC - 1) >> 8);
|
||||
L push((PC - 1) >> 0);
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionCSL() -> void {
|
||||
L io();
|
||||
r.cs = 4;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionCSH() -> void {
|
||||
L io();
|
||||
r.cs = 1;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJMPAbsolute() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
L io();
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJMPIndirect(uint8 index) -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
PC.byte(0) = load16(address + index + 0);
|
||||
L PC.byte(1) = load16(address + index + 1);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJSR() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
push((PC - 1) >> 8);
|
||||
L push((PC - 1) >> 0);
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionNOP() -> void {
|
||||
L io();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPLP() -> void {
|
||||
io();
|
||||
io();
|
||||
L P = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionRMB(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 0;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionRTI() -> void {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
P = pull();
|
||||
PC.byte(0) = pull();
|
||||
L PC.byte(1) = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionRTS() -> void {
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
PC.byte(0) = pull();
|
||||
PC.byte(1) = pull();
|
||||
L io();
|
||||
PC++;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSMB(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 1;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionST(uint2 index) -> void {
|
||||
auto data = operand();
|
||||
io();
|
||||
io();
|
||||
L store(index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTAM() -> void {
|
||||
auto mask = operand();
|
||||
io();
|
||||
io();
|
||||
L io();
|
||||
for(uint index : range(8)) {
|
||||
if(mask.bit(index)) r.mpr[index] = A;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTMA() -> void {
|
||||
auto mask = operand();
|
||||
io();
|
||||
L io();
|
||||
for(uint index : range(8)) {
|
||||
if(mask.bit(index)) { A = r.mpr[index]; break; }
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTSTAbsolute(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
L uint8 data = load16(absolute + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTSTZeroPage(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
auto zeropage = operand();
|
||||
io();
|
||||
io();
|
||||
io();
|
||||
L uint8 data = load8(zeropage + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTXS() -> void {
|
||||
L io();
|
||||
S = X;
|
||||
}
|
||||
|
@@ -43,6 +43,8 @@ template<uint Size> auto M68K::_immediate() -> string {
|
||||
}
|
||||
|
||||
template<uint Size> auto M68K::_address(EffectiveAddress& ea) -> string {
|
||||
if(ea.mode == 7) return {"$", hex((int16)_readPC<Word>(), 6L)};
|
||||
if(ea.mode == 8) return {"$", hex(_readPC<Long>(), 6L)};
|
||||
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
|
||||
return "???";
|
||||
}
|
||||
@@ -291,7 +293,9 @@ template<uint Size> auto M68K::disassembleEXT(DataRegister with) -> string {
|
||||
return {"ext", _suffix<Size>(), " ", _dataRegister(with)};
|
||||
}
|
||||
|
||||
auto M68K::disassembleILLEGAL() -> string {
|
||||
auto M68K::disassembleILLEGAL(uint16 code) -> string {
|
||||
if(code.bits(12,15) == 0xa) return {"linea $", hex(code.bits(0,11), 3L)};
|
||||
if(code.bits(12,15) == 0xf) return {"linef $", hex(code.bits(0,11), 3L)};
|
||||
return {"illegal "};
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
|
||||
template<uint Size, bool hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
|
||||
ea.address = fetch<Size>(ea);
|
||||
|
||||
switch(ea.mode) {
|
||||
@@ -86,14 +86,16 @@ template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
|
||||
auto data = read<Size>(ea.address);
|
||||
if(!Hold) write(AddressRegister{ea.reg}, ea.address += bytes<Size>());
|
||||
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
|
||||
return data;
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
auto data = read<Size>(ea.address - bytes<Size>());
|
||||
if(!Hold) write(AddressRegister{ea.reg}, ea.address -= bytes<Size>());
|
||||
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
|
||||
auto data = read<Size>(address);
|
||||
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -130,7 +132,7 @@ template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<uint Size, bool Hold> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
|
||||
template<uint Size, bool hold> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
|
||||
ea.address = fetch<Size>(ea);
|
||||
|
||||
switch(ea.mode) {
|
||||
@@ -148,14 +150,16 @@ template<uint Size, bool Hold> auto M68K::write(EffectiveAddress& ea, uint32 dat
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPostIncrement: {
|
||||
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
|
||||
write<Size>(ea.address, data);
|
||||
if(!Hold) write(AddressRegister{ea.reg}, ea.address += bytes<Size>());
|
||||
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
|
||||
return;
|
||||
}
|
||||
|
||||
case AddressRegisterIndirectWithPreDecrement: {
|
||||
write<Size, Reverse>(ea.address - bytes<Size>(), data);
|
||||
if(!Hold) write(AddressRegister{ea.reg}, ea.address -= bytes<Size>());
|
||||
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
|
||||
write<Size, Reverse>(address, data);
|
||||
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -538,7 +538,7 @@ M68K::M68K() {
|
||||
//ILLEGAL
|
||||
{ auto opcode = pattern("0100 1010 1111 1100");
|
||||
|
||||
bind(opcode, ILLEGAL);
|
||||
bind(opcode, ILLEGAL, opcode);
|
||||
}
|
||||
|
||||
//JMP
|
||||
@@ -1257,7 +1257,7 @@ M68K::M68K() {
|
||||
//ILLEGAL
|
||||
for(uint16 opcode : range(65536)) {
|
||||
if(instructionTable[opcode]) continue;
|
||||
bind(opcode, ILLEGAL);
|
||||
bind(opcode, ILLEGAL, opcode);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
|
@@ -79,13 +79,13 @@ auto M68K::instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void
|
||||
r.x = r.c;
|
||||
}
|
||||
|
||||
template<uint Size, bool Extend> auto M68K::ADD(uint32 source, uint32 target) -> uint32 {
|
||||
template<uint Size, bool extend> auto M68K::ADD(uint32 source, uint32 target) -> uint32 {
|
||||
auto result = (uint64)source + target;
|
||||
if(Extend) result += r.x;
|
||||
if(extend) result += r.x;
|
||||
|
||||
r.c = sign<Size>(result >> 1) < 0;
|
||||
r.v = sign<Size>(~(target ^ source) & (target ^ result)) < 0;
|
||||
r.z = clip<Size>(result) ? 0 : (Extend ? r.z : 1);
|
||||
r.z = clip<Size>(result) ? 0 : (extend ? r.z : 1);
|
||||
r.n = sign<Size>(result) < 0;
|
||||
r.x = r.c;
|
||||
|
||||
@@ -521,10 +521,10 @@ template<> auto M68K::instructionEXT<Long>(DataRegister with) -> void {
|
||||
r.n = sign<Long>(result) < 0;
|
||||
}
|
||||
|
||||
auto M68K::instructionILLEGAL() -> void {
|
||||
auto M68K::instructionILLEGAL(uint16 code) -> void {
|
||||
r.pc -= 2;
|
||||
if(opcode >> 12 == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA);
|
||||
if(opcode >> 12 == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF);
|
||||
if(code.bits(12,15) == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA);
|
||||
if(code.bits(12,15) == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF);
|
||||
return exception(Exception::Illegal, Vector::Illegal);
|
||||
}
|
||||
|
||||
@@ -1059,13 +1059,13 @@ auto M68K::instructionSTOP() -> void {
|
||||
r.stop = true;
|
||||
}
|
||||
|
||||
template<uint Size, bool Extend> auto M68K::SUB(uint32 source, uint32 target) -> uint32 {
|
||||
template<uint Size, bool extend> auto M68K::SUB(uint32 source, uint32 target) -> uint32 {
|
||||
auto result = (uint64)target - source;
|
||||
if(Extend) result -= r.x;
|
||||
if(extend) result -= r.x;
|
||||
|
||||
r.c = sign<Size>(result >> 1) < 0;
|
||||
r.v = sign<Size>((target ^ source) & (target ^ result)) < 0;
|
||||
r.z = clip<Size>(result) ? 0 : (Extend ? r.z : 1);
|
||||
r.z = clip<Size>(result) ? 0 : (extend ? r.z : 1);
|
||||
r.n = sign<Size>(result) < 0;
|
||||
r.x = r.c;
|
||||
|
||||
|
@@ -45,10 +45,12 @@ auto M68K::exception(uint exception, uint vector, uint priority) -> void {
|
||||
auto pc = r.pc;
|
||||
auto sr = readSR();
|
||||
|
||||
if(!r.s) swap(r.a[7], r.sp);
|
||||
r.i = priority;
|
||||
r.s = 1;
|
||||
r.t = 0;
|
||||
if(exception != Exception::Illegal) {
|
||||
if(!r.s) swap(r.a[7], r.sp);
|
||||
r.i = priority;
|
||||
r.s = 1;
|
||||
r.t = 0;
|
||||
}
|
||||
|
||||
push<Long>(pc);
|
||||
push<Word>(sr);
|
||||
|
@@ -102,8 +102,8 @@ struct M68K {
|
||||
};
|
||||
|
||||
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
|
||||
template<uint Size, bool Hold = 0> auto read(EffectiveAddress& ea) -> uint32;
|
||||
template<uint Size, bool Hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
|
||||
template<uint Size, bool hold = 0> auto read(EffectiveAddress& ea) -> uint32;
|
||||
template<uint Size, bool hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto instruction() -> void;
|
||||
@@ -120,7 +120,7 @@ struct M68K {
|
||||
template<uint Size> auto sign(uint32 data) -> int32;
|
||||
|
||||
auto instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void;
|
||||
template<uint Size, bool Extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size, bool extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionADD(EffectiveAddress from, DataRegister with) -> void;
|
||||
template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void;
|
||||
template<uint Size> auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
@@ -171,7 +171,7 @@ struct M68K {
|
||||
auto instructionEXG(AddressRegister x, AddressRegister y) -> void;
|
||||
auto instructionEXG(DataRegister x, AddressRegister y) -> void;
|
||||
template<uint Size> auto instructionEXT(DataRegister with) -> void;
|
||||
auto instructionILLEGAL() -> void;
|
||||
auto instructionILLEGAL(uint16 code) -> void;
|
||||
auto instructionJMP(EffectiveAddress target) -> void;
|
||||
auto instructionJSR(EffectiveAddress target) -> void;
|
||||
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
|
||||
@@ -233,7 +233,7 @@ struct M68K {
|
||||
auto instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void;
|
||||
auto instructionSCC(uint4 condition, EffectiveAddress to) -> void;
|
||||
auto instructionSTOP() -> void;
|
||||
template<uint Size, bool Extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size, bool extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
|
||||
template<uint Size> auto instructionSUB(EffectiveAddress source, DataRegister target) -> void;
|
||||
template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void;
|
||||
template<uint Size> auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void;
|
||||
@@ -326,7 +326,7 @@ private:
|
||||
auto disassembleEXG(AddressRegister x, AddressRegister y) -> string;
|
||||
auto disassembleEXG(DataRegister x, AddressRegister y) -> string;
|
||||
template<uint Size> auto disassembleEXT(DataRegister with) -> string;
|
||||
auto disassembleILLEGAL() -> string;
|
||||
auto disassembleILLEGAL(uint16 code) -> string;
|
||||
auto disassembleJMP(EffectiveAddress target) -> string;
|
||||
auto disassembleJSR(EffectiveAddress target) -> string;
|
||||
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;
|
||||
|
@@ -18,11 +18,11 @@ auto MOS6502::instruction() -> void {
|
||||
auto code = opcode();
|
||||
|
||||
switch(code) {
|
||||
op(0x00, BRK)
|
||||
op(0x00, Break)
|
||||
op(0x01, IndirectXRead, fp(ORA), A)
|
||||
op(0x05, ZeroPageRead, fp(ORA), A)
|
||||
op(0x06, ZeroPageModify, fp(ASL))
|
||||
op(0x08, PHP)
|
||||
op(0x08, PushP)
|
||||
op(0x09, Immediate, fp(ORA), A)
|
||||
op(0x0a, Implied, fp(ASL), A)
|
||||
op(0x0d, AbsoluteRead, fp(ORA), A)
|
||||
@@ -35,12 +35,12 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x19, AbsoluteRead, fp(ORA), A, Y)
|
||||
op(0x1d, AbsoluteRead, fp(ORA), A, X)
|
||||
op(0x1e, AbsoluteModify, fp(ASL), X)
|
||||
op(0x20, JSRAbsolute)
|
||||
op(0x20, CallAbsolute)
|
||||
op(0x21, IndirectXRead, fp(AND), A)
|
||||
op(0x24, ZeroPageRead, fp(BIT), A)
|
||||
op(0x25, ZeroPageRead, fp(AND), A)
|
||||
op(0x26, ZeroPageModify, fp(ROL))
|
||||
op(0x28, PLP)
|
||||
op(0x28, PullP)
|
||||
op(0x29, Immediate, fp(AND), A)
|
||||
op(0x2a, Implied, fp(ROL), A)
|
||||
op(0x2c, AbsoluteRead, fp(BIT), A)
|
||||
@@ -54,14 +54,14 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x39, AbsoluteRead, fp(AND), A, Y)
|
||||
op(0x3d, AbsoluteRead, fp(AND), A, X)
|
||||
op(0x3e, AbsoluteModify, fp(ROL), X)
|
||||
op(0x40, RTI)
|
||||
op(0x40, ReturnInterrupt)
|
||||
op(0x41, IndirectXRead, fp(EOR), A)
|
||||
op(0x45, ZeroPageRead, fp(EOR), A)
|
||||
op(0x46, ZeroPageModify, fp(LSR))
|
||||
op(0x48, Push, A)
|
||||
op(0x49, Immediate, fp(EOR), A)
|
||||
op(0x4a, Implied, fp(LSR), A)
|
||||
op(0x4c, JMPAbsolute)
|
||||
op(0x4c, JumpAbsolute)
|
||||
op(0x4d, AbsoluteRead, fp(EOR), A)
|
||||
op(0x4e, AbsoluteModify, fp(LSR))
|
||||
op(0x50, Branch, V == 0)
|
||||
@@ -72,14 +72,14 @@ auto MOS6502::instruction() -> void {
|
||||
op(0x59, AbsoluteRead, fp(EOR), A, Y)
|
||||
op(0x5d, AbsoluteRead, fp(EOR), A, X)
|
||||
op(0x5e, AbsoluteModify, fp(LSR), X)
|
||||
op(0x60, RTS)
|
||||
op(0x60, ReturnSubroutine)
|
||||
op(0x61, IndirectXRead, fp(ADC), A)
|
||||
op(0x65, ZeroPageRead, fp(ADC), A)
|
||||
op(0x66, ZeroPageModify, fp(ROR))
|
||||
op(0x68, Pull, A)
|
||||
op(0x69, Immediate, fp(ADC), A)
|
||||
op(0x6a, Implied, fp(ROR), A)
|
||||
op(0x6c, JMPIndirect)
|
||||
op(0x6c, JumpIndirect)
|
||||
op(0x6d, AbsoluteRead, fp(ADC), A)
|
||||
op(0x6e, AbsoluteModify, fp(ROR))
|
||||
op(0x70, Branch, V == 1)
|
||||
@@ -157,7 +157,7 @@ auto MOS6502::instruction() -> void {
|
||||
op(0xe6, ZeroPageModify, fp(INC))
|
||||
op(0xe8, Implied, fp(INC), X)
|
||||
op(0xe9, Immediate, fp(SBC), A)
|
||||
op(0xea, NOP)
|
||||
op(0xea, NoOperation)
|
||||
op(0xec, AbsoluteRead, fp(CPX), X)
|
||||
op(0xed, AbsoluteRead, fp(SBC), A)
|
||||
op(0xee, AbsoluteModify, fp(INC))
|
||||
@@ -172,7 +172,7 @@ auto MOS6502::instruction() -> void {
|
||||
}
|
||||
|
||||
//unimplemented instruction
|
||||
return instructionNOP();
|
||||
return instructionNoOperation();
|
||||
}
|
||||
|
||||
#undef op
|
||||
|
@@ -52,6 +52,28 @@ auto MOS6502::instructionBranch(bool take) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto MOS6502::instructionBreak() -> void {
|
||||
operand();
|
||||
push(PCH);
|
||||
push(PCL);
|
||||
uint16 vector = 0xfffe;
|
||||
nmi(vector);
|
||||
push(P | 0x30);
|
||||
I = 1;
|
||||
PCL = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionCallAbsolute() -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
PC--;
|
||||
push(PCH);
|
||||
L push(PCL);
|
||||
PC = absolute;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionClear(bool& flag) -> void {
|
||||
L idle();
|
||||
flag = 0;
|
||||
@@ -98,6 +120,25 @@ auto MOS6502::instructionIndirectYWrite(uint8& data) -> void {
|
||||
L write(absolute + Y, data);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionJumpAbsolute() -> void {
|
||||
uint16 absolute = operand();
|
||||
L absolute |= operand() << 8;
|
||||
PC = absolute;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionJumpIndirect() -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
uint16 pc = read(absolute);
|
||||
absolute.byte(0)++; //MOS6502: $00ff wraps here to $0000; not $0100
|
||||
L pc |= read(absolute) << 8;
|
||||
PC = pc;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionNoOperation() -> void {
|
||||
L idle();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPull(uint8& data) -> void {
|
||||
idle();
|
||||
idle();
|
||||
@@ -106,11 +147,39 @@ L data = pull();
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPullP() -> void {
|
||||
idle();
|
||||
idle();
|
||||
L P = pull();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPush(uint8& data) -> void {
|
||||
idle();
|
||||
L push(data);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPushP() -> void {
|
||||
idle();
|
||||
L push(P | 0x30);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionReturnInterrupt() -> void {
|
||||
idle();
|
||||
idle();
|
||||
P = pull();
|
||||
PCL = pull();
|
||||
L PCH = pull();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionReturnSubroutine() -> void {
|
||||
idle();
|
||||
idle();
|
||||
PCL = pull();
|
||||
PCH = pull();
|
||||
L idle();
|
||||
PC++;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionSet(bool& flag) -> void {
|
||||
L idle();
|
||||
flag = 1;
|
||||
@@ -160,74 +229,3 @@ auto MOS6502::instructionZeroPageWrite(uint8& data, uint8 index) -> void {
|
||||
read(zeroPage);
|
||||
L store(zeroPage + index, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto MOS6502::instructionBRK() -> void {
|
||||
operand();
|
||||
push(PCH);
|
||||
push(PCL);
|
||||
uint16 vector = 0xfffe;
|
||||
nmi(vector);
|
||||
push(P | 0x30);
|
||||
I = 1;
|
||||
PCL = read(vector++);
|
||||
L PCH = read(vector++);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionJMPAbsolute() -> void {
|
||||
uint16 absolute = operand();
|
||||
L absolute |= operand() << 8;
|
||||
PC = absolute;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionJMPIndirect() -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
uint16 pc = read(absolute);
|
||||
absolute.byte(0)++; //MOS6502: $00ff wraps here to $0000; not $0100
|
||||
L pc |= read(absolute) << 8;
|
||||
PC = pc;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionJSRAbsolute() -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
PC--;
|
||||
push(PCH);
|
||||
L push(PCL);
|
||||
PC = absolute;
|
||||
}
|
||||
|
||||
auto MOS6502::instructionNOP() -> void {
|
||||
L idle();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPHP() -> void {
|
||||
idle();
|
||||
L push(P | 0x30);
|
||||
}
|
||||
|
||||
auto MOS6502::instructionPLP() -> void {
|
||||
idle();
|
||||
idle();
|
||||
L P = pull();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionRTI() -> void {
|
||||
idle();
|
||||
idle();
|
||||
P = pull();
|
||||
PCL = pull();
|
||||
L PCH = pull();
|
||||
}
|
||||
|
||||
auto MOS6502::instructionRTS() -> void {
|
||||
idle();
|
||||
idle();
|
||||
PCL = pull();
|
||||
PCH = pull();
|
||||
L idle();
|
||||
PC++;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user