Full Code of andrew-hoffman/halfnes for AI

master 16476263cd95 cached
152 files
2.2 MB
592.8k tokens
1002 symbols
1 requests
Download .txt
Showing preview only (2,371K chars total). Download the full file or copy to clipboard to get everything.
Repository: andrew-hoffman/halfnes
Branch: master
Commit: 16476263cd95
Files: 152
Total size: 2.2 MB

Directory structure:
gitextract_4vbeh24w/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── nbactions.xml
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── grapeshot/
    │   │           └── halfnes/
    │   │               ├── APU.java
    │   │               ├── CPU.java
    │   │               ├── CPURAM.java
    │   │               ├── FileUtils.java
    │   │               ├── HeadlessNES.java
    │   │               ├── JInputHelper.java
    │   │               ├── JavaFXNES.java
    │   │               ├── NES.java
    │   │               ├── PPU.java
    │   │               ├── PrefsSingleton.java
    │   │               ├── ROMLoader.java
    │   │               ├── Twiddler.form
    │   │               ├── Twiddler.java
    │   │               ├── audio/
    │   │               │   ├── AudioOutInterface.java
    │   │               │   ├── CircularBuffer.java
    │   │               │   ├── ExpansionSoundChip.java
    │   │               │   ├── FDSSoundChip.java
    │   │               │   ├── FFT.java
    │   │               │   ├── MMC5SoundChip.java
    │   │               │   ├── Namco163SoundChip.java
    │   │               │   ├── NoiseTimer.java
    │   │               │   ├── Reverberator.java
    │   │               │   ├── SquareTimer.java
    │   │               │   ├── Sunsoft5BSoundChip.java
    │   │               │   ├── SwingAudioImpl.java
    │   │               │   ├── Timer.java
    │   │               │   ├── TriangleTimer.java
    │   │               │   ├── VRC6SoundChip.java
    │   │               │   └── VRC7SoundChip.java
    │   │               ├── cheats/
    │   │               │   ├── ActionReplay.java
    │   │               │   ├── ActionReplayGui.form
    │   │               │   ├── ActionReplayGui.java
    │   │               │   └── Patch.java
    │   │               ├── halfNES.java
    │   │               ├── mappers/
    │   │               │   ├── Action52Mapper.java
    │   │               │   ├── AfterburnerMapper.java
    │   │               │   ├── AnromMapper.java
    │   │               │   ├── BadMapperException.java
    │   │               │   ├── BnromMapper.java
    │   │               │   ├── CaltronMapper.java
    │   │               │   ├── CnromMapper.java
    │   │               │   ├── CodemastersMapper.java
    │   │               │   ├── ColorDreamsMapper.java
    │   │               │   ├── CrazyClimberMapper.java
    │   │               │   ├── CrimeBustersMapper.java
    │   │               │   ├── FME7Mapper.java
    │   │               │   ├── GnromMapper.java
    │   │               │   ├── IremH3001Mapper.java
    │   │               │   ├── MIMICMapper.java
    │   │               │   ├── MMC1Mapper.java
    │   │               │   ├── MMC2Mapper.java
    │   │               │   ├── MMC3Mapper.java
    │   │               │   ├── MMC4Mapper.java
    │   │               │   ├── MMC5Mapper.java
    │   │               │   ├── Mapper.java
    │   │               │   ├── Mapper107.java
    │   │               │   ├── Mapper112.java
    │   │               │   ├── Mapper119.java
    │   │               │   ├── Mapper140.java
    │   │               │   ├── Mapper15.java
    │   │               │   ├── Mapper152.java
    │   │               │   ├── Mapper182.java
    │   │               │   ├── Mapper185.java
    │   │               │   ├── Mapper200.java
    │   │               │   ├── Mapper201.java
    │   │               │   ├── Mapper203.java
    │   │               │   ├── Mapper212.java
    │   │               │   ├── Mapper213.java
    │   │               │   ├── Mapper214.java
    │   │               │   ├── Mapper225.java
    │   │               │   ├── Mapper226.java
    │   │               │   ├── Mapper229.java
    │   │               │   ├── Mapper231.java
    │   │               │   ├── Mapper240.java
    │   │               │   ├── Mapper241.java
    │   │               │   ├── Mapper242.java
    │   │               │   ├── Mapper244.java
    │   │               │   ├── Mapper246.java
    │   │               │   ├── Mapper255.java
    │   │               │   ├── Mapper31.java
    │   │               │   ├── Mapper33.java
    │   │               │   ├── Mapper36.java
    │   │               │   ├── Mapper47.java
    │   │               │   ├── Mapper48.java
    │   │               │   ├── Mapper58.java
    │   │               │   ├── Mapper60.java
    │   │               │   ├── Mapper61.java
    │   │               │   ├── Mapper62.java
    │   │               │   ├── Mapper70.java
    │   │               │   ├── Mapper72.java
    │   │               │   ├── Mapper76.java
    │   │               │   ├── Mapper78.java
    │   │               │   ├── Mapper86.java
    │   │               │   ├── Mapper87.java
    │   │               │   ├── Mapper92.java
    │   │               │   ├── Mapper94.java
    │   │               │   ├── Mapper97.java
    │   │               │   ├── NINA_001_Mapper.java
    │   │               │   ├── NINA_003_006_Mapper.java
    │   │               │   ├── NSFMapper.java
    │   │               │   ├── NSFPlayerFont.java
    │   │               │   ├── NamcoMapper.java
    │   │               │   ├── Namcot34x3Mapper.java
    │   │               │   ├── NromMapper.java
    │   │               │   ├── Sunsoft01Mapper.java
    │   │               │   ├── Sunsoft02Mapper.java
    │   │               │   ├── Sunsoft03Mapper.java
    │   │               │   ├── TengenRamboMapper.java
    │   │               │   ├── UnromMapper.java
    │   │               │   ├── VRC1Mapper.java
    │   │               │   ├── VRC2Mapper.java
    │   │               │   ├── VRC3Mapper.java
    │   │               │   ├── VRC4Mapper.java
    │   │               │   ├── VRC6Mapper.java
    │   │               │   └── VRC7Mapper.java
    │   │               ├── ui/
    │   │               │   ├── ControllerImpl.java
    │   │               │   ├── ControllerInterface.java
    │   │               │   ├── ControlsDialog.form
    │   │               │   ├── ControlsDialog.java
    │   │               │   ├── DebugUI.java
    │   │               │   ├── DummyController.java
    │   │               │   ├── FrameLimiterImpl.java
    │   │               │   ├── FrameLimiterInterface.java
    │   │               │   ├── GUIInterface.java
    │   │               │   ├── HeadlessUI.java
    │   │               │   ├── NESFileFilter.java
    │   │               │   ├── OnScreenMenu.java
    │   │               │   ├── Oscilloscope.java
    │   │               │   ├── PreferencesDialog.form
    │   │               │   ├── PreferencesDialog.java
    │   │               │   ├── PuppetController.java
    │   │               │   └── SwingUI.java
    │   │               ├── utils.java
    │   │               └── video/
    │   │                   ├── AltNTSCRenderer.java
    │   │                   ├── NTSCRenderer.java
    │   │                   ├── NesColors.java
    │   │                   ├── RGBRenderer.java
    │   │                   └── Renderer.java
    │   ├── java-templates/
    │   │   └── com/
    │   │       └── grapeshot/
    │   │           └── halfnes/
    │   │               └── ProjectInfo.java
    │   └── resources/
    │       ├── changelog.txt
    │       └── todo.txt
    └── test/
        ├── java/
        │   └── com/
        │       └── grapeshot/
        │           └── halfnes/
        │               ├── JInputTest.java
        │               └── nestest/
        │                   └── NesTest.java
        └── resources/
            └── nestest/
                ├── compare.log
                ├── nestest.log
                └── nestest.nes

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
nesdebug*.txt


#unnecessary javadocs
/lib/javadoc/**
/lib/src/**
/proguard4.7/examples/**
/proguard4.7/src/**
/build/**

#include necessary jars for building
!jarsplice-0.40-CLI-CUSTPATCH.jar
!proguard*.jar
!retrace.jar


/dist/
/HalfNES.exe
proguard4.7
/HalfNES.app
/*.app
/battletoads double dragon.txt
/justbreedbug.txt
/.idea
/*.iml
/target
/.settings/
.classpath
.project


================================================
FILE: .travis.yml
================================================
language: java

jdk:
  - oraclejdk8


================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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:

    {project}  Copyright (C) {year}  {fullname}
    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
<http://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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

================================================
FILE: README.md
================================================
[DOWNLOAD HERE](https://github.com/andrew-hoffman/halfnes/releases)

halfnes
=======

An accurate NES/Famicom emulator

[![Join the chat at https://gitter.im/andrew-hoffman/halfnes](https://badges.gitter.im/Join%20Chat.svg)]
(https://gitter.im/andrew-hoffman/halfnes?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Current Features
----------------

- Joystick support through both DirectInput and xInput (thanks Zlika) 
- Cross-Platform
- Supports Mapper 0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 15, 19, 21, 22, 23, 24, 25, 26,
 31, 33, 34, 38, 41, 48, 58, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
 75, 76, 78, 79, 86, 87, 88, 89, 92, 93, 94, 97, 107, 112, 113, 118, 119, 140,
 152, 154, 180, 182, 185, 200, 201, 203, 206, 212, 213, 214, 225, 226, 229, 231,
 240, 241, 242, 244, 246, 255
- Accurate sound core
- Fast display code
- Battery save support (No savestates! Come on. You can live without them.)
- Remappable controls
- Full screen mode 
- NTSC filter
- NSF player

Running HalfNES
---------------

Download the latest version from https://github.com/andrew-hoffman/halfnes/releases .
There are two versions of HalfNES included in this package: a Windows
executable and a JAR file for other platforms.
Use whichever one works best on your platform, but you will need
Java 8 or newer installed no matter what file is to be used.
Linux users will need to set execute permissions on the JAR.

# Default Controls (See Preferences dialog to remap them)
Controller 1:
- D-Pad: Arrow Keys
- B Button: Z
- A Button: X
- Select: Right Shift
- Start: Enter 

# Controller 2:
- D-Pad: WASD
- B Button: F
- A Button: G
- Select: R
- Start: T 

The keys mapped to the A and B buttons are used to change tracks in the NSF player.

# Note on joystick support

The first detected gamepad will be used as Controller 1, and the second 
will be Controller 2. Currently the buttons used are not configurable. 
(the controller needs to be plugged in before a game is loaded in order to be detected.)

# Compatibility

At this point in 
development, almost all US released games will start, but certain games 
still have graphics corruption or freezing problems. Please report any 
issues you encounter with the emulator or with games on the Github Issues page 
(https://github.com/andrew-hoffman/halfnes/issues). 
PAL games are now supported as well but are likely to have more issues.
Please change the system type to PAL in preferences to run these. 

Building instructions
---------------------

The project requires JInput library to build.  
The project comes with a Maven build script that will automatically download
that and package the natives as a library. To use it you will need to 
install Maven, change to the project directory and run

    mvn install

and that should produce an exe and a JAR with all the natives in the
/target/ directory under the project root. 

Do NOT ask me where to find ROM files of commercial games. Some public 
domain homebrew ROMs are available at www.pdroms.de for testing 
purposes. 

A 2 ghz Athlon 64 or better is currently required to run all games full 
speed. (The NTSC filter requires MUCH more processing power, however.)
Saved games are placed in the folder that the ROM file is in for 
now. 

If you are having problems getting the emulator to run, make sure to 
update your Java Runtime to the latest version. Go to 
http://java.com/en/download/manual.jsp and get the correct version for 
your OS. 

Special Thanks to the NESDev wiki and forum community for the invaluable 
NES hardware reference that made this project possible. 


================================================
FILE: nbactions.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<actions>
        <action>
            <actionName>run</actionName>
            <packagings>
                <packaging>jar</packaging>
            </packagings>
            <goals>
                <goal>process-classes</goal>
                <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
            </goals>
            <properties>
                <exec.args>-classpath %classpath com.grapeshot.halfnes.halfNES</exec.args>
                <exec.executable>java</exec.executable>
            </properties>
        </action>
        <action>
            <actionName>debug</actionName>
            <packagings>
                <packaging>jar</packaging>
            </packagings>
            <goals>
                <goal>process-classes</goal>
                <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
            </goals>
            <properties>
                <exec.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.grapeshot.halfnes.halfNES</exec.args>
                <exec.executable>java</exec.executable>
                <jpda.listen>true</jpda.listen>
            </properties>
        </action>
    </actions>


================================================
FILE: pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- The Basics -->
    <groupId>com.grapeshot</groupId>
    <artifactId>halfnes</artifactId>
    <version>0.6.3-SNAPSHOT</version>
    <dependencies>
        <!-- Controller input -->
        <dependency>
            <groupId>net.java.jinput</groupId>
            <artifactId>jinput</artifactId>
            <version>2.0.6</version>
        </dependency>
        <!-- Tests -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.9.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>1.9.5</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <!-- Build Settings -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                            <goal>test-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.9</version>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                            <goal>test-jar</goal>
                        </goals>
                        <configuration>
                            <failOnError>false</failOnError>
                            <verbose>false</verbose>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>templating-maven-plugin</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <id>filter-src</id>
                        <goals>
                            <goal>filter-sources</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <!-- More Project Information -->
    <name>halfNES</name>
    <description>An accurate NES/Famicom emulator</description>
    <url>https://github.com/andrew-hoffman/halfnes</url>
    <inceptionYear>2010</inceptionYear>
    <!--<licenses>...</licenses>-->
    <developers>
        <developer>
            <id>andrew-hoffman</id>
            <name>Andrew Hoffman</name>
        </developer>
    </developers>
    <contributors>
        <contributor>
            <name>Klaus Hauschild</name>
        </contributor>
        <contributor>
            <name>Stephen Chin</name>
        </contributor>
        <contributor>
            <name>Thomas Lorblanches</name>
        </contributor>	
        <contributor>
            <name>Nawrot Krzystof</name>
        </contributor>
    </contributors>

    <!-- Environment Settings -->
    <scm>
        <url>https://github.com/andrew-hoffman/halfnes</url>
        <connection>scm:git:https://github.com/andrew-hoffman/halfnes.git</connection>
        <developerConnection>scm:git:https://github.com/andrew-hoffman/halfnes.git</developerConnection>
    </scm>
    <prerequisites>
        <maven>3.0.5</maven>
    </prerequisites>
    <profiles>
        <profile>
            <id>make-binary</id>
            <build>
                <defaultGoal>package</defaultGoal>
                <plugins>
                    <plugin>
                        <artifactId>maven-assembly-plugin</artifactId>
                        <version>2.6</version>
                        <executions>
                            <execution>
                                <id>make-assembly</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>single</goal>
                                </goals>
                                <configuration>
                                    <descriptorRefs>
                                        <descriptorRef>jar-with-dependencies</descriptorRef>
                                    </descriptorRefs>
                                    <archive>
                                        <manifest>
                                            <mainClass>com.grapeshot.halfnes.halfNES</mainClass>
                                        </manifest>
                                    </archive>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>com.akathist.maven.plugins.launch4j</groupId>
                        <artifactId>launch4j-maven-plugin</artifactId>
                        <version>1.7.8</version>
                        <executions>
                            <execution>
                                <phase>package</phase>
                                <goals>
                                    <goal>launch4j</goal>
                                </goals>
                                <configuration>
                                    <headerType>gui</headerType>
                                    <outfile>target/halfNES.exe</outfile>
                                    <jar>target/${project.build.finalName}-jar-with-dependencies.jar</jar>
                                    <jre>
                                        <minVersion>1.8.0</minVersion>
                                        <initialHeapSize>128</initialHeapSize>
                                        <maxHeapSize>1024</maxHeapSize>
                                    </jre>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>


================================================
FILE: src/main/java/com/grapeshot/halfnes/APU.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.ui.Oscilloscope;
import com.grapeshot.halfnes.audio.*;
import com.grapeshot.halfnes.mappers.Mapper;
import java.util.ArrayList;

public class APU {

    public int samplerate;
    private final Timer[] timers = {new SquareTimer(8, 2), new SquareTimer(8, 2),
        new TriangleTimer(), new NoiseTimer()};
    private double cyclespersample;
    public final NES nes;
    CPU cpu;
    CPURAM cpuram;
    public int sprdma_count;
    private int apucycle = 0, remainder = 0;
    private int[] noiseperiod;
    // different for PAL
    private long accum = 0;
    private final ArrayList<ExpansionSoundChip> expnSound = new ArrayList<>();
    private boolean soundFiltering;
    private final static int[] TNDLOOKUP = initTndLookup(), SQUARELOOKUP = initSquareLookup();
    private int framectrreload;
    private int framectrdiv = 7456;
    private int dckiller = -6392; //removes icky power on thump
    private int lpaccum = 0;
    private boolean apuintflag = true, statusdmcint = false, statusframeint = false;
    private int framectr = 0, ctrmode = 4;
    private final boolean[] lenCtrEnable = {true, true, true, true};
    private final int[] volume = new int[4];
    //dmc instance variables
    private int[] dmcperiods;
    private int dmcrate = 0x36, dmcpos = 0, dmcshiftregister = 0, dmcbuffer = 0,
            dmcvalue = 0, dmcsamplelength = 1, dmcsamplesleft = 0,
            dmcstartaddr = 0xc000, dmcaddr = 0xc000, dmcbitsleft = 8;
    private boolean dmcsilence = true, dmcirq = false, dmcloop = false, dmcBufferEmpty = true;
    //length ctr instance variables
    private final int[] lengthctr = {0, 0, 0, 0};
    private final static int[] lenctrload = {10, 254, 20, 2, 40, 4, 80, 6,
        160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22,
        192, 24, 72, 26, 16, 28, 32, 30};
    private final boolean[] lenctrHalt = {true, true, true, true};
    //linear counter instance vars
    private int linearctr = 0;
    private int linctrreload = 0;
    private boolean linctrflag = false;
    //instance variables for envelope units
    private final int[] envelopeValue = {15, 15, 15, 15};
    private final int[] envelopeCounter = {0, 0, 0, 0};
    private final int[] envelopePos = {0, 0, 0, 0};
    private final boolean[] envConstVolume = {true, true, true, true};
    private final boolean[] envelopeStartFlag = {false, false, false, false};
    //instance variables for sweep unit
    private final boolean[] sweepenable = {false, false},
            sweepnegate = {false, false},
            sweepsilence = {false, false},
            sweepreload = {false, false};
    private final int[] sweepperiod = {15, 15}, sweepshift = {0, 0}, sweeppos = {0, 0};
    private int cyclesperframe;
    private AudioOutInterface ai;

    public APU(final NES nes, final CPU cpu, final CPURAM cpuram) {
        this.samplerate = 1; //just in case we can't init audio
        //then init the audio stream
        this.nes = nes;
        this.cpu = cpu;
        this.cpuram = cpuram;
        setParameters();
    }

    private static int[] initTndLookup() {
        int[] lookup = new int[203];
        for (int i = 0; i < lookup.length; ++i) {
            lookup[i] = (int) ((163.67 / (24329.0 / i + 100)) * 49151);
        }
        return lookup;
    }

    private static int[] initSquareLookup() {
        //fill square, triangle volume lookup tables
        int[] lookup = new int[31];
        for (int i = 0; i < lookup.length; ++i) {
            lookup[i] = (int) ((95.52 / (8128.0 / i + 100)) * 49151);
        }
        return lookup;
    }

    public final synchronized void setParameters() {
        Mapper.TVType tvtype = cpuram.mapper.getTVType();
        soundFiltering = PrefsSingleton.get().getBoolean("soundFiltering", true);
        samplerate = PrefsSingleton.get().getInt("sampleRate", 44100);
        if (ai != null) {
            ai.destroy();
        }
        ai = new SwingAudioImpl(nes, samplerate, tvtype);
        if (PrefsSingleton.get().getBoolean("showScope", false)) {
            ai = new Oscilloscope(ai);
        }
        //pick the appropriate pitches and lengths for NTSC or PAL
        switch (tvtype) {
            case NTSC:
            default:
                this.dmcperiods = new int[]{428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54};
                this.noiseperiod = new int[]{4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068};
                this.framectrreload = 7456;
                cyclespersample = 1789773.0 / samplerate;
                cyclesperframe = 29781;
                break;

            case DENDY:
                this.dmcperiods = new int[]{428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54};
                this.noiseperiod = new int[]{4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068};
                this.framectrreload = 7456;
                cyclespersample = 1773448.0 / samplerate;
                cyclesperframe = 35469;
                break;
            case PAL:
                cyclespersample = 1662607.0 / samplerate;
                this.dmcperiods = new int[]{398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50};
                this.noiseperiod = new int[]{4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778};
                this.framectrreload = 8312;
                cyclesperframe = 33252;
                break;
        }
//        ai = new Reverberator(ai, 2,0.7,0.8,0.99);
//        ai = new Reverberator(ai, 243,0.5,0.7,0.99);
//       ai = new Reverberator(ai, 4001,0.3,0.5,0.99);
//       ai = new Reverberator(ai, 20382,0.2,0.3,0.9);
    }

    public boolean bufferHasLessThan(int samples) {
        return ai.bufferHasLessThan(samples);
    }

    public final int read(final int addr) {
        updateto((int) cpu.clocks);
        switch (addr) {
            case 0x15:
                //returns channel status
                //for future ref: NEED to put those ternary operators in parentheses!
                //otherwise order of operations does the wrong thing.
                final int returnval = ((lengthctr[0] > 0) ? 1 : 0)
                        | ((lengthctr[1] > 0) ? 2 : 0)
                        | ((lengthctr[2] > 0) ? 4 : 0)
                        | ((lengthctr[3] > 0) ? 8 : 0)
                        | ((dmcsamplesleft > 0) ? 16 : 0)
                        | (statusframeint ? 64 : 0)
                        | (statusdmcint ? 128 : 0);
                if (statusframeint) {
                    //System.err.println("Frame interrupt ack at " + cpu.cycles);
                    --cpu.interrupt;
                    statusframeint = false;
                }

                //System.err.println("*" + utils.hex(returnval));
                return returnval;
            case 0x16:
                nes.getcontroller1().strobe();
                return nes.getcontroller1().getbyte() | 0x40;
            case 0x17:
                nes.getcontroller2().strobe();
                return nes.getcontroller2().getbyte() | 0x40;
            default:
                return 0x40; //open bus
        }
    }
    final private static int[][] DUTYLOOKUP = {
        {0, 1, 0, 0, 0, 0, 0, 0},
        {0, 1, 1, 0, 0, 0, 0, 0},
        {0, 1, 1, 1, 1, 0, 0, 0},
        {1, 0, 0, 1, 1, 1, 1, 1}
    };

    public void addExpnSound(ExpansionSoundChip chip) {
        expnSound.add(chip);
    }

    public void destroy() {
        ai.destroy();
    }

    public void pause() {
        ai.pause();
    }

    public void resume() {
        ai.resume();
    }

    public final void write(final int reg, final int data) {
        //This is how values written to any of the APU's memory
        //mapped registers change the state of the system.
        updateto((int) cpu.clocks - 1);
        //System.err.println("Wrote " + utils.hex(data) + " to " + utils.hex(reg) + " @ cycle " + cpu.cycles);
        switch (reg) {
            case 0x0:
                //length counter 1 halt
                lenctrHalt[0] = ((data & (utils.BIT5)) != 0);
                // pulse 1 duty cycle
                timers[0].setduty(DUTYLOOKUP[data >> 6]);
                // and envelope
                envConstVolume[0] = ((data & (utils.BIT4)) != 0);
                envelopeValue[0] = data & 15;
                //setvolumes();
                break;
            case 0x1:
                //pulse 1 sweep setup
                //sweep enabled
                sweepenable[0] = ((data & (utils.BIT7)) != 0);
                //sweep divider period
                sweepperiod[0] = (data >> 4) & 7;
                //sweep negate flag
                sweepnegate[0] = ((data & (utils.BIT3)) != 0);
                //sweep shift count
                sweepshift[0] = (data & 7);
                sweepreload[0] = true;
                break;
            case 0x2:
                // pulse 1 timer low bit
                timers[0].setperiod((timers[0].getperiod() & 0xfe00) + (data << 1));
                break;
            case 0x3:
                // length counter load, timer 1 high bits
                if (lenCtrEnable[0]) {
                    lengthctr[0] = lenctrload[data >> 3];
                }
                timers[0].setperiod((timers[0].getperiod() & 0x1ff) + ((data & 7) << 9));
                // sequencer restarted
                timers[0].reset();
                //envelope also restarted
                envelopeStartFlag[0] = true;
                break;
            case 0x4:
                //length counter 2 halt
                lenctrHalt[1] = ((data & (utils.BIT5)) != 0);
                // pulse 2 duty cycle
                timers[1].setduty(DUTYLOOKUP[data >> 6]);
                // and envelope
                envConstVolume[1] = ((data & (utils.BIT4)) != 0);
                envelopeValue[1] = data & 15;
                //setvolumes();
                break;
            case 0x5:
                //pulse 2 sweep setup
                //sweep enabled
                sweepenable[1] = ((data & (utils.BIT7)) != 0);
                //sweep divider period
                sweepperiod[1] = (data >> 4) & 7;
                //sweep negate flag
                sweepnegate[1] = ((data & (utils.BIT3)) != 0);
                //sweep shift count
                sweepshift[1] = (data & 7);
                sweepreload[1] = true;
                break;
            case 0x6:
                // pulse 2 timer low bit
                timers[1].setperiod((timers[1].getperiod() & 0xfe00) + (data << 1));
                break;
            case 0x7:
                if (lenCtrEnable[1]) {
                    lengthctr[1] = lenctrload[data >> 3];
                }
                timers[1].setperiod((timers[1].getperiod() & 0x1ff) + ((data & 7) << 9));
                // sequencer restarted
                timers[1].reset();
                //envelope also restarted
                envelopeStartFlag[1] = true;
                break;
            case 0x8:
                //triangle linear counter load
                linctrreload = data & 0x7f;
                //and length counter halt
                lenctrHalt[2] = ((data & (utils.BIT7)) != 0);
                break;
            case 0x9:
                break;
            case 0xA:
                // triangle low bits of timer
                timers[2].setperiod((((timers[2].getperiod() * 1) & 0xff00) + data));
                break;
            case 0xB:
                // triangle length counter load
                // and high bits of timer
                if (lenCtrEnable[2]) {
                    lengthctr[2] = lenctrload[data >> 3];
                }
                timers[2].setperiod((((timers[2].getperiod() * 1) & 0xff) + ((data & 7) << 8)));
                linctrflag = true;
                break;
            case 0xC:
                //noise halt and envelope
                lenctrHalt[3] = ((data & (utils.BIT5)) != 0);
                envConstVolume[3] = ((data & (utils.BIT4)) != 0);
                envelopeValue[3] = data & 0xf;
                //setvolumes();
                break;
            case 0xD:
                break;
            case 0xE:
                timers[3].setduty(((data & (utils.BIT7)) != 0) ? 6 : 1);
                timers[3].setperiod(noiseperiod[data & 15]);
                break;
            case 0xF:
                //noise length counter load, envelope restart
                if (lenCtrEnable[3]) {
                    lengthctr[3] = lenctrload[data >> 3];
                }
                envelopeStartFlag[3] = true;
                break;
            case 0x10:
                dmcirq = ((data & (utils.BIT7)) != 0);
                dmcloop = ((data & (utils.BIT6)) != 0);
                dmcrate = dmcperiods[data & 0xf];
                if (!dmcirq && statusdmcint) {
                    --cpu.interrupt;
                    statusdmcint = false;
                }
                //System.err.println(dmcirq ? "dmc irq on" : "dmc irq off");
                break;
            case 0x11:
                dmcvalue = data & 0x7f;
                break;
            case 0x12:
                dmcstartaddr = (data << 6) + 0xc000;
                break;
            case 0x13:
                dmcsamplelength = (data << 4) + 1;
                break;
            case 0x14:
                //sprite dma
                for (int i = 0; i < 256; ++i) {
                    cpuram.write(0x2004, cpuram.read((data << 8) + i));
                }
                //account for time stolen from cpu
                sprdma_count = 2;
                break;
            case 0x15:
                //status register
                // counter enable(silence channel when bit is off)
                for (int i = 0; i < 4; ++i) {
                    lenCtrEnable[i] = ((data & (1 << i)) != 0);
                    //THIS was the channels not cutting off bug! If you toggle a channel's
                    //status on and off very quickly then the length counter should
                    //IMMEDIATELY be forced to zero.
                    if (!lenCtrEnable[i]) {
                        lengthctr[i] = 0;
                    }
                }
                if (((data & (utils.BIT4)) != 0)) {
                    if (dmcsamplesleft == 0) {
                        restartdmc();
                    }
                } else {
                    dmcsamplesleft = 0;
                    dmcsilence = true;
                }
                if (statusdmcint) {
                    --cpu.interrupt;
                    statusdmcint = false;
                }
                break;
            case 0x16:
                // latch controller 1 + 2
                nes.getcontroller1().output(((data & (utils.BIT0)) != 0));
                nes.getcontroller2().output(((data & (utils.BIT0)) != 0));
                break;
            case 0x17:
                ctrmode = ((data & (utils.BIT7)) != 0) ? 5 : 4;
                //System.err.println("reset " + ctrmode + ' ' + cpu.cycles);
                apuintflag = ((data & (utils.BIT6)) != 0);
                //set is no interrupt, clear is an interrupt
                framectr = 0;
                framectrdiv = framectrreload + 8; //Why +8?
                if (apuintflag && statusframeint) {
                    statusframeint = false;
                    --cpu.interrupt;
                    //System.err.println("Frame interrupt off at " + cpu.cycles);
                }
                if (ctrmode == 5) {
                    //everything frame counter runs is clocked no matter what
                    setenvelope();
                    setlinctr();
                    setlength();
                    setsweep();
                }
                break;
            default:
                break;
        }
    }

    public final void updateto(final int cpucycle) {
        //still have to run this even if sound is disabled, some games rely on DMC IRQ etc.
        if (soundFiltering) {
            //linear sampling code
            //should really be a FIR filter + decimator instead
            //but I don't have the DSP experience to design something like that
            //that would be fast enough to work / not require calculating every sample
            //this works well enough at eliminating aliasing anyway.
            while (apucycle < cpucycle) {
                ++remainder;
                clockdmc();
                if (--framectrdiv <= 0) {
                    framectrdiv = framectrreload;
                    clockframecounter();
                }
                timers[0].clock();
                timers[1].clock();
                if (lengthctr[2] > 0 && linearctr > 0) {
                    timers[2].clock();
                }
                timers[3].clock();
                if (!expnSound.isEmpty()) {
                    for (ExpansionSoundChip c : expnSound) {
                        c.clock(1);
                    }
                }
                accum += getOutputLevel();

                if ((apucycle % cyclespersample) < 1) {
                    //not quite right - there's a non-integer # cycles per sample.
                    ai.outputSample(lowpass_filter(highpass_filter((int) (accum / remainder))));
                    remainder = 0;
                    accum = 0;
                }
                ++apucycle;
            }
        } else {
            //point sampling code
            while (apucycle < cpucycle) {
                ++remainder;
                clockdmc();
                if (--framectrdiv <= 0) {
                    framectrdiv = framectrreload;
                    clockframecounter();
                }
                if ((apucycle % cyclespersample) < 1) {
                    //not quite right - there's a non-integer # cycles per sample.
                    timers[0].clock(remainder);
                    timers[1].clock(remainder);
                    if (lengthctr[2] > 0 && linearctr > 0) {
                        timers[2].clock(remainder);
                    }
                    timers[3].clock(remainder);
                    int mixvol = getOutputLevel();
                    if (!expnSound.isEmpty()) {
                        for (ExpansionSoundChip c : expnSound) {
                            c.clock(remainder);
                        }
                    }
                    remainder = 0;
                    ai.outputSample(lowpass_filter(highpass_filter(mixvol)));
                }
                ++apucycle;
            }
        }
    }

    private int getOutputLevel() {
        int vol;
        vol = SQUARELOOKUP[volume[0] * timers[0].getval()
                + volume[1] * timers[1].getval()];
        vol += TNDLOOKUP[3 * timers[2].getval()
                + 2 * volume[3] * timers[3].getval()
                + dmcvalue];
        if (!expnSound.isEmpty()) {
            vol *= 0.8;
            for (ExpansionSoundChip c : expnSound) {
                vol += c.getval();
            }
        }
        return vol; //as usual, lack of unsigned types causes unending pain.
    }

    private int highpass_filter(int sample) {
        //for killing the dc in the signal
        sample -= dckiller;
        dckiller += sample >> 8;//the actual high pass part
        dckiller += (sample > 0 ? 1 : -1);//guarantees the signal decays to exactly zero
        return sample;
    }

    private int lowpass_filter(int sample) {
        return lpaccum += 0.5 * (sample - lpaccum); //y = y + a * (x - y)
    }

    public final void finishframe() {
        updateto(cyclesperframe);
        apucycle = 0;
        ai.flushFrame(nes.isFrameLimiterOn());
    }

    private void clockframecounter() {
        //System.err.println("frame ctr clock " + framectr + ' ' + cpu.cycles);
        //should be ~4x a frame, 240 Hz
        //but the problem is this isn't exactly related to the video signal,
        //it's a completely separate timer, so the phase can shift in relation to the
        //video signal. also in the current implementation APU interrupts can only be fired when
        //an APU register is written/read from, or @ end of frame. So both of those need work
        if ((ctrmode == 4)
                || (ctrmode == 5 && (framectr != 3))) {
            setenvelope();
            setlinctr();
        }
        if ((ctrmode == 4 && (framectr == 1 || framectr == 3))
                || (ctrmode == 5 && (framectr == 1 || framectr == 4))) {
            setlength();
            setsweep();
        }
        if (!apuintflag && (framectr == 3) && (ctrmode == 4) && !statusframeint) {
            ++cpu.interrupt;
            //System.err.println("frame interrupt set at " + cpu.cycles);
            statusframeint = true;

        }
        ++framectr;
        framectr %= ctrmode;
        setvolumes();
    }

    private void setvolumes() {
        volume[0] = ((lengthctr[0] <= 0 || sweepsilence[0]) ? 0 : (((envConstVolume[0]) ? envelopeValue[0] : envelopeCounter[0])));
        volume[1] = ((lengthctr[1] <= 0 || sweepsilence[1]) ? 0 : (((envConstVolume[1]) ? envelopeValue[1] : envelopeCounter[1])));
        volume[3] = ((lengthctr[3] <= 0) ? 0 : ((envConstVolume[3]) ? envelopeValue[3] : envelopeCounter[3]));
        //System.err.println("setvolumes " + volume[1]);
    }

    private void clockdmc() {
        if (dmcBufferEmpty && dmcsamplesleft > 0) {
            dmcfillbuffer();
        }
        dmcpos = (dmcpos + 1) % dmcrate;
        if (dmcpos == 0) {
            if (dmcbitsleft <= 0) {
                dmcbitsleft = 8;
                if (dmcBufferEmpty) {
                    dmcsilence = true;
                } else {
                    dmcsilence = false;
                    dmcshiftregister = dmcbuffer;
                    dmcBufferEmpty = true;
                }
            }
            if (!dmcsilence) {
                dmcvalue += (((dmcshiftregister & (utils.BIT0)) != 0) ? 2 : -2);
                //DMC output register doesn't wrap around
                if (dmcvalue > 0x7f) {
                    dmcvalue = 0x7f;
                }
                if (dmcvalue < 0) {
                    dmcvalue = 0;
                }
                dmcshiftregister >>= 1;
                --dmcbitsleft;

            }
        }
    }

    private void dmcfillbuffer() {
        if (dmcsamplesleft > 0) {
            dmcbuffer = cpuram.read(dmcaddr++);
            dmcBufferEmpty = false;
            cpu.stealcycles(4);
            //DPCM Does steal cpu cycles - this should actually vary between 1-4
            //can't do this properly without a cycle accurate cpu/ppu
            if (dmcaddr > 0xffff) {
                dmcaddr = 0x8000;
            }
            --dmcsamplesleft;
            if (dmcsamplesleft == 0) {
                if (dmcloop) {
                    restartdmc();
                } else if (dmcirq && !statusdmcint) {
                    //this is supposed to fire after we've just READ the
                    //last byte, not when coming back AFTER reading the last byte
                    //and finding that there are no more bytes left to read.
                    //that meant all dmc timing was too long.
                    ++cpu.interrupt;
                    statusdmcint = true;
                    //System.err.println("dmc irq fire");
                }

            }
        } else {
            dmcsilence = true;
        }
    }

    private void restartdmc() {
        dmcaddr = dmcstartaddr;
        dmcsamplesleft = dmcsamplelength;
        dmcsilence = false;
    }

    private void setlength() {
        for (int i = 0; i < 4; ++i) {
            if (!lenctrHalt[i] && lengthctr[i] > 0) {
                --lengthctr[i];
                if (lengthctr[i] == 0) {
                    setvolumes();
                }
            }
        }
    }

    private void setlinctr() {
        if (linctrflag) {
            linearctr = linctrreload;
        } else if (linearctr > 0) {
            --linearctr;
        }
        if (!lenctrHalt[2]) {
            linctrflag = false;
        }
    }

    private void setenvelope() {
        //System.err.println("envelope");
        for (int i = 0; i < 4; ++i) {
            if (envelopeStartFlag[i]) {
                envelopeStartFlag[i] = false;
                envelopePos[i] = envelopeValue[i] + 1;
                envelopeCounter[i] = 15;
            } else {
                --envelopePos[i];
            }
            if (envelopePos[i] <= 0) {
                envelopePos[i] = envelopeValue[i] + 1;
                if (envelopeCounter[i] > 0) {
                    --envelopeCounter[i];
                } else if (lenctrHalt[i] && envelopeCounter[i] <= 0) {
                    envelopeCounter[i] = 15;
                }
            }
        }
    }

    private void setsweep() {
        //System.err.println("sweep");
        for (int i = 0; i < 2; ++i) {
            sweepsilence[i] = false;
            if (sweepreload[i]) {
                sweepreload[i] = false;
                sweeppos[i] = sweepperiod[i];
            }
            ++sweeppos[i];
            final int rawperiod = (timers[i].getperiod() >> 1);
            int shiftedperiod = (rawperiod >> sweepshift[i]);
            if (sweepnegate[i]) {
                //invert bits of period
                //add 1 on second channel only
                shiftedperiod = -shiftedperiod + i;
            }
            shiftedperiod += rawperiod;
            if ((rawperiod < 8) || shiftedperiod > 0x7ff) {
                // silence channel
                sweepsilence[i] = true;
            } else if (sweepenable[i] && (sweepshift[i] != 0) && lengthctr[i] > 0
                    && sweeppos[i] > sweepperiod[i]) {
                sweeppos[i] = 0;
                timers[i].setperiod(shiftedperiod << 1);
            }
        }
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/CPU.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public final class CPU {

    private final CPURAM ram;
    private int cycles; //increment to steal cycles from cpu
    public int clocks; //use for synchronizing with cpu
    private int A, X, Y, S; // registers
    public int PC;
    private boolean carryFlag = false, zeroFlag = false,
            interruptsDisabled = true, decimalModeFlag = false;
    private boolean overflowFlag = false, negativeFlag = false,
            previntflag = false, nmi = false, prevnmi = false, logging = false;
    private int pb = 0;// set to 1 if access crosses page boundary
    public int interrupt = 0;
    public boolean nmiNext = false, idle = false;
    private final static boolean decimalModeEnable = false,
            idleLoopSkip = true;
    //NES 6502 is missing decimal mode, but most other 6502s have it
    private boolean interruptDelay = false;
    private final static String[] opcodes = opcodes();

    //Battletoads Hack until I get around to making a truly cycle accurate CPU core.
    //Delays the write of a STA, STX, or STY until the first cycle of the NEXT instruction
    //which is enough to move it a few PPU clocks after the scroll is changed
    //making sure that Battletoads gets its sprite 0 hit. 
    final private static boolean battletoadsHackOn = true;
    private boolean dirtyBattletoadsHack = false;
    private int hackAddr = 0;
    private int hackData = 0;

    private static enum dummy {

        ONCARRY, ALWAYS; //type of dummy read
    }
    OutputStreamWriter w; //debug log writer

    public CPU(final CPURAM cpuram) {
        ram = cpuram;
        //ram is the ONLY thing the cpu tries to talk to.
        if (logging) {
            startLog();
        }
    }

    public void startLog() {
        logging = true;
        try {
            w = new OutputStreamWriter(new FileOutputStream(new File("nesdebug.txt")), StandardCharsets.UTF_8); 
        } catch (IOException e) {
            System.err.println("Cannot create debug log" + e.getLocalizedMessage());
        }
    }

    public void startLog(String path) {
        logging = true;
        try {
            w = new OutputStreamWriter(new FileOutputStream(new File(path)), StandardCharsets.UTF_8); 
        } catch (IOException e) {
            System.err.println("Cannot create debug log" + e.getLocalizedMessage());
        }
    }

    public void stopLog() {
        logging = false;
        flushLog();
    }

    public void init() {
        init(null);
    }

    public void init(Integer initialPC) {// different than reset
        // puts RAM in NES poweron state
        for (int i = 0; i < 0x800; ++i) {
            ram.write(i, 0xFF);
        }

        //poweron RAM values from one specific console (nesdev wiki pre-2015)
        ram.write(0x0008, 0xF7);
        ram.write(0x0009, 0xEF);
        ram.write(0x000A, 0xDF);
        ram.write(0x000F, 0xBF);

        for (int i = 0x4000; i <= 0x400F; ++i) {
            ram.write(i, 0x00);
        }

        ram.write(0x4015, 0x00);
        ram.write(0x4017, 0x00);

        //clocks = 27393; //correct for position we start vblank in
        A = 0;
        X = 0;
        Y = 0;
        S = 0xFD;
        if (initialPC == null) {
            PC = ram.read(0xFFFD) * 256 + ram.read(0xFFFC);
        } else {
            PC = initialPC;
        }
    }

    public void reset() {
        PC = ram.read(0xFFFD) * 256 + ram.read(0xFFFC);
        ram.write(0x4015, 0);
        ram.write(0x4017, ram.read(0x4017));
        //disable audio on reset
        S -= 3;
        S &= 0xff;
        interruptsDisabled = true;
    }

    public void modcycles() {
        //System.err.println(clocks);
        clocks = 0;
    }

    public void stealcycles(int cyclestosteal) {
        cycles += cyclestosteal;
        log("**STEAL " + cyclestosteal + "**");
    }

    public final void runcycle(final int scanline, final int pixel) {
        ram.read(0x4000); //attempt to sync the APU every cycle and make dmc irqs work properly, which they still don't. Feh.
        ++clocks;

        //guard against overflows
//        if ((A & 0xff) != A) {
//            System.err.println("houston we have A problem");
//        }
//        if ((X & 0xff) != X) {
//            System.err.println("houston we have X problem");
//        }
//        if ((Y & 0xff) != Y) {
//            System.err.println("houston we have Y problem");
//        }
//        if ((S & 0xff) != S) {
//            System.err.println("houston we have S problem");
//        }
//        if ((PC & 0xffff) != PC) {
//            System.err.println("houston we have PC problem");
//        }
        if (ram.apu.sprdma_count > 0) {
            ram.apu.sprdma_count--;
            if (ram.apu.sprdma_count == 0) {
                cycles += 513;
            }
            //this doesn't look right any more
            //who patched this in and when? (wasn't me, it was for some bug...)
        }

        if (dirtyBattletoadsHack && cycles == 1) {
            ram.write(hackAddr, hackData);
            dirtyBattletoadsHack = false;
        }

        if (cycles-- > 0) { //count down cycles until there is work to do again
            return;
        }
        
        //now we're at the start of a new instruction

        //handle nmi requests (NMI line is edge sensitive not level sensitive)
        if (nmiNext) {
            nmi();
            nmiNext = false;
        }
        if (nmi && !prevnmi) {//only trigger on positive rising edge of NMI
            nmiNext = true;
        }
        prevnmi = nmi;

        if (interrupt > 0) {
            if (!interruptsDisabled && !interruptDelay) {
                interrupt();
                cycles += 7;
                return;
            } else if (interruptDelay) {
                interruptDelay = false;
                if (!previntflag) {
                    interrupt();
                    cycles += 7;
                    return;
                }
            }
        } else {
            interruptDelay = false;
        }

        //Idle loop skipping
        if (idle && idleLoopSkip) {
            cycles += 3; //not accurate should depend on type of instr we skip decoding
            return;
        }

        pb = 0;
        final int instr = ram.read(PC++);
        //note: 
        if (logging) {
            //that looks redundant, but this is a really expensive operation to create the log string
            //also, logging *might* trigger side effects if logging while executing
            //code from i/o registers (reading twice). So we don't want to do it always.
            //TODO: Optimize this! It gets called a LOT
            //and slows logging to 16 fps
            //even when not actually writing anything
            String op = String.format(opcodes[instr],
                    ram.read(PC),
                    ram.read(PC + 1),
                    PC + (byte) (ram.read(PC)) + 1);
            log(utils.hex(PC - 1) + " " + utils.hex(instr)
                    + String.format(" %-14s ", op)
                    + status() + " CYC:" + pixel + " SL:" + scanline + "\n");
        }
        if (cycles == 0) {
            flushLog();
        }

        switch (instr) {
            // ADC
            case 0x69:
                adc(imm());
                cycles += 2;
                break;
            case 0x65:
                adc(zpg());
                cycles += 3;
                break;
            case 0x75:
                adc(zpg(X));
                cycles += 4;
                break;
            case 0x6d:
                adc(abs());
                cycles += 4;
                break;
            case 0x7d:
                adc(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x79:
                adc(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x61:
                adc(indX());
                cycles += 6;
                break;
            case 0x71:
                adc(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // AHX (unofficial)
            case 0x93:
                ahx(indY(dummy.ALWAYS));
                cycles += 6;
                break;
            case 0x9f:
                ahx(abs(Y, dummy.ALWAYS));
                cycles += 5;
                break;
            // ALR (unofficial)
            case 0x4b:
                alr(imm());
                cycles += 2;
                break;
            // ANC (unofficial)
            case 0x0b:
                anc(imm());
                cycles += 2;
                break;
            case 0x2b:
                anc(imm());
                cycles += 2;
                break;
            // AND
            case 0x29:
                and(imm());
                cycles += 2;
                break;
            case 0x25:
                and(zpg());
                cycles += 3;
                break;
            case 0x35:
                and(zpg(X));
                cycles += 4;
                break;
            case 0x2D:
                and(abs());
                cycles += 4;
                break;
            case 0x3D:
                and(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x39:
                and(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x21:
                and(indX());
                cycles += 6;
                break;
            case 0x31:
                and(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // ARR (unofficial)
            case 0x6b:
                arr(imm());
                cycles += 2;
                break;
            // ASL
            case 0x0A:
                aslA();
                cycles += 2;
                break;
            case 0x06:
                asl(zpg());
                cycles += 5;
                break;
            case 0x16:
                asl(zpg(X));
                cycles += 6;
                break;
            case 0x0e:
                asl(abs());
                cycles += 6;
                break;
            case 0x1e:
                asl(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // AXS (unofficial)
            case 0xcb:
                axs(imm());
                cycles += 2;
                break;
            // BIT
            case 0x24:
                bit(zpg());
                cycles += 3;
                break;
            case 0x2c:
                bit(abs());
                cycles += 4;
                break;
            // Branches: every branch uses rel. addressing
            case 0x10:
                branch(!negativeFlag);
                cycles += 2 + pb;
                break;
            case 0x30:
                branch(negativeFlag);
                cycles += 2 + pb;
                break;
            case 0x50:
                branch(!overflowFlag);
                cycles += 2 + pb;
                break;
            case 0x70:
                branch(overflowFlag);
                cycles += 2 + pb;
                break;
            case 0x90:
                branch(!carryFlag);
                cycles += 2 + pb;
                break;
            case 0xB0:
                branch(carryFlag);
                cycles += 2 + pb;
                break;
            case 0xD0:
                branch(!zeroFlag);
                cycles += 2 + pb;
                break;
            case 0xF0:
                branch(zeroFlag);
                cycles += 2 + pb;
                break;
            // BRK
            case 0x00:
                //System.err.println("Hey! A break!");
                breakinterrupt();
                cycles += 7;
                break;
            // CMP
            case 0xc9:
                cmp(A, imm());
                cycles += 2;
                break;
            case 0xc5:
                cmp(A, zpg());
                cycles += 3;
                break;
            case 0xd5:
                cmp(A, zpg(X));
                cycles += 4;
                break;
            case 0xcd:
                cmp(A, abs());
                cycles += 4;
                break;
            case 0xdd:
                cmp(A, abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0xd9:
                cmp(A, abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0xc1:
                cmp(A, indX());
                cycles += 6;
                break;
            case 0xd1:
                cmp(A, indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // CPX
            case 0xe0:
                cmp(X, imm());
                cycles += 2;
                break;
            case 0xe4:
                cmp(X, zpg());
                cycles += 3;
                break;
            case 0xec:
                cmp(X, abs());
                cycles += 4;
                break;
            // CPY
            case 0xc0:
                cmp(Y, imm());
                cycles += 2;
                break;
            case 0xc4:
                cmp(Y, zpg());
                cycles += 3;
                break;
            case 0xcc:
                cmp(Y, abs());
                cycles += 4;
                break;
            // DEC
            case 0xc6:
                dec(zpg());
                cycles += 5;
                break;
            case 0xd6:
                dec(zpg(X));
                cycles += 6;
                break;
            case 0xce:
                dec(abs());
                cycles += 6;
                break;
            case 0xde:
                dec(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // DCP (unofficial)
            case 0xc3:
                dcp(A, indX());
                cycles += 8;
                break;
            case 0xd3:
                dcp(A, indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0xc7:
                dcp(A, zpg());
                cycles += 5;
                break;
            case 0xd7:
                dcp(A, zpg(X));
                cycles += 6;
                break;
            case 0xdb:
                dcp(A, abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0xcf:
                dcp(A, abs());
                cycles += 6;
                break;
            case 0xdf:
                dcp(A, abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // EOR
            case 0x49:
                eor(imm());
                cycles += 2;
                break;
            case 0x45:
                eor(zpg());
                cycles += 3;
                break;
            case 0x55:
                eor(zpg(X));
                cycles += 4;
                break;
            case 0x4d:
                eor(abs());
                cycles += 4;
                break;
            case 0x5d:
                eor(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x59:
                eor(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x41:
                eor(indX());
                cycles += 6;
                break;
            case 0x51:
                eor(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // Flag set/clear
            case 0x18:
                carryFlag = false;
                cycles += 2;
                break;
            case 0x38:
                carryFlag = true;
                cycles += 2;
                break;
            case 0x58:
                //cli
                //interrupts shouldn't fire for 1 cycle after cli
                delayInterrupt();
                interruptsDisabled = false;
                cycles += 2;
                break;
            case 0x78:
                //sei
                delayInterrupt();
                interruptsDisabled = true;
                cycles += 2;
                break;
            case 0xb8:
                overflowFlag = false;
                cycles += 2;
                break;
            case 0xd8:
                decimalModeFlag = false;
                cycles += 2;
                break;// decimal mode doesnt
            case 0xf8:
                decimalModeFlag = true;
                cycles += 2;
                break;// do anything on NES
            // INC
            case 0xe6:
                inc(zpg());
                cycles += 5;
                break;
            case 0xf6:
                inc(zpg(X));
                cycles += 6;
                break;
            case 0xee:
                inc(abs());
                cycles += 6;
                break;
            case 0xfe:
                inc(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // ISC (unofficial)
            case 0xe3:
                isc(indX());
                cycles += 8;
                break;
            case 0xf3:
                isc(indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0xe7:
                isc(zpg());
                cycles += 5;
                break;
            case 0xf7:
                isc(zpg(X));
                cycles += 6;
                break;
            case 0xfb:
                isc(abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0xef:
                isc(abs());
                cycles += 6;
                break;
            case 0xff:
                isc(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // JMP
            case 0x4c:
                int tempe = PC;
                PC = abs();
                if (PC == (tempe - 1)) {
                    idle = true;
                }
                cycles += 3;
                break;
            case 0x6c:
                int tempf = PC;
                PC = ind();
                if (PC == (tempf - 1)) {
                    idle = true;
                }
                cycles += 5;
                break;
            // JSR
            case 0x20:
                jsr(abs());
                cycles += 6;
                break;
            // KIL (unofficial)
            case 0x02:
            case 0x12:
            case 0x22:
            case 0x32:
            case 0x42:
            case 0x52:
            case 0x62:
            case 0x72:
            case 0x92:
            case 0xb2:
            case 0xd2:
            case 0xf2:
                System.err.println("KIL - CPU locked");
                flushLog();
                ram.apu.nes.runEmulation = false;
                break;
            // LAS (unofficial)
            case 0xbb:
                las(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            // LAX (unofficial)
            case 0xa3:
                lax(indX());
                cycles += 6;
                break;
            case 0xb3:
                lax(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            case 0xa7:
                lax(zpg());
                cycles += 3;
                break;
            case 0xb7:
                lax(zpg(Y));
                cycles += 4;
                break;
            case 0xab:
                lax(imm());
                cycles += 2;
                break;
            case 0xaf:
                lax(abs());
                cycles += 4;
                break;
            case 0xbf:
                lax(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            // LDA
            case 0xa9:
                lda(imm());
                cycles += 2;
                break;
            case 0xa5:
                lda(zpg());
                cycles += 3;
                break;
            case 0xb5:
                lda(zpg(X));
                cycles += 4;
                break;
            case 0xad:
                lda(abs());
                cycles += 4;
                break;
            case 0xbd:
                lda(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0xb9:
                lda(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0xa1:
                lda(indX());
                cycles += 6;
                break;
            case 0xb1:
                lda(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // LDX
            case 0xa2:
                ldx(imm());
                cycles += 2;
                break;
            case 0xa6:
                ldx(zpg());
                cycles += 3;
                break;
            case 0xb6:
                ldx(zpg(Y));
                cycles += 4;
                break;
            case 0xae:
                ldx(abs());
                cycles += 4;
                break;
            case 0xbe:
                ldx(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            // LDY
            case 0xa0:
                ldy(imm());
                cycles += 2;
                break;
            case 0xa4:
                ldy(zpg());
                cycles += 3;
                break;
            case 0xb4:
                ldy(zpg(X));
                cycles += 4;
                break;
            case 0xac:
                ldy(abs());
                cycles += 4;
                break;
            case 0xbc:
                ldy(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            // LSR
            case 0x4a:
                lsrA();
                cycles += 2;
                break;
            case 0x46:
                lsr(zpg());
                cycles += 5;
                break;
            case 0x56:
                lsr(zpg(X));
                cycles += 6;
                break;
            case 0x4e:
                lsr(abs());
                cycles += 6;
                break;
            case 0x5e:
                lsr(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // NOP
            case 0x1a:
            case 0x3a:
            case 0x5a:
            case 0x7a:
            case 0xda:
            case 0xEA:
            case 0xfa:
                cycles += 2;
                break;
            case 0x80:
            case 0x82:
            case 0xc2:
            case 0xe2:
            case 0x89:
                imm();
                cycles += 2;
                break;
            case 0x04:
            case 0x44:
            case 0x64:
                zpg();
                cycles += 3;
                break;
            case 0x14:
            case 0x34:
            case 0x54:
            case 0x74:
            case 0xd4:
            case 0xf4:
                zpg(X);
                cycles += 4;
                break;
            case 0x0C:
                abs();
                cycles += 4;
                break;
            case 0x1c:
            case 0x3c:
            case 0x5c:
            case 0x7c:
            case 0xdc:
            case 0xfc:
                abs(X, dummy.ONCARRY);
                cycles += 4 + pb;
                break;
            // ORA
            case 0x09:
                ora(imm());
                cycles += 2;
                break;
            case 0x05:
                ora(zpg());
                cycles += 3;
                break;
            case 0x15:
                ora(zpg(X));
                cycles += 4;
                break;
            case 0x0d:
                ora(abs());
                cycles += 4;
                break;
            case 0x1d:
                ora(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x19:
                ora(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0x01:
                ora(indX());
                cycles += 6;
                break;
            case 0x11:
                ora(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            // Register instrs.
            case 0xAA:
                X = A;
                cycles += 2;
                setflags(A);
                break;
            case 0x8a:
                A = X;
                cycles += 2;
                setflags(A);
                break;
            case 0xca:
                X--;
                X &= 0xFF;
                setflags(X);
                cycles += 2;
                break;
            case 0xe8:
                X++;
                X &= 0xFF;
                setflags(X);
                cycles += 2;
                break;
            case 0xa8:
                Y = A;
                cycles += 2;
                setflags(A);
                break;
            case 0x98:
                A = Y;
                cycles += 2;
                setflags(A);
                break;
            case 0x88:
                Y--;
                Y &= 0xFF;
                setflags(Y);
                cycles += 2;
                break;
            case 0xc8:
                Y++;
                Y &= 0xFF;
                setflags(Y);
                cycles += 2;
                break;
            // RLA (unofficial)
            case 0x23:
                rla(indX());
                cycles += 8;
                break;
            case 0x33:
                rla(indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0x27:
                rla(zpg());
                cycles += 5;
                break;
            case 0x37:
                rla(zpg(X));
                cycles += 6;
                break;
            case 0x3b:
                rla(abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0x2f:
                rla(abs());
                cycles += 6;
                break;
            case 0x3f:
                rla(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // ROL
            case 0x2a:
                rolA();
                cycles += 2;
                break;
            case 0x26:
                rol(zpg());
                cycles += 5;
                break;
            case 0x36:
                rol(zpg(X));
                cycles += 6;
                break;
            case 0x2e:
                rol(abs());
                cycles += 6;
                break;
            case 0x3e:
                rol(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // ROR
            case 0x6a:
                rorA();
                cycles += 2;
                break;
            case 0x66:
                ror(zpg());
                cycles += 5;
                break;
            case 0x76:
                ror(zpg(X));
                cycles += 6;
                break;
            case 0x6e:
                ror(abs());
                cycles += 6;
                break;
            case 0x7e:
                ror(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // RRA (unofficial)
            case 0x63:
                rra(indX());
                cycles += 8;
                break;
            case 0x73:
                rra(indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0x67:
                rra(zpg());
                cycles += 5;
                break;
            case 0x77:
                rra(zpg(X));
                cycles += 6;
                break;
            case 0x7b:
                rra(abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0x6f:
                rra(abs());
                cycles += 6;
                break;
            case 0x7f:
                rra(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // RTI
            case 0x40:
                rti();
                cycles += 6;
                break;
            // RTS
            case 0x60:
                rts();
                cycles += 6;
                break;
            // SAX (unofficial)
            case 0x83:
                sax(indX());
                cycles += 6;
                break;
            case 0x87:
                sax(zpg());
                cycles += 3;
                break;
            case 0x97:
                sax(zpg(Y));
                cycles += 4;
                break;
            case 0x8f:
                sax(abs());
                cycles += 4;
                break;
            // SBC
            case 0xE1:
                sbc(indX());
                cycles += 6;
                break;
            case 0xF1:
                sbc(indY(dummy.ONCARRY));
                cycles += 5 + pb;
                break;
            case 0xE5:
                sbc(zpg());
                cycles += 3;
                break;
            case 0xF5:
                sbc(zpg(X));
                cycles += 4;
                break;
            case 0xE9:
                sbc(imm());
                cycles += 2;
                break;
            case 0xF9:
                sbc(abs(Y, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            case 0xeb:
                sbc(imm());
                cycles += 2;
                break;
            case 0xEd:
                sbc(abs());
                cycles += 4;
                break;
            case 0xFd:
                sbc(abs(X, dummy.ONCARRY));
                cycles += 4 + pb;
                break;
            // SHX (unofficial)
            case 0x9e:
                shx(abs(Y, dummy.ALWAYS));
                cycles += 5;
                break;
            // SHY (unofficial)
            case 0x9c:
                shy(abs(X, dummy.ALWAYS));
                cycles += 5;
                break;
            // SLO (unofficial)
            case 0x03:
                slo(indX());
                cycles += 8;
                break;
            case 0x07:
                slo(zpg());
                cycles += 5;
                break;
            case 0x0f:
                slo(abs());
                cycles += 6;
                break;
            case 0x13:
                slo(indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0x17:
                slo(zpg(X));
                cycles += 6;
                break;
            case 0x1b:
                slo(abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0x1f:
                slo(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // SRE (unofficial)
            case 0x43:
                sre(indX());
                cycles += 8;
                break;
            case 0x53:
                sre(indY(dummy.ALWAYS));
                cycles += 8;
                break;
            case 0x47:
                sre(zpg());
                cycles += 5;
                break;
            case 0x57:
                sre(zpg(X));
                cycles += 6;
                break;
            case 0x5b:
                sre(abs(Y, dummy.ALWAYS));
                cycles += 7;
                break;
            case 0x4f:
                sre(abs());
                cycles += 6;
                break;
            case 0x5f:
                sre(abs(X, dummy.ALWAYS));
                cycles += 7;
                break;
            // STA
            case 0x85:
                sta(zpg());
                cycles += 3;
                break;
            case 0x95:
                sta(zpg(X));
                cycles += 4;
                break;
            case 0x8d:
                sta(abs());
                cycles += 4;
                break;
            case 0x9d:
                sta(abs(X, dummy.ALWAYS));
                cycles += 5;
                break;
            case 0x99:
                sta(abs(Y, dummy.ALWAYS));
                cycles += 5;
                break;
            case 0x81:
                sta(indX());
                cycles += 6;
                break;
            case 0x91:
                sta(indY(dummy.ALWAYS));
                cycles += 6;
                break;
            // Stack instructions
            case 0x9A:
                S = X;
                cycles += 2;
                break;
            case 0xBA:
                X = S;
                cycles += 2;
                setflags(X);
                break;
            case 0x48:
                ram.read(PC + 1);   //dummy fetch
                push(A);
                cycles += 3;
                break;
            case 0x68:
                ram.read(PC + 1);   //dummy fetch
                A = pop();
                setflags(A);
                cycles += 4;
                break;
            case 0x08:
                ram.read(PC + 1);   //dummy fetch
                push(flagstobyte() | utils.BIT4);
                cycles += 3;
                break;
            case 0x28:
                //plp
                delayInterrupt();
                ram.read(PC + 1);   //dummy fetch
                bytetoflags(pop());
                cycles += 4;
                break;
            // STX
            case 0x86:
                stx(zpg());
                cycles += 3;
                break;
            case 0x96:
                stx(zpg(Y));
                cycles += 4;
                break;
            case 0x8E:
                stx(abs());
                cycles += 4;
                break;
            // STY
            case 0x84:
                sty(zpg());
                cycles += 3;
                break;
            case 0x94:
                sty(zpg(X));
                cycles += 4;
                break;
            case 0x8c:
                sty(abs());
                cycles += 4;
                break;
            // TAS (unofficial)
            case 0x9b:
                tas(abs(Y, dummy.ALWAYS));
                cycles += 5;
                break;
            // XAA (unofficial)
            case 0x8b:
                xaa(imm());
                cycles += 2;
                break;
            default:
                cycles += 2;
                System.err.println("Illegal opcode:" + utils.hex(instr) + " @ "
                        + utils.hex(PC - 1));
                break;
        }
        pb = 0;
        PC &= 0xffff;
    }

    /*
     really every instruction should be reading from or writing something to memory every cycle.
     Even when all that's happening that cycle is the processor updating state internally
     Fetching the next opcode cn overlap with last cycle of prev instruction
     if that last cycle is purely internal.
     but since the second cycle of all instructions (even single byte ones)
     is reading the nest byte after the PC, the fastest we can do even a single
     byte NOP instruction is still 2 cycles. 
     that's where the dummy reads+writes come from.
     how to represent this in the smallest space possible?
     probably the way they did it on the real chip:
     using a PLA that does certain things conditionally based on bits of the current
     opcode and the current cycle (up to 7 i suppose)
     Bisqwit did some really nifty template stuff with his C==10 emu that I can't match.
     */
    private void delayInterrupt() {
        interruptDelay = true;
        previntflag = interruptsDisabled;
    }

    private void rol(final int addr) {
        int data = (ram.read(addr));
        ram.write(addr, data);  //dummy write
        data = (data << 1) | (carryFlag ? 1 : 0);
        carryFlag = ((data & (utils.BIT8)) != 0);
        data &= 0xFF;
        setflags(data);
        ram.write(addr, data);
    }

    private void rolA() {
        A = A << 1 | (carryFlag ? 1 : 0);
        carryFlag = ((A & (utils.BIT8)) != 0);
        A &= 0xFF;
        setflags(A);
    }

    private void ror(final int addr) {
        int data = ram.read(addr);
        ram.write(addr, data);  //dummy write
        final boolean tmp = carryFlag;
        carryFlag = ((data & (utils.BIT0)) != 0);
        data >>= 1;
        data &= 0x7F;
        data |= (tmp ? 0x80 : 0);
        setflags(data);
        ram.write(addr, data);
    }

    private void rorA() {
        final boolean tmp = carryFlag;
        carryFlag = ((A & (utils.BIT0)) != 0);
        A >>= 1;
        A &= 0x7F;
        A |= (tmp ? 128 : 0);
        setflags(A);
    }

    public void setNMI(boolean val) {
        this.nmi = val;
    }

    private void nmi() {
        idle = false;
        log("**NMI**");
        //System.err.println("  NMI");
        push(PC >> 8); // high bit 1st
        push((PC) & 0xFF);// check that this pushes right address
        push(flagstobyte() & ~utils.BIT4);
        PC = ram.read(0xFFFA) + (ram.read(0xFFFB) << 8);
        cycles += 7;
        interruptsDisabled = true;
    }

    private void interrupt() {
        idle = false;
        log("**INTERRUPT**");
        //System.err.println("IRQ " + interrupt);
        push(PC >> 8); // high bit 1st
        push(PC & 0xFF);// check that this pushes right address
        push(flagstobyte() & ~utils.BIT4);
        //jump to reset vector
        PC = ram.read(0xFFFE) + (ram.read(0xFFFF) << 8);
        interruptsDisabled = true;
    }

    private void breakinterrupt() {
        //same as interrupt but BRK flag is turned on
        log("**BREAK**");
        ram.read(PC++); //dummy fetch
        push(PC >> 8); // high bit 1st
        push(PC & 0xFF);// check that this pushes right address
        push(flagstobyte() | utils.BIT4 | utils.BIT5);//push byte w/bits 4+5 set
        PC = ram.read(0xFFFE) + (ram.read(0xFFFF) << 8);
        interruptsDisabled = true;
    }

    private void lsr(final int addr) {
        int data = ram.read(addr);
        ram.write(addr, data);  //dummy write
        carryFlag = ((data & (utils.BIT0)) != 0);
        data >>= 1;
        data &= 0x7F;
        ram.write(addr, data);
        setflags(data);
    }

    private void lsrA() {
        carryFlag = ((A & (utils.BIT0)) != 0);
        A >>= 1;
        A &= 0x7F;
        setflags(A);
    }

    private void eor(final int addr) {
        A ^= ram.read(addr);
        A &= 0xff;
        setflags(A);
    }

    private void ora(final int addr) {
        A |= ram.read(addr);
        A &= 0xff;
        setflags(A);
    }

    // Instructions
    private void bit(final int addr) {
        final int data = ram.read(addr);
        zeroFlag = ((data & A) == 0);
        negativeFlag = ((data & (utils.BIT7)) != 0);
        overflowFlag = ((data & (utils.BIT6)) != 0);
    }

    private void jsr(final int addr) {
        PC--;
        ram.read(PC);   //dummy fetch
        push(PC >> 8); // high bit 1st
        push(PC & 0xFF);// check that this pushes right address
        PC = addr;
    }

    private void rts() {
        ram.read(PC++); //dummy fetch
        PC = (pop() & 0xff) | (pop() << 8);// page crossing bug again?
        PC++;
    }

    private void rti() {
        //System.err.println("RTI");
        ram.read(PC++); //dummy fetch
        bytetoflags(pop());
        PC = (pop() & 0xff) | (pop() << 8); // not plus one
    }

    private int pop() {
        ++S;
        S &= 0xff;
        return ram.read(0x100 + S);
    }

    public void push(final int byteToPush) {
        ram.write((0x100 + (S & 0xff)), byteToPush);
        --S;
        S &= 0xff;
    }

    private void branch(final boolean isTaken) {
        if (isTaken) {
            final int pcprev = PC + 1;// store prev. PC
            PC = rel();
            // System.err.println(pcprev + " "+ PC);
            //page boundary penalty
            if ((pcprev & 0xff00) != (PC & 0xff00)) {
                pb = 2;//page crossing for branch takes 2 cycles
            } else {
                cycles++;
            }

            if ((pcprev - 2) == PC) {
                idle = true;
            }
        } else {
            rel();
            // have to do the memory access even if we're not branching
        }
    }

    private void inc(final int addr) {
        int tmp = ram.read(addr);
        ram.write(addr, tmp);
        //dummy write
        ++tmp;
        tmp &= 0xff;
        ram.write(addr, tmp);
        //THEN real write
        setflags(tmp);
    }

    private void dec(final int addr) {
        int tmp = ram.read(addr);
        ram.write(addr, tmp);
        //dummy write
        --tmp;
        tmp &= 0xff;
        ram.write(addr, tmp);
        //THEN real write
        setflags(tmp);
    }

    private void adc(final int addr) {
        final int value = ram.read(addr);
        int result;
        if (decimalModeFlag && decimalModeEnable) {
            int AL = (A & 0xF) + (value & 0xF) + (carryFlag ? 1 : 0);
            if (AL >= 0x0A) {
                AL = ((AL + 0x6) & 0xF) + 0x10;
            }
            result = (A & 0xF0) + (value & 0xF0) + AL;
            if (result >= 0xA0) {
                result += 0x60;
            }
        } else {
            result = value + A + (carryFlag ? 1 : 0);
        }
        carryFlag = (result >> 8 != 0);
        // set overflow flag
        overflowFlag = (((A ^ value) & 0x80) == 0)
                && (((A ^ result) & 0x80) != 0);
        A = result & 0xff;
        setflags(A);// set other flags
    }

    private void sbc(final int addr) {
        final int value = ram.read(addr);
        int result;
        if (decimalModeFlag && decimalModeEnable) {
            int AL = (A & 0xF) - (value & 0xF) + (carryFlag ? 1 : 0) - 1;
            if (AL < 0) {
                AL = ((AL - 0x6) & 0xF) - 0x10;
            }
            result = (A & 0xF0) + (value & 0xF0) + AL;
            if (result < 0) {
                result -= 0x60;
            }
        } else {
            result = A - value - (carryFlag ? 0 : 1);
        }
        carryFlag = (result >> 8 == 0);
        // set overflow flag
        overflowFlag = (((A ^ value) & 0x80) != 0)
                && (((A ^ result) & 0x80) != 0);
        A = result & 0xff;
        setflags(A);// set other flags

    }

    private void and(final int addr) {
        A &= ram.read(addr);
        setflags(A);
    }

    private void asl(final int addr) {
        int data = ram.read(addr);
        ram.write(addr, data);  //dummy write
        carryFlag = ((data & (utils.BIT7)) != 0);
        data = data << 1;
        data &= 0xff;
        setflags(data);
        ram.write(addr, data);
    }

    private void aslA() {
        carryFlag = ((A & (utils.BIT7)) != 0);
        A <<= 1;
        A &= 0xff;
        setflags(A);

    }

    private void cmp(final int regval, final int addr) {
        final int result = regval - ram.read(addr);
        if (result < 0) {
            negativeFlag = ((result & (utils.BIT7)) != 0);
            carryFlag = false;
            zeroFlag = false;
        } else if (result == 0) {
            negativeFlag = false;
            carryFlag = true;
            zeroFlag = true;
        } else {
            negativeFlag = ((result & (utils.BIT7)) != 0);
            carryFlag = true;
            zeroFlag = false;
        }
    }

    private void lda(final int addr) {
        A = ram.read(addr);
        setflags(A);
    }

    private void ldx(final int addr) {
        X = ram.read(addr);
        setflags(X);
    }

    private void ldy(final int addr) {
        Y = ram.read(addr);
        setflags(Y);
    }

    private void setflags(final int result) {
        zeroFlag = (result == 0);
        negativeFlag = ((result & (utils.BIT7)) != 0);
    }

    private void sta(final int addr) {
        if (!battletoadsHackOn) {
            ram.write(addr, A);
        } else {
            hackAddr = addr;
            hackData = A;
            dirtyBattletoadsHack = true;
        }
    }

    private void stx(final int addr) {
        if (!battletoadsHackOn) {
            ram.write(addr, X);
        } else {
            hackAddr = addr;
            hackData = X;
            dirtyBattletoadsHack = true;
        }
    }

    private void sty(final int addr) {
        if (!battletoadsHackOn) {
            ram.write(addr, Y);
        } else {
            hackAddr = addr;
            hackData = Y;
            dirtyBattletoadsHack = true;
        }
    }

    // Unofficial opcodes
    private void ahx(final int addr) {
        final int data = (A & X & ((addr >> 8) + 1)) & 0xFF;
        final int tmp = (addr - Y) & 0xFF;
        if ((Y + tmp) <= 0xFF) {
            ram.write(addr, data);
        } else {
            ram.write(addr, ram.read(addr));
        }
    }

    private void alr(final int addr) {
        and(addr);
        lsrA();
    }

    private void anc(final int addr) {
        and(addr);
        carryFlag = negativeFlag;
    }

    private void arr(final int addr) {
        A = (((ram.read(addr) & A) >> 1) | (carryFlag ? 0x80 : 0x00));
        setflags(A);

        carryFlag = ((A & (utils.BIT6)) != 0);
        overflowFlag = carryFlag ^ ((A & (utils.BIT5)) != 0);
    }

    private void axs(final int addr) {
        X = ((A & X) - ram.read(addr)) & 0xff;
        setflags(X);
        carryFlag = (X >= 0);
    }

    private void dcp(final int regval, final int addr) {
        dec(addr);
        cmp(regval, addr);
    }

    private void las(final int addr) {
        S &= ram.read(addr);
        A = X = S;
        setflags(S);
    }

    private void lax(final int addr) {
        A = X = ram.read(addr);
        setflags(A);
    }

    private void isc(final int addr) {
        inc(addr);
        sbc(addr);
    }

    private void rla(final int addr) {
        rol(addr);
        and(addr);
    }

    private void rra(int addr) {
        ror(addr);
        adc(addr);
    }

    private void sax(int addr) {
        ram.write(addr, (A & X) & 0xFF);
    }

    private void shx(final int addr) {
        final int data = (X & ((addr >> 8) + 1)) & 0xFF;
        final int tmp = (addr - Y) & 0xFF;
        if ((Y + tmp) <= 0xFF) {
            ram.write(addr, data);
        } else {
            ram.write(addr, ram.read(addr));
        }
    }

    private void shy(final int addr) {
        final int data = (Y & ((addr >> 8) + 1)) & 0xFF;
        final int tmp = (addr - X) & 0xFF;
        if ((X + tmp) <= 0xFF) {
            ram.write(addr, data);
        } else {
            ram.write(addr, ram.read(addr));
        }
    }

    private void slo(int addr) {
        asl(addr);
        ora(addr);
    }

    private void sre(int addr) {
        lsr(addr);
        eor(addr);
    }

    private void tas(int addr) {
        S = A & X;
        final int data = (S & ((addr >> 8) + 1)) & 0xFF;
        final int tmp = (addr - Y) & 0xFF;
        if ((Y + tmp) <= 0xFF) {
            ram.write(addr, data);
        } else {
            ram.write(addr, ram.read(addr));
        }
    }

    private void xaa(int addr) {
        A = X & ram.read(addr);
        setflags(A);
    }

    // Functions for memory address types; each returns the _memory_address_ for
    // the next fn
    private int imm() {
        return PC++;
    }

    private int zpg() {
        // zero page mode
        return ram.read(PC++);
    }

    private int zpg(final int reg) {
        // zero page added to register (modulus page boundary)
        return (ram.read(PC++) + reg) & 0xff;
    }

    private int rel() {
        // returns actual value of PC, not memory location to look at
        // because only branches use this
        return ((byte) ram.read(PC++)) + PC;
    }

    private int abs() {
        // absolute mode
        return ram.read(PC++) + (ram.read(PC++) << 8);
    }

    private int abs(final int reg, final dummy dummy) {
        // absolute plus value from reg
        final int addr = (ram.read(PC++) | (ram.read(PC++) << 8));

        if (addr >> 8 != (addr + reg) >> 8) {
            pb = 1;
        }

        if ((addr & 0xFF00) != ((addr + reg) & 0xFF00) && dummy == dummy.ONCARRY) {
            ram.read((addr & 0xFF00) | ((addr + reg) & 0xFF));
        }
        if (dummy == dummy.ALWAYS) {
            ram.read((addr & 0xFF00) | ((addr + reg) & 0xFF));
        }

        return (addr + reg) & 0xffff;
    }

    private int ind() {
        // weird mode. only used by jmp
        final int readloc = abs();
        return ram.read(readloc)
                + (ram.read(((readloc & 0xff) == 0xff) ? readloc - 0xff
                        : readloc + 1) << 8);
        //if reading from the last byte in a page, high bit of address
        //is taken from first byte on the page, not first byte on NEXT page.
    }

    private int indX() {
        // indirect mode
        final int arg = ram.read(PC++);
        return ram.read((arg + X) & 0xff)
                + (ram.read((arg + 1 + X) & 0xff) << 8);
        // doesn't suffer from the same bug as jump indirect
    }

    private int indY(final dummy dummy) {
        final int arg = ram.read(PC++);
        final int addr = (ram.read((arg) & 0xff) | (ram.read((arg + 1) & 0xff) << 8));

        if (addr >> 8 != (addr + Y) >> 8) {
            pb = 1;
        }

        if ((addr & 0xFF00) != ((addr + Y) & 0xFF00) && dummy == dummy.ONCARRY) {
            ram.read((addr & 0xFF00) | ((addr + Y) & 0xFF));
        }
        if (dummy == dummy.ALWAYS) {
            ram.read((addr & 0xFF00) | ((addr + Y) & 0xFF));
        }

        return (addr + Y) & 0xffff;
    }

    public final int flagstobyte() {
        return ((negativeFlag ? utils.BIT7 : 0)
                | (overflowFlag ? utils.BIT6 : 0)
                | utils.BIT5
                | (decimalModeFlag ? utils.BIT3 : 0)
                | (interruptsDisabled ? utils.BIT2 : 0)
                | (zeroFlag ? utils.BIT1 : 0)
                | (carryFlag ? utils.BIT0 : 0));
    }

    private void bytetoflags(final int statusbyte) {

        negativeFlag = ((statusbyte & utils.BIT7) != 0);
        overflowFlag = ((statusbyte & utils.BIT6) != 0);
        //breakFlag = ((b & 32) != 0);
        // unusedFlag = ((b & 16) != 0);
        // actually nestest wants the unused flag to always be zero,
        // and doesn't set the break flag with a plp
        decimalModeFlag = ((statusbyte & utils.BIT3) != 0);
        interruptsDisabled = ((statusbyte & utils.BIT2) != 0);
        zeroFlag = ((statusbyte & utils.BIT1) != 0);
        carryFlag = ((statusbyte & utils.BIT0) != 0);

    }

    public String status() {
        //TODO: convert to format string. lots of wasted strings
        return " PC:" + utils.hex(PC) + " A:" + utils.hex(A) + " X:"
                + utils.hex(X) + " Y:" + utils.hex(Y) + " P:"
                + utils.hex(flagstobyte()) + " SP:" + utils.hex(S);
    }

    public static String[] opcodes() {
        //%1 1st byte, %2 2nd byte, %3 relative offset from PC
        //odd combination of format string and eventual syntax in file here.
        String[] op = new String[0x100];
        op[0x00] = "BRK";
        op[0x01] = "ORA $(%2$02X%1$02X,x)";
        op[0x02] = "KIL";
        op[0x03] = "SLO $(%2$02X%1$02X,x)";
        op[0x04] = "NOP $%1$02X";
        op[0x05] = "ORA $%1$02X";
        op[0x06] = "ASL $%1$02X";
        op[0x07] = "SLO $%1$02X";
        op[0x08] = "PHP";
        op[0x09] = "ORA #$%1$02X";
        op[0x0A] = "ASL A";
        op[0x0B] = "ANC #$%1$02X";
        op[0x0C] = "NOP $%2$02X%1$02X";
        op[0x0D] = "ORA $%2$02X%1$02X";
        op[0x0E] = "ASL $%2$02X%1$02X";
        op[0x0F] = "SLO $%2$02X%1$02X";
        op[0x10] = "BPL $%3$02X";
        op[0x11] = "ORA ($%1$02X), y";
        op[0x12] = "KIL";
        op[0x13] = "SLO ($%1$02X), y";
        op[0x14] = "NOP $%1$02X,x";
        op[0x15] = "ORA $%1$02X,x";
        op[0x16] = "ASL $%1$02X,x";
        op[0x17] = "SLO $%1$02X,x";
        op[0x18] = "CLC";
        op[0x19] = "ORA $%2$02X%1$02X,y";
        op[0x1A] = "NOP";
        op[0x1B] = "SLO $%2$02X%1$02X,y";
        op[0x1C] = "NOP $%2$02X%1$02X,x";
        op[0x1D] = "ORA $%2$02X%1$02X,x";
        op[0x1E] = "ASL $%2$02X%1$02X,x";
        op[0x1F] = "SLO $%2$02X%1$02X,x";
        op[0x20] = "JSR $%2$02X%1$02X";
        op[0x21] = "AND $(%2$02X%1$02X,x)";
        op[0x22] = "KIL";
        op[0x23] = "RLA $(%2$02X%1$02X,x)";
        op[0x24] = "BIT $%1$02X";
        op[0x25] = "AND $%1$02X";
        op[0x26] = "ROL $%1$02X";
        op[0x27] = "RLA $%1$02X";
        op[0x28] = "PLP";
        op[0x29] = "AND #$%1$02X";
        op[0x2A] = "ROL";
        op[0x2B] = "ANC #$%1$02X";
        op[0x2C] = "BIT $%2$02X%1$02X";
        op[0x2D] = "AND $%2$02X%1$02X";
        op[0x2E] = "ROL $%2$02X%1$02X";
        op[0x2F] = "RLA $%2$02X%1$02X";
        op[0x30] = "BMI $%3$02X";
        op[0x31] = "AND ($%1$02X), y";
        op[0x32] = "KIL";
        op[0x33] = "RLA ($%1$02X), y";
        op[0x34] = "NOP $%1$02X,x";
        op[0x35] = "AND $%1$02X,x";
        op[0x36] = "ROL $%1$02X,x";
        op[0x37] = "RLA $%1$02X,x";
        op[0x38] = "SEC";
        op[0x39] = "AND $%2$02X%1$02X,y";
        op[0x3A] = "NOP";
        op[0x3B] = "RLA $%2$02X%1$02X,y";
        op[0x3C] = "NOP $%2$02X%1$02X,x";
        op[0x3D] = "AND $%2$02X%1$02X,x";
        op[0x3E] = "ROL $%2$02X%1$02X,x";
        op[0x3F] = "RLA $%2$02X%1$02X,x";
        op[0x40] = "RTI";
        op[0x41] = "EOR $(%2$02X%1$02X,x)";
        op[0x42] = "KIL";
        op[0x43] = "SRE $(%2$02X%1$02X,x)";
        op[0x44] = "NOP $%1$02X";
        op[0x45] = "EOR $%1$02X";
        op[0x46] = "LSR $%1$02X";
        op[0x47] = "SRE $%1$02X";
        op[0x48] = "PHA";
        op[0x49] = "EOR #$%1$02X";
        op[0x4A] = "LSR";
        op[0x4B] = "ALR #$%1$02X";
        op[0x4C] = "JMP $%2$02X%1$02X";
        op[0x4D] = "EOR $%2$02X%1$02X";
        op[0x4E] = "LSR $%2$02X%1$02X";
        op[0x4F] = "SRE $%2$02X%1$02X";
        op[0x50] = "BVC $%3$02X";
        op[0x51] = "EOR ($%1$02X), y";
        op[0x52] = "KIL";
        op[0x53] = "SRE ($%1$02X), y";
        op[0x54] = "NOP $%1$02X,x";
        op[0x55] = "EOR $%1$02X,x";
        op[0x56] = "LSR $%1$02X,x";
        op[0x57] = "SRE $%1$02X,x";
        op[0x58] = "CLI";
        op[0x59] = "EOR $%2$02X%1$02X,y";
        op[0x5A] = "NOP";
        op[0x5B] = "SRE $%2$02X%1$02X,y";
        op[0x5C] = "NOP $%2$02X%1$02X,x";
        op[0x5D] = "EOR $%2$02X%1$02X,x";
        op[0x5E] = "LSR $%2$02X%1$02X,x";
        op[0x5F] = "SRE $%2$02X%1$02X,x";
        op[0x60] = "RTS";
        op[0x61] = "ADC $(%2$02X%1$02X,x)";
        op[0x62] = "KIL";
        op[0x63] = "RRA $(%2$02X%1$02X,x)";
        op[0x64] = "NOP $%1$02X";
        op[0x65] = "ADC $%1$02X";
        op[0x66] = "ROR $%1$02X";
        op[0x67] = "RRA $%1$02X";
        op[0x68] = "PLA";
        op[0x69] = "ADC #$%1$02X";
        op[0x6A] = "ROR";
        op[0x6B] = "ARR #$%1$02X";
        op[0x6C] = "JMP ($%2$02X%1$02X)";
        op[0x6D] = "ADC $%2$02X%1$02X";
        op[0x6E] = "ROR $%2$02X%1$02X";
        op[0x6F] = "RRA $%2$02X%1$02X";
        op[0x70] = "BVS $%3$02X";
        op[0x71] = "ADC ($%1$02X), y";
        op[0x72] = "KIL";
        op[0x73] = "RRA ($%1$02X), y";
        op[0x74] = "NOP $%1$02X,x";
        op[0x75] = "ADC $%1$02X,x";
        op[0x76] = "ROR $%1$02X,x";
        op[0x77] = "RRA $%1$02X,x";
        op[0x78] = "SEI";
        op[0x79] = "ADC $%2$02X%1$02X,y";
        op[0x7A] = "NOP";
        op[0x7B] = "RRA $%2$02X%1$02X,y";
        op[0x7C] = "NOP $%2$02X%1$02X,x";
        op[0x7D] = "ADC $%2$02X%1$02X,x";
        op[0x7E] = "ROR $%2$02X%1$02X,x";
        op[0x7F] = "RRA $%2$02X%1$02X,x";
        op[0x80] = "NOP #$%1$02X";
        op[0x81] = "STA $(%2$02X%1$02X,x)";
        op[0x82] = "NOP #$%1$02X";
        op[0x83] = "SAX $(%2$02X%1$02X,x)";
        op[0x84] = "STY $%1$02X";
        op[0x85] = "STA $%1$02X";
        op[0x86] = "STX $%1$02X";
        op[0x87] = "SAX $%1$02X";
        op[0x88] = "DEY";
        op[0x89] = "NOP #$%1$02X";
        op[0x8A] = "TXA";
        op[0x8B] = "XAA #$%1$02X";
        op[0x8C] = "STY $%2$02X%1$02X";
        op[0x8D] = "STA $%2$02X%1$02X";
        op[0x8E] = "STX $%2$02X%1$02X";
        op[0x8F] = "SAX $%2$02X%1$02X";
        op[0x90] = "BCC $%3$02X";
        op[0x91] = "STA ($%1$02X), y";
        op[0x92] = "KIL";
        op[0x93] = "AHX ($%1$02X), y";
        op[0x94] = "STY $%1$02X,x";
        op[0x95] = "STA $%1$02X,x";
        op[0x96] = "STX $%1$02X,y";
        op[0x97] = "SAX $%1$02X,y";
        op[0x98] = "TYA";
        op[0x99] = "STA $%2$02X%1$02X,y";
        op[0x9A] = "TXS";
        op[0x9B] = "TAS $%2$02X%1$02X,y";
        op[0x9C] = "SHY $%2$02X%1$02X,x";
        op[0x9D] = "STA $%2$02X%1$02X,x";
        op[0x9E] = "SHX $%2$02X%1$02X,y";
        op[0x9F] = "AHX $%2$02X%1$02X,y";
        op[0xA0] = "LDY #$%1$02X";
        op[0xA1] = "LDA $(%2$02X%1$02X,x)";
        op[0xA2] = "LDX #$%1$02X";
        op[0xA3] = "LAX $(%2$02X%1$02X,x)";
        op[0xA4] = "LDY $%1$02X";
        op[0xA5] = "LDA $%1$02X";
        op[0xA6] = "LDX $%1$02X";
        op[0xA7] = "LAX $%1$02X";
        op[0xA8] = "TAY";
        op[0xA9] = "LDA #$%1$02X";
        op[0xAA] = "TAX";
        op[0xAB] = "LAX #$%1$02X";
        op[0xAC] = "LDY $%2$02X%1$02X";
        op[0xAD] = "LDA $%2$02X%1$02X";
        op[0xAE] = "LDX $%2$02X%1$02X";
        op[0xAF] = "LAX $%2$02X%1$02X";
        op[0xB0] = "BCS $%3$02X";
        op[0xB1] = "LDA ($%1$02X), y";
        op[0xB2] = "KIL";
        op[0xB3] = "LAX ($%1$02X), y";
        op[0xB4] = "LDY $%1$02X,x";
        op[0xB5] = "LDA $%1$02X,x";
        op[0xB6] = "LDX $%1$02X,y";
        op[0xB7] = "LAX $%1$02X,y";
        op[0xB8] = "CLV";
        op[0xB9] = "LDA $%2$02X%1$02X,y";
        op[0xBA] = "TSX";
        op[0xBB] = "LAS $%2$02X%1$02X,y";
        op[0xBC] = "LDY $%2$02X%1$02X,x";
        op[0xBD] = "LDA $%2$02X%1$02X,x";
        op[0xBE] = "LDX $%2$02X%1$02X,y";
        op[0xBF] = "LAX $%2$02X%1$02X,y";
        op[0xC0] = "CPY #$%1$02X";
        op[0xC1] = "CMP $(%2$02X%1$02X,x)";
        op[0xC2] = "NOP #$%1$02X";
        op[0xC3] = "DCP $(%2$02X%1$02X,x)";
        op[0xC4] = "CPY $%1$02X";
        op[0xC5] = "CMP $%1$02X";
        op[0xC6] = "DEC $%1$02X";
        op[0xC7] = "DCP $%1$02X";
        op[0xC8] = "INY";
        op[0xC9] = "CMP #$%1$02X";
        op[0xCA] = "DEX";
        op[0xCB] = "AXS #$%1$02X";
        op[0xCC] = "CPY $%2$02X%1$02X";
        op[0xCD] = "CMP $%2$02X%1$02X";
        op[0xCE] = "DEC $%2$02X%1$02X";
        op[0xCF] = "DCP $%2$02X%1$02X";
        op[0xD0] = "BNE $%3$02X";
        op[0xD1] = "CMP ($%1$02X), y";
        op[0xD2] = "KIL";
        op[0xD3] = "DCP ($%1$02X), y";
        op[0xD4] = "NOP $%1$02X,x";
        op[0xD5] = "CMP $%1$02X,x";
        op[0xD6] = "DEC $%1$02X,x";
        op[0xD7] = "DCP $%1$02X,x";
        op[0xD8] = "CLD";
        op[0xD9] = "CMP $%2$02X%1$02X,y";
        op[0xDA] = "NOP";
        op[0xDB] = "DCP $%2$02X%1$02X,y"; //did i delete this line somehow?
        op[0xDC] = "NOP $%2$02X%1$02X,x";
        op[0xDD] = "CMP $%2$02X%1$02X,x";
        op[0xDE] = "DEC $%2$02X%1$02X,x";
        op[0xDF] = "DCP $%2$02X%1$02X,x";
        op[0xE0] = "CPX #$%1$02X";
        op[0xE1] = "SBC $(%2$02X%1$02X,x)";
        op[0xE2] = "NOP #$%1$02X";
        op[0xE3] = "ISC $(%2$02X%1$02X,x)";
        op[0xE4] = "CPX $%1$02X";
        op[0xE5] = "SBC $%1$02X";
        op[0xE6] = "INC $%1$02X";
        op[0xE7] = "ISC $%1$02X";
        op[0xE8] = "INX";
        op[0xE9] = "SBC #$%1$02X";
        op[0xEA] = "NOP";
        op[0xEB] = "SBC #$%1$02X";
        op[0xEC] = "CPX $%2$02X%1$02X";
        op[0xED] = "SBC $%2$02X%1$02X";
        op[0xEE] = "INC $%2$02X%1$02X";
        op[0xEF] = "ISC $%2$02X%1$02X";
        op[0xF0] = "BEQ $%3$02X";
        op[0xF1] = "SBC ($%1$02X), y";
        op[0xF2] = "KIL";
        op[0xF3] = "ISC ($%1$02X), y";
        op[0xF4] = "NOP $%1$02X,x";
        op[0xF5] = "SBC $%1$02X,x";
        op[0xF6] = "INC $%1$02X,x";
        op[0xF7] = "ISC $%1$02X,x";
        op[0xF8] = "SED";
        op[0xF9] = "SBC $%2$02X%1$02X,y";
        op[0xFA] = "NOP";
        op[0xFB] = "ISC $%2$02X%1$02X,y";
        op[0xFC] = "NOP $%2$02X%1$02X,x";
        op[0xFD] = "SBC $%2$02X%1$02X,x";
        op[0xFE] = "INC $%2$02X%1$02X,x";
        op[0xFF] = "ISC $%2$02X%1$02X,x";
        return op;
    }

    //these methods are needed for NSF playing use
    public void setRegA(int value) {
        A = value & 0xff;
    }

    public void setRegX(int value) {
        X = value & 0xff;
    }

    public void setPC(int value) {
        PC = value & 0xffff;
        idle = false;
        log("**PC SET**");
    }

    public final void log(String tolog) {
        if (logging) {
            try {
                w.write(tolog);
            } catch (IOException e) {
                System.err.println("Cannot write to debug log" + e.getLocalizedMessage());
            }
        }
    }

    private void flushLog() {
        if (logging) {
            try {
                w.flush();
            } catch (IOException e) {
                System.err.println("Cannot write to debug log" + e.getLocalizedMessage());
            }
        }
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/CPURAM.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.cheats.Patch;
import com.grapeshot.halfnes.mappers.Mapper;
import java.util.Arrays;
import java.util.HashMap;

/**
 *
 * @author Andrew Hoffman
 *
 *
 */
public class CPURAM {

    private final int[] wram = new int[2048];
    Mapper mapper;
    public APU apu;
    PPU ppu; //need these to call their write handlers from here.
    private HashMap<Integer, Patch> patches = new HashMap<>();

    public CPURAM(final Mapper mappy) {
        mapper = mappy;
        // init memory
        Arrays.fill(wram, 0xff);
    }

    public final int read(final int addr) {
        if (!patches.isEmpty()) {
            int retval = _read(addr);
            Patch p = patches.get(addr);
            if (p != null && p.getAddress() == addr && p.matchesData(retval)) {
                return p.getData();
            }
            return retval;
        } else {
            return _read(addr);
        }
    }

    public final int _read(final int addr) {
        if (addr > 0x4018) {
            return mapper.cartRead(addr);
        } else if (addr <= 0x1fff) {
            return wram[addr & 0x7FF];
        } else if (addr <= 0x3fff) {
            // 8 byte ppu regs; mirrored lots
            return ppu.read(addr & 7);
        } else if (0x4000 <= addr && addr <= 0x4018) {
            return apu.read(addr - 0x4000);
        } else {
            return addr >> 8; //open bus
        }
    }

    public final void write(final int addr, final int data) {
//        if((data & 0xff) != data){
//            System.err.println("DANGER WILL ROBINSON");
//        }
        if (addr > 0x4018) {
            mapper.cartWrite(addr, data);
        } else if (addr <= 0x1fff) {
            wram[addr & 0x7FF] = data;
        } else if (addr <= 0x3fff) {
            // 8 byte ppu regs; mirrored lots
            ppu.write(addr & 7, data);
        } else if (0x4000 <= addr && addr <= 0x4018) {
            apu.write(addr - 0x4000, data);
        }
    }

    public void setAPU(APU apu) {
        this.apu = apu;
    }

    public void setPPU(PPU ppu) {
        this.ppu = ppu;
    }

    public void setPatches(HashMap<Integer, Patch> p) {
        this.patches = p;
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/FileUtils.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import java.awt.EventQueue;
import java.io.*;

/**
 *
 * @author Andrew
 */
public class FileUtils {
    
    private FileUtils() {}

    public static String getExtension(final File f) {
        return getExtension(f.getName());
    }

    public static String getExtension(final String s) {
        if (s == null || s.equals("")) {
            return "";
        }
        int split = s.lastIndexOf('.');
        if (split < 0) {
            return "";
        }
        return s.substring(split);

    }

    public static String stripExtension(final File f) {
        String s = f.getName();
        if (s == null || s.equals("")) {
            return "";
        }
        int split = s.lastIndexOf('.');
        if (split < 0) {
            return "";
        }
        return s.substring(0, split);
    }

    public static String stripExtension(final String s) {
        if (s == null || s.equals("")) {
            return "";
        }
        int split = s.lastIndexOf('.');
        if (split < 0) {
            return "";
        }
        return s.substring(0, split);
    }

    public static void writetofile(final int[] array, final String path) {
        //note: does NOT write the ints directly to the file - only the low bytes.
        AsyncWriter writer = new AsyncWriter(array, path);
        writer.run();
    }

    public static void asyncwritetofile(final int[] array, final String path) {
        //now does the file writing in the dispatch thread
        //hopefully that will eliminate annoying hitches when file system's slow
        //and not do pathological stuff like threads are prone to
        AsyncWriter writer = new AsyncWriter(array, path);
        EventQueue.invokeLater(writer);
    }

    private static class AsyncWriter implements Runnable {

        private final int[] a;
        private final String path;

        public AsyncWriter(final int[] a, final String path) {
            this.a = a;
            this.path = path;
        }

        @Override
        public void run() {
            if (a != null && path != null) {
                try {
                    FileOutputStream b = new FileOutputStream(path);
                    byte[] buf = new byte[a.length];
                    for (int i = 0; i < a.length; ++i) {
                        buf[i] = (byte) (a[i] & 0xff);
                    }
                    b.write(buf);
                    b.flush();
                    b.close();
                } catch (IOException e) {
                    System.err.print("Could not save. ");
                    System.err.println(e);
                }
            }
        }
    }

    public static String getFilenamefromPath(String path) {
        return new File(path).getName();
    }

    public static int[] readfromfile(final String path) {
        File f = new File(path);
        byte[] bytes = new byte[(int) f.length()];
        FileInputStream fis;
        try {
            fis = new FileInputStream(f);
                fis.read(bytes);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                System.err.println("Failed to load file");
            e.printStackTrace();
            }
        int[] ints = new int[bytes.length];

        for (int i = 0;
                i < bytes.length;
                i++) {
            ints[i] = (short) (bytes[i] & 0xFF);
        }

        return ints;
    }

    public static boolean exists(final String path) {
        File f = new File(path);
        return f.canRead() && !f.isDirectory();
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/HeadlessNES.java
================================================
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.ui.HeadlessUI;
import com.grapeshot.halfnes.ui.PuppetController;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * @author Mitchell Skaggs
 */
public class HeadlessNES {
    
    private HeadlessNES() {}
    
    public static final int scale = 4;
    public static void main(String[] args) {
        BufferedImage bufferedImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB_PRE);
        HeadlessUI ui = new HeadlessUI("src/test/resources/nestest/nestest.nes", true);

        for (int i = 0; i < 100; i++) {
            ui.runFrame();
        }
        ui.getController1().pressButton(PuppetController.Button.START);
        ui.runFrame();
        ui.getController1().releaseButton(PuppetController.Button.START);
        for (int i = 0; i < 5; i++) {
            ui.runFrame();
        }

        BufferedImage image = ui.getLastFrame();

        JFrame frame = new JFrame("Display") {
            @Override
            public void paint(Graphics g) {
                super.paint(g);
                g.drawImage(image, 0, 0, image.getWidth() * scale, image.getHeight() * scale, this);
            }
        };
        frame.setSize(256 * scale, 224 * scale);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/JInputHelper.java
================================================
package com.grapeshot.halfnes;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * Created by KlausH on 29.11.2015.
 */
public enum JInputHelper {

    ;

    private static final String[] NATIVE_LIBRARIES = new String[]{
        // Windows
        "jinput-dx8.dll",
        "jinput-dx8_64.dll",
        "jinput-raw.dll",
        "jinput-raw_64.dll",
        "jinput-wintab.dll",
        "jinput-wintab.dll",
        // Linux
        "libjinput-linux.so",
        "libjinput-linux64.so",
        // OsX (Mac)
        "libjinput-osx.jnilib",};

    public static void setupJInput() {
        try {
            File nativesDirectory = createTempDirectory();
            unpackNativeLibraries(nativesDirectory);
            setLibraryPath(nativesDirectory);
            fixInputPluginForWindows8();
        } catch (Exception exception) {
            throw new RuntimeException("Unable to setup native libraries.", exception);
        }
    }

    private static void unpackNativeLibraries(File nativesDirectory) throws IOException {
        for (String nativeLibrary : NATIVE_LIBRARIES) {
            unpackNativeLibrary(nativesDirectory, nativeLibrary);
        }
    }

    private static void unpackNativeLibrary(File nativesDirectory, String nativeLibrary) throws IOException {
        try (InputStream nativeLibraryInputStream = ClassLoader.getSystemResourceAsStream(nativeLibrary)) {
            File nativeLibraryTempFile = new File(nativesDirectory, nativeLibrary);
            nativeLibraryTempFile.deleteOnExit();
            if (!nativeLibraryTempFile.exists()) {
                try (BufferedOutputStream nativeLibraryTempFileOutputStream 
                        = new BufferedOutputStream(new FileOutputStream(nativeLibraryTempFile))) {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = nativeLibraryInputStream.read(buffer)) > 0) {
                        nativeLibraryTempFileOutputStream.write(buffer, 0, length);
                    }
                }
            }
        }
    }

    private static File createTempDirectory() throws IOException {

        String tmpdir = System.getProperty("java.io.tmpdir") + "/halfnes-" + NES.VERSION;
        System.err.println(tmpdir);
        File f = new File(tmpdir);
        if (!f.exists()) {
            f.mkdir();
        }

        //File nativeDirectory = Files.createTempDirectory("halfNES-natives").toFile();
        f.deleteOnExit();
        return f;
    }

    private static void setLibraryPath(final File nativesDirectory) throws NoSuchFieldException, IllegalAccessException {
        System.setProperty("java.library.path", nativesDirectory.getAbsolutePath());
        final Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);
    }

    private static void fixInputPluginForWindows8() {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            String os = System.getProperty("os.name", "").trim();
            if (os.startsWith("Windows")) {
                if (os.startsWith("Windows 8")) {
                    // disable default plugin lookup
                    System.setProperty("jinput.useDefaultPlugin", "false");
                    // set to same as windows 7
                    System.setProperty("net.java.games.input.plugins", "net.java.games.input.DirectAndRawInputEnvironmentPlugin");
                }
                if (os.startsWith("Windows 10") || isWindows10()) {
                    // disable default plugin lookup
                    System.setProperty("jinput.useDefaultPlugin", "false");
                    // set fallback to AWT plugin
                    System.setProperty("net.java.games.input.plugins", "net.java.games.input.DirectAndRawInputEnvironmentPlugin");
                }
            }
            return null;
        });
    }

    private static boolean isWindows10() {
        try {
            Process process = Runtime.getRuntime().exec("cmd.exe /c ver");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
            bufferedReader.readLine();
            String line = bufferedReader.readLine();
            process.waitFor();
            return line.contains("10");
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }

}


================================================
FILE: src/main/java/com/grapeshot/halfnes/JavaFXNES.java
================================================
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.ui.ControllerImpl;
import com.grapeshot.halfnes.ui.GUIInterface;
import com.grapeshot.halfnes.ui.OnScreenMenu;
import com.grapeshot.halfnes.video.NesColors;
import java.nio.ByteBuffer;
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritablePixelFormat;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCombination;
import javafx.scene.paint.Color;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;

/**
 * @author Stephen Chin - steveonjava@gmail.com
 */
public class JavaFXNES extends Application implements GUIInterface {


    // Set the overscan insets to match your config
    // And make sure your framebuffer is set to:
    // * screen.width + overscan.right
    // * screen.height + overscan.bottom
    
    //overscan for PC
    private static final Insets overscan = new Insets(0, 0, 0, 0);
    
    //overscan for Pi screen
    //private static final Insets overscan = new Insets(-59, 160, 150, 0);
    private static final Insets extraOverscan = new Insets(8, 0, 8, 0);

    private NES nes;
    private Canvas gameCanvas;
    private Stage stage;
    private OnScreenMenu menu;

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        //Rectangle2D bounds = Screen.getPrimary().getBounds();
        Rectangle2D bounds = new Rectangle2D(0,0,640,480);
        gameCanvas = new Canvas(256, 240);
        stage.addEventHandler(javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST, e -> nes.quit());
        menu = new OnScreenMenu(this);
        //menu.setPadding(extraOverscan);
        menu.setPrefWidth(256);
        menu.setPrefHeight(240);
        Group root = new Group(gameCanvas, menu);
        Scene scene = new Scene(root, bounds.getWidth(), bounds.getHeight(), Color.BLACK);
        stage.setScene(scene);
        //stage.setFullScreen(true);
        stage.setFullScreenExitKeyCombination(KeyCombination.valueOf("F11"));
        stage.addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, e -> {
            if (e.getCode().equals(KeyCode.ESCAPE)) {
                menu.show();
            }
        });
        root.setLayoutX(overscan.getRight() - overscan.getLeft() - extraOverscan.getLeft() * bounds.getWidth() / 256);
        root.setLayoutY(overscan.getBottom() - overscan.getTop() - extraOverscan.getTop() * bounds.getHeight() / 240);
        root.getTransforms().add(new Scale(
            (bounds.getWidth() - (overscan.getRight() - overscan.getLeft())) / (256 - extraOverscan.getLeft() - extraOverscan.getRight()),
            (bounds.getHeight() - (overscan.getBottom() - overscan.getTop())) / (240 - extraOverscan.getTop() - extraOverscan.getBottom())));
        nes = new NES(this);
        ControllerImpl padController1 = new ControllerImpl(scene, 0);
        ControllerImpl padController2 = new ControllerImpl(scene, 1);
        padController1.startEventQueue();
        padController2.startEventQueue();
        nes.setControllers(padController1, padController2);
        final List<String> params = getParameters().getRaw();
        new Thread(() -> {
            if (params.isEmpty()) {
                nes.run();
            } else {
                nes.run(params.get(0));
            }
        }, "Game Thread").start();
    }

    public static void main(String[] args) {
        JInputHelper.setupJInput();
        launch(args);
    }

    @Override
    public NES getNes() {
        return nes;
    }

    @Override
    public void setNES(NES nes) {
        this.nes = nes;
    }

    final byte[] buffer = new byte[256 * 240 * 4];
    final WritablePixelFormat<ByteBuffer> format = WritablePixelFormat.getByteBgraPreInstance();

    private final long[] frametimes = new long[60];
    private int frametimeptr = 0;
    private double fps;

    @Override
    public void setFrame(int[] nespixels, int[] bgcolor, boolean dotcrawl) {
        Platform.runLater(() -> {
            frametimes[frametimeptr] = nes.getFrameTime();
            ++frametimeptr;
            frametimeptr %= frametimes.length;

            if (frametimeptr == 0) {
                long averageframes = 0;
                for (long l : frametimes) {
                    averageframes += l;
                }
                averageframes /= frametimes.length;
                fps = 1E9 / averageframes;
                stage.setTitle(String.format("HalfNES %s, %2.2f fps",
                    //                    + ((nes.frameskip > 0) ? " frameskip " + nes.frameskip : ""),
                    NES.VERSION,
                    //                    nes.getCurrentRomName(),
                    fps));
            }
            PixelWriter writer = gameCanvas.getGraphicsContext2D().getPixelWriter();
            for (int i = 0; i < nespixels.length; i++) {
                byte[] colbytes = NesColors.colbytes[(nespixels[i] & 0x1c0) >> 6][nespixels[i] & 0x3f];
                System.arraycopy(colbytes, 0, buffer, i * 4, 3);
            }
            writer.setPixels(0, 0, 256, 240, format, buffer, 0, 256 * 4);
        });
    }

    @Override
    public void messageBox(String message) {
        System.out.println("message = " + message);
    }

    @Override
    public void run() {
        Platform.runLater(() -> {
            stage.show();
            menu.show();
        });
    }

    @Override
    public void render() {
        // whatever...
    }

    public void loadROMs(String path) {
        menu.loadROMs(path);
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/NES.java
================================================
/**
 *
 * @author Andrew Hoffman
 */
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.cheats.ActionReplay;
import com.grapeshot.halfnes.mappers.BadMapperException;
import com.grapeshot.halfnes.mappers.Mapper;
import com.grapeshot.halfnes.ui.ControllerInterface;
import com.grapeshot.halfnes.ui.FrameLimiterImpl;
import com.grapeshot.halfnes.ui.FrameLimiterInterface;
import com.grapeshot.halfnes.ui.GUIInterface;
import javafx.application.Platform;

public class NES implements ProjectInfo {

    private Mapper mapper;
    private APU apu;
    private CPU cpu;
    private CPURAM cpuram;
    private PPU ppu;
    private GUIInterface gui;
    private ControllerInterface controller1, controller2;
    public boolean runEmulation = false;
    private boolean dontSleep = false;
    private boolean shutdown = false;
    public long frameStartTime, framecount, frameDoneTime;
    private boolean frameLimiterOn = true;
    private String curRomPath, curRomName;
    private final FrameLimiterInterface limiter = new FrameLimiterImpl(this, 16639267);
    // Pro Action Replay device
    private ActionReplay actionReplay;

    public NES(GUIInterface gui) {
        if (gui != null) {
            this.gui = gui;
            gui.setNES(this);
            gui.run();
        }
    }

    public CPURAM getCPURAM() {
        return this.cpuram;
    }

    public CPU getCPU() {
        return this.cpu;
    }

    public void run(final String romtoload) {
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1);
        //set thread priority higher than the interface thread
        curRomPath = romtoload;
        gui.loadROMs(romtoload);
        run();
    }

    public void run() {
        while (!shutdown) {
            if (runEmulation) {
                frameStartTime = System.nanoTime();
                actionReplay.applyPatches();
                runframe();
                if (frameLimiterOn && !dontSleep) {
                    limiter.sleep();
                }
                frameDoneTime = System.nanoTime() - frameStartTime;
            } else {
                limiter.sleepFixed();
                if (ppu != null && framecount > 1) {
                    gui.render();
                }
            }
        }
    }

    private synchronized void runframe() {
        //run cpu, ppu for a whole frame
        ppu.runFrame();

        //do end of frame stuff
        dontSleep = apu.bufferHasLessThan(1000);
        //if the audio buffer is completely drained, don't sleep for this frame
        //this is to prevent the emulator from getting stuck sleeping too much
        //on a slow system or when the audio buffer runs dry.

        apu.finishframe();
        cpu.modcycles();

//        if (framecount == 13 * 60) {
//            cpu.startLog();
//            System.err.println("log on");
//        }
        //render the frame
        ppu.renderFrame(gui);
        if ((framecount & 2047) == 0) {
            //save sram every 30 seconds or so
            saveSRAM(true);
        }
        ++framecount;
        //System.err.println(framecount);
    }

    public void setControllers(ControllerInterface controller1, ControllerInterface controller2) {
        this.controller1 = controller1;
        this.controller2 = controller2;
    }

    public void toggleFrameLimiter() {
        frameLimiterOn = !frameLimiterOn;
    }

    public synchronized void loadROM(final String filename) {
        loadROM(filename, null);
    }

    public synchronized void loadROM(final String filename, Integer initialPC) {
        runEmulation = false;
        if (FileUtils.exists(filename)
                && (FileUtils.getExtension(filename).equalsIgnoreCase(".nes")
                || FileUtils.getExtension(filename).equalsIgnoreCase(".nsf"))) {
            Mapper newmapper;
            try {
                final ROMLoader loader = new ROMLoader(filename);
                loader.parseHeader();
                newmapper = Mapper.getCorrectMapper(loader);
                newmapper.setLoader(loader);
                newmapper.loadrom();
            } catch (BadMapperException e) {
                gui.messageBox("Error Loading File: ROM is"
                        + " corrupted or uses an unsupported mapper.\n" + e.getMessage());
                return;
            } catch (Exception e) {
                gui.messageBox("Error Loading File: ROM is"
                        + " corrupted or uses an unsupported mapper.\n" + e.toString() + e.getMessage());
                e.printStackTrace();
                return;
            }
            if (apu != null) {
                //if rom already running save its sram before closing
                apu.destroy();
                saveSRAM(false);
                //also get rid of mapper etc.
                mapper.destroy();
                cpu = null;
                cpuram = null;
                ppu = null;
            }
            mapper = newmapper;
            //now some annoying getting of all the references where they belong
            cpuram = mapper.getCPURAM();
            actionReplay = new ActionReplay(cpuram);
            cpu = mapper.cpu;
            ppu = mapper.ppu;
            apu = new APU(this, cpu, cpuram);
            cpuram.setAPU(apu);
            cpuram.setPPU(ppu);
            curRomPath = filename;
            curRomName = FileUtils.getFilenamefromPath(filename);

            framecount = 0;
            //if savestate exists, load it
            if (mapper.hasSRAM()) {
                loadSRAM();
            }
            //and start emulation
            cpu.init(initialPC);
            mapper.init();
            setParameters();
            runEmulation = true;
        } else {
            gui.messageBox("Could not load file:\nFile " + filename + "\n"
                    + "does not exist or is not a valid NES game.");
        }
    }

    private void saveSRAM(final boolean async) {
        if (mapper != null && mapper.hasSRAM() && mapper.supportsSaves()) {
            if (async) {
                FileUtils.asyncwritetofile(mapper.getPRGRam(), FileUtils.stripExtension(curRomPath) + ".sav");
            } else {
                FileUtils.writetofile(mapper.getPRGRam(), FileUtils.stripExtension(curRomPath) + ".sav");
            }
        }
    }

    private void loadSRAM() {
        final String name = FileUtils.stripExtension(curRomPath) + ".sav";
        if (FileUtils.exists(name) && mapper.supportsSaves()) {
            mapper.setPRGRAM(FileUtils.readfromfile(name));
        }

    }

    public void quit() {
        //save SRAM and quit
        //should wait for any save sram workers to be done before here
       if (cpu != null && curRomPath != null) {
            runEmulation = false;
            saveSRAM(false);
        }
        //there might be some subtle threading bug with saving?
        //System.Exit is very dirty and does NOT let the delete on exit handler
        //fire so the natives stick around...
        shutdown = true;
        Platform.exit();
    }

    public synchronized void reset() {
        if (cpu != null) {
            mapper.reset();
            cpu.reset();
            runEmulation = true;
            apu.pause();
            apu.resume();
        }
        //reset frame counter as well because PPU is reset
        //on Famicom, PPU is not reset when Reset is pressed
        //but some NES games expect it to be and you get garbage.
        framecount = 0;
    }

    public synchronized void reloadROM() {
        loadROM(curRomPath);
    }

    public synchronized void pause() {
        if (apu != null) {
            apu.pause();
        }
        runEmulation = false;
    }

    public long getFrameTime() {
        return frameDoneTime;
    }

    public String getrominfo() {
        if (mapper != null) {
            return mapper.getrominfo();
        }
        return null;
    }

    public synchronized void frameAdvance() {
        runEmulation = false;
        if (cpu != null) {
            runframe();
        }
    }

    public synchronized void resume() {
        if (apu != null) {
            apu.resume();
        }
        if (cpu != null) {
            runEmulation = true;
        }
    }

    public String getCurrentRomName() {
        return curRomName;
    }

    public boolean isFrameLimiterOn() {
        return frameLimiterOn;
    }

    public void messageBox(final String string) {
        if (gui != null) {
            gui.messageBox(string);
        }
    }

    public ControllerInterface getcontroller1() {
        return controller1;
    }

    public ControllerInterface getcontroller2() {
        return controller2;
    }

    public synchronized void setParameters() {
        if (apu != null) {
            apu.setParameters();
        }
        if (ppu != null) {
            ppu.setParameters();
        }
        if (limiter != null && mapper != null) {
            switch (mapper.getTVType()) {
                case NTSC:
                default:
                    limiter.setInterval(16639267);
                    break;
                case PAL:
                case DENDY:
                    limiter.setInterval(19997200);
            }
        }
    }

    /**
     * Access to the Pro Action Replay device.
     */
    public synchronized ActionReplay getActionReplay() {
        return actionReplay;
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/PPU.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import static com.grapeshot.halfnes.PrefsSingleton.get;
import com.grapeshot.halfnes.mappers.Mapper;
import com.grapeshot.halfnes.ui.DebugUI;
import com.grapeshot.halfnes.ui.GUIInterface;
import static com.grapeshot.halfnes.utils.reverseByte;
import java.awt.image.BufferedImage;
import static java.awt.image.BufferedImage.TYPE_INT_BGR;
import java.util.Arrays;
import static java.util.Arrays.fill;
import static java.util.Arrays.fill;

public class PPU {

    public Mapper mapper;
    private int oamaddr, oamstart, readbuffer = 0;
    private int loopyV = 0x0;//ppu memory pointer
    private int loopyT = 0x0;//temp pointer
    private int loopyX = 0;//fine x scroll
    public int scanline = 0;
    public int cycles = 0;
    private int framecount = 0;
    private int div = 2;
    private final int[] OAM = new int[256], secOAM = new int[32],
            spriteshiftregH = new int[8],
            spriteshiftregL = new int[8], spriteXlatch = new int[8],
            spritepals = new int[8], bitmap = new int[240 * 256];
    private int found, bgShiftRegH, bgShiftRegL, bgAttrShiftRegH, bgAttrShiftRegL;
    private final boolean[] spritebgflags = new boolean[8];
    private boolean even = true, bgpattern = true, sprpattern, spritesize, nmicontrol,
            grayscale, bgClip, spriteClip, bgOn, spritesOn,
            vblankflag, sprite0hit, spriteoverflow;
    private int emph;
    public final int[] pal;
    private DebugUI debuggui;
    private int vraminc = 1;
    private final static boolean PPUDEBUG = get().getBoolean("ntView", false);
    private BufferedImage nametableView;
    private final int[] bgcolors = new int[256];
    private int openbus = 0; //the last value written to the PPU
    private int nextattr;
    private int linelowbits;
    private int linehighbits;
    private int penultimateattr;
    private int numscanlines;
    private int vblankline;
    private final int[] cpudivider = {3, 3, 3, 3, 3};

    public PPU(final Mapper mapper) {
        this.pal = new int[]{0x09, 0x01, 0x00, 0x01, 0x00, 0x02, 0x02, 0x0D,
            0x08, 0x10, 0x08, 0x24, 0x00, 0x00, 0x04, 0x2C, 0x09, 0x01, 0x34,
            0x03, 0x00, 0x04, 0x00, 0x14, 0x08, 0x3A, 0x00, 0x02, 0x00, 0x20,
            0x2C, 0x08};
        /*
     power-up pallette checked by Blargg's power_up_palette test. Different
     revs of NES PPU might give different initial results but there's a test
     expecting this set of values and nesemu1, BizHawk, RockNES, MyNes use it
         */
        this.mapper = mapper;
        fill(OAM, 0xff);
        if (PPUDEBUG) {
            nametableView = new BufferedImage(512, 480, TYPE_INT_BGR);
            debuggui = new DebugUI(512, 480);
            debuggui.run();
        }
        setParameters();
    }

    final void setParameters() {
        //set stuff to NTSC or PAL or Dendy values
        switch (mapper.getTVType()) {
            case NTSC:
            default:
                numscanlines = 262;
                vblankline = 241;
                cpudivider[0] = 3;
                break;
            case PAL:
                numscanlines = 312;
                vblankline = 241;
                cpudivider[0] = 4;
                break;
            case DENDY:
                numscanlines = 312;
                vblankline = 291;
                cpudivider[0] = 3;
                break;
        }
    }

    public void runFrame() {
        for (int line = 0; line < numscanlines; ++line) {
            clockLine(line);
        }
    }

    /**
     * Performs a read from a PPU register, as well as causes any side effects
     * of reading that specific register.
     *
     * @param regnum register to read (address with 0x2000 already subtracted)
     * @return the data in the PPU register, or open bus (the last value written
     * to a PPU register) if the register is read only
     */
    public final int read(final int regnum) {
        switch (regnum) {
            case 2:
                even = true;
                if (scanline == 241) {
                    if (cycles == 1) {//suppress NMI flag if it was just turned on this same cycle
                        vblankflag = false;
                    }
                    //OK, uncommenting this makes blargg's NMI suppression test
                    //work but breaks Antarctic Adventure.
                    //I'm going to need a cycle accurate CPU to fix that...
//                    if (cycles < 4) {
//                        //show vblank flag but cancel pending NMI before the CPU
//                        //can actually do anything with it
//                        //TODO: use proper interface for this
//                        mapper.cpu.nmiNext = false;
//                    }
                }
                openbus = (vblankflag ? 0x80 : 0)
                        | (sprite0hit ? 0x40 : 0)
                        | (spriteoverflow ? 0x20 : 0)
                        | (openbus & 0x1f);
                vblankflag = false;
                break;
            case 4:
                // reading this is NOT reliable but some games do it anyways
                openbus = OAM[oamaddr];
                //System.err.println("codemasters?");
                if (renderingOn() && (scanline <= 240)) {
                    if (cycles < 64) {
                        return 0xFF;
                    } else if (cycles <= 256) {
                        return 0x00;
                    } //Micro Machines relies on this:
                    else if (cycles < 320) {
                        return 0xFF;
                    } //and this:
                    else {
                        return secOAM[0]; //is this the right value @ the time?
                    }
                }
                break;
            case 7:
                // PPUDATA
                // correct behavior. read is delayed by one
                // -unless- is a read from sprite pallettes
                final int temp;
                if ((loopyV & 0x3fff) < 0x3f00) {
                    temp = readbuffer;
                    readbuffer = mapper.ppuRead(loopyV & 0x3fff);
                } else {
                    readbuffer = mapper.ppuRead((loopyV & 0x3fff) - 0x1000);
                    temp = mapper.ppuRead(loopyV);
                }
                if (!renderingOn() || (scanline > 240 && scanline < (numscanlines - 1))) {
                    loopyV += vraminc;
                } else {
                    //if 2007 is read during rendering PPU increments both horiz
                    //and vert counters erroneously.
                    incLoopyVHoriz();
                    incLoopyVVert();
                }
                openbus = temp;
                break;

            // and don't increment on read
            default:
                return openbus; // last value written to ppu
        }
        return openbus;
    }

    /**
     * Performs a write to a PPU register
     *
     * @param regnum register number from 0 to 7, memory addresses are decoded
     * to these elsewhere
     * @param data the value to write to the register (0x00 to 0xff valid)
     */
    public final void write(final int regnum, final int data) {
//        if (regnum != 4 /*&& regnum != 7*/) {
//            System.err.println("PPU write - wrote " + utils.hex(data) + " to reg "
//                    + utils.hex(regnum + 0x2000)
//                    + " frame " + framecount + " scanline " + scanline);
//        }
        //debugdraw();
        openbus = data;
        switch (regnum) {
            case 0: //PPUCONTROL (2000)
                //set 2 bits of vram address (nametable select)
                //bits 0 and 1 affect loopyT to change nametable start by 0x400
                loopyT &= ~0xc00;
                loopyT |= (data & 3) << 10;
                /*
                 SMB1 writes here at the end of its main loop and if this write
                 lands on one exact PPU clock, the address bits are set to 0.
                 This only happens on one CPU/PPU alignment of real hardware 
                 though so it only shows up ~33% of the time.
                 */
                vraminc = (((data & (utils.BIT2)) != 0) ? 32 : 1);
                sprpattern = ((data & (utils.BIT3)) != 0);
                bgpattern = ((data & (utils.BIT4)) != 0);
                spritesize = ((data & (utils.BIT5)) != 0);
                /*bit 6 is kind of a halt and catch fire situation since it outputs
                 ppu color data on the EXT pins that are tied to ground if set
                 and that'll make the PPU get very hot from sourcing the current. 
                 Only really useful for the NESRGB interposer board, kind of
                 useless for emulators. I will ignore it.
                 */
                nmicontrol = ((data & (utils.BIT7)) != 0);

                break;
            case 1: //PPUMASK (2001)
                grayscale = ((data & (utils.BIT0)) != 0);
                bgClip = !((data & (utils.BIT1)) != 0); //clip left 8 pixels when its on
                spriteClip = !((data & (utils.BIT2)) != 0);
                bgOn = ((data & (utils.BIT3)) != 0);
                spritesOn = ((data & (utils.BIT4)) != 0);
                emph = (data & 0xe0) << 1;
                if (numscanlines == 312) {
                    //if PAL switch position of red and green emphasis bits (6 and 5)
                    //red is bit 6 -> bit 7
                    //green is bit 7 -> bit 6
                    int red = (emph >> 6) & 1;
                    int green = (emph >> 7) & 1;
                    emph &= 0xf3f;
                    emph |= (red << 7) | (green << 6);
                }
                break;
            case 3:
                // PPUOAMADDR (2003)
                // most games just write zero and use the dma
                oamaddr = data & 0xff;
                break;
            case 4:
                // PPUOAMDATA(2004)
                if ((oamaddr & 3) == 2) {
                    OAM[oamaddr++] = (data & 0xE3);
                } else {
                    OAM[oamaddr++] = data;
                }
                oamaddr &= 0xff;
                // games don't usually write this directly anyway, it's unreliable
                break;

            // PPUSCROLL(2005)
            case 5:
                if (even) {
                    // update horizontal scroll
                    loopyT &= ~0x1f;
                    loopyX = data & 7;
                    loopyT |= data >> 3;

                    even = false;
                } else {
                    // update vertical scroll
                    loopyT &= ~0x7000;
                    loopyT |= ((data & 7) << 12);
                    loopyT &= ~0x3e0;
                    loopyT |= (data & 0xf8) << 2;
                    even = true;

                }
                break;

            case 6:
                // PPUADDR (2006)
                if (even) {
                    // high byte
                    loopyT &= 0xc0ff;
                    loopyT |= ((data & 0x3f) << 8);
                    loopyT &= 0x3fff;
                    even = false;
                } else {
                    loopyT &= 0xfff00;
                    loopyT |= data;
                    loopyV = loopyT;
                    even = true;
                }
                break;
            case 7:
                // PPUDATA             
                mapper.ppuWrite((loopyV & 0x3fff), data);
                if (!renderingOn() || (scanline > 240 && scanline < (numscanlines - 1))) {
                    loopyV += vraminc;
                } else if ((loopyV & 0x7000) == 0x7000) {
                    int YScroll = loopyV & 0x3E0;
                    loopyV &= 0xFFF;
                    switch (YScroll) {
                        case 0x3A0:
                            loopyV ^= 0xBA0;
                            break;
                        case 0x3E0:
                            loopyV ^= 0x3E0;
                            break;
                        default:
                            loopyV += 0x20;
                            break;
                    }
                } else {
                    // while rendering, it seems to drop by 1 line, regardless of increment mode
                    loopyV += 0x1000;
                }
                break;
            default:
                break;
        }
    }

    /**
     * PPU is on if either background or sprites are enabled
     *
     * @return true
     */
    public boolean renderingOn() {
        return bgOn || spritesOn;
    }

    /**
     * MMC3 scan line counter isn't clocked if background and sprites are using
     * the same half of the pattern table
     *
     * @return true if PPU is rendering and BG and sprites are using different
     * pattern tables
     */
    public final boolean mmc3CounterClocking() {
        return (bgpattern != sprpattern) && renderingOn();
    }

    /**
     * Runs the PPU emulation for one NES scan line.
     */
    public final void clockLine(int scanline) {
        //skip a PPU clock on line 0 of odd frames when rendering is on
        //and we are in NTSC mode (pal has no skip)
        int skip = (numscanlines == 262
                && scanline == 0
                && renderingOn()
                && !((framecount & (utils.BIT1)) != 0)) ? 1 : 0;
        for (cycles = skip; cycles < 341; ++cycles) {
            clock();
        }
    }

    private int tileAddr = 0;
    private int cpudividerctr = 0;

    /**
     * runs the emulation for one PPU clock cycle.
     */
    public final void clock() {

        //cycle based ppu stuff will go here
        if (cycles == 1) {
            if (scanline == 0) {
                dotcrawl = renderingOn();
            }
            if (scanline < 240) {
                bgcolors[scanline] = pal[0];
            }
        }
        if (scanline < 240 || scanline == (numscanlines - 1)) {
            //on all rendering lines
            if (renderingOn()
                    && ((cycles >= 1 && cycles <= 256)
                    || (cycles >= 321 && cycles <= 336))) {
                //fetch background tiles, load shift registers
                bgFetch();
            } else if (cycles == 257 && renderingOn()) {
                //x scroll reset
                //horizontal bits of loopyV = loopyT
                loopyV &= ~0x41f;
                loopyV |= loopyT & 0x41f;

            } else if (cycles > 257 && cycles <= 341) {
                //clear the oam address from pxls 257-341 continuously
                oamaddr = 0;
            }
            if ((cycles == 340) && renderingOn()) {
                //read the same nametable byte twice
                //this signals the MMC5 to increment the scanline counter
                fetchNTByte();
                fetchNTByte();
            }
            if (cycles == 65 && renderingOn()) {
                oamstart = oamaddr;
            }
            if (cycles == 260 && renderingOn()) {
                //evaluate sprites for NEXT scanline (as long as either background or sprites are enabled)
                //this does in fact happen on scanline 261 but it doesn't do anything useful
                //it's cycle 260 because that's when the first important sprite byte is read
                //actually sprite overflow should be set by sprite eval somewhat before
                //so this needs to be split into 2 parts, the eval and the data fetches
                evalSprites();
            }
            if (scanline == (numscanlines - 1)) {
                if (cycles == 0) {// turn off vblank, sprite 0, sprite overflow flags
                    vblankflag = false;
                    sprite0hit = false;
                    spriteoverflow = false;
                } else if (cycles >= 280 && cycles <= 304 && renderingOn()) {
                    //loopyV = (all of)loopyT for each of these cycles
                    loopyV = loopyT;
                }
            }
        } else if (scanline == vblankline && cycles == 1) {
            //handle vblank on / off
            vblankflag = true;
        }
        if (!renderingOn() || (scanline > 240 && scanline < (numscanlines - 1))) {
            //HACK ALERT
            //handle the case of MMC3 mapper watching A12 toggle
            //even when read or write aren't asserted on the bus
            //needed to pass Blargg's mmc3 tests
            mapper.checkA12(loopyV & 0x3fff);
        }
        if (scanline < 240 && cycles >= 1 && cycles <= 256) {
            int bufferoffset = (scanline << 8) + (cycles - 1);
            //bg drawing
            if (bgOn) { //if background is on, draw a dot of that first
                final boolean isBG = drawBGPixel(bufferoffset);
                //sprite drawing
                drawSprites(scanline, cycles - 1, isBG);

            } else if (spritesOn) {
                //just the sprites then
                int bgcolor = ((loopyV > 0x3f00 && loopyV < 0x3fff) ? mapper.ppuRead(loopyV) : pal[0]);
                bitmap[bufferoffset] = bgcolor;
                drawSprites(scanline, cycles - 1, true);
            } else {
                //rendering is off, so draw either the background color OR
                //if the PPU address points to the palette, draw that color instead.
                int bgcolor = ((loopyV > 0x3f00 && loopyV < 0x3fff) ? mapper.ppuRead(loopyV) : pal[0]);
                bitmap[bufferoffset] = bgcolor;
            }
            //deal with the grayscale flag
            if (grayscale) {
                bitmap[bufferoffset] &= 0x30;
            }
            //handle color emphasis
            bitmap[bufferoffset] = (bitmap[bufferoffset] & 0x3f) | emph;

        }
        //handle nmi
        if (vblankflag && nmicontrol) {
            //pull NMI line on when conditions are right
            mapper.cpu.setNMI(true);
        } else {
            mapper.cpu.setNMI(false);
        }

        //clock CPU, once every 3 ppu cycles
        div = (div + 1) % cpudivider[cpudividerctr];
        if (div == 0) {
            mapper.cpu.runcycle(scanline, cycles);
            mapper.cpucycle(1);
            cpudividerctr = (cpudividerctr + 1) % cpudivider.length;
        }
        if (cycles == 257) {
            mapper.notifyscanline(scanline);
        } else if (cycles == 340) {
            scanline = (scanline + 1) % numscanlines;
            if (scanline == 0) {
                ++framecount;
            }
        }
    }

    private void bgFetch() {
        //fetch tiles for background
        //on real PPU this logic is repurposed for sprite fetches as well
        //System.err.println(hex(loopyV));
        bgAttrShiftRegH |= ((nextattr >> 1) & 1);
        bgAttrShiftRegL |= (nextattr & 1);
        //background fetches
        switch ((cycles - 1) & 7) {
            case 1:
                fetchNTByte();
                break;
            case 3:
                //fetch attribute (FIX MATH)
                penultimateattr = getAttribute(((loopyV & 0xc00) + 0x23c0),
                        (loopyV) & 0x1f,
                        (((loopyV) & 0x3e0) >> 5));
                break;
            case 5:
                //fetch low bg byte
                linelowbits = mapper.ppuRead((tileAddr)
                        + ((loopyV & 0x7000) >> 12));
                break;
            case 7:
                //fetch high bg byte
                linehighbits = mapper.ppuRead((tileAddr) + 8
                        + ((loopyV & 0x7000) >> 12));
                bgShiftRegL |= linelowbits;
                bgShiftRegH |= linehighbits;
                nextattr = penultimateattr;
                if (cycles != 256) {
                    incLoopyVHoriz();
                } else {
                    incLoopyVVert();
                }
                break;
            default:
                break;
        }
        if (cycles >= 321 && cycles <= 336) {
            bgShiftClock();
        }
    }

    private void incLoopyVVert() {
        //increment loopy_v to next row of tiles
        if ((loopyV & 0x7000) == 0x7000) {
            //reset the fine scroll bits and increment tile address to next row
            loopyV &= ~0x7000;
            int y = (loopyV & 0x03E0) >> 5;
            if (y == 29) {
                //if row is 29 zero fine scroll and bump to next nametable
                y = 0;
                loopyV ^= 0x0800;
            } else {
                //increment (wrap to 5 bits) but if row is already over 29
                //we don't bump loopyV to next nt.
                y = (y + 1) & 31;
            }
            loopyV = (loopyV & ~0x03E0) | (y << 5);
        } else {
            //increment the fine scroll
            loopyV += 0x1000;
        }
    }

    private void incLoopyVHoriz() {
        //increment horizontal part of loopyv
        if ((loopyV & 0x001F) == 31) // if coarse X == 31
        {
            loopyV &= ~0x001F; // coarse X = 0
            loopyV ^= 0x0400;// switch horizontal nametable
        } else {
            loopyV += 1;// increment coarse X
        }
    }

    private void fetchNTByte() {
        //fetch nt byte
        tileAddr = mapper.ppuRead(
                ((loopyV & 0xc00) | 0x2000) + (loopyV & 0x3ff)) * 16
                + (bgpattern ? 0x1000 : 0);
    }

    private boolean drawBGPixel(int bufferoffset) {
        //background drawing
        //loopyX picks bits
        final boolean isBG;
        if (bgClip && (bufferoffset & 0xff) < 8) {
            //left hand of screen clipping
            //(needs to be marked as BG and not cause a sprite hit)
            bitmap[bufferoffset] = pal[0];
            isBG = true;
        } else {
            final int bgPix = (((bgShiftRegH >> -loopyX + 16) & 1) << 1)
                    + ((bgShiftRegL >> -loopyX + 16) & 1);
            final int bgPal = (((bgAttrShiftRegH >> -loopyX + 8) & 1) << 1)
                    + ((bgAttrShiftRegL >> -loopyX + 8) & 1);
            isBG = (bgPix == 0);
            bitmap[bufferoffset] = isBG ? pal[0] : pal[(bgPal << 2) + bgPix];
        }
        bgShiftClock();
        return isBG;
    }

    private void bgShiftClock() {
        bgShiftRegH <<= 1;
        bgShiftRegL <<= 1;
        bgAttrShiftRegH <<= 1;
        bgAttrShiftRegL <<= 1;
    }

    boolean dotcrawl = true;
    private boolean sprite0here = false;

    /**
     * evaluates PPU sprites for the NEXT scanline
     */
    private void evalSprites() {
        sprite0here = false;
        int ypos, offset;
        found = 0;
        Arrays.fill(secOAM, 0xff);
        //primary evaluation
        //need to emulate behavior when OAM address is set to nonzero here
        for (int spritestart = oamstart; spritestart < 255; spritestart += 4) {
            //for each sprite, first we cull the non-visible ones
            ypos = OAM[spritestart];
            offset = scanline - ypos;
            if (ypos > scanline || offset > (spritesize ? 15 : 7)) {
                //sprite is out of range vertically
                continue;
            }
            //if we're here it's a valid renderable sprite
            if (spritestart == 0) {
                sprite0here = true;
            }
            //actually which sprite is flagged for sprite 0 depends on the starting
            //oam address which is, on the real thing, not necessarily zero.
            if (found >= 8) {
                //if more than 8 sprites, set overflow bit and STOP looking
                //todo: add "no sprite limit" option back
                spriteoverflow = true;
                break; //also the real PPU does strange stuff on sprite overflow
                //todo: emulate register trashing that happens when overflow
            } else {
                //set up ye sprite for rendering
                secOAM[found * 4] = OAM[spritestart];
//                secOAM[found * 4 + 1] = OAM[spritestart + 1];
//                secOAM[found * 4 + 2] = OAM[spritestart + 2];
//                secOAM[found * 4 + 3] = OAM[spritestart + 3];
                final int oamextra = OAM[spritestart + 2];

                //bg flag
                spritebgflags[found] = ((oamextra & (utils.BIT5)) != 0);
                //x value
                spriteXlatch[found] = OAM[spritestart + 3];
                spritepals[found] = ((oamextra & 3) + 4) * 4;
                if (((oamextra & (utils.BIT7)) != 0)) {
                    //if sprite is flipped vertically, reverse the offset
                    offset = (spritesize ? 15 : 7) - offset;
                }
                //now correction for the fact that 8x16 tiles are 2 separate tiles
                if (offset > 7) {
                    offset += 8;
                }
                //get tile address (8x16 sprites can use both pattern tbl pages but only the even tiles)
                final int tilenum = OAM[spritestart + 1];
                spriteFetch(spritesize, tilenum, offset, oamextra);
                ++found;
            }
        }
        for (int i = found; i < 8; ++i) {
            //fill unused sprite registers with zeros
            spriteshiftregL[found] = 0;
            spriteshiftregH[found] = 0;
            //also, we need to do 8 reads no matter how many sprites we found
            //dummy reads are to sprite 0xff
            spriteFetch(spritesize, 0xff, 0, 0);
        }
    }

    private void spriteFetch(final boolean spritesize, final int tilenum, int offset, final int oamextra) {
        int tilefetched;
        if (spritesize) {
            tilefetched = ((tilenum & 1) * 0x1000)
                    + (tilenum & 0xfe) * 16;
        } else {
            tilefetched = tilenum * 16
                    + ((sprpattern) ? 0x1000 : 0);
        }
        tilefetched += offset;
        //now load up the shift registers for said sprite
        final boolean hflip = ((oamextra & (utils.BIT6)) != 0);
        if (!hflip) {
            spriteshiftregL[found] = reverseByte(mapper.ppuRead(tilefetched));
            spriteshiftregH[found] = reverseByte(mapper.ppuRead(tilefetched + 8));
        } else {
            spriteshiftregL[found] = mapper.ppuRead(tilefetched);
            spriteshiftregH[found] = mapper.ppuRead(tilefetched + 8);
        }
    }

    /**
     * draws appropriate pixel of the sprites selected by sprite evaluation
     */
    private void drawSprites(int line, int x, boolean bgflag) {
        final int startdraw = !spriteClip ? 0 : 8;//sprite left 8 pixels clip
        int sprpxl = 0;
        int index = 7;
        //check all the used sprite slots to see if any sprite covers this pixel
        for (int y = found - 1; y >= 0; --y) {
            int off = x - spriteXlatch[y];
            if (off >= 0 && off <= 8) {
                if ((spriteshiftregH[y] & 1) + (spriteshiftregL[y] & 1) != 0) {
                    index = y;
                    sprpxl = 2 * (spriteshiftregH[y] & 1) + (spriteshiftregL[y] & 1);
                }
                spriteshiftregH[y] >>= 1;
                spriteshiftregL[y] >>= 1;
            }
        }
        if (sprpxl == 0 || x < startdraw || !spritesOn) {
            //no opaque sprite pixel here
            return;
        }

        if (sprite0here && (index == 0) && !bgflag
                && x < 255) {
            //sprite 0 hit!
            sprite0hit = true;
        }
        //now, FINALLY, drawing.
        if (!spritebgflags[index] || bgflag) {
            bitmap[(line << 8) + x] = pal[spritepals[index] + sprpxl];
        }
    }

    /**
     * Read the appropriate color attribute byte for the current tile. this is
     * fetched 2x as often as it really needs to be, the MMC5 takes advantage of
     * that for ExGrafix mode.
     *
     * @param ntstart //start of the current attribute table
     * @param tileX //x position of tile (0-31)
     * @param tileY //y position of tile (0-29)
     * @return attribute table value (0-3)
     */
    private int getAttribute(final int ntstart, final int tileX, final int tileY) {
        final int base = mapper.ppuRead(ntstart + (tileX >> 2) + 8 * (tileY >> 2));
        if (((tileY & (utils.BIT1)) != 0)) {
            if (((tileX & (utils.BIT1)) != 0)) {
                return (base >> 6) & 3;
            } else {
                return (base >> 4) & 3;
            }
        } else if (((tileX & (utils.BIT1)) != 0)) {
            return (base >> 2) & 3;
        } else {
            return base & 3;
        }
    }

    /**
     * draw all 4 nametables/tileset/pallette to debug window. (for the
     * nametable viewer)
     */
    private void debugDraw() {
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 30; ++j) {
                nametableView.setRGB(i * 8, j * 8, 8, 8,
                        debugGetTile(mapper.ppuRead(0x2000 + i + 32 * j) * 16
                                + (bgpattern ? 0x1000 : 0)), 0, 8);
            }
        }
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 30; ++j) {
                nametableView.setRGB(i * 8 + 255, j * 8, 8, 8,
                        debugGetTile(mapper.ppuRead(0x2400 + i + 32 * j) * 16
                                + (bgpattern ? 0x1000 : 0)), 0, 8);
            }
        }
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 30; ++j) {
                nametableView.setRGB(i * 8, j * 8 + 239, 8, 8,
                        debugGetTile(mapper.ppuRead(0x2800 + i + 32 * j) * 16
                                + (bgpattern ? 0x1000 : 0)), 0, 8);
            }
        }
        for (int i = 0; i < 32; ++i) {
            for (int j = 0; j < 30; ++j) {
                nametableView.setRGB(i * 8 + 255, j * 8 + 239, 8, 8,
                        debugGetTile(mapper.ppuRead(0x2C00 + i + 32 * j) * 16
                                + (bgpattern ? 0x1000 : 0)), 0, 8);
            }
        }

        //draw the tileset
//        for (int i = 0; i < 16; ++i) {
//            for (int j = 0; j < 32; ++j) {
//                nametableView.setRGB(i * 8, j * 8, 8, 8,
//                        debugGetTile((i + 16 * j) * 16), 0, 8);
//            }
//        }
        //draw the palettes on the bottom.
//        for (int i = 0; i < 32; ++i) {
//            for (int j = 0; j < 16; ++j) {
//                for (int k = 0; k < 16; ++k) {
//                    nametableView.setRGB(j + i * 16, k + 256, nescolor[0][pal[i]]);
//                }
//            }
//        }
        debuggui.setFrame(nametableView);
        //debugbuff.clear();
    }

    /**
     * Fetches 8x8 NES tile stored at the given offset. This is an artifact of
     * the first renderer I wrote which drew 8 scanlines at a time.
     *
     * @return an 8x8 array with colors stored as RGB packed in int
     */
    private int[] debugGetTile(final int offset) {
        //read one whole tile from nametable and convert from bitplane to packed
        //only used for debugging
        int[] dat = new int[64];
        for (int i = 0; i < 8; ++i) {
            //per line of tile ( 1 byte)
            for (int j = 0; j < 8; ++j) {
                //per pixel(1 bit)
                dat[8 * i + j]
                        = ((((mapper.ppuRead(i + offset) & (utils.BIT7 - j)) != 0))
                        ? 0x555555 : 0)
                        + ((((mapper.ppuRead(i + offset + 8) & (utils.BIT7 - j)) != 0))
                        ? 0xaaaaaa : 0);
            }
        }
        return dat;
    }

    /**
     * Sends off a frame of NES video to be rendered by the GUI. also includes
     * dot crawl flag and BG color to be displayed around edges which are needed
     * for the NTSC renderer.
     *
     * @param gui the GUI window to render to
     */
    public final void renderFrame(GUIInterface gui) {
        if (PPUDEBUG) {
            debugDraw();
        }
        if (gui != null) {
            gui.setFrame(bitmap, bgcolors, dotcrawl);
        }

    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/PrefsSingleton.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import java.util.prefs.Preferences;

/**
 *
 * @author Andrew
 */
public class PrefsSingleton {

    private static Preferences instance = null;

    protected PrefsSingleton() {
        // Exists only to defeat instantiation.
    }

    public synchronized static Preferences get() {
        if (instance == null) {
            instance = Preferences.userNodeForPackage(com.grapeshot.halfnes.NES.class);
        }
        return instance;
    }
}


================================================
FILE: src/main/java/com/grapeshot/halfnes/ROMLoader.java
================================================
/*
 * HalfNES by Andrew Hoffman
 * Licensed under the GNU GPL Version 3. See LICENSE file
 */
package com.grapeshot.halfnes;

import com.grapeshot.halfnes.mappers.BadMapperException;
import com.grapeshot.halfnes.mappers.Mapper;

public class ROMLoader {
    //this is the oldest code in the project... I'm honestly ashamed
    //at how it's structured but for now it works.
    //TODO: fix this up

    //this SHOULD do just enough to figure out the file type
    //and the correct mapper for it, and no more.
    public String name;
    public int prgsize;
    public int chrsize;
    public Mapper.MirrorType scrolltype;
    public Mapper.TVType tvtype;
    public int mappertype;
    public int submapper;
    public int prgoff, chroff;
    public boolean savesram = false;
    public int[] header;
    private final int[] therom;

    public ROMLoader(String filename) {
        therom = FileUtils.readfromfile(filename);
        name = filename;
    }

    private void ReadHeader(int len) {
        // iNES header is 16 bytes, nsf header is 128,
        //other headers increasingly large
        header = new int[len];
        System.arraycopy(therom, 0, header, 0, len);
    }

    public void parseHeader() throws BadMapperException {
        ReadHeader(16);
        // decode iNES 1.0 headers
        // 1st 4 bytes : $4E $45 $53 $1A
        if (header[0] == 'N' && header[1] == 'E'
                && header[2] == 'S' && header[3] == 0x1A) {
            //a valid iNES file, proceed

            scrolltype = ((header[6] & (utils.BIT3)) != 0)
                    ? Mapper.MirrorType.FOUR_SCREEN_MIRROR
                    : ((header[6] & (utils.BIT0)) != 0)
                            ? Mapper.MirrorType.V_MIRROR
                            : Mapper.MirrorType.H_MIRROR;
            savesram = ((header[6] & (utils.BIT1)) != 0);
            mappertype = (header[6] >> 4);
   
Download .txt
gitextract_4vbeh24w/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── nbactions.xml
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── grapeshot/
    │   │           └── halfnes/
    │   │               ├── APU.java
    │   │               ├── CPU.java
    │   │               ├── CPURAM.java
    │   │               ├── FileUtils.java
    │   │               ├── HeadlessNES.java
    │   │               ├── JInputHelper.java
    │   │               ├── JavaFXNES.java
    │   │               ├── NES.java
    │   │               ├── PPU.java
    │   │               ├── PrefsSingleton.java
    │   │               ├── ROMLoader.java
    │   │               ├── Twiddler.form
    │   │               ├── Twiddler.java
    │   │               ├── audio/
    │   │               │   ├── AudioOutInterface.java
    │   │               │   ├── CircularBuffer.java
    │   │               │   ├── ExpansionSoundChip.java
    │   │               │   ├── FDSSoundChip.java
    │   │               │   ├── FFT.java
    │   │               │   ├── MMC5SoundChip.java
    │   │               │   ├── Namco163SoundChip.java
    │   │               │   ├── NoiseTimer.java
    │   │               │   ├── Reverberator.java
    │   │               │   ├── SquareTimer.java
    │   │               │   ├── Sunsoft5BSoundChip.java
    │   │               │   ├── SwingAudioImpl.java
    │   │               │   ├── Timer.java
    │   │               │   ├── TriangleTimer.java
    │   │               │   ├── VRC6SoundChip.java
    │   │               │   └── VRC7SoundChip.java
    │   │               ├── cheats/
    │   │               │   ├── ActionReplay.java
    │   │               │   ├── ActionReplayGui.form
    │   │               │   ├── ActionReplayGui.java
    │   │               │   └── Patch.java
    │   │               ├── halfNES.java
    │   │               ├── mappers/
    │   │               │   ├── Action52Mapper.java
    │   │               │   ├── AfterburnerMapper.java
    │   │               │   ├── AnromMapper.java
    │   │               │   ├── BadMapperException.java
    │   │               │   ├── BnromMapper.java
    │   │               │   ├── CaltronMapper.java
    │   │               │   ├── CnromMapper.java
    │   │               │   ├── CodemastersMapper.java
    │   │               │   ├── ColorDreamsMapper.java
    │   │               │   ├── CrazyClimberMapper.java
    │   │               │   ├── CrimeBustersMapper.java
    │   │               │   ├── FME7Mapper.java
    │   │               │   ├── GnromMapper.java
    │   │               │   ├── IremH3001Mapper.java
    │   │               │   ├── MIMICMapper.java
    │   │               │   ├── MMC1Mapper.java
    │   │               │   ├── MMC2Mapper.java
    │   │               │   ├── MMC3Mapper.java
    │   │               │   ├── MMC4Mapper.java
    │   │               │   ├── MMC5Mapper.java
    │   │               │   ├── Mapper.java
    │   │               │   ├── Mapper107.java
    │   │               │   ├── Mapper112.java
    │   │               │   ├── Mapper119.java
    │   │               │   ├── Mapper140.java
    │   │               │   ├── Mapper15.java
    │   │               │   ├── Mapper152.java
    │   │               │   ├── Mapper182.java
    │   │               │   ├── Mapper185.java
    │   │               │   ├── Mapper200.java
    │   │               │   ├── Mapper201.java
    │   │               │   ├── Mapper203.java
    │   │               │   ├── Mapper212.java
    │   │               │   ├── Mapper213.java
    │   │               │   ├── Mapper214.java
    │   │               │   ├── Mapper225.java
    │   │               │   ├── Mapper226.java
    │   │               │   ├── Mapper229.java
    │   │               │   ├── Mapper231.java
    │   │               │   ├── Mapper240.java
    │   │               │   ├── Mapper241.java
    │   │               │   ├── Mapper242.java
    │   │               │   ├── Mapper244.java
    │   │               │   ├── Mapper246.java
    │   │               │   ├── Mapper255.java
    │   │               │   ├── Mapper31.java
    │   │               │   ├── Mapper33.java
    │   │               │   ├── Mapper36.java
    │   │               │   ├── Mapper47.java
    │   │               │   ├── Mapper48.java
    │   │               │   ├── Mapper58.java
    │   │               │   ├── Mapper60.java
    │   │               │   ├── Mapper61.java
    │   │               │   ├── Mapper62.java
    │   │               │   ├── Mapper70.java
    │   │               │   ├── Mapper72.java
    │   │               │   ├── Mapper76.java
    │   │               │   ├── Mapper78.java
    │   │               │   ├── Mapper86.java
    │   │               │   ├── Mapper87.java
    │   │               │   ├── Mapper92.java
    │   │               │   ├── Mapper94.java
    │   │               │   ├── Mapper97.java
    │   │               │   ├── NINA_001_Mapper.java
    │   │               │   ├── NINA_003_006_Mapper.java
    │   │               │   ├── NSFMapper.java
    │   │               │   ├── NSFPlayerFont.java
    │   │               │   ├── NamcoMapper.java
    │   │               │   ├── Namcot34x3Mapper.java
    │   │               │   ├── NromMapper.java
    │   │               │   ├── Sunsoft01Mapper.java
    │   │               │   ├── Sunsoft02Mapper.java
    │   │               │   ├── Sunsoft03Mapper.java
    │   │               │   ├── TengenRamboMapper.java
    │   │               │   ├── UnromMapper.java
    │   │               │   ├── VRC1Mapper.java
    │   │               │   ├── VRC2Mapper.java
    │   │               │   ├── VRC3Mapper.java
    │   │               │   ├── VRC4Mapper.java
    │   │               │   ├── VRC6Mapper.java
    │   │               │   └── VRC7Mapper.java
    │   │               ├── ui/
    │   │               │   ├── ControllerImpl.java
    │   │               │   ├── ControllerInterface.java
    │   │               │   ├── ControlsDialog.form
    │   │               │   ├── ControlsDialog.java
    │   │               │   ├── DebugUI.java
    │   │               │   ├── DummyController.java
    │   │               │   ├── FrameLimiterImpl.java
    │   │               │   ├── FrameLimiterInterface.java
    │   │               │   ├── GUIInterface.java
    │   │               │   ├── HeadlessUI.java
    │   │               │   ├── NESFileFilter.java
    │   │               │   ├── OnScreenMenu.java
    │   │               │   ├── Oscilloscope.java
    │   │               │   ├── PreferencesDialog.form
    │   │               │   ├── PreferencesDialog.java
    │   │               │   ├── PuppetController.java
    │   │               │   └── SwingUI.java
    │   │               ├── utils.java
    │   │               └── video/
    │   │                   ├── AltNTSCRenderer.java
    │   │                   ├── NTSCRenderer.java
    │   │                   ├── NesColors.java
    │   │                   ├── RGBRenderer.java
    │   │                   └── Renderer.java
    │   ├── java-templates/
    │   │   └── com/
    │   │       └── grapeshot/
    │   │           └── halfnes/
    │   │               └── ProjectInfo.java
    │   └── resources/
    │       ├── changelog.txt
    │       └── todo.txt
    └── test/
        ├── java/
        │   └── com/
        │       └── grapeshot/
        │           └── halfnes/
        │               ├── JInputTest.java
        │               └── nestest/
        │                   └── NesTest.java
        └── resources/
            └── nestest/
                ├── compare.log
                ├── nestest.log
                └── nestest.nes
Download .txt
SYMBOL INDEX (1002 symbols across 137 files)

FILE: src/main/java-templates/com/grapeshot/halfnes/ProjectInfo.java
  type ProjectInfo (line 7) | public interface ProjectInfo {

FILE: src/main/java/com/grapeshot/halfnes/APU.java
  class APU (line 12) | public class APU {
    method APU (line 68) | public APU(final NES nes, final CPU cpu, final CPURAM cpuram) {
    method initTndLookup (line 77) | private static int[] initTndLookup() {
    method initSquareLookup (line 85) | private static int[] initSquareLookup() {
    method setParameters (line 94) | public final synchronized void setParameters() {
    method bufferHasLessThan (line 137) | public boolean bufferHasLessThan(int samples) {
    method read (line 141) | public final int read(final int addr) {
    method addExpnSound (line 180) | public void addExpnSound(ExpansionSoundChip chip) {
    method destroy (line 184) | public void destroy() {
    method pause (line 188) | public void pause() {
    method resume (line 192) | public void resume() {
    method write (line 196) | public final void write(final int reg, final int data) {
    method updateto (line 398) | public final void updateto(final int cpucycle) {
    method getOutputLevel (line 465) | private int getOutputLevel() {
    method highpass_filter (line 481) | private int highpass_filter(int sample) {
    method lowpass_filter (line 489) | private int lowpass_filter(int sample) {
    method finishframe (line 493) | public final void finishframe() {
    method clockframecounter (line 499) | private void clockframecounter() {
    method setvolumes (line 527) | private void setvolumes() {
    method clockdmc (line 534) | private void clockdmc() {
    method dmcfillbuffer (line 566) | private void dmcfillbuffer() {
    method restartdmc (line 596) | private void restartdmc() {
    method setlength (line 602) | private void setlength() {
    method setlinctr (line 613) | private void setlinctr() {
    method setenvelope (line 624) | private void setenvelope() {
    method setsweep (line 645) | private void setsweep() {

FILE: src/main/java/com/grapeshot/halfnes/CPU.java
  class CPU (line 14) | public final class CPU {
    type dummy (line 43) | private static enum dummy {
    method CPU (line 49) | public CPU(final CPURAM cpuram) {
    method startLog (line 57) | public void startLog() {
    method startLog (line 66) | public void startLog(String path) {
    method stopLog (line 75) | public void stopLog() {
    method init (line 80) | public void init() {
    method init (line 84) | public void init(Integer initialPC) {// different than reset
    method reset (line 115) | public void reset() {
    method modcycles (line 125) | public void modcycles() {
    method stealcycles (line 130) | public void stealcycles(int cyclestosteal) {
    method runcycle (line 135) | public final void runcycle(final int scanline, final int pixel) {
    method delayInterrupt (line 1265) | private void delayInterrupt() {
    method rol (line 1270) | private void rol(final int addr) {
    method rolA (line 1280) | private void rolA() {
    method ror (line 1287) | private void ror(final int addr) {
    method rorA (line 1299) | private void rorA() {
    method setNMI (line 1308) | public void setNMI(boolean val) {
    method nmi (line 1312) | private void nmi() {
    method interrupt (line 1324) | private void interrupt() {
    method breakinterrupt (line 1336) | private void breakinterrupt() {
    method lsr (line 1347) | private void lsr(final int addr) {
    method lsrA (line 1357) | private void lsrA() {
    method eor (line 1364) | private void eor(final int addr) {
    method ora (line 1370) | private void ora(final int addr) {
    method bit (line 1377) | private void bit(final int addr) {
    method jsr (line 1384) | private void jsr(final int addr) {
    method rts (line 1392) | private void rts() {
    method rti (line 1398) | private void rti() {
    method pop (line 1405) | private int pop() {
    method push (line 1411) | public void push(final int byteToPush) {
    method branch (line 1417) | private void branch(final boolean isTaken) {
    method inc (line 1438) | private void inc(final int addr) {
    method dec (line 1449) | private void dec(final int addr) {
    method adc (line 1460) | private void adc(final int addr) {
    method sbc (line 1483) | private void sbc(final int addr) {
    method and (line 1507) | private void and(final int addr) {
    method asl (line 1512) | private void asl(final int addr) {
    method aslA (line 1522) | private void aslA() {
    method cmp (line 1530) | private void cmp(final int regval, final int addr) {
    method lda (line 1547) | private void lda(final int addr) {
    method ldx (line 1552) | private void ldx(final int addr) {
    method ldy (line 1557) | private void ldy(final int addr) {
    method setflags (line 1562) | private void setflags(final int result) {
    method sta (line 1567) | private void sta(final int addr) {
    method stx (line 1577) | private void stx(final int addr) {
    method sty (line 1587) | private void sty(final int addr) {
    method ahx (line 1598) | private void ahx(final int addr) {
    method alr (line 1608) | private void alr(final int addr) {
    method anc (line 1613) | private void anc(final int addr) {
    method arr (line 1618) | private void arr(final int addr) {
    method axs (line 1626) | private void axs(final int addr) {
    method dcp (line 1632) | private void dcp(final int regval, final int addr) {
    method las (line 1637) | private void las(final int addr) {
    method lax (line 1643) | private void lax(final int addr) {
    method isc (line 1648) | private void isc(final int addr) {
    method rla (line 1653) | private void rla(final int addr) {
    method rra (line 1658) | private void rra(int addr) {
    method sax (line 1663) | private void sax(int addr) {
    method shx (line 1667) | private void shx(final int addr) {
    method shy (line 1677) | private void shy(final int addr) {
    method slo (line 1687) | private void slo(int addr) {
    method sre (line 1692) | private void sre(int addr) {
    method tas (line 1697) | private void tas(int addr) {
    method xaa (line 1708) | private void xaa(int addr) {
    method imm (line 1715) | private int imm() {
    method zpg (line 1719) | private int zpg() {
    method zpg (line 1724) | private int zpg(final int reg) {
    method rel (line 1729) | private int rel() {
    method abs (line 1735) | private int abs() {
    method abs (line 1740) | private int abs(final int reg, final dummy dummy) {
    method ind (line 1758) | private int ind() {
    method indX (line 1768) | private int indX() {
    method indY (line 1776) | private int indY(final dummy dummy) {
    method flagstobyte (line 1794) | public final int flagstobyte() {
    method bytetoflags (line 1804) | private void bytetoflags(final int statusbyte) {
    method status (line 1819) | public String status() {
    method opcodes (line 1826) | public static String[] opcodes() {
    method setRegA (line 2090) | public void setRegA(int value) {
    method setRegX (line 2094) | public void setRegX(int value) {
    method setPC (line 2098) | public void setPC(int value) {
    method log (line 2104) | public final void log(String tolog) {
    method flushLog (line 2114) | private void flushLog() {

FILE: src/main/java/com/grapeshot/halfnes/CPURAM.java
  class CPURAM (line 18) | public class CPURAM {
    method CPURAM (line 26) | public CPURAM(final Mapper mappy) {
    method read (line 32) | public final int read(final int addr) {
    method _read (line 45) | public final int _read(final int addr) {
    method write (line 60) | public final void write(final int addr, final int data) {
    method setAPU (line 76) | public void setAPU(APU apu) {
    method setPPU (line 80) | public void setPPU(PPU ppu) {
    method setPatches (line 84) | public void setPatches(HashMap<Integer, Patch> p) {

FILE: src/main/java/com/grapeshot/halfnes/FileUtils.java
  class FileUtils (line 14) | public class FileUtils {
    method FileUtils (line 16) | private FileUtils() {}
    method getExtension (line 18) | public static String getExtension(final File f) {
    method getExtension (line 22) | public static String getExtension(final String s) {
    method stripExtension (line 34) | public static String stripExtension(final File f) {
    method stripExtension (line 46) | public static String stripExtension(final String s) {
    method writetofile (line 57) | public static void writetofile(final int[] array, final String path) {
    method asyncwritetofile (line 63) | public static void asyncwritetofile(final int[] array, final String pa...
    class AsyncWriter (line 71) | private static class AsyncWriter implements Runnable {
      method AsyncWriter (line 76) | public AsyncWriter(final int[] a, final String path) {
      method run (line 81) | @Override
    method getFilenamefromPath (line 101) | public static String getFilenamefromPath(String path) {
    method readfromfile (line 105) | public static int[] readfromfile(final String path) {
    method exists (line 128) | public static boolean exists(final String path) {

FILE: src/main/java/com/grapeshot/halfnes/HeadlessNES.java
  class HeadlessNES (line 13) | public class HeadlessNES {
    method HeadlessNES (line 15) | private HeadlessNES() {}
    method main (line 18) | public static void main(String[] args) {

FILE: src/main/java/com/grapeshot/halfnes/JInputHelper.java
  type JInputHelper (line 13) | public enum JInputHelper {
    method setupJInput (line 31) | public static void setupJInput() {
    method unpackNativeLibraries (line 42) | private static void unpackNativeLibraries(File nativesDirectory) throw...
    method unpackNativeLibrary (line 48) | private static void unpackNativeLibrary(File nativesDirectory, String ...
    method createTempDirectory (line 65) | private static File createTempDirectory() throws IOException {
    method setLibraryPath (line 79) | private static void setLibraryPath(final File nativesDirectory) throws...
    method fixInputPluginForWindows8 (line 86) | private static void fixInputPluginForWindows8() {
    method isWindows10 (line 107) | private static boolean isWindows10() {

FILE: src/main/java/com/grapeshot/halfnes/JavaFXNES.java
  class JavaFXNES (line 27) | public class JavaFXNES extends Application implements GUIInterface {
    method start (line 47) | @Override
    method main (line 89) | public static void main(String[] args) {
    method getNes (line 94) | @Override
    method setNES (line 99) | @Override
    method setFrame (line 111) | @Override
    method messageBox (line 140) | @Override
    method run (line 145) | @Override
    method render (line 153) | @Override
    method loadROMs (line 158) | public void loadROMs(String path) {

FILE: src/main/java/com/grapeshot/halfnes/NES.java
  class NES (line 16) | public class NES implements ProjectInfo {
    method NES (line 35) | public NES(GUIInterface gui) {
    method getCPURAM (line 43) | public CPURAM getCPURAM() {
    method getCPU (line 47) | public CPU getCPU() {
    method run (line 51) | public void run(final String romtoload) {
    method run (line 59) | public void run() {
    method runframe (line 78) | private synchronized void runframe() {
    method setControllers (line 105) | public void setControllers(ControllerInterface controller1, Controller...
    method toggleFrameLimiter (line 110) | public void toggleFrameLimiter() {
    method loadROM (line 114) | public synchronized void loadROM(final String filename) {
    method loadROM (line 118) | public synchronized void loadROM(final String filename, Integer initia...
    method saveSRAM (line 178) | private void saveSRAM(final boolean async) {
    method loadSRAM (line 188) | private void loadSRAM() {
    method quit (line 196) | public void quit() {
    method reset (line 210) | public synchronized void reset() {
    method reloadROM (line 224) | public synchronized void reloadROM() {
    method pause (line 228) | public synchronized void pause() {
    method getFrameTime (line 235) | public long getFrameTime() {
    method getrominfo (line 239) | public String getrominfo() {
    method frameAdvance (line 246) | public synchronized void frameAdvance() {
    method resume (line 253) | public synchronized void resume() {
    method getCurrentRomName (line 262) | public String getCurrentRomName() {
    method isFrameLimiterOn (line 266) | public boolean isFrameLimiterOn() {
    method messageBox (line 270) | public void messageBox(final String string) {
    method getcontroller1 (line 276) | public ControllerInterface getcontroller1() {
    method getcontroller2 (line 280) | public ControllerInterface getcontroller2() {
    method setParameters (line 284) | public synchronized void setParameters() {
    method getActionReplay (line 307) | public synchronized ActionReplay getActionReplay() {

FILE: src/main/java/com/grapeshot/halfnes/PPU.java
  class PPU (line 18) | public class PPU {
    method PPU (line 54) | public PPU(final Mapper mapper) {
    method setParameters (line 74) | final void setParameters() {
    method runFrame (line 96) | public void runFrame() {
    method read (line 110) | public final int read(final int regnum) {
    method write (line 189) | public final void write(final int regnum, final int data) {
    method renderingOn (line 324) | public boolean renderingOn() {
    method mmc3CounterClocking (line 335) | public final boolean mmc3CounterClocking() {
    method clockLine (line 342) | public final void clockLine(int scanline) {
    method clock (line 360) | public final void clock() {
    method bgFetch (line 478) | private void bgFetch() {
    method incLoopyVVert (line 521) | private void incLoopyVVert() {
    method incLoopyVHoriz (line 543) | private void incLoopyVHoriz() {
    method fetchNTByte (line 554) | private void fetchNTByte() {
    method drawBGPixel (line 561) | private boolean drawBGPixel(int bufferoffset) {
    method bgShiftClock (line 582) | private void bgShiftClock() {
    method evalSprites (line 595) | private void evalSprites() {
    method spriteFetch (line 659) | private void spriteFetch(final boolean spritesize, final int tilenum, ...
    method drawSprites (line 683) | private void drawSprites(int line, int x, boolean bgflag) {
    method getAttribute (line 725) | private int getAttribute(final int ntstart, final int tileX, final int...
    method debugDraw (line 744) | private void debugDraw() {
    method debugGetTile (line 799) | private int[] debugGetTile(final int offset) {
    method renderFrame (line 824) | public final void renderFrame(GUIInterface gui) {

FILE: src/main/java/com/grapeshot/halfnes/PrefsSingleton.java
  class PrefsSingleton (line 13) | public class PrefsSingleton {
    method PrefsSingleton (line 17) | protected PrefsSingleton() {
    method get (line 21) | public synchronized static Preferences get() {

FILE: src/main/java/com/grapeshot/halfnes/ROMLoader.java
  class ROMLoader (line 10) | public class ROMLoader {
    method ROMLoader (line 29) | public ROMLoader(String filename) {
    method ReadHeader (line 34) | private void ReadHeader(int len) {
    method parseHeader (line 41) | public void parseHeader() throws BadMapperException {
    method load (line 136) | public int[] load(int size, int offset) {
    method romlen (line 142) | public int romlen() {

FILE: src/main/java/com/grapeshot/halfnes/Twiddler.java
  class Twiddler (line 13) | public class Twiddler extends javax.swing.JFrame {
    method Twiddler (line 20) | public Twiddler() {
    method Twiddler (line 24) | public Twiddler(double v) {
    method get (line 30) | public double get() {
    method initComponents (line 39) | @SuppressWarnings("unchecked")
    method jButton1ActionPerformed (line 81) | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {...

FILE: src/main/java/com/grapeshot/halfnes/audio/AudioOutInterface.java
  type AudioOutInterface (line 11) | public interface AudioOutInterface {
    method outputSample (line 13) | public void outputSample(int sample);
    method flushFrame (line 15) | public void flushFrame(boolean waitIfBufferFull);
    method pause (line 17) | public void pause();
    method resume (line 19) | public void resume();
    method destroy (line 21) | public void destroy();
    method bufferHasLessThan (line 23) | public boolean bufferHasLessThan(int samples);

FILE: src/main/java/com/grapeshot/halfnes/audio/CircularBuffer.java
  class CircularBuffer (line 11) | public class CircularBuffer {
    method CircularBuffer (line 18) | public CircularBuffer(int size) {
    method write (line 36) | public void write(final int data) {
    method read (line 42) | public int read() {
    method advanceRead (line 49) | public void advanceRead(int amt) {
    method advanceWrite (line 53) | public void advanceWrite(int amt) {
    method peek (line 57) | public int peek() {

FILE: src/main/java/com/grapeshot/halfnes/audio/ExpansionSoundChip.java
  type ExpansionSoundChip (line 11) | public interface ExpansionSoundChip {
    method clock (line 13) | public void clock(final int cycles);
    method write (line 15) | public void write(int register, int data);
    method getval (line 17) | public int getval();

FILE: src/main/java/com/grapeshot/halfnes/audio/FDSSoundChip.java
  class FDSSoundChip (line 13) | public class FDSSoundChip implements ExpansionSoundChip {
    method clock (line 46) | @Override
    method runUnits (line 53) | private void runUnits() {
    method CalculateModulator (line 106) | private void CalculateModulator() {
    method CalculateEnvelopes (line 173) | private void CalculateEnvelopes() {
    method write (line 213) | @Override
    method read (line 300) | public int read(int register) {
    method getval (line 316) | @Override

FILE: src/main/java/com/grapeshot/halfnes/audio/FFT.java
  class FFT (line 11) | public class FFT {
    method FFT (line 20) | public FFT(int n) {
    method fft (line 40) | public void fft(double[] x, double[] y) {

FILE: src/main/java/com/grapeshot/halfnes/audio/MMC5SoundChip.java
  class MMC5SoundChip (line 13) | public class MMC5SoundChip implements ExpansionSoundChip {
    method clock (line 23) | @Override
    method write (line 34) | @Override
    method getval (line 118) | @Override
    method status (line 128) | public int status() {
    method setlength (line 137) | private void setlength() {
    method setenvelope (line 154) | private void setenvelope() {
    method setvolumes (line 174) | private void setvolumes() {
    method clockframecounter (line 182) | private void clockframecounter() {

FILE: src/main/java/com/grapeshot/halfnes/audio/Namco163SoundChip.java
  class Namco163SoundChip (line 13) | public class Namco163SoundChip implements ExpansionSoundChip {
    method clock (line 25) | @Override
    method clock_channel (line 37) | private void clock_channel(final int ch) {
    method getWavefromRAM (line 75) | private int getWavefromRAM(final int addr) {
    method write (line 80) | @Override
    method read (line 86) | public int read(int register) {
    method getval (line 90) | @Override
    method output (line 96) | private void output() {

FILE: src/main/java/com/grapeshot/halfnes/audio/NoiseTimer.java
  class NoiseTimer (line 13) | public class NoiseTimer extends Timer {
    method NoiseTimer (line 20) | public NoiseTimer() {
    method setduty (line 24) | @Override
    method clock (line 33) | @Override
    method getval (line 45) | @Override
    method reset (line 50) | @Override
    method clock (line 55) | @Override
    method setperiod (line 67) | @Override
    method genvalues (line 72) | public static int[] genvalues(int whichbit, int seed) {
    method setduty (line 85) | @Override

FILE: src/main/java/com/grapeshot/halfnes/audio/Reverberator.java
  class Reverberator (line 11) | public class Reverberator implements AudioOutInterface {
    method Reverberator (line 17) | public Reverberator(AudioOutInterface i, int length, double echo_gain,...
    method lowpass_filter (line 26) | private int lowpass_filter(int sample) {
    method highpass_filter (line 33) | private int highpass_filter(int sample) {
    method outputSample (line 41) | @Override
    method flushFrame (line 58) | @Override
    method pause (line 66) | @Override
    method resume (line 73) | @Override
    method destroy (line 80) | @Override
    method bufferHasLessThan (line 87) | @Override

FILE: src/main/java/com/grapeshot/halfnes/audio/SquareTimer.java
  class SquareTimer (line 11) | public class SquareTimer extends Timer {
    method clock (line 17) | @Override
    method clock (line 32) | @Override
    method SquareTimer (line 47) | public SquareTimer(final int ctrlen, final int periodadd) {
    method SquareTimer (line 55) | public SquareTimer(final int ctrlen) {
    method reset (line 63) | @Override
    method setduty (line 68) | @Override
    method setduty (line 75) | @Override
    method getval (line 80) | @Override
    method setperiod (line 85) | @Override

FILE: src/main/java/com/grapeshot/halfnes/audio/Sunsoft5BSoundChip.java
  class Sunsoft5BSoundChip (line 13) | public class Sunsoft5BSoundChip implements ExpansionSoundChip {
    method write (line 24) | @Override
    method clock (line 71) | @Override
    method getval (line 79) | @Override
    method getvoltbl (line 86) | public static int[] getvoltbl() {
    method clockenvelope (line 97) | private void clockenvelope(final int cycles) {

FILE: src/main/java/com/grapeshot/halfnes/audio/SwingAudioImpl.java
  class SwingAudioImpl (line 17) | public class SwingAudioImpl implements AudioOutInterface {
    method SwingAudioImpl (line 25) | public SwingAudioImpl(final NES nes, final int samplerate, Mapper.TVTy...
    method flushFrame (line 67) | @Override
    method outputSample (line 90) | @Override
    method pause (line 114) | @Override
    method resume (line 122) | @Override
    method destroy (line 129) | @Override
    method bufferHasLessThan (line 137) | public final boolean bufferHasLessThan(final int samples) {

FILE: src/main/java/com/grapeshot/halfnes/audio/Timer.java
  class Timer (line 7) | public abstract class Timer {
    method getperiod (line 12) | public final int getperiod() {
    method setperiod (line 16) | public abstract void setperiod(final int newperiod);
    method setduty (line 18) | public abstract void setduty(int duty);
    method setduty (line 20) | public abstract void setduty(int[] duty);
    method reset (line 22) | public abstract void reset();
    method clock (line 24) | public abstract void clock();
    method clock (line 26) | public abstract void clock(final int cycles);
    method getval (line 28) | public abstract int getval();

FILE: src/main/java/com/grapeshot/halfnes/audio/TriangleTimer.java
  class TriangleTimer (line 11) | public class TriangleTimer extends Timer {
    method TriangleTimer (line 19) | public TriangleTimer() {
    method reset (line 24) | @Override
    method clock (line 29) | @Override
    method clock (line 44) | @Override
    method getval (line 59) | @Override
    method setperiod (line 65) | @Override
    method setduty (line 73) | @Override
    method setduty (line 78) | @Override

FILE: src/main/java/com/grapeshot/halfnes/audio/VRC6SoundChip.java
  class VRC6SoundChip (line 13) | public class VRC6SoundChip implements ExpansionSoundChip {
    method write (line 26) | @Override
    method clock (line 68) | @Override
    method getval (line 77) | @Override
    method clocksaw (line 84) | private void clocksaw() {

FILE: src/main/java/com/grapeshot/halfnes/audio/VRC7SoundChip.java
  class VRC7SoundChip (line 16) | public class VRC7SoundChip implements ExpansionSoundChip {
    type EnvState (line 23) | private static enum EnvState {
    method VRC7SoundChip (line 63) | public VRC7SoundChip() {
    method clamp (line 70) | public static int clamp(final int a) {
    method genvibtbl (line 74) | private static double[] genvibtbl() {
    method genamtbl (line 89) | private static int[] genamtbl() {
    method tri (line 101) | private static double tri(double x) {
    method genlogsintbl (line 113) | private static int[] genlogsintbl() {
    method genexptbl (line 123) | private static int[] genexptbl() {
    method write (line 132) | @Override
    method clock (line 198) | @Override
    method operate (line 217) | private void operate() {
    method operator (line 268) | private int operator(final int phase, final int gain, final boolean re...
    method exp (line 272) | private int exp(int val) {
    method logsin (line 292) | private int logsin(final int x, final boolean rectify) {
    method outputSample (line 314) | private void outputSample(int ch) {
    method getval (line 324) | @Override
    method setenvelope (line 332) | private int setenvelope(final int[] instrument, final EnvState[] state,

FILE: src/main/java/com/grapeshot/halfnes/cheats/ActionReplay.java
  class ActionReplay (line 14) | public class ActionReplay {
    method ActionReplay (line 29) | public ActionReplay(CPURAM cpuram) {
    method getPatches (line 36) | public HashMap<Integer, Patch> getPatches() {
    method addMemoryPatch (line 44) | public void addMemoryPatch(Patch patch) {
    method applyPatches (line 53) | public void applyPatches() {
    method clear (line 60) | public void clear() {
    method newSearchInMemory (line 71) | public List<Integer> newSearchInMemory(byte value) {
    method getFoundAddresses (line 84) | public List<Integer> getFoundAddresses() {
    method continueSearch (line 95) | public List<Integer> continueSearch(byte value) {

FILE: src/main/java/com/grapeshot/halfnes/cheats/ActionReplayGui.java
  class ActionReplayGui (line 23) | public class ActionReplayGui extends javax.swing.JDialog {
    method ActionReplayGui (line 34) | public ActionReplayGui(java.awt.Frame parent, boolean modal, ActionRep...
    method updateCurrentCodesList (line 79) | private void updateCurrentCodesList() {
    method updateListPossibleCodes (line 88) | private void updateListPossibleCodes() {
    method isCodeValid (line 100) | private boolean isCodeValid() {
    method GGtoHex (line 196) | private long GGtoHex(String code) {
    method initComponents (line 213) | @SuppressWarnings("unchecked")
    method btnCloseActionPerformed (line 541) | private void btnCloseActionPerformed(java.awt.event.ActionEvent evt)//...
    method btnApplyActionPerformed (line 546) | private void btnApplyActionPerformed(java.awt.event.ActionEvent evt)//...
    method textCodeCaretUpdate (line 554) | private void textCodeCaretUpdate(javax.swing.event.CaretEvent evt)//GE...
    method btnRemoveAllActionPerformed (line 559) | private void btnRemoveAllActionPerformed(java.awt.event.ActionEvent ev...
    method btnResetActionPerformed (line 565) | private void btnResetActionPerformed(java.awt.event.ActionEvent evt)//...
    method textFindDataCaretUpdate (line 571) | private void textFindDataCaretUpdate(javax.swing.event.CaretEvent evt)...
    method btnSearchActionPerformed (line 580) | private void btnSearchActionPerformed(java.awt.event.ActionEvent evt)/...
    method btnTryActionPerformed (line 590) | private void btnTryActionPerformed(java.awt.event.ActionEvent evt)//GE...

FILE: src/main/java/com/grapeshot/halfnes/cheats/Patch.java
  class Patch (line 9) | public class Patch {
    method Patch (line 22) | public Patch(int address, int data) {
    method Patch (line 29) | public Patch(int address, int data, int check) {
    method getAddress (line 39) | public int getAddress() {
    method getData (line 46) | public int getData() {
    method matchesData (line 54) | public boolean matchesData(int data) {
    method hashCode (line 58) | @Override
    method equals (line 66) | @Override
    method toString (line 84) | @Override

FILE: src/main/java/com/grapeshot/halfnes/halfNES.java
  class halfNES (line 12) | public class halfNES {
    method halfNES (line 14) | private halfNES() {}
    method main (line 16) | public static void main(String[] args) throws IOException {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Action52Mapper.java
  class Action52Mapper (line 13) | public class Action52Mapper extends Mapper {
    method loadrom (line 21) | @Override
    method cartWrite (line 27) | @Override
    method cartRead (line 67) | @Override
    method reset (line 79) | public void reset() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/AfterburnerMapper.java
  class AfterburnerMapper (line 14) | public class AfterburnerMapper extends Mapper {
    method loadrom (line 21) | @Override
    method cartWrite (line 38) | @Override
    method setppubank (line 67) | private void setppubank(int banksize, int bankpos, int banknum) {
    method ppuRead (line 74) | public int ppuRead(int addr) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/AnromMapper.java
  class AnromMapper (line 9) | public class AnromMapper extends Mapper {
    method loadrom (line 11) | @Override
    method cartWrite (line 22) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/BadMapperException.java
  class BadMapperException (line 7) | public class BadMapperException extends Exception {
    method BadMapperException (line 11) | public BadMapperException(String e) {
    method getMessage (line 15) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/BnromMapper.java
  class BnromMapper (line 7) | public class BnromMapper extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 20) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/CaltronMapper.java
  class CaltronMapper (line 5) | public class CaltronMapper extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 21) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/CnromMapper.java
  class CnromMapper (line 7) | public class CnromMapper extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 21) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/CodemastersMapper.java
  class CodemastersMapper (line 13) | public class CodemastersMapper extends Mapper {
    method loadrom (line 17) | @Override
    method cartWrite (line 34) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/ColorDreamsMapper.java
  class ColorDreamsMapper (line 11) | public class ColorDreamsMapper extends Mapper {
    method loadrom (line 13) | @Override
    method cartWrite (line 25) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/CrazyClimberMapper.java
  class CrazyClimberMapper (line 7) | public class CrazyClimberMapper extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 22) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/CrimeBustersMapper.java
  class CrimeBustersMapper (line 5) | public class CrimeBustersMapper extends Mapper {
    method loadrom (line 8) | @Override
    method cartWrite (line 20) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/FME7Mapper.java
  class FME7Mapper (line 15) | public class FME7Mapper extends Mapper {
    method loadrom (line 30) | public void loadrom() throws BadMapperException {
    method cartRead (line 47) | @Override
    method cartWrite (line 63) | @Override
    method cpucycle (line 153) | @Override
    method setbanks (line 169) | private void setbanks() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/GnromMapper.java
  class GnromMapper (line 13) | public class GnromMapper extends Mapper {
    method loadrom (line 15) | @Override
    method cartWrite (line 27) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/IremH3001Mapper.java
  class IremH3001Mapper (line 5) | public class IremH3001Mapper extends Mapper {
    method loadrom (line 11) | @Override
    method cartWrite (line 23) | @Override
    method cpucycle (line 66) | @Override
    method setppubank (line 81) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MIMICMapper.java
  class MIMICMapper (line 13) | public class MIMICMapper extends Mapper {
    method loadrom (line 20) | @Override
    method cartWrite (line 33) | @Override
    method setupchr (line 64) | private void setupchr() {
    method setppubank (line 74) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MMC1Mapper.java
  class MMC1Mapper (line 9) | public class MMC1Mapper extends Mapper {
    method loadrom (line 21) | @Override
    method cartWrite (line 34) | @Override
    method setbanks (line 111) | private void setbanks() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MMC2Mapper.java
  class MMC2Mapper (line 13) | public class MMC2Mapper extends Mapper {
    method loadrom (line 22) | @Override
    method cartWrite (line 36) | @Override
    method ppuRead (line 63) | @Override
    method setupPPUBanks (line 102) | private void setupPPUBanks() {
    method setppubank (line 115) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MMC3Mapper.java
  class MMC3Mapper (line 13) | public class MMC3Mapper extends Mapper {
    method loadrom (line 26) | @Override
    method cartWrite (line 41) | @Override
    method setupchr (line 109) | protected void setupchr() {
    method setbank6 (line 131) | protected void setbank6() {
    method ppuRead (line 149) | @Override
    method ppuWrite (line 160) | @Override
    method checkA12 (line 168) | @Override
    method clockScanCounter (line 189) | private void clockScanCounter() {
    method setppubank (line 205) | protected void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MMC4Mapper.java
  class MMC4Mapper (line 5) | public class MMC4Mapper extends Mapper {
    method loadrom (line 14) | @Override
    method cartWrite (line 27) | @Override
    method ppuRead (line 54) | @Override
    method setupPPUBanks (line 86) | private void setupPPUBanks() {
    method setppubank (line 99) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/MMC5Mapper.java
  class MMC5Mapper (line 15) | public class MMC5Mapper extends Mapper {
    method loadrom (line 33) | @Override
    method cartWrite (line 51) | @Override
    method cartRead (line 245) | @Override
    method setupPRG (line 304) | public void setupPRG() {
    method setupCHR (line 333) | public void setupCHR() {
    method setppubank (line 370) | private void setppubank(int banksize, int bankpos, int banknum) {
    method setppubankB (line 376) | private void setppubankB(int banksize, int bankpos, int banknum) {
    method setcpubank (line 382) | private void setcpubank(int banksize, int bankpos, int banknum) {
    method ppuRead (line 390) | @Override
    method incScanline (line 456) | public void incScanline() {
    method setMirroring (line 475) | public void setMirroring(int ntsetup, int[] exram) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper.java
  class Mapper (line 13) | public abstract class Mapper {
    method supportsSaves (line 35) | public boolean supportsSaves() {
    method destroy (line 39) | public void destroy() {
    type MirrorType (line 45) | public static enum MirrorType {
    type TVType (line 50) | public static enum TVType {
    method crc32 (line 57) | public static long crc32(int[] array) {
    method loadrom (line 65) | public void loadrom() throws BadMapperException {
    method reset (line 110) | public void reset() {
    method cartWrite (line 116) | public void cartWrite(final int addr, final int data) {
    method cartRead (line 123) | public int cartRead(final int addr) {
    method ppuRead (line 134) | public int ppuRead(int addr) {
    method ppuWrite (line 160) | public void ppuWrite(int addr, final int data) {
    method notifyscanline (line 198) | public void notifyscanline(final int scanline) {
    method cpucycle (line 202) | public void cpucycle(int cycles) {
    method getCorrectMapper (line 206) | public static Mapper getCorrectMapper(final ROMLoader l) throws BadMap...
    method getrominfo (line 385) | public String getrominfo() {
    method hasSRAM (line 396) | public boolean hasSRAM() {
    method setLoader (line 400) | public void setLoader(final ROMLoader l) {
    method getCPURAM (line 404) | public CPURAM getCPURAM() {
    method checkA12 (line 408) | public void checkA12(int addr) {
    method setPRGRAM (line 412) | public void setPRGRAM(final int[] newprgram) {
    method getPRGRam (line 417) | public int[] getPRGRam() {
    method setmirroring (line 421) | public final void setmirroring(final Mapper.MirrorType type) {
    method getTVType (line 458) | public TVType getTVType() {
    method init (line 473) | public void init() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper107.java
  class Mapper107 (line 5) | public class Mapper107 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper112.java
  class Mapper112 (line 5) | public class Mapper112 extends Mapper {
    method loadrom (line 11) | @Override
    method cartWrite (line 24) | @Override
    method setupchr (line 55) | private void setupchr() {
    method setppubank (line 65) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper119.java
  class Mapper119 (line 15) | public class Mapper119 extends MMC3Mapper {
    method ppuRead (line 19) | @Override
    method ppuWrite (line 31) | @Override
    method loadrom (line 43) | @Override
    method setppubank (line 65) | protected void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper140.java
  class Mapper140 (line 5) | public class Mapper140 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper15.java
  class Mapper15 (line 5) | public class Mapper15 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper152.java
  class Mapper152 (line 5) | public class Mapper152 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper182.java
  class Mapper182 (line 5) | public class Mapper182 extends Mapper {
    method loadrom (line 19) | @Override
    method cartWrite (line 34) | @Override
    method setupchr (line 121) | private void setupchr() {
    method setbank6 (line 143) | private void setbank6() {
    method notifyscanline (line 159) | @Override
    method setppubank (line 188) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper185.java
  class Mapper185 (line 8) | public class Mapper185 extends Mapper {
    method loadrom (line 12) | @Override
    method ppuRead (line 24) | @Override
    method cartWrite (line 37) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper200.java
  class Mapper200 (line 5) | public class Mapper200 extends Mapper {
    method loadrom (line 7) | @Override
    method cartRead (line 19) | @Override
    method cartWrite (line 30) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper201.java
  class Mapper201 (line 5) | public class Mapper201 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper203.java
  class Mapper203 (line 5) | public class Mapper203 extends Mapper {
    method loadrom (line 7) | @Override
    method cartRead (line 19) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper212.java
  class Mapper212 (line 5) | public class Mapper212 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper213.java
  class Mapper213 (line 5) | public class Mapper213 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper214.java
  class Mapper214 (line 5) | public class Mapper214 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper225.java
  class Mapper225 (line 5) | public class Mapper225 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper226.java
  class Mapper226 (line 5) | public class Mapper226 extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 21) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper229.java
  class Mapper229 (line 5) | public class Mapper229 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper231.java
  class Mapper231 (line 5) | public class Mapper231 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper240.java
  class Mapper240 (line 5) | public class Mapper240 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper241.java
  class Mapper241 (line 5) | public class Mapper241 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper242.java
  class Mapper242 (line 5) | public class Mapper242 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper244.java
  class Mapper244 (line 5) | public class Mapper244 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper246.java
  class Mapper246 (line 5) | public class Mapper246 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper255.java
  class Mapper255 (line 5) | public class Mapper255 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper31.java
  class Mapper31 (line 14) | public class Mapper31 extends Mapper {
    method loadrom (line 21) | @Override
    method cartWrite (line 28) | @Override
    method cartRead (line 42) | @Override
    method setBanks (line 60) | private void setBanks() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper33.java
  class Mapper33 (line 5) | public class Mapper33 extends Mapper {
    method loadrom (line 10) | @Override
    method cartWrite (line 27) | @Override
    method setbanks (line 73) | private void setbanks() {
    method setppubank (line 98) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper36.java
  class Mapper36 (line 3) | public class Mapper36 extends Mapper {
    method loadrom (line 5) | @Override
    method cartWrite (line 17) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper47.java
  class Mapper47 (line 13) | public class Mapper47 extends MMC3Mapper {
    method loadrom (line 19) | @Override
    method cartWrite (line 33) | @Override
    method setbank6 (line 113) | protected void setbank6() {
    method setppubank (line 129) | protected void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper48.java
  class Mapper48 (line 9) | public class Mapper48 extends Mapper {
    method loadrom (line 19) | @Override
    method cartWrite (line 36) | @Override
    method setbanks (line 115) | private void setbanks() {
    method setppubank (line 140) | private void setppubank(int banksize, int bankpos, int banknum) {
    method notifyscanline (line 146) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper58.java
  class Mapper58 (line 5) | public class Mapper58 extends Mapper {
    method loadrom (line 7) | @Override
    method reset (line 19) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper60.java
  class Mapper60 (line 5) | public class Mapper60 extends Mapper {
    method loadrom (line 9) | @Override
    method reset (line 26) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper61.java
  class Mapper61 (line 5) | public class Mapper61 extends Mapper {
    method loadrom (line 7) | @Override
    method reset (line 19) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper62.java
  class Mapper62 (line 5) | public class Mapper62 extends Mapper {
    method loadrom (line 10) | @Override
    method cartWrite (line 22) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper70.java
  class Mapper70 (line 3) | public class Mapper70 extends Mapper {
    method loadrom (line 5) | @Override
    method cartWrite (line 22) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper72.java
  class Mapper72 (line 5) | public class Mapper72 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper76.java
  class Mapper76 (line 13) | public class Mapper76 extends Mapper {
    method loadrom (line 20) | @Override
    method cartWrite (line 33) | @Override
    method setupchr (line 61) | private void setupchr() {
    method setppubank (line 68) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper78.java
  class Mapper78 (line 13) | public class Mapper78 extends Mapper {
    method loadrom (line 15) | @Override
    method cartWrite (line 27) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper86.java
  class Mapper86 (line 3) | public class Mapper86 extends Mapper {
    method loadrom (line 5) | @Override
    method cartWrite (line 17) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper87.java
  class Mapper87 (line 13) | public class Mapper87 extends Mapper {
    method loadrom (line 15) | @Override
    method cartWrite (line 27) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper92.java
  class Mapper92 (line 5) | public class Mapper92 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper94.java
  class Mapper94 (line 7) | public class Mapper94 extends Mapper {
    method loadrom (line 9) | @Override
    method cartWrite (line 26) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Mapper97.java
  class Mapper97 (line 5) | public class Mapper97 extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/NINA_001_Mapper.java
  class NINA_001_Mapper (line 5) | public class NINA_001_Mapper extends Mapper {
    method loadrom (line 7) | @Override
    method cartWrite (line 19) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/NINA_003_006_Mapper.java
  class NINA_003_006_Mapper (line 5) | public class NINA_003_006_Mapper extends Mapper {
    method NINA_003_006_Mapper (line 9) | public NINA_003_006_Mapper(int mappernum) {
    method loadrom (line 22) | @Override
    method reset (line 34) | @Override
    method cartWrite (line 41) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/NSFMapper.java
  class NSFMapper (line 15) | public class NSFMapper extends Mapper {
    method loadrom (line 38) | @Override
    method init (line 121) | @Override
    method reset (line 177) | @Override
    method cartWrite (line 185) | @Override
    method cartRead (line 254) | @Override
    method ppuWrite (line 311) | @Override
    method notifyscanline (line 319) | @Override
    method getrominfo (line 388) | @Override
    method expSound (line 402) | private String expSound() {
    method setBanks (line 425) | private void setBanks() {
    method setSoundChip (line 442) | private void setSoundChip() {
    method writeTracks (line 481) | private void writeTracks() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/NSFPlayerFont.java
  class NSFPlayerFont (line 11) | public class NSFPlayerFont {
    method NSFPlayerFont (line 13) | private NSFPlayerFont() {}

FILE: src/main/java/com/grapeshot/halfnes/mappers/NamcoMapper.java
  class NamcoMapper (line 15) | public class NamcoMapper extends Mapper {
    method loadrom (line 25) | @Override
    method cartRead (line 38) | @Override
    method cartWrite (line 66) | public final void cartWrite(final int addr, final int data) {
    method irqack (line 155) | private void irqack() {
    method cpucycle (line 163) | @Override
    method setppubank (line 175) | private void setppubank(final int banksize, final int bankpos, final i...
    method ppuRead (line 183) | @Override
    method ppuWrite (line 204) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Namcot34x3Mapper.java
  class Namcot34x3Mapper (line 5) | public class Namcot34x3Mapper extends Mapper {
    method Namcot34x3Mapper (line 14) | public Namcot34x3Mapper(int mappernum) {
    method loadrom (line 19) | @Override
    method cartWrite (line 32) | @Override
    method setupchr (line 65) | private void setupchr() {
    method setppubank (line 75) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/NromMapper.java
  class NromMapper (line 13) | public class NromMapper extends Mapper {
    method loadrom (line 15) | @Override
    method cartRead (line 29) | @Override
    method ppuRead (line 39) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Sunsoft01Mapper.java
  class Sunsoft01Mapper (line 7) | public class Sunsoft01Mapper extends Mapper {
    method loadrom (line 12) | @Override
    method cartWrite (line 24) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Sunsoft02Mapper.java
  class Sunsoft02Mapper (line 5) | public class Sunsoft02Mapper extends Mapper {
    method Sunsoft02Mapper (line 9) | public Sunsoft02Mapper(int mappernum) {
    method loadrom (line 14) | @Override
    method cartWrite (line 31) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/Sunsoft03Mapper.java
  class Sunsoft03Mapper (line 5) | public class Sunsoft03Mapper extends Mapper {
    method loadrom (line 13) | @Override
    method cartWrite (line 30) | @Override
    method cpucycle (line 83) | @Override
    method setupchr (line 99) | private void setupchr() {
    method setppubank (line 106) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/TengenRamboMapper.java
  class TengenRamboMapper (line 13) | public class TengenRamboMapper extends Mapper {
    method loadrom (line 26) | @Override
    method cartWrite (line 48) | @Override
    method setupchr (line 136) | private void setupchr() {
    method setprgregs (line 178) | private void setprgregs() {
    method notifyscanline (line 197) | @Override
    method cpucycle (line 215) | @Override
    method clockscanlinecounter (line 236) | public void clockscanlinecounter() {
    method setppubank (line 249) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/UnromMapper.java
  class UnromMapper (line 7) | public class UnromMapper extends Mapper {
    method loadrom (line 11) | @Override
    method cartWrite (line 28) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC1Mapper.java
  class VRC1Mapper (line 9) | public class VRC1Mapper extends Mapper {
    method loadrom (line 14) | @Override
    method cartWrite (line 31) | @Override
    method setbanks (line 68) | private void setbanks() {
    method setppubank (line 92) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC2Mapper.java
  class VRC2Mapper (line 9) | public class VRC2Mapper extends Mapper {
    method loadrom (line 15) | @Override
    method cartWrite (line 28) | @Override
    method setbanks (line 79) | private void setbanks() {
    method setppubank (line 101) | private void setppubank(int banksize, int bankpos, int banknum) {

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC3Mapper.java
  class VRC3Mapper (line 9) | public class VRC3Mapper extends Mapper {
    method loadrom (line 14) | @Override
    method cartWrite (line 31) | @Override
    method cpucycle (line 85) | @Override

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC4Mapper.java
  class VRC4Mapper (line 9) | public class VRC4Mapper extends Mapper {
    method VRC4Mapper (line 21) | public VRC4Mapper(int mappernum) {
    method loadrom (line 40) | @Override
    method cartWrite (line 62) | @Override
    method setbanks (line 165) | private void setbanks() {
    method setppubank (line 204) | private void setppubank(int banksize, int bankpos, int banknum) {
    method cpucycle (line 214) | @Override
    method scanlinecount (line 230) | public void scanlinecount() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC6Mapper.java
  class VRC6Mapper (line 10) | public class VRC6Mapper extends Mapper {
    method VRC6Mapper (line 21) | public VRC6Mapper(int mappernum) {
    method loadrom (line 38) | @Override
    method cartWrite (line 51) | @Override
    method setbanks (line 138) | private void setbanks() {
    method setppubank (line 159) | private void setppubank(final int banksize, final int bankpos, final i...
    method cpucycle (line 169) | @Override
    method scanlinecount (line 185) | public void scanlinecount() {

FILE: src/main/java/com/grapeshot/halfnes/mappers/VRC7Mapper.java
  class VRC7Mapper (line 10) | public class VRC7Mapper extends Mapper {
    method loadrom (line 21) | @Override
    method cartWrite (line 34) | @Override
    method setbanks (line 140) | private void setbanks() {
    method setppubank (line 165) | private void setppubank(final int banksize, final int bankpos, final i...
    method cpucycle (line 174) | @Override
    method scanlinecount (line 190) | public void scanlinecount() {

FILE: src/main/java/com/grapeshot/halfnes/ui/ControllerImpl.java
  class ControllerImpl (line 30) | public class ControllerImpl implements ControllerInterface, KeyListener {
    method ControllerImpl (line 40) | public ControllerImpl(final java.awt.Component parent, final int contr...
    method ControllerImpl (line 46) | public ControllerImpl(final Scene scene, final int controllernum) {
    method ControllerImpl (line 52) | public ControllerImpl(final int controllernum) {
    method keyPressed (line 60) | @Override
    method pressKey (line 65) | private void pressKey(int keyCode) {
    method keyReleased (line 85) | @Override
    method releaseKey (line 90) | private void releaseKey(int keyCode) {
    method getbyte (line 98) | @Override
    method peekOutput (line 103) | @Override
    method keyTyped (line 108) | @Override
    method strobe (line 113) | public void strobe() {
    method output (line 119) | public void output(final boolean state) {
    method startEventQueue (line 128) | public void startEventQueue() {
    method eventQueueLoop (line 135) | private Runnable eventQueueLoop() {
    method isPressed (line 206) | private boolean isPressed(Event event) {
    method stopEventQueue (line 225) | public void stopEventQueue() {
    method getAvailablePadControllers (line 235) | private static Controller[] getAvailablePadControllers() {
    method getButtons (line 267) | private static Component[] getButtons(Controller controller) {
    method setButtons (line 279) | public final void setButtons() {

FILE: src/main/java/com/grapeshot/halfnes/ui/ControllerInterface.java
  type ControllerInterface (line 11) | public interface ControllerInterface {
    method strobe (line 13) | public void strobe();
    method output (line 15) | public void output(final boolean state);
    method peekOutput (line 17) | public int peekOutput();
    method getbyte (line 19) | public int getbyte();

FILE: src/main/java/com/grapeshot/halfnes/ui/ControlsDialog.java
  class ControlsDialog (line 24) | public class ControlsDialog extends javax.swing.JDialog {
    method ControlsDialog (line 32) | public ControlsDialog(java.awt.Frame parent) {
    method initComponents (line 90) | @SuppressWarnings("unchecked")
    method jButtonCancelActionPerformed (line 473) | private void jButtonCancelActionPerformed(java.awt.event.ActionEvent e...
    method jButtonOKActionPerformed (line 479) | private void jButtonOKActionPerformed(java.awt.event.ActionEvent evt) ...
    method okClicked (line 508) | public boolean okClicked() {
    method jField1UpKeyReleased (line 511) | private void jField1UpKeyReleased(java.awt.event.KeyEvent evt) {//GEN-...
    method jField1DownKeyReleased (line 517) | private void jField1DownKeyReleased(java.awt.event.KeyEvent evt) {//GE...
    method jField1LeftKeyReleased (line 523) | private void jField1LeftKeyReleased(java.awt.event.KeyEvent evt) {//GE...
    method jField1RightKeyReleased (line 529) | private void jField1RightKeyReleased(java.awt.event.KeyEvent evt) {//G...
    method jField2StartActionPerformed (line 535) | private void jField2StartActionPerformed(java.awt.event.ActionEvent ev...
    method jField1AKeyReleased (line 539) | private void jField1AKeyReleased(java.awt.event.KeyEvent evt) {//GEN-F...
    method jField1BKeyReleased (line 545) | private void jField1BKeyReleased(java.awt.event.KeyEvent evt) {//GEN-F...
    method jField1SelectKeyReleased (line 551) | private void jField1SelectKeyReleased(java.awt.event.KeyEvent evt) {//...
    method jField1StartKeyReleased (line 557) | private void jField1StartKeyReleased(java.awt.event.KeyEvent evt) {//G...
    method jField2UpKeyReleased (line 563) | private void jField2UpKeyReleased(java.awt.event.KeyEvent evt) {//GEN-...
    method jField2StartKeyReleased (line 569) | private void jField2StartKeyReleased(java.awt.event.KeyEvent evt) {//G...
    method jField2DownKeyReleased (line 575) | private void jField2DownKeyReleased(java.awt.event.KeyEvent evt) {//GE...
    method jField2LeftKeyReleased (line 581) | private void jField2LeftKeyReleased(java.awt.event.KeyEvent evt) {//GE...
    method jField2RightKeyReleased (line 587) | private void jField2RightKeyReleased(java.awt.event.KeyEvent evt) {//G...
    method jField2AKeyReleased (line 593) | private void jField2AKeyReleased(java.awt.event.KeyEvent evt) {//GEN-F...
    method jField2BKeyReleased (line 599) | private void jField2BKeyReleased(java.awt.event.KeyEvent evt) {//GEN-F...
    method jField2SelectKeyReleased (line 605) | private void jField2SelectKeyReleased(java.awt.event.KeyEvent evt) {//...
    method jButton1ActionPerformed (line 611) | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {...
    method jButton2ActionPerformed (line 615) | private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {...

FILE: src/main/java/com/grapeshot/halfnes/ui/DebugUI.java
  class DebugUI (line 12) | public class DebugUI extends JFrame {
    method DebugUI (line 19) | public DebugUI(int height, int width) {
    method run (line 26) | public void run() {
    method messageBox (line 35) | public void messageBox(String s) {
    method setFrame (line 39) | public void setFrame(BufferedImage b) {
    class Repainter (line 46) | public class Repainter implements Runnable {
      method run (line 48) | public void run() {
    class ShowFrame (line 53) | public class ShowFrame extends javax.swing.JPanel {
      method ShowFrame (line 60) | public ShowFrame() {
      method paint (line 65) | @Override

FILE: src/main/java/com/grapeshot/halfnes/ui/DummyController.java
  class DummyController (line 21) | public class DummyController implements ControllerInterface {
    method DummyController (line 58) | public DummyController(int controllernum) {
    method strobe (line 70) | @Override
    method output (line 77) | @Override
    method peekOutput (line 87) | @Override
    method getbyte (line 92) | @Override

FILE: src/main/java/com/grapeshot/halfnes/ui/FrameLimiterImpl.java
  class FrameLimiterImpl (line 14) | public class FrameLimiterImpl implements FrameLimiterInterface {
    method FrameLimiterImpl (line 20) | public FrameLimiterImpl(NES nes, long framens) {
    method setInterval (line 26) | public void setInterval(long ns) {
    method sleep (line 30) | @Override
    method sleepFixed (line 57) | @Override
    method forceHighResolutionTimer (line 67) | public static void forceHighResolutionTimer() {

FILE: src/main/java/com/grapeshot/halfnes/ui/FrameLimiterInterface.java
  type FrameLimiterInterface (line 11) | public interface FrameLimiterInterface {
    method sleep (line 13) | public void sleep();
    method sleepFixed (line 15) | public void sleepFixed();
    method setInterval (line 17) | public void setInterval(long ns);

FILE: src/main/java/com/grapeshot/halfnes/ui/GUIInterface.java
  type GUIInterface (line 13) | public interface GUIInterface extends Runnable {
    method getNes (line 15) | public NES getNes();
    method setNES (line 17) | public void setNES(NES nes);
    method setFrame (line 19) | public void setFrame(int[] frame, int[] bgcolor, boolean dotcrawl);
    method messageBox (line 23) | public void messageBox(String message);
    method run (line 25) | @Override
    method render (line 28) | public void render();
    method loadROMs (line 30) | public void loadROMs(String path);

FILE: src/main/java/com/grapeshot/halfnes/ui/HeadlessUI.java
  class HeadlessUI (line 13) | public class HeadlessUI implements GUIInterface {
    method HeadlessUI (line 22) | public HeadlessUI(String romToLoad, boolean renderFrames) {
    method loadROM (line 32) | public void loadROM(String romToLoad) {
    method getLastFrame (line 36) | public BufferedImage getLastFrame() {
    method getController1 (line 40) | public PuppetController getController1() {
    method getController2 (line 44) | public PuppetController getController2() {
    method runFrame (line 48) | public synchronized void runFrame() {
    method getNESCPURAM (line 52) | public CPURAM getNESCPURAM() {
    method getNes (line 56) | @Override
    method setNES (line 61) | @Override
    method setFrame (line 66) | @Override
    method messageBox (line 73) | @Override
    method run (line 78) | @Override
    method render (line 83) | @Override
    method loadROMs (line 87) | @Override

FILE: src/main/java/com/grapeshot/halfnes/ui/NESFileFilter.java
  class NESFileFilter (line 15) | public class NESFileFilter implements FilenameFilter {
    method getDescription (line 34) | public String getDescription() {
    method accept (line 38) | public boolean accept(File dir, String name) {

FILE: src/main/java/com/grapeshot/halfnes/ui/OnScreenMenu.java
  class OnScreenMenu (line 28) | public class OnScreenMenu extends StackPane {
    method OnScreenMenu (line 42) | public OnScreenMenu(GUIInterface gui) {
    method addMenuListeners (line 53) | private void addMenuListeners(ListView<MenuAction> menu) {
    method show (line 66) | public void show() {
    method hide (line 71) | private void hide() {
    method loadROMs (line 75) | public void loadROMs(String path) {
    method loadRomFromZip (line 88) | private void loadRomFromZip(String zipName) throws IOException {
    method listRomsInZip (line 97) | private List<String> listRomsInZip(String zipName) throws IOException {
    method extractRomFromZip (line 117) | private File extractRomFromZip(String zipName, String romName) throws ...
    method resume (line 151) | private void resume() {
    method loadGame (line 156) | private void loadGame() {
    method runGame (line 161) | private void runGame(String path) {
    method reset (line 169) | private void reset() {
    method exit (line 174) | private void exit() {
    method powerOff (line 179) | private void powerOff() {
    class MenuAction (line 187) | class MenuAction {
      method MenuAction (line 192) | MenuAction() {
      method MenuAction (line 195) | MenuAction(String name, Runnable action) {
      method run (line 200) | public void run() {
      method toString (line 204) | @Override
    class GameAction (line 210) | class GameAction extends MenuAction {
      method GameAction (line 212) | GameAction(File game) {
      method GameAction (line 227) | GameAction(final String zipName, final String romName) {

FILE: src/main/java/com/grapeshot/halfnes/ui/Oscilloscope.java
  class Oscilloscope (line 16) | public class Oscilloscope implements AudioOutInterface {
    method Oscilloscope (line 28) | public Oscilloscope(AudioOutInterface i) {
    method Oscilloscope (line 39) | public Oscilloscope() {
    method outputSample (line 50) | @Override
    method flushFrame (line 65) | @Override
    method pause (line 81) | @Override
    method resume (line 88) | @Override
    method destroy (line 95) | @Override
    method bufferHasLessThan (line 105) | @Override

FILE: src/main/java/com/grapeshot/halfnes/ui/PreferencesDialog.java
  class PreferencesDialog (line 24) | public class PreferencesDialog extends javax.swing.JDialog {
    method PreferencesDialog (line 32) | public PreferencesDialog(java.awt.Frame parent) {
    method initComponents (line 62) | @SuppressWarnings("unchecked")
    method jButtonCancelActionPerformed (line 292) | private void jButtonCancelActionPerformed(java.awt.event.ActionEvent e...
    method jButtonOKActionPerformed (line 298) | private void jButtonOKActionPerformed(java.awt.event.ActionEvent evt) ...
    method okClicked (line 324) | public boolean okClicked() {
    method jSampleRateBoxActionPerformed (line 327) | private void jSampleRateBoxActionPerformed(java.awt.event.ActionEvent ...
    method jCheckSoundFilteringActionPerformed (line 331) | private void jCheckSoundFilteringActionPerformed(java.awt.event.Action...
    method jCheckBoxNTSCActionPerformed (line 335) | private void jCheckBoxNTSCActionPerformed(java.awt.event.ActionEvent e...
    method jCheckBoxSmoothVideoActionPerformed (line 339) | private void jCheckBoxSmoothVideoActionPerformed(java.awt.event.Action...
    method jCheckBoxSleepActionPerformed (line 343) | private void jCheckBoxSleepActionPerformed(java.awt.event.ActionEvent ...
    method jRegionBoxActionPerformed (line 347) | private void jRegionBoxActionPerformed(java.awt.event.ActionEvent evt)...

FILE: src/main/java/com/grapeshot/halfnes/ui/PuppetController.java
  class PuppetController (line 15) | public class PuppetController implements ControllerInterface {
    method strobe (line 18) | @Override
    method output (line 25) | @Override
    method peekOutput (line 30) | @Override
    method getbyte (line 35) | @Override
    method resetButtons (line 40) | public void resetButtons() {
    method releaseButton (line 44) | public void releaseButton(Button button) {
    method pressButton (line 73) | public void pressButton(Button button) {
    type Button (line 102) | public enum Button {

FILE: src/main/java/com/grapeshot/halfnes/ui/SwingUI.java
  class SwingUI (line 34) | public class SwingUI extends JFrame implements GUIInterface {
    method SwingUI (line 50) | public SwingUI() {
    method getNes (line 60) | @Override
    method setNES (line 65) | @Override
    method setRenderOptions (line 70) | public synchronized void setRenderOptions() {
    method start (line 102) | public void start(String[] args) {
    method run (line 110) | @Override
    method buildMenus (line 163) | public void buildMenus() {
    method loadROM (line 248) | public void loadROM() {
    method loadROM (line 278) | private void loadROM(String path) {
    method loadRomFromZip (line 290) | private void loadRomFromZip(String zipName) throws IOException {
    method listRomsInZip (line 301) | private List<String> listRomsInZip(String zipName) throws IOException {
    method selectRomInZip (line 320) | private String selectRomInZip(List<String> romNames) {
    method extractRomFromZip (line 332) | private File extractRomFromZip(String zipName, String romName) throws ...
    method toggleFullScreen (line 365) | public synchronized void toggleFullScreen() {
    method messageBox (line 396) | @Override
    method setFrame (line 405) | @Override
    method render (line 435) | @Override
    method showOptions (line 474) | private void showOptions() {
    method showControlsDialog (line 483) | private void showControlsDialog() {
    method showActionReplayDialog (line 492) | private void showActionReplayDialog() {
    method savewindowposition (line 504) | public void savewindowposition() {
    method getmaxscale (line 509) | private double getmaxscale(final int width, final int height) {
    method loadROMs (line 513) | @Override
    class AL (line 518) | public class AL implements ActionListener, WindowListener {
      method actionPerformed (line 520) | @Override
      method windowOpened (line 569) | @Override
      method windowClosing (line 573) | @Override
      method close (line 578) | private void close() {
      method windowClosed (line 586) | @Override
      method windowIconified (line 591) | @Override
      method windowDeiconified (line 596) | @Override
      method windowActivated (line 601) | @Override
      method windowDeactivated (line 605) | @Override

FILE: src/main/java/com/grapeshot/halfnes/utils.java
  class utils (line 9) | public class utils {
    method utils (line 11) | private utils() {}
    method setbit (line 18) | public static int setbit(final int num, final int bitnum, final boolea...
    method hex (line 22) | public static String hex(final int num) {
    method hex (line 30) | public static String hex(final long num) {
    method reverseByte (line 38) | public static int reverseByte(int nibble) {
    method printarray (line 43) | public static void printarray(final int[] a) {
    method printarray (line 56) | public static void printarray(final boolean[] a) {
    method printarray (line 69) | public static void printarray(final double[] a) {
    method printarray (line 82) | public static void printarray(final float[] a) {
    method printarray (line 95) | public static void printarray(final Object[] a) {
    method max (line 108) | public static int max(final int[] array) {

FILE: src/main/java/com/grapeshot/halfnes/video/AltNTSCRenderer.java
  class AltNTSCRenderer (line 18) | public class AltNTSCRenderer extends Renderer {
    method AltNTSCRenderer (line 20) | public AltNTSCRenderer() {
    method render (line 39) | @Override
    method ntsc_render (line 59) | private void ntsc_render(int pixel) {
    method inColorPhase (line 86) | private static boolean inColorPhase(final int color, final int phase) {
    method ntsc_decode (line 93) | private void ntsc_decode(final double phase) {
    method render_pixel (line 115) | private void render_pixel(final double y, final double i, final double...
    method clamp (line 124) | public static int clamp(final double a) {
    method gammafix (line 128) | public static double gammafix(double luma) {

FILE: src/main/java/com/grapeshot/halfnes/video/NTSCRenderer.java
  class NTSCRenderer (line 16) | public class NTSCRenderer extends Renderer {
    method NTSCRenderer (line 62) | public NTSCRenderer() {
    method genColorCorrectTbl (line 74) | public static int[] genColorCorrectTbl() {
    method genlumas (line 87) | public static float[][][] genlumas() {
    method ntsc_encode (line 103) | public final float[] ntsc_encode(final int[] nescolors, final int offs...
    method ntsc_decode (line 158) | public final int[] ntsc_decode(final float[] ntsc, final int offset) {
    method box_filter (line 188) | public static void box_filter(final float[] in, final float[] lpout, f...
    method lowpass_filter (line 197) | public static void lowpass_filter(final float[] arr, final float order) {
    method compose_col (line 206) | private static int compose_col(int r, int g, int b) {
    method clamp (line 211) | public static int clamp(final int a) {
    method render (line 222) | @Override
    method cacheRender (line 236) | private void cacheRender(final int[] nespixels, final int line, final ...
    method crc32 (line 257) | public static long crc32(int[] array, int offset, int bgcolor) {

FILE: src/main/java/com/grapeshot/halfnes/video/NesColors.java
  class NesColors (line 11) | public class NesColors {
    method NesColors (line 13) | private NesColors() {}
    method GetNESColors (line 19) | private static int[][] GetNESColors() {
    method NESColorsToBytes (line 74) | private static byte[][][] NESColorsToBytes(int[][] col) {
    method r (line 88) | private static int r(int col) {
    method g (line 92) | private static int g(int col) {
    method b (line 96) | private static int b(int col) {
    method compose_col (line 100) | private static int compose_col(double r, double g, double b) {

FILE: src/main/java/com/grapeshot/halfnes/video/RGBRenderer.java
  class RGBRenderer (line 15) | public class RGBRenderer extends Renderer {
    method RGBRenderer (line 17) | public RGBRenderer() {
    method render (line 22) | @Override

FILE: src/main/java/com/grapeshot/halfnes/video/Renderer.java
  class Renderer (line 15) | public abstract class Renderer {
    method init_images (line 28) | protected final void init_images() {
    method render (line 34) | public abstract BufferedImage render(int[] nespixels, int[] bgcolors, ...
    method setClip (line 36) | public void setClip(int i) {
    method getBufferedImage (line 42) | public BufferedImage getBufferedImage(int[] frame) {

FILE: src/test/java/com/grapeshot/halfnes/JInputTest.java
  class JInputTest (line 12) | public class JInputTest {
    method testJInput (line 18) | @Test

FILE: src/test/java/com/grapeshot/halfnes/nestest/NesTest.java
  class NesTest (line 14) | public class NesTest {
    method nesTest (line 16) | @Test
Condensed preview — 152 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,398K chars).
[
  {
    "path": ".gitignore",
    "chars": 567,
    "preview": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, se"
  },
  {
    "path": ".travis.yml",
    "chars": 36,
    "preview": "language: java\n\njdk:\n  - oraclejdk8\n"
  },
  {
    "path": "LICENSE",
    "chars": 35120,
    "preview": "GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation,"
  },
  {
    "path": "README.md",
    "chars": 3607,
    "preview": "[DOWNLOAD HERE](https://github.com/andrew-hoffman/halfnes/releases)\n\nhalfnes\n=======\n\nAn accurate NES/Famicom emulator\n\n"
  },
  {
    "path": "nbactions.xml",
    "chars": 1245,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<actions>\n        <action>\n            <actionName>run</actionName>\n            <"
  },
  {
    "path": "pom.xml",
    "chars": 7348,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n      "
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/APU.java",
    "chars": 26082,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/CPU.java",
    "chars": 61868,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/CPURAM.java",
    "chars": 2316,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/FileUtils.java",
    "chars": 3684,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/HeadlessNES.java",
    "chars": 1383,
    "preview": "package com.grapeshot.halfnes;\n\nimport com.grapeshot.halfnes.ui.HeadlessUI;\nimport com.grapeshot.halfnes.ui.PuppetContro"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/JInputHelper.java",
    "chars": 4642,
    "preview": "package com.grapeshot.halfnes;\n\nimport java.io.*;\nimport java.lang.reflect.Field;\nimport java.nio.charset.StandardCharse"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/JavaFXNES.java",
    "chars": 5767,
    "preview": "package com.grapeshot.halfnes;\n\nimport com.grapeshot.halfnes.ui.ControllerImpl;\nimport com.grapeshot.halfnes.ui.GUIInter"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/NES.java",
    "chars": 9384,
    "preview": "/**\n *\n * @author Andrew Hoffman\n */\npackage com.grapeshot.halfnes;\n\nimport com.grapeshot.halfnes.cheats.ActionReplay;\ni"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/PPU.java",
    "chars": 32082,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/PrefsSingleton.java",
    "chars": 574,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ROMLoader.java",
    "chars": 5993,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/Twiddler.form",
    "chars": 3072,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<Form version=\"1.3\" maxVersion=\"1.9\" type=\"org.netbeans.modules.form.forminfo.J"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/Twiddler.java",
    "chars": 3223,
    "preview": "/*\n * To change this license header, choose License Headers in Project Properties.\n * To change this template file, choo"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/AudioOutInterface.java",
    "chars": 431,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/CircularBuffer.java",
    "chars": 1396,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/ExpansionSoundChip.java",
    "chars": 317,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/FDSSoundChip.java",
    "chars": 10515,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/FFT.java",
    "chars": 2178,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/MMC5SoundChip.java",
    "chars": 7023,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/Namco163SoundChip.java",
    "chars": 3652,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/NoiseTimer.java",
    "chars": 2406,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/Reverberator.java",
    "chars": 2266,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/SquareTimer.java",
    "chars": 2276,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/Sunsoft5BSoundChip.java",
    "chars": 3528,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/SwingAudioImpl.java",
    "chars": 4352,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/Timer.java",
    "chars": 590,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/TriangleTimer.java",
    "chars": 2264,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/VRC6SoundChip.java",
    "chars": 3280,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/audio/VRC7SoundChip.java",
    "chars": 21753,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/cheats/ActionReplay.java",
    "chars": 2994,
    "preview": "package com.grapeshot.halfnes.cheats;\n\nimport com.grapeshot.halfnes.CPURAM;\nimport java.util.ArrayList;\nimport java.util"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/cheats/ActionReplayGui.form",
    "chars": 28325,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<Form version=\"1.5\" maxVersion=\"1.8\" type=\"org.netbeans.modules.form.forminfo.J"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/cheats/ActionReplayGui.java",
    "chars": 31054,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/cheats/Patch.java",
    "chars": 2451,
    "preview": "package com.grapeshot.halfnes.cheats;\n\n/**\n * A patch object includes an address to modify and the value to write at thi"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/halfNES.java",
    "chars": 616,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Action52Mapper.java",
    "chars": 2466,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/AfterburnerMapper.java",
    "chars": 3409,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/AnromMapper.java",
    "chars": 990,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/BadMapperException.java",
    "chars": 351,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/BnromMapper.java",
    "chars": 877,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/CaltronMapper.java",
    "chars": 1197,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class CaltronMapper extends Mapper {\n\n  "
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/CnromMapper.java",
    "chars": 894,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/CodemastersMapper.java",
    "chars": 1625,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/ColorDreamsMapper.java",
    "chars": 1154,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/CrazyClimberMapper.java",
    "chars": 975,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/CrimeBustersMapper.java",
    "chars": 1121,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class CrimeBustersMapper extends Mapper "
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/FME7Mapper.java",
    "chars": 5898,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/GnromMapper.java",
    "chars": 1173,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/IremH3001Mapper.java",
    "chars": 2979,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class IremH3001Mapper extends Mapper {\n\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MIMICMapper.java",
    "chars": 2393,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MMC1Mapper.java",
    "chars": 5698,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MMC2Mapper.java",
    "chars": 3719,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MMC3Mapper.java",
    "chars": 7430,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MMC4Mapper.java",
    "chars": 3266,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class MMC4Mapper extends Mapper {\n\n    b"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/MMC5Mapper.java",
    "chars": 19069,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper.java",
    "chars": 14864,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper107.java",
    "chars": 1004,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper107 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper112.java",
    "chars": 2291,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper112 extends Mapper {\n    //C"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper119.java",
    "chars": 1976,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper140.java",
    "chars": 1051,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper140 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper15.java",
    "chars": 3667,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper15 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper152.java",
    "chars": 1313,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper152 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper182.java",
    "chars": 6817,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper182 extends Mapper {\n    //P"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper185.java",
    "chars": 1365,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper200.java",
    "chars": 1502,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper200 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper201.java",
    "chars": 964,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper201 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper203.java",
    "chars": 1187,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper203 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper212.java",
    "chars": 1487,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper212 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper213.java",
    "chars": 978,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper213 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper214.java",
    "chars": 1099,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper214 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper225.java",
    "chars": 1470,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper225 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper226.java",
    "chars": 1428,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper226 extends Mapper {\n\n    in"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper229.java",
    "chars": 1296,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper229 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper231.java",
    "chars": 1093,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper231 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper240.java",
    "chars": 1053,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper240 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper241.java",
    "chars": 825,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper241 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper242.java",
    "chars": 929,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper242 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper244.java",
    "chars": 1085,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper244 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper246.java",
    "chars": 2342,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper246 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper255.java",
    "chars": 1338,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper255 extends Mapper {\n\n    @O"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper31.java",
    "chars": 2237,
    "preview": "/*\n * To change this license header, choose License Headers in Project Properties.\n * To change this template file, choo"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper33.java",
    "chars": 3151,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper33 extends Mapper {\n\n    int"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper36.java",
    "chars": 939,
    "preview": "package com.grapeshot.halfnes.mappers;\n\npublic class Mapper36 extends Mapper {\n    \n    @Override\n    public void loadro"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper47.java",
    "chars": 5228,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper48.java",
    "chars": 5331,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper58.java",
    "chars": 1392,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper58 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper60.java",
    "chars": 1128,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper60 extends Mapper {\n\n    int"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper61.java",
    "chars": 1540,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper61 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper62.java",
    "chars": 1636,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper62 extends Mapper {\n\n    boo"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper70.java",
    "chars": 1178,
    "preview": "package com.grapeshot.halfnes.mappers;\n\npublic class Mapper70 extends Mapper {\n\n    @Override\n    public void loadrom() "
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper72.java",
    "chars": 1248,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper72 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper76.java",
    "chars": 2184,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper78.java",
    "chars": 1496,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper86.java",
    "chars": 2963,
    "preview": "package com.grapeshot.halfnes.mappers;\n\npublic class Mapper86 extends Mapper {\n\n    @Override\n    public void loadrom() "
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper87.java",
    "chars": 1051,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper92.java",
    "chars": 1110,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper92 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper94.java",
    "chars": 1127,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Mapper97.java",
    "chars": 1487,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Mapper97 extends Mapper {\n\n    @Ov"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NINA_001_Mapper.java",
    "chars": 1288,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class NINA_001_Mapper extends Mapper {\n\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NINA_003_006_Mapper.java",
    "chars": 2041,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class NINA_003_006_Mapper extends Mapper"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NSFMapper.java",
    "chars": 17722,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NSFPlayerFont.java",
    "chars": 55448,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NamcoMapper.java",
    "chars": 8043,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Namcot34x3Mapper.java",
    "chars": 2622,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Namcot34x3Mapper extends Mapper {\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/NromMapper.java",
    "chars": 1943,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Sunsoft01Mapper.java",
    "chars": 1124,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Sunsoft02Mapper.java",
    "chars": 1582,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Sunsoft02Mapper extends Mapper {\n\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/Sunsoft03Mapper.java",
    "chars": 3472,
    "preview": "package com.grapeshot.halfnes.mappers;\n\nimport com.grapeshot.halfnes.*;\n\npublic class Sunsoft03Mapper extends Mapper {\n\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/TengenRamboMapper.java",
    "chars": 9024,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/UnromMapper.java",
    "chars": 1166,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC1Mapper.java",
    "chars": 2973,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC2Mapper.java",
    "chars": 3329,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC3Mapper.java",
    "chars": 3731,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC4Mapper.java",
    "chars": 8341,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC6Mapper.java",
    "chars": 6699,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/mappers/VRC7Mapper.java",
    "chars": 6831,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/ControllerImpl.java",
    "chars": 12710,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/ControllerInterface.java",
    "chars": 333,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/ControlsDialog.form",
    "chars": 27917,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<Form version=\"1.5\" maxVersion=\"1.7\" type=\"org.netbeans.modules.form.forminfo.J"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/ControlsDialog.java",
    "chars": 34239,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\n\n/*\n * OptionsDialog.java\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/DebugUI.java",
    "chars": 1759,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/DummyController.java",
    "chars": 4068,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/FrameLimiterImpl.java",
    "chars": 2576,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/FrameLimiterInterface.java",
    "chars": 301,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/GUIInterface.java",
    "chars": 659,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/HeadlessUI.java",
    "chars": 2076,
    "preview": "package com.grapeshot.halfnes.ui;\n\nimport com.grapeshot.halfnes.CPURAM;\nimport com.grapeshot.halfnes.NES;\nimport com.gra"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/NESFileFilter.java",
    "chars": 1214,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/OnScreenMenu.java",
    "chars": 8220,
    "preview": "package com.grapeshot.halfnes.ui;\n\nimport com.grapeshot.halfnes.FileUtils;\nimport static com.grapeshot.halfnes.utils.BIT"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/Oscilloscope.java",
    "chars": 2769,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/PreferencesDialog.form",
    "chars": 17930,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n<Form version=\"1.5\" maxVersion=\"1.7\" type=\"org.netbeans.modules.form.forminfo.J"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/PreferencesDialog.java",
    "chars": 20056,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\n\n/*\n * OptionsDialog.java\n"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/PuppetController.java",
    "chars": 2699,
    "preview": "package com.grapeshot.halfnes.ui;\n\nimport static com.grapeshot.halfnes.utils.BIT0;\nimport static com.grapeshot.halfnes.u"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/ui/SwingUI.java",
    "chars": 23102,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/utils.java",
    "chars": 3155,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/video/AltNTSCRenderer.java",
    "chars": 4391,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/video/NTSCRenderer.java",
    "chars": 11649,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/video/NesColors.java",
    "chars": 4230,
    "preview": "/*\n * To change this template, choose Tools | Templates\n * and open the template in the editor.\n */\npackage com.grapesho"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/video/RGBRenderer.java",
    "chars": 818,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java/com/grapeshot/halfnes/video/Renderer.java",
    "chars": 1436,
    "preview": "/*\n * HalfNES by Andrew Hoffman\n * Licensed under the GNU GPL Version 3. See LICENSE file\n */\npackage com.grapeshot.half"
  },
  {
    "path": "src/main/java-templates/com/grapeshot/halfnes/ProjectInfo.java",
    "chars": 209,
    "preview": "package com.grapeshot.halfnes;\n\n/**\n * Specifies the version and url as defined in the POM\n *\n */\npublic interface Proje"
  },
  {
    "path": "src/main/resources/changelog.txt",
    "chars": 24154,
    "preview": "HalfNES Version Notes:\n062 (3/25/2018)\n-first release in 2 years\n-fixed temp file creation issue\n-fixed Micro Machines\n-"
  },
  {
    "path": "src/main/resources/todo.txt",
    "chars": 6378,
    "preview": "Todo List For HalfNES:\n\n - Add FDS support\n\n - Add rest of the expansion sound for MMC5 (PCM out is not working right)\n\n"
  },
  {
    "path": "src/test/java/com/grapeshot/halfnes/JInputTest.java",
    "chars": 791,
    "preview": "package com.grapeshot.halfnes;\n\nimport net.java.games.input.Controller;\nimport net.java.games.input.ControllerEnvironmen"
  },
  {
    "path": "src/test/java/com/grapeshot/halfnes/nestest/NesTest.java",
    "chars": 1598,
    "preview": "package com.grapeshot.halfnes.nestest;\n\nimport com.grapeshot.halfnes.NES;\nimport com.grapeshot.halfnes.mappers.BadMapper"
  },
  {
    "path": "src/test/resources/nestest/compare.log",
    "chars": 682920,
    "preview": "C000 4C JMP $C5F5       PC:C001 A:00 X:00 Y:00 P:24 SP:FD CYC:0 SL:0\nC5F5 A2 LDX #$00        PC:C5F6 A:00 X:00 Y:00 P:24"
  },
  {
    "path": "src/test/resources/nestest/nestest.log",
    "chars": 796087,
    "preview": "C000  4C F5 C5  JMP $C5F5                       A:00 X:00 Y:00 P:24 SP:FD CYC:  0 SL:241\nC5F5  A2 00     LDX #$00       "
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the andrew-hoffman/halfnes GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 152 files (2.2 MB), approximately 592.8k tokens, and a symbol index with 1002 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!