Compare commits
46 Commits
v0.5.0.573
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ef91ce464c | |||
| 0ba54f14d3 | |||
| 0a330b490f | |||
| 65e0083de0 | |||
| 6237b9f50e | |||
| ba04dbb4ef | |||
| 2fffad141d | |||
| 44182cc6eb | |||
| 72bb48afdd | |||
| ecbaa4142b | |||
| e69312eabd | |||
| b5a97f1d55 | |||
| 00e8ac983c | |||
| be62b682da | |||
| 8868472869 | |||
| beba11c372 | |||
| 5c1a41ec41 | |||
| 01f163576d | |||
| be0e841c42 | |||
| 40e9ff65bb | |||
| c4bd988726 | |||
| 17ccc013a8 | |||
| bb866b0f91 | |||
| ac3ceae429 | |||
| 69a6fe7856 | |||
| 5fd058a7ea | |||
| f463dc6b7a | |||
| d8d6f0d807 | |||
| 08f893779e | |||
| 23b9a5de5a | |||
| e5b42325c9 | |||
| fb4cc1323e | |||
| 8e6c44a63e | |||
| 052a4b7020 | |||
| fd5294ab09 | |||
| 3ee18feec9 | |||
| a69f54e944 | |||
| c1823b4021 | |||
| 27b26480c6 | |||
| fd071b24b5 | |||
| 34bc63a962 | |||
| 41e7cbb149 | |||
| 4cc81aa4ac | |||
| eac78b39e1 | |||
| 8245238796 | |||
| d16ec11885 |
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
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
|
||||
convey 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
@@ -0,0 +1,551 @@
|
||||
Version 0.5.1
|
||||
-------------
|
||||
- Build improvements
|
||||
- Increase standards compliance and code quality
|
||||
- Add the SoX Resampler for higher quality (but higher CPU usage) resampling
|
||||
- Add SameBoy's "Modern - Accurate" colour correction
|
||||
|
||||
Version 0.5.0
|
||||
-------------
|
||||
- Initial tagged release after fork from final public revision of Gambatte
|
||||
- Stricter build flags
|
||||
- Removal of stale, bitrotten code
|
||||
- Rearrange and simplify codebase layout
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- 0.4.1 -- 2009-01-10
|
||||
libgambatte:
|
||||
- Fix HqXx filter pitch.
|
||||
- Fix mbc2 not getting a rambank.
|
||||
- Make sure to reset passed pointers when deleted. Fixes potential crash
|
||||
when loading ROM during OAM busy.
|
||||
common:
|
||||
- Substantially improved rate estimation averaging.
|
||||
- RateEst: Add a convenient way of filtering measures that extend beyond
|
||||
a buffer time, and are as such probably invalid.
|
||||
- RateEst: Allow using a custom timestamp in feed().
|
||||
- RateEst: Keep a queue of the last ~100 msec worth of samples and
|
||||
duration, and filter out collective samples that give a pre-estimate
|
||||
that seems way off.
|
||||
- Replace "Game Boy / Game Boy Color emulator" with "Game Boy Color
|
||||
emulator" for now to avoid misleading anyone on the current status.
|
||||
gambatte_qt:
|
||||
- Disable BlitterWidget updates (paintEvents) while not paused.
|
||||
- QGLBlitter: Do a cheap front blit rather than a vsynced flip if audio
|
||||
buffers are low.
|
||||
- Allow BlitterWidgets to opt in to get paintEvents while unpaused. Do so
|
||||
for QGLBlitter since it may need to clear buffers afterwards.
|
||||
- QGLBlitter: Try to blit right after sync in the case of single buffering.
|
||||
- Up default audio buffer latency to 100 ms (some common system audio
|
||||
servers require a lot of buffering to work well).
|
||||
- Adaptively skip BlitterWidget syncs if audio buffer is low, in a manner
|
||||
that should minimize wasted skips in sync to vblank situation, and tries
|
||||
to be non-disturbing. This replaces frame time halving, and blitter
|
||||
specific rescueing.
|
||||
- Clear display buffers in DirectDrawBlitter and Direct3DBlitter in
|
||||
exclusive mode, since blits don't necessarily cover the entire buffers.
|
||||
- DirectDrawBlitter: Make sure that a minimum amount of time has passed
|
||||
between calls to WaitForVerticalBlank, since it can return in the same
|
||||
vblank period twice on a fast system.
|
||||
- DirectDrawBlitter: Support vsync for refresh rate ~= 2x frame rate.
|
||||
- DirectDrawBlitter: Refactor somewhat and get rid of a couple minor
|
||||
potential bugs.
|
||||
- DirectDrawBlitter: Some tweaks to get updates closer to sync time in
|
||||
certain situations.
|
||||
- DirectDrawBlitter: Some tweaks to better support DONOTWAIT.
|
||||
- DirectDrawBlitter: Make only updating during vblank while page flipping
|
||||
optional.
|
||||
- Direct3DBlitter: Some tweaks to get updates closer to sync time in
|
||||
certain situations.
|
||||
- Filter out very short frame times in frame time estimation.
|
||||
- Don't adjust frame time during turbo, but rather skip BlitterWidget
|
||||
syncs to speed up, which avoids vsync limits without disabling vsync.
|
||||
- DirectDrawBlitter: Add triple buffering option.
|
||||
- Direct3DBlitter: Use D3DSWAPEFFECT_DISCARD in non-exclusive mode.
|
||||
- Direct3DBlitter: Allow triple buffering and vblank-only updates in
|
||||
non-excusive mode.
|
||||
- Rename "Page flipping" in Direct3D and DirectDraw blitters to
|
||||
"Exclusive full screen".
|
||||
- Pause audio on win32 titlebar clicks/drags to avoid looping audio due to
|
||||
underruns from blocked timerEvents.
|
||||
- Use wildcards for platform detection to avoid being unnecessarily
|
||||
compiler/architecture specific. Fixes bug 2377772.
|
||||
- Rewrite most of DirectSoundEngine, supporting primary buffer option,
|
||||
making it more robust, correct and hopefully cleaner. Only use part of
|
||||
the primary buffer if the desired buffer size is lower than the
|
||||
primary buffer size.
|
||||
- Direct3DBlitter and DirectDrawBlitter: Force blocking updates when sync
|
||||
to vblank is enabled. Some updates only block if there's a prior
|
||||
unfinished update in progress. This screws up frame time estimation in
|
||||
turn screwing up vsync. To fix this we do a double update (and extra blit)
|
||||
if close to a frame time period has passed since the last update when
|
||||
sync to vblank is enabled. I really should have noticed this earlier as
|
||||
it pretty much breaks vsync adaption completely.
|
||||
- Direct3DBlitter: Use the D3DCREATE_FPU_PRESERVE flag when creating
|
||||
device. Omitting this flag can screw up floating point calculations in
|
||||
other parts of the code. For instance WASAPI cursor timestamps get
|
||||
utterly screwed up here.
|
||||
- Direct3DBlitter: It appears that managed textures are updated before
|
||||
they are unlocked, which screws up redraws, making things appear choppy
|
||||
in some situations. Use a default memory texture and a system memory
|
||||
texture and the UpdateTexure method instead.
|
||||
- DirectSoundEngine: Make use of the sample period limit feature of
|
||||
RateEst, rather than duplicating the feature.
|
||||
- Add polling WASAPI engine with exclusive mode support. Latency and rate
|
||||
estimation is generally better than DirectSound, and in exclusive mode
|
||||
there is less blocking as well as exclusive mode being better than
|
||||
shared mode in the other areas too.
|
||||
- WasapiEngine: Add device selection.
|
||||
- WasapiEngine: Add static isUsable() method. Only listed if isUsable().
|
||||
Default engine if isUsable().
|
||||
- WasapiEngine: Use default device if there's only one device available,
|
||||
since we don't show the combobox anyway.
|
||||
- DirectSoundEngine: Provide the integrated read and status get write
|
||||
method optimization.
|
||||
- XvBlitter: Set NosystemBackground attribute rather than OpaquePaintEvent.
|
||||
Reimplement paintEngine to return NULL as suggested by Qt docs.
|
||||
- X11Blitter: Reimplement paintEngine to return NULL.
|
||||
- AlsaEngine: Make use of sample period limit feature of RateEst. Don't
|
||||
increase estimated sample rate on underrun.
|
||||
- OssEngine: Make use of sample period limit feature of RateEst. Don't
|
||||
increase estimated sample rate on underrun.
|
||||
- Esc exits fullscreen on macx.
|
||||
- Drop OpenAL from default macx binary.
|
||||
- Add some useful but commented build flags for macx to .pro files.
|
||||
|
||||
-- 0.4.0 -- 2008-10-27
|
||||
libgambatte:
|
||||
- less fixed-width type dependencies. don't assume unsigned int > 16 bits
|
||||
- slightly faster sprite mapping
|
||||
- Skip potential high frequency events when they don't matter.
|
||||
- do sprite sorting and cycle calculations pr line as needed instead of all
|
||||
at once
|
||||
- fix broken volume on/off event notification
|
||||
- less int > 16-bits assumptions
|
||||
- more type width dependency fixes
|
||||
- int width deps. Gambatte namespace
|
||||
- wx affects sprite m3 cycles
|
||||
- cache m3 cycles, related refactoring
|
||||
- readjust cgb dma cycles to previously changed m3 timing
|
||||
- clean up goofy lyc calculation.
|
||||
- cgb dma from various areas results in 0xFF being written.
|
||||
- 0xFEA0-0xFEFF not writable when OAM isn't
|
||||
- unusable ioram bits fixes
|
||||
- dmg ioram startup state fixes.
|
||||
- various oamdma accuracy
|
||||
- oamdma bus conflicts with cpu, ppu, cgbdma.
|
||||
- rewritten memory read/write methods.
|
||||
- accurate timing of ppu sprite mapping reads.
|
||||
- fix recent cgb sprite cycles sorting slip up.
|
||||
- preoffset mem pointers.
|
||||
- get rid of unused memory.
|
||||
- save state infrastructure,
|
||||
- clean up video timing code,
|
||||
- use save state for initialization and reset,
|
||||
- do color conversion outside filters
|
||||
- fast rgb32ToUyvy,
|
||||
- add overlooked oamdma event,
|
||||
- adjust subcycle irq timing (shouldn't affect anything),
|
||||
- various refactoring
|
||||
- save savedata before loading state
|
||||
- fix silly initstate ifreg regression
|
||||
- save state selection
|
||||
- save state osd preview snapshots
|
||||
- fix a few potential security holes when loading invalid state
|
||||
- get rid of some undefined behaviour in statesaver
|
||||
- always draw in rgb32, color convert afterwards, too bad for maemo/16-bit
|
||||
depth users
|
||||
- get rid of silly c string stuff
|
||||
- add bitmap font rendering with font based on Bitstream Vera Sans
|
||||
- osd state n saved/loaded text
|
||||
- empty state osd thumbs marked with "Empty" text
|
||||
- adjust thumbnail interpolation weighing slightly
|
||||
- utilize templates for more flexible osd text printing
|
||||
- use grey osd text with black outline for save/load state messages
|
||||
- move state 0 OSD pos to rightmost to match kbd layout
|
||||
- state 1 default on ROM load
|
||||
- support external save state files
|
||||
- missing includes
|
||||
- missing virtual destructor
|
||||
- std::ifstream construction missing binary flag
|
||||
- fix gcc-4.3 compilation
|
||||
- avoid signed overflow in constant (which is both undefined and likely
|
||||
to cause problems on architectures where sizeof(long) != sizeof(int)) in
|
||||
rgb2yuv code.
|
||||
- Fix wrong pitch passed to filter if color conversion is needed.
|
||||
- Fix potential problem with rgb32ToUyvy cache init values on 16-bit systems
|
||||
- Correct unhalttime when resetting counters. Fixes perodic infinite halt
|
||||
issue in Kirby's Star Stacker and probably other games.
|
||||
- Fix LY display disable regression
|
||||
- Use deltas and a running sum to decrease buffer writes in sound emulation
|
||||
sample generation.
|
||||
- Rearrange sound emulation event loop to optimize for high-frequency event
|
||||
units.
|
||||
- Initialize palette arrays to avoid valgrind noise.
|
||||
- Don't do resampling in libgambatte. Update API to reflect this.
|
||||
- No rambanks for ROMs that don't request any.
|
||||
- Route invalid rombank addresses in non-power-of-2 number of rombanks
|
||||
cases to disabled area assuming ceiled power of 2 address bus.
|
||||
- no sprites or sprite mapping busy cycles on first line after display
|
||||
enable. slight cleanup.
|
||||
- small oam accessibility correction.
|
||||
- Tile loading and tile rendering can seemingly get out of sync when
|
||||
modifying scx at a critical time. Another pessimation with little gain in
|
||||
the name of accuracy.
|
||||
- Use a look-up table to do tile byte merging.
|
||||
- Append "_dmg" to save base name when forcing DMG mode, to avoid
|
||||
corrupting CGB save files and vice versa.
|
||||
- saner ly write behaviour
|
||||
- Add adapted and optimized hq3x.
|
||||
- Revert to big f'ing switch hq2x code, as there's less duplication now.
|
||||
Also optimized interpolation functions further. No idea how I missed that
|
||||
initially.
|
||||
- Lower opacity OSD text.
|
||||
gambatte_sdl:
|
||||
- less retarded indenting
|
||||
- saner placement of fill_buffer function
|
||||
- int width deps. Gambatte namespace
|
||||
- Scalebuffer dstpitch aware.
|
||||
- save state selection
|
||||
- add number key slot selection shortcuts
|
||||
- Estimate actual output sample rate in terms of OS timers
|
||||
and derive frame rate from it.
|
||||
- Move AudioData and RingBuffer classes to separate files.
|
||||
- Make underruns slightly less painful, by resetting buffer
|
||||
positions.
|
||||
- Skip resampling when fast-forwarding
|
||||
- Fill available buffer space before waiting for more.
|
||||
- Audio buffer command line options.
|
||||
- Use half video frame sleep time if audio buffer is close to underrun.
|
||||
- Adjust estimated frame time each frame.
|
||||
gambatte_qt:
|
||||
- more likely to build on mac os x
|
||||
- Fix fixed window size issues with various window managers (metacity,
|
||||
xfwm4...)
|
||||
- macx build fixes
|
||||
- hopefully fix opengl clearing issues
|
||||
- Gambatte namespace
|
||||
- Decouple Qt GUI from gambatte.
|
||||
- Lots of cleanups, flexibility added
|
||||
- setting of various properties, frame time, aspect ratio, button events,
|
||||
video sources, sample rates, pauseOnDialogExec, custom menus etc.
|
||||
- Document some interfaces.
|
||||
- Support for setting approximate sound buffer latency.
|
||||
- Use rational math for 100% exact timers (even though the actual system
|
||||
timers are unlikely to be accurate).
|
||||
- Add fast-forward to input settings.
|
||||
- timeGetTime() fallback for win32
|
||||
- Store full screen mode values/text rather than less reliable indexes.
|
||||
- Repaint on xvblitter port changes to avoid color key not getting
|
||||
repainted.
|
||||
- improved ALSA buffer reporting
|
||||
- add sampleRate info to MediaSource::setSampleBuffer.
|
||||
- clarify that "samples" refers to stereo samples
|
||||
- fix 24-bit depth non-shm ximage creation
|
||||
- fix blittercontainer incorrectly using minimumSize for integer scaling
|
||||
- add unrestricted fast bilinear and nearest neighbor sw scaling to
|
||||
x11/qpainter blitter
|
||||
- swscale: remove forgotten static qualifiers
|
||||
- swscale: center linear weighing bias
|
||||
- swscale: exclude iostream
|
||||
- swscale: less bloated
|
||||
- macx fixed/variable window size change issue fixed
|
||||
- macx opengl drawbuffer change issues worked around
|
||||
- add openal engine, default on macx
|
||||
- add macx quartz video mode toggler
|
||||
- multi-head infrastructure
|
||||
- support multiple monitors in macx quartz toggler
|
||||
- more work-arounds for Qt failing to set correct geometry on video mode
|
||||
changes.
|
||||
- more explicit fast-forward button handling, to avoid missed key
|
||||
press/release events on macx
|
||||
- opengl doublebuffer preblitting, try to make actual screen updates as
|
||||
close to right after sync wait is over as possible
|
||||
- add xf86vidmode toggler (xrandrtoggler is default)
|
||||
- x11blitter: check for other supported visuals if the default is
|
||||
unsupported.
|
||||
- temporarily return to original video mode and minimize on full screen
|
||||
alt-tab (except on macx or if there are multiple screens), switch back on
|
||||
focus-in
|
||||
- hide mouse cursor after move timeout, or key/joystick pressed (more sane
|
||||
on macx)
|
||||
- exit fullscreen rather than toggle menubar on macx (note that the menubar
|
||||
will automatically pop-up on macx full screen if the mouse is moved to
|
||||
the top of the primary screen)
|
||||
- add (independent) pause counter for non-client pauses.
|
||||
- reset X11 screen saver on joystick activity
|
||||
- change "turbo"-mode to temporarily set frametime as a way of avoiding
|
||||
vsync issues (for a laugh, check out the video dialog while in
|
||||
fast-forward mode and see "Sync to vertical blank in 65535 and 131070 Hz
|
||||
modes").
|
||||
- fix win32 compilation
|
||||
- refix win32 fullscreen geometry correction
|
||||
- neater win32 BlitterWidget::sync
|
||||
- avoid misleading minimize on fullscreen close
|
||||
- refactor Blitterwidget::sync
|
||||
- directdrawblitter: remove unecessary turbo conditions
|
||||
- gditoggler: add multi-monitor support (win32)
|
||||
- videodialog: save actual hz values for real this time
|
||||
- quartztoggler: avoid potentially reverting to the wrong mode on double
|
||||
setFullMode(false) in multi-head configs
|
||||
- make sure window is within screen after mode change, so Qt doesn't reset
|
||||
it to the primary screen
|
||||
- revert to previous win32 fullscreen geometry correction behaviour so that
|
||||
the geometry gets properly reset after fullscreen
|
||||
- Add directdraw device selection.
|
||||
- directsoundengine: add device selection.
|
||||
- directdrawblitter: only list devices if there are more than 2 devices
|
||||
(including primary)
|
||||
- directdrawblitter: use private static member rather than global friend
|
||||
enumeration callback
|
||||
- capitalization changes
|
||||
- add direct3d9 blitter with support for vsync, bf, page flipping, triple
|
||||
buffering, device selection, multi-head etc. d3d9.dll loaded at runtime
|
||||
- more strict and thorough exclusive mode handling to support d3d fullscreen
|
||||
- work around file open dialog not returning focus properly
|
||||
- gditoggler: use current registry settings for return modes
|
||||
- directsoundengine: set DSBCAPS_GETCURRENTPOSITION2 flag
|
||||
- revert bad macx return from fullscreen on menu-toggle
|
||||
- don't build xf86vidmodetoggler by default
|
||||
- add save state actions to GUI menu
|
||||
- clean up GUI menu creation code
|
||||
- move GUI recent files to submenu
|
||||
- support external save state files
|
||||
- add number key slot selection shortcuts
|
||||
- missing includes
|
||||
- missing virtual destructor
|
||||
- make sure windows path arguments don't use backslashes by using QFileInfo
|
||||
- add Play menu with Pause, Frame Step, Dec/Inc/Reset Frame Rate
|
||||
- Add tab support to input settings dialog.
|
||||
- Add alternate key support to input settings dialog.
|
||||
- Auto-focus to next likely input box after settings key in input dialog.
|
||||
- Add "Play" and "State" input settings dialog tabs.
|
||||
- Avoid using the most convenient keys as forced menu short-cuts, set them
|
||||
as default keys in input settings dialog instead. This unfortunately
|
||||
makes the more useful shortcuts less visible, but it allows remapping
|
||||
the most convenient keyboard keys.
|
||||
- Avoid duplicate joystick axis "press" events by keeping a map of axis
|
||||
states.
|
||||
- Make sure to discard irrelevant/old joystick events.
|
||||
- Don't give MediaSource button events when stopped.
|
||||
- Allow joystick-based button events while paused by using a very
|
||||
low-frequency poll timer.
|
||||
- Make some of the joystick event wrapping stuff less messy.
|
||||
- missing string include
|
||||
- use QString for videoSourceLabel passed to MainWindow constructor
|
||||
- store currently selected scheme as string, since it appears ModelIndex
|
||||
is neither tied to the data it points to nor invalidated by changes.
|
||||
enforce valid state on reject since the list of schemes may have
|
||||
changed.
|
||||
- Direct3DCreate function pointer typedef needs WINAPI macro
|
||||
- disable page flipping dependent checkboxes in constructor to ensure
|
||||
correct start state
|
||||
- add custom sample rate support
|
||||
- change default buffer latency to 67 ms
|
||||
- don't auto-repeat buttons bound to keyboard
|
||||
- use enums for somewhat more robust gambattesource button setup
|
||||
- fix silly "alsa not using default device by default" bug
|
||||
- Only ask for xrandr config once to avoid potential server roundtrips in
|
||||
some xrandr versions.
|
||||
- Make sure xrandr version is >= 1.1 and < 2
|
||||
- Prevent all text editing of input boxes.
|
||||
- Add custom context menu to input boxes.
|
||||
- Update AudioEngine to support sample rate estimation in terms of OS
|
||||
timers.
|
||||
- Implement sample rate estimation in ALSA and OSS audio engines.
|
||||
- AlsaEngine: Revert to using snd_pcm_avail_update for buffer status since
|
||||
snd_pcm_delay may consider external latencies.
|
||||
- AlsaEngine: Use snd_pcm_hw_params_set_buffer_time_near. Don't request a
|
||||
particular number of periods per buffer.
|
||||
- AlsaEngine: Use hw as default custom device string, rather than hw:0,0.
|
||||
- OssEngine: Don't trust GETOSPACE fragment info.
|
||||
- Estimate optimal frame rate based on sample rate estimations.
|
||||
- Extend BlitterWidget to support estimation of vsynced frame rate in terms
|
||||
of OS timers.
|
||||
- Implement vsync frame rate estimation in QGlBlitter, Direct3DBlitter and
|
||||
DirectDrawBlitter.
|
||||
- Use a combination of OS timer sample rate estimation and vsync frame rate
|
||||
estimation to derive resampling ratio for no-frame-duplication vsync.
|
||||
- Change API to reflect MediaSources not being responsible for resampling.
|
||||
- Make sure to parent PaletteDialog list model, so it gets deleted properly.
|
||||
- Various refactoring, small changes and stuff I forgot.
|
||||
- limit vsync frame rate estimation deviation
|
||||
- More averaging in estimation code.
|
||||
- Stricter estimate deviation limit
|
||||
- Adjust estimated frame time each frame.
|
||||
- Use half frame time if audio buffer is close to underrun.
|
||||
- Provide combined audioengine write and status get, to avoid doing
|
||||
potentially expensive operations twice. Utilized in OSS and ALSA engines.
|
||||
- Saner vsync estimate variance protection.
|
||||
- allow dynamically setting samples per frame
|
||||
- Don't bother allowing sources the choice of which output sample rates are
|
||||
selecrable, as it's not really a per source thing at this point. If
|
||||
resampling avoidance is desired, then that should rather be a user option
|
||||
(to depend on the OS for resampling, which is mostly nonsensical for the
|
||||
Game Boy/NES/PSG-system case btw).
|
||||
- Move Qt media framework to a separate subdir
|
||||
- postpone buffered x11 blits to after sync.
|
||||
- Add support for XRandR 1.2 + multi-head
|
||||
- use crtc mode dimensions rather than crtc dimensions when discarding
|
||||
modes since crtc dimensions may be rotated
|
||||
- Fractional bits for intermediate rate estimation averages.
|
||||
- Add RateEst reset method. Initialize RateEst count to 1.
|
||||
- Less refresh rate estimation averaging.
|
||||
- Allow more refresh rate estimation deviation.
|
||||
- Return NULL paintEngine in windows blitters that use the PaintToScreen
|
||||
attribute.
|
||||
- Add checks for things not being initialized in DirectDraw-blitter and
|
||||
QPainterBlitter paintEvents.
|
||||
- Don't reparent blitters (mainly to make a bug in Qt 4.4.3 win less
|
||||
annoying, widgets that do internal reparenting are still affected).
|
||||
- Check for window position less than screen top-left after mode change,
|
||||
before full screen, to avoid Qt moving it to the primary screen.
|
||||
- Add rate estimation to DirectSound engine.
|
||||
- Better underrun detection in DirectSound engine.
|
||||
- Don't duplicate blitter pointer in mainwindow.
|
||||
- Use RateEst.reset rather than re-initing on pause.
|
||||
- Add CoreAudio engine with rate estimation and buffer status support.
|
||||
Default engine on Mac OS X.
|
||||
- 44100 Hz default sample rate on OS X, since OS X tends to resample
|
||||
everything to 44100 Hz.
|
||||
- Get rid of buffer status averaging in OpenAlEngine, since it makes
|
||||
assumptions on usage pattern that shouldn't be made.
|
||||
- Fix CoreAudio engine reporting buffer status in samples rather than
|
||||
frames.
|
||||
- Update SDL_Joystick to SDL-1.2 SVN.
|
||||
- #undef UNICODE in win32/SDL_mmjoystick.c to avoid joystick name mangling.
|
||||
- work around annoying random non-updating OpenGL on Mac OS X after full
|
||||
screen.
|
||||
common/other:
|
||||
- Fix GCC 4.3 warnings about people getting confused by operator precedence
|
||||
by adding parentheses.
|
||||
- Real-time, sophisticated resampling framework with several
|
||||
performance/quality profiles for dynamically generated windowed sinc and
|
||||
CIC chains based on analysis of fourier transforms and optimal cost
|
||||
equations. Fast 2-tap linear as a low quality alternative.
|
||||
- Move non-emulation common code to a common directory to avoid duplication.
|
||||
- Update front-ends to new libgambatte API.
|
||||
- Utilize resampling framework in front-ends. Selectable resamplers.
|
||||
- Improved adaptive sleep class that estimates oversleep.
|
||||
- Various refactoring, small changes and stuff I forgot.
|
||||
- Do per phase normalization to avoid dc fluctuations.
|
||||
- More averaging in estimation code.
|
||||
- Stricter estimate deviation limit
|
||||
- Fractional bits for intermediate rate estimation averages.
|
||||
- Add RateEst reset method. Initialize RateEst count to 1.
|
||||
- Extend ringbuffer.h to support resetting size, and move it to common dir
|
||||
since gambatte_qt/coreaudioengine uses it too now.
|
||||
- Add "force DMG mode" option.
|
||||
- Allow more rate estimation deviation.
|
||||
hwtests:
|
||||
- wx affects sprite m3 cycles.
|
||||
- cgb dma from various areas results in 0xFF being written.
|
||||
- add hwtests for oam dma
|
||||
- m3 cycles wo bg
|
||||
- more oamdma tests
|
||||
- various oamdma accuracy. oamdma bus conflicts with cpu, ppu, cgbdma.
|
||||
- accurate timing of ppu sprite mapping reads.
|
||||
|
||||
-- 0.3.1 -- 2007-10-26 --
|
||||
gambatte_qt:
|
||||
- Enable Joystick POV-Hat events.
|
||||
|
||||
-- 0.3.0 -- 2007-10-26 --
|
||||
libgambatte:
|
||||
- Fix adc/sbc and add_hl_rr hfc calc, sp_plus_n cf/hcf calc and daa thanks
|
||||
to blargg.
|
||||
- document HF2 better
|
||||
- Update sound core according to blargg's findings.
|
||||
- Improve resampling quality and performance.
|
||||
- Fix overlooked "add hl,sp" flag calculation.
|
||||
- fix initial endtime value
|
||||
- check for resampling ratio < 1
|
||||
- Add support for DMG palette customization.
|
||||
gambatte_sdl:
|
||||
- use std::map for parser
|
||||
- Don't bother hashing.
|
||||
- Add input config support.
|
||||
- Add joystick support.
|
||||
- Fix horrid "turbo can affect emulation" bug.
|
||||
- Add sw and yuv overlay scaling.
|
||||
- Use cond/mutex for thread syncing, RAII, refactor.
|
||||
- add option for sample rate choice
|
||||
- Add option to list valid input keys
|
||||
- don't die if audio fails
|
||||
gambatte_qt:
|
||||
- no point in filter being non-static anymore
|
||||
- use std::map for input vectors
|
||||
- remove unused unusedBool
|
||||
- Fix horrid "turbo can affect emulation" bug.
|
||||
- remove some useless optimizations
|
||||
- auto_ptr love.
|
||||
- support joystick hat.
|
||||
- nicer input handling.
|
||||
- Add sound dialog.
|
||||
- Add custom dev choice for oss, alsa engines.
|
||||
- Use rgb if available for xv.
|
||||
- Get rid of BAD_MATCH warnings for setting non-existent xv attributes.
|
||||
- make subblitters private nested classes
|
||||
- add reset action
|
||||
- Add support for DMG palette customization.
|
||||
- Add global buffer option for dsound engine
|
||||
|
||||
-- 0.2.0 -- 2007-09-05 --
|
||||
libgambatte:
|
||||
- fix 64-bit compile and segfault. Thanks to Nach for noticing.
|
||||
- Add zip support. Thanks to Nach for contributing nice, clear code
|
||||
- fix sound ch4 frequency calculation
|
||||
- Several PPU reads timings depend on wx. Thanks to franpa for noticing the
|
||||
corrupt line in The LoZ: Oracle of Seasons.
|
||||
- remove unused doubleSpeed parameter from m3ExtraCycles call
|
||||
gambatte_sdl:
|
||||
- Thread safety, bigger sound buffer
|
||||
- Compile on more platforms. Thanks to Thristian for the find.
|
||||
- actually increment iterator so the loop makes some sense (parser.cpp)
|
||||
gambatte_qt:
|
||||
- fix 64-bit compile. Thanks to Nach.
|
||||
- better license info for x11getprocaddress.cpp
|
||||
- initial joystick support, mostly using SDL's joystick code (separated from
|
||||
the rest of SDL)
|
||||
- use binary search for gb inputs.
|
||||
all:
|
||||
- make sure to use std:: despite sloppy compilers allowing omission. Thanks
|
||||
to blargg for the reminder.
|
||||
- get rid of some valgrind warnings. Thanks to Nach for noticing.
|
||||
hwtests:
|
||||
- add tests for wx effects on PPU read timings.
|
||||
build:
|
||||
- add -Wextra to default compile flags
|
||||
doc:
|
||||
- mention optional zlib dependency
|
||||
- additions to thanks section
|
||||
|
||||
-- 0.1.1 -- 2007-08-29 --
|
||||
libgambatte:
|
||||
- fix integer overflow in color conversion to rgb16
|
||||
- only accept valid filter indexes
|
||||
gambatte_sdl:
|
||||
- print version
|
||||
- print usage
|
||||
- support command line arguments.
|
||||
- add option for starting in full-screen
|
||||
- add option for using video filter
|
||||
gambatte_qt:
|
||||
- clean up obsolete includes.
|
||||
- directdraw: only use alpha if primary surface uses it.
|
||||
- add support for loading rom from porgam argument.
|
||||
- s/"a highly accurate"/"an accuracy-focused"/ in about box
|
||||
- gditoggler: fix unordered video mode listing
|
||||
build:
|
||||
- Support external CPPFLAGS
|
||||
- Use sdl-config
|
||||
doc:
|
||||
- fix silly wording in README about section
|
||||
- s/seperate/separate/
|
||||
- s/Automake/Make/
|
||||
- mention XShm dependency
|
||||
- mention sys/shm.h requirement
|
||||
- document key mapping better
|
||||
- s/"a highly accurate"/"an accuracy-focused"/
|
||||
- add man pages
|
||||
Binary file not shown.
+335
-196
@@ -35,6 +35,14 @@
|
||||
#include "resamplerinfo.h"
|
||||
#include "resampler.h"
|
||||
|
||||
#define OptionDefault(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @YES, }
|
||||
#define Option(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, }
|
||||
#define OptionIndented(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeIndentationLevelKey : @(1), }
|
||||
#define OptionToggleable(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, }
|
||||
#define OptionToggleableNoSave(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, OEGameCoreDisplayModeDisallowPrefSaveKey : @YES, }
|
||||
#define Label(_NAME_) @{ OEGameCoreDisplayModeLabelKey : _NAME_, }
|
||||
#define SeparatorItem() @{ OEGameCoreDisplayModeSeparatorItemKey : @"",}
|
||||
|
||||
gambatte::GB gb;
|
||||
Resampler *resampler;
|
||||
uint32_t pad[OEGBButtonCount];
|
||||
@@ -50,15 +58,22 @@ public:
|
||||
|
||||
@interface GBGameCore () <OEGBSystemResponderClient>
|
||||
{
|
||||
uint32_t *videoBuffer;
|
||||
uint32_t *inSoundBuffer;
|
||||
int16_t *outSoundBuffer;
|
||||
double sampleRate;
|
||||
int displayMode;
|
||||
uint32_t *_videoBuffer;
|
||||
uint32_t *_inSoundBuffer;
|
||||
int16_t *_outSoundBuffer;
|
||||
double _sampleRate;
|
||||
NSMutableDictionary <NSString *, NSNumber *> *_cheatList;
|
||||
NSMutableArray <NSMutableDictionary <NSString *, id> *> *_availableDisplayModes;
|
||||
}
|
||||
|
||||
- (void)applyCheat:(NSString *)code;
|
||||
|
||||
- (void)loadDisplayModeOptions;
|
||||
- (NSString *)gameInternalName;
|
||||
- (BOOL)gameHasInternalPalette;
|
||||
- (void)loadPalette;
|
||||
- (void)loadPaletteDefault;
|
||||
- (void)changePalette:(NSString *)palette;
|
||||
|
||||
@end
|
||||
|
||||
@@ -68,10 +83,9 @@ public:
|
||||
{
|
||||
if((self = [super init]))
|
||||
{
|
||||
videoBuffer = (uint32_t *)malloc(160 * 144 * 4);
|
||||
inSoundBuffer = (uint32_t *)malloc(2064 * 2 * 4);
|
||||
outSoundBuffer = (int16_t *)malloc(2064 * 2 * 2);
|
||||
displayMode = 0;
|
||||
_inSoundBuffer = (uint32_t *)malloc(2064 * 2 * 4);
|
||||
_outSoundBuffer = (int16_t *)malloc(2064 * 2 * 2);
|
||||
_cheatList = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -79,21 +93,21 @@ public:
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(videoBuffer);
|
||||
free(inSoundBuffer);
|
||||
free(outSoundBuffer);
|
||||
free(_videoBuffer);
|
||||
free(_inSoundBuffer);
|
||||
free(_outSoundBuffer);
|
||||
}
|
||||
|
||||
# pragma mark - Execution
|
||||
|
||||
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
|
||||
{
|
||||
memset(pad, 0, sizeof(uint32_t) * OEGBButtonCount);
|
||||
memset(pad, 0, sizeof(pad));
|
||||
|
||||
// Set battery save dir
|
||||
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
|
||||
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
|
||||
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
gb.setSaveDir([[batterySavesDirectory path] UTF8String]);
|
||||
gb.setSaveDir(batterySavesDirectory.fileSystemRepresentation);
|
||||
|
||||
// Set input state callback
|
||||
gb.setInputGetter(&GetInput);
|
||||
@@ -109,14 +123,12 @@ public:
|
||||
resampler->exactRatio(mul, div);
|
||||
|
||||
double outSampleRate = inSampleRate * mul / div;
|
||||
sampleRate = outSampleRate; // 47994.326636
|
||||
_sampleRate = outSampleRate; // 47994.326636
|
||||
|
||||
if (gb.load([path UTF8String]) != 0)
|
||||
if (gb.load(path.fileSystemRepresentation) != 0)
|
||||
return NO;
|
||||
|
||||
// Load built-in GBC palette for monochrome games if supported
|
||||
if (!gb.isCgb())
|
||||
[self loadPalette];
|
||||
[self loadDisplayModeOptions];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -125,8 +137,10 @@ public:
|
||||
{
|
||||
size_t samples = 2064;
|
||||
|
||||
while (gb.runFor(videoBuffer, 160, inSoundBuffer, samples) == -1)
|
||||
while (gb.runFor(_videoBuffer, 160, _inSoundBuffer, samples) == -1) {
|
||||
[self outputAudio:samples];
|
||||
samples = 2064;
|
||||
}
|
||||
|
||||
[self outputAudio:samples];
|
||||
}
|
||||
@@ -152,9 +166,13 @@ public:
|
||||
|
||||
# pragma mark - Video
|
||||
|
||||
- (const void *)videoBuffer
|
||||
- (const void *)getVideoBufferWithHint:(void *)hint
|
||||
{
|
||||
return videoBuffer;
|
||||
if (!hint) {
|
||||
if (!_videoBuffer) _videoBuffer = (uint32_t *)malloc(160 * 144 * 4);
|
||||
hint = _videoBuffer;
|
||||
}
|
||||
return _videoBuffer = (uint32_t*)hint;
|
||||
}
|
||||
|
||||
- (OEIntRect)screenRect
|
||||
@@ -182,16 +200,11 @@ public:
|
||||
return GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
}
|
||||
|
||||
- (GLenum)internalPixelFormat
|
||||
{
|
||||
return GL_RGB8;
|
||||
}
|
||||
|
||||
# pragma mark - Audio
|
||||
|
||||
- (double)audioSampleRate
|
||||
{
|
||||
return sampleRate;
|
||||
return _sampleRate;
|
||||
}
|
||||
|
||||
- (NSUInteger)channelCount
|
||||
@@ -203,28 +216,28 @@ public:
|
||||
|
||||
- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
int success = gb.saveState(0, 0, [fileName UTF8String]);
|
||||
int success = gb.saveState(0, 0, fileName.fileSystemRepresentation);
|
||||
if(block) block(success==1, nil);
|
||||
}
|
||||
|
||||
- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block
|
||||
{
|
||||
int success = gb.loadState([fileName UTF8String]);
|
||||
int success = gb.loadState(fileName.fileSystemRepresentation);
|
||||
if(block) block(success==1, nil);
|
||||
}
|
||||
|
||||
- (NSData *)serializeStateWithError:(NSError **)outError
|
||||
{
|
||||
std::stringstream stream(std::ios::in|std::ios::out|std::ios::binary);
|
||||
|
||||
|
||||
if(gb.serializeState(stream)) {
|
||||
stream.seekg(0, std::ios::end);
|
||||
NSUInteger length = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
|
||||
char *bytes = (char *)malloc(length);
|
||||
stream.read(bytes, length);
|
||||
|
||||
|
||||
return [NSData dataWithBytesNoCopy:bytes length:length];
|
||||
}
|
||||
|
||||
@@ -234,18 +247,18 @@ public:
|
||||
NSLocalizedRecoverySuggestionErrorKey : @"The emulator could not write the state data."
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
|
||||
{
|
||||
std::stringstream stream(std::ios::in|std::ios::out|std::ios::binary);
|
||||
|
||||
char const *bytes = (char const *)([state bytes]);
|
||||
std::streamsize size = [state length];
|
||||
|
||||
char const *bytes = (char const *)(state.bytes);
|
||||
std::streamsize size = state.length;
|
||||
stream.write(bytes, size);
|
||||
|
||||
|
||||
if(gb.deserializeState(stream))
|
||||
return YES;
|
||||
|
||||
@@ -273,189 +286,188 @@ const int GBMap[] = {gambatte::InputGetter::UP, gambatte::InputGetter::DOWN, gam
|
||||
|
||||
#pragma mark - Cheats
|
||||
|
||||
NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
|
||||
|
||||
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
|
||||
{
|
||||
// Sanitize
|
||||
code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
code = [code stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
|
||||
|
||||
// Gambatte expects cheats UPPERCASE
|
||||
code = [code uppercaseString];
|
||||
code = code.uppercaseString;
|
||||
|
||||
// Remove any spaces
|
||||
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
|
||||
if (enabled)
|
||||
[cheatList setValue:@YES forKey:code];
|
||||
_cheatList[code] = @YES;
|
||||
else
|
||||
[cheatList removeObjectForKey:code];
|
||||
[_cheatList removeObjectForKey:code];
|
||||
|
||||
NSMutableArray *combinedGameSharkCodes = [[NSMutableArray alloc] init];
|
||||
NSMutableArray *combinedGameGenieCodes = [[NSMutableArray alloc] init];
|
||||
NSMutableArray <NSString *> *combinedGameSharkCodes = [NSMutableArray array];
|
||||
NSMutableArray <NSString *> *combinedGameGenieCodes = [NSMutableArray array];
|
||||
|
||||
// Gambatte expects all cheats in one combined string per-type e.g. 01xxxxxx+01xxxxxx
|
||||
// Add enabled per-type cheats to arrays and later join them all by a '+' separator
|
||||
for (id key in cheatList)
|
||||
for (NSString *key in _cheatList)
|
||||
{
|
||||
if ([[cheatList valueForKey:key] isEqual:@YES])
|
||||
if ([_cheatList[key] boolValue])
|
||||
{
|
||||
// GameShark
|
||||
if ([key rangeOfString:@"-"].location == NSNotFound)
|
||||
if (![key containsString:@"-"])
|
||||
[combinedGameSharkCodes addObject:key];
|
||||
// Game Genie
|
||||
else if ([key rangeOfString:@"-"].location != NSNotFound)
|
||||
else if ([key containsString:@"-"])
|
||||
[combinedGameGenieCodes addObject:key];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply combined cheats or force a final reset if all cheats are disabled
|
||||
[self applyCheat:[combinedGameSharkCodes count] != 0 ? [combinedGameSharkCodes componentsJoinedByString:@"+"] : @"0"];
|
||||
[self applyCheat:[combinedGameGenieCodes count] != 0 ? [combinedGameGenieCodes componentsJoinedByString:@"+"] : @"0-"];
|
||||
[self applyCheat:combinedGameSharkCodes.count != 0 ? [combinedGameSharkCodes componentsJoinedByString:@"+"] : @"0"];
|
||||
[self applyCheat:combinedGameGenieCodes.count != 0 ? [combinedGameGenieCodes componentsJoinedByString:@"+"] : @"0-"];
|
||||
}
|
||||
|
||||
# pragma mark - Display Mode
|
||||
|
||||
- (void)changeDisplayMode
|
||||
- (NSArray <NSDictionary <NSString *, id> *> *)displayModes
|
||||
{
|
||||
if (gb.isCgb())
|
||||
if (_availableDisplayModes.count == 0)
|
||||
{
|
||||
_availableDisplayModes = [NSMutableArray array];
|
||||
|
||||
NSArray <NSDictionary <NSString *, id> *> *availableModesWithDefault;
|
||||
|
||||
if (gb.isCgb())
|
||||
{
|
||||
availableModesWithDefault =
|
||||
@[
|
||||
Label(@"Color Correction"),
|
||||
OptionDefault(@"Default", @"colorCorrection"),
|
||||
Option(@"Modern", @"colorCorrection"),
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
availableModesWithDefault =
|
||||
@[
|
||||
Option(@"Internal", @"palette"),
|
||||
Option(@"Grayscale", @"palette"),
|
||||
Option(@"Greenscale", @"palette"),
|
||||
Option(@"Pocket", @"palette"),
|
||||
SeparatorItem(),
|
||||
Label(@"GBC Palettes"),
|
||||
Option(@"Blue", @"palette"),
|
||||
Option(@"Dark Blue", @"palette"),
|
||||
Option(@"Green", @"palette"),
|
||||
Option(@"Dark Green", @"palette"),
|
||||
Option(@"Brown", @"palette"),
|
||||
Option(@"Dark Brown", @"palette"),
|
||||
Option(@"Red", @"palette"),
|
||||
Option(@"Yellow", @"palette"),
|
||||
Option(@"Orange", @"palette"),
|
||||
Option(@"Pastel Mix", @"palette"),
|
||||
Option(@"Inverted", @"palette"),
|
||||
];
|
||||
}
|
||||
|
||||
// Deep mutable copy
|
||||
_availableDisplayModes = (NSMutableArray *)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)availableModesWithDefault, kCFPropertyListMutableContainers));
|
||||
|
||||
if (!gb.isCgb() && ![self gameHasInternalPalette])
|
||||
[_availableDisplayModes removeObjectAtIndex:0];
|
||||
}
|
||||
|
||||
return [_availableDisplayModes copy];
|
||||
}
|
||||
|
||||
- (void)changeDisplayWithMode:(NSString *)displayMode
|
||||
{
|
||||
// NOTE: This is a more complex implementation to serve as an example for handling submenus,
|
||||
// toggleable options and multiple groups of mutually exclusive options.
|
||||
|
||||
if (_availableDisplayModes.count == 0)
|
||||
[self displayModes];
|
||||
|
||||
// First check if 'displayMode' is toggleable and grab its preference key
|
||||
BOOL isDisplayModeToggleable = NO;
|
||||
BOOL isValidDisplayMode = NO;
|
||||
BOOL displayModeState = NO;
|
||||
NSString *displayModePrefKey;
|
||||
|
||||
for (NSDictionary *modeDict in _availableDisplayModes)
|
||||
{
|
||||
if ([modeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode])
|
||||
{
|
||||
displayModeState = [modeDict[OEGameCoreDisplayModeStateKey] boolValue];
|
||||
displayModePrefKey = modeDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
isDisplayModeToggleable = [modeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
|
||||
isValidDisplayMode = YES;
|
||||
break;
|
||||
}
|
||||
// Submenu Items
|
||||
for (NSDictionary *subModeDict in modeDict[OEGameCoreDisplayModeGroupItemsKey])
|
||||
{
|
||||
if ([subModeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode])
|
||||
{
|
||||
displayModeState = [subModeDict[OEGameCoreDisplayModeStateKey] boolValue];
|
||||
displayModePrefKey = subModeDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
isDisplayModeToggleable = [subModeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
|
||||
isValidDisplayMode = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow a 'displayMode' not found in _availableDisplayModes
|
||||
if (!isValidDisplayMode)
|
||||
return;
|
||||
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
|
||||
switch (displayMode)
|
||||
// Handle option state changes
|
||||
for (NSMutableDictionary *optionDict in _availableDisplayModes)
|
||||
{
|
||||
case 0:
|
||||
NSString *modeName = optionDict[OEGameCoreDisplayModeNameKey];
|
||||
NSString *prefKey = optionDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
|
||||
if (!modeName && !optionDict[OEGameCoreDisplayModeGroupNameKey])
|
||||
continue;
|
||||
// Mutually exclusive option state change
|
||||
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @YES;
|
||||
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
|
||||
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @NO;
|
||||
// Toggleable option state change
|
||||
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
|
||||
optionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
|
||||
// Submenu group
|
||||
else if (optionDict[OEGameCoreDisplayModeGroupNameKey])
|
||||
{
|
||||
// GB Pea Soup Green
|
||||
gb.setDmgPaletteColor(0, 0, 8369468);
|
||||
gb.setDmgPaletteColor(0, 1, 6728764);
|
||||
gb.setDmgPaletteColor(0, 2, 3629872);
|
||||
gb.setDmgPaletteColor(0, 3, 3223857);
|
||||
gb.setDmgPaletteColor(1, 0, 8369468);
|
||||
gb.setDmgPaletteColor(1, 1, 6728764);
|
||||
gb.setDmgPaletteColor(1, 2, 3629872);
|
||||
gb.setDmgPaletteColor(1, 3, 3223857);
|
||||
gb.setDmgPaletteColor(2, 0, 8369468);
|
||||
gb.setDmgPaletteColor(2, 1, 6728764);
|
||||
gb.setDmgPaletteColor(2, 2, 3629872);
|
||||
gb.setDmgPaletteColor(2, 3, 3223857);
|
||||
|
||||
displayMode++;
|
||||
return;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
// GB Pocket
|
||||
gb.setDmgPaletteColor(0, 0, 13487791);
|
||||
gb.setDmgPaletteColor(0, 1, 10987158);
|
||||
gb.setDmgPaletteColor(0, 2, 6974033);
|
||||
gb.setDmgPaletteColor(0, 3, 2828823);
|
||||
gb.setDmgPaletteColor(1, 0, 13487791);
|
||||
gb.setDmgPaletteColor(1, 1, 10987158);
|
||||
gb.setDmgPaletteColor(1, 2, 6974033);
|
||||
gb.setDmgPaletteColor(1, 3, 2828823);
|
||||
gb.setDmgPaletteColor(2, 0, 13487791);
|
||||
gb.setDmgPaletteColor(2, 1, 10987158);
|
||||
gb.setDmgPaletteColor(2, 2, 6974033);
|
||||
gb.setDmgPaletteColor(2, 3, 2828823);
|
||||
|
||||
displayMode++;
|
||||
return;
|
||||
}
|
||||
|
||||
case 2:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Blue"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Dark Blue"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Green"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Dark Green"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Brown"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Dark Brown"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Red"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Yellow"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Orange"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Pastel Mix"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Inverted"));
|
||||
displayMode++;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
{
|
||||
std::string str = gb.romTitle(); // read ROM internal title
|
||||
const char *internal_game_name = str.c_str();
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(internal_game_name));
|
||||
|
||||
if (gbc_bios_palette == 0)
|
||||
// Submenu items
|
||||
for (NSMutableDictionary *subOptionDict in optionDict[OEGameCoreDisplayModeGroupItemsKey])
|
||||
{
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Grayscale"));
|
||||
displayMode = 0;
|
||||
NSString *modeName = subOptionDict[OEGameCoreDisplayModeNameKey];
|
||||
NSString *prefKey = subOptionDict[OEGameCoreDisplayModePrefKeyNameKey];
|
||||
|
||||
if (!modeName)
|
||||
continue;
|
||||
// Mutually exclusive option state change
|
||||
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @YES;
|
||||
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
|
||||
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @NO;
|
||||
// Toggleable option state change
|
||||
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
|
||||
subOptionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
|
||||
}
|
||||
else
|
||||
displayMode++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 14:
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Grayscale"));
|
||||
displayMode = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned rgb32 = 0;
|
||||
for (unsigned palnum = 0; palnum < 3; ++palnum)
|
||||
{
|
||||
for (unsigned colornum = 0; colornum < 4; ++colornum)
|
||||
{
|
||||
rgb32 = gbcToRgb32(gbc_bios_palette[palnum * 4 + colornum]);
|
||||
gb.setDmgPaletteColor(palnum, colornum, rgb32);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the new palette
|
||||
if ([displayModePrefKey isEqualToString:@"palette"])
|
||||
[self changePalette:displayMode];
|
||||
else if ([displayModePrefKey isEqualToString:@"colorCorrection"])
|
||||
gb.setCgbColorCorrection([displayMode isEqual:@"Modern"] ? 1 : 0);
|
||||
}
|
||||
|
||||
# pragma mark - Misc Helper Methods
|
||||
@@ -465,10 +477,10 @@ NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
|
||||
if (!frames)
|
||||
return;
|
||||
|
||||
size_t len = resampler->resample(outSoundBuffer, reinterpret_cast<const int16_t *>(inSoundBuffer), frames);
|
||||
size_t len = resampler->resample(_outSoundBuffer, reinterpret_cast<const int16_t *>(_inSoundBuffer), frames);
|
||||
|
||||
if (len)
|
||||
[[self ringBufferAtIndex:0] write:outSoundBuffer maxLength:len << 2];
|
||||
[[self audioBufferAtIndex:0] write:_outSoundBuffer maxLength:len << 2];
|
||||
}
|
||||
|
||||
- (void)applyCheat:(NSString *)code
|
||||
@@ -480,22 +492,149 @@ NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
|
||||
gb.setGameShark(s);
|
||||
}
|
||||
|
||||
- (void)loadDisplayModeOptions
|
||||
{
|
||||
if (gb.isCgb())
|
||||
{
|
||||
// Restore color correction
|
||||
NSString *lastColorCorrection = self.displayModeInfo[@"colorCorrection"] ?: @"Default";
|
||||
[self changeDisplayWithMode:lastColorCorrection];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load built-in GBC palette for monochrome games if supported
|
||||
[self loadPalette];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)gameInternalName
|
||||
{
|
||||
NSString *title = [NSString stringWithUTF8String:gb.romTitle().c_str()];
|
||||
return title;
|
||||
}
|
||||
|
||||
- (BOOL)gameHasInternalPalette
|
||||
{
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
NSString *title = [self gameInternalName];
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(title.UTF8String));
|
||||
|
||||
return gbc_bios_palette != 0 ? YES : NO;
|
||||
}
|
||||
|
||||
- (void)loadPalette
|
||||
{
|
||||
std::string str = gb.romTitle(); // read ROM internal title
|
||||
const char *internal_game_name = str.c_str();
|
||||
|
||||
// load a GBC BIOS builtin palette
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(internal_game_name));
|
||||
|
||||
if (gbc_bios_palette == 0)
|
||||
// Only temporary, so core doesn't crash on an older OpenEmu version
|
||||
if (![self respondsToSelector:@selector(displayModeInfo)])
|
||||
{
|
||||
// no custom palette found, load the default (Original Grayscale)
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal("GBC - Grayscale"));
|
||||
[self loadPaletteDefault];
|
||||
}
|
||||
// No previous palette saved, set a default
|
||||
else if (self.displayModeInfo[@"palette"] == nil)
|
||||
{
|
||||
[self loadPaletteDefault];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *lastPalette = self.displayModeInfo[@"palette"];
|
||||
// Don't try to load "Internal" palette for a game without one
|
||||
if ([lastPalette isEqualToString:@"Internal"] && ![self gameHasInternalPalette])
|
||||
[self changeDisplayWithMode:@"Grayscale"];
|
||||
else
|
||||
[self changeDisplayWithMode:lastPalette];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned rgb32 = 0;
|
||||
- (void)loadPaletteDefault
|
||||
{
|
||||
if ([self gameHasInternalPalette])
|
||||
// load a GBC BIOS builtin palette
|
||||
[self changeDisplayWithMode:@"Internal"];
|
||||
else
|
||||
// no custom palette found, load the default (Original Grayscale)
|
||||
[self changeDisplayWithMode:@"Grayscale"];
|
||||
}
|
||||
|
||||
- (void)changePalette:(NSString *)palette
|
||||
{
|
||||
NSDictionary <NSString *, NSString *> *paletteNames =
|
||||
@{
|
||||
@"Internal" : @"Internal",
|
||||
@"Grayscale" : @"GBC - Grayscale",
|
||||
@"Greenscale" : @"Greenscale",
|
||||
@"Pocket" : @"Pocket",
|
||||
@"Blue" : @"GBC - Blue",
|
||||
@"Dark Blue" : @"GBC - Dark Blue",
|
||||
@"Green" : @"GBC - Green",
|
||||
@"Dark Green" : @"GBC - Dark Green",
|
||||
@"Brown" : @"GBC - Brown",
|
||||
@"Dark Brown" : @"GBC - Dark Brown",
|
||||
@"Red" : @"GBC - Red",
|
||||
@"Yellow" : @"GBC - Yellow",
|
||||
@"Orange" : @"GBC - Orange",
|
||||
@"Pastel Mix" : @"GBC - Pastel Mix",
|
||||
@"Inverted" : @"GBC - Inverted",
|
||||
};
|
||||
|
||||
palette = paletteNames[palette];
|
||||
unsigned short *gbc_bios_palette = NULL;
|
||||
|
||||
if ([palette isEqualToString:@"Internal"])
|
||||
{
|
||||
NSString *title = [self gameInternalName];
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcTitlePal(title.UTF8String));
|
||||
}
|
||||
else if ([palette isEqualToString:@"Greenscale"])
|
||||
{
|
||||
// GB Pea Soup Green
|
||||
gb.setDmgPaletteColor(0, 0, 8369468);
|
||||
gb.setDmgPaletteColor(0, 1, 6728764);
|
||||
gb.setDmgPaletteColor(0, 2, 3629872);
|
||||
gb.setDmgPaletteColor(0, 3, 3223857);
|
||||
gb.setDmgPaletteColor(1, 0, 8369468);
|
||||
gb.setDmgPaletteColor(1, 1, 6728764);
|
||||
gb.setDmgPaletteColor(1, 2, 3629872);
|
||||
gb.setDmgPaletteColor(1, 3, 3223857);
|
||||
gb.setDmgPaletteColor(2, 0, 8369468);
|
||||
gb.setDmgPaletteColor(2, 1, 6728764);
|
||||
gb.setDmgPaletteColor(2, 2, 3629872);
|
||||
gb.setDmgPaletteColor(2, 3, 3223857);
|
||||
return;
|
||||
}
|
||||
else if ([palette isEqualToString:@"Pocket"])
|
||||
{
|
||||
// GB Pocket
|
||||
gb.setDmgPaletteColor(0, 0, 13487791);
|
||||
gb.setDmgPaletteColor(0, 1, 10987158);
|
||||
gb.setDmgPaletteColor(0, 2, 6974033);
|
||||
gb.setDmgPaletteColor(0, 3, 2828823);
|
||||
gb.setDmgPaletteColor(1, 0, 13487791);
|
||||
gb.setDmgPaletteColor(1, 1, 10987158);
|
||||
gb.setDmgPaletteColor(1, 2, 6974033);
|
||||
gb.setDmgPaletteColor(1, 3, 2828823);
|
||||
gb.setDmgPaletteColor(2, 0, 13487791);
|
||||
gb.setDmgPaletteColor(2, 1, 10987158);
|
||||
gb.setDmgPaletteColor(2, 2, 6974033);
|
||||
gb.setDmgPaletteColor(2, 3, 2828823);
|
||||
|
||||
// gb.setDmgPaletteColor(0, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(0, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(0, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(0, 3, 1580056);
|
||||
// gb.setDmgPaletteColor(1, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(1, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(1, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(1, 3, 1580056);
|
||||
// gb.setDmgPaletteColor(2, 0, 13029285);
|
||||
// gb.setDmgPaletteColor(2, 1, 9213547);
|
||||
// gb.setDmgPaletteColor(2, 2, 4870457);
|
||||
// gb.setDmgPaletteColor(2, 3, 1580056);
|
||||
return;
|
||||
}
|
||||
else
|
||||
gbc_bios_palette = const_cast<unsigned short *>(findGbcDirPal(palette.UTF8String));
|
||||
|
||||
unsigned long rgb32 = 0;
|
||||
for (unsigned palnum = 0; palnum < 3; ++palnum)
|
||||
{
|
||||
for (unsigned colornum = 0; colornum < 4; ++colornum)
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
828387BB0E6CDB6500A96E2C /* gameboy.icns in Resources */ = {isa = PBXBuildFile; fileRef = B5F6D8A80E66914F001CA5D3 /* gameboy.icns */; };
|
||||
828387BD0E6CDB6500A96E2C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; };
|
||||
828387E20E6CDB6E00A96E2C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; };
|
||||
8F14C4F929FF7217000D080B /* statesaver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F14C4F829FF7217000D080B /* statesaver.cpp */; };
|
||||
9499B5D81AB242B200276D21 /* chainresampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B54E1AB242B200276D21 /* chainresampler.cpp */; };
|
||||
9499B5D91AB242B200276D21 /* i0.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5541AB242B200276D21 /* i0.cpp */; };
|
||||
9499B5DA1AB242B200276D21 /* kaiser50sinc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5561AB242B200276D21 /* kaiser50sinc.cpp */; };
|
||||
@@ -67,7 +68,6 @@
|
||||
9499B5FE1AB242B300276D21 /* length_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5BA1AB242B200276D21 /* length_counter.cpp */; };
|
||||
9499B5FF1AB242B300276D21 /* sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5BF1AB242B200276D21 /* sound.cpp */; };
|
||||
9499B6001AB242B300276D21 /* state_osd_elements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C11AB242B200276D21 /* state_osd_elements.cpp */; };
|
||||
9499B6011AB242B300276D21 /* statesaver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C31AB242B200276D21 /* statesaver.cpp */; };
|
||||
9499B6021AB242B300276D21 /* tima.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C51AB242B200276D21 /* tima.cpp */; };
|
||||
9499B6031AB242B300276D21 /* ly_counter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5C91AB242B200276D21 /* ly_counter.cpp */; };
|
||||
9499B6041AB242B300276D21 /* lyc_irq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9499B5CB1AB242B200276D21 /* lyc_irq.cpp */; };
|
||||
@@ -109,17 +109,14 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
089C1660FE840EACC02AAC07 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
828387810E6CDB2200A96E2C /* Gambatte.oecoreplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Gambatte.oecoreplugin; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
828387820E6CDB2200A96E2C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
942597C7151470210074E3A3 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenEmuBase.framework; path = ../OpenEmu/build/Release/OpenEmuBase.framework; sourceTree = "<group>"; };
|
||||
9499B5431AB242B200276D21 /* adaptivesleep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = adaptivesleep.cpp; sourceTree = "<group>"; };
|
||||
9499B5441AB242B200276D21 /* adaptivesleep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adaptivesleep.h; sourceTree = "<group>"; };
|
||||
8F14C4F729FF7204000D080B /* memfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = memfile.h; sourceTree = "<group>"; };
|
||||
8F14C4F829FF7217000D080B /* statesaver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = statesaver.cpp; sourceTree = "<group>"; };
|
||||
9499B5451AB242B200276D21 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = "<group>"; };
|
||||
9499B5461AB242B200276D21 /* defined_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = defined_ptr.h; sourceTree = "<group>"; };
|
||||
9499B5471AB242B200276D21 /* rateest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rateest.cpp; sourceTree = "<group>"; };
|
||||
9499B5481AB242B200276D21 /* rateest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rateest.h; sourceTree = "<group>"; };
|
||||
9499B54A1AB242B200276D21 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
|
||||
9499B54B1AB242B200276D21 /* resamplerinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resamplerinfo.h; sourceTree = "<group>"; };
|
||||
9499B54D1AB242B200276D21 /* blackmansinc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blackmansinc.h; sourceTree = "<group>"; };
|
||||
@@ -146,34 +143,14 @@
|
||||
9499B5621AB242B200276D21 /* u48div.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = u48div.cpp; sourceTree = "<group>"; };
|
||||
9499B5631AB242B200276D21 /* u48div.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = u48div.h; sourceTree = "<group>"; };
|
||||
9499B5641AB242B200276D21 /* upsampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upsampler.h; sourceTree = "<group>"; };
|
||||
9499B5651AB242B200276D21 /* ringbuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ringbuffer.h; sourceTree = "<group>"; };
|
||||
9499B5661AB242B200276D21 /* scoped_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scoped_ptr.h; sourceTree = "<group>"; };
|
||||
9499B5671AB242B200276D21 /* skipsched.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = skipsched.cpp; sourceTree = "<group>"; };
|
||||
9499B5681AB242B200276D21 /* skipsched.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = skipsched.h; sourceTree = "<group>"; };
|
||||
9499B5691AB242B200276D21 /* transfer_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transfer_ptr.h; sourceTree = "<group>"; };
|
||||
9499B56A1AB242B200276D21 /* uncopyable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uncopyable.h; sourceTree = "<group>"; };
|
||||
9499B56B1AB242B200276D21 /* usec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usec.h; sourceTree = "<group>"; };
|
||||
9499B56D1AB242B200276D21 /* rgb32conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rgb32conv.cpp; sourceTree = "<group>"; };
|
||||
9499B56E1AB242B200276D21 /* rgb32conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rgb32conv.h; sourceTree = "<group>"; };
|
||||
9499B56F1AB242B200276D21 /* vfilterinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vfilterinfo.cpp; sourceTree = "<group>"; };
|
||||
9499B5701AB242B200276D21 /* vfilterinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vfilterinfo.h; sourceTree = "<group>"; };
|
||||
9499B5721AB242B200276D21 /* catrom2x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catrom2x.cpp; sourceTree = "<group>"; };
|
||||
9499B5731AB242B200276D21 /* catrom2x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catrom2x.h; sourceTree = "<group>"; };
|
||||
9499B5741AB242B200276D21 /* catrom3x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catrom3x.cpp; sourceTree = "<group>"; };
|
||||
9499B5751AB242B200276D21 /* catrom3x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catrom3x.h; sourceTree = "<group>"; };
|
||||
9499B5761AB242B200276D21 /* kreed2xsai.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = kreed2xsai.cpp; sourceTree = "<group>"; };
|
||||
9499B5771AB242B200276D21 /* kreed2xsai.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kreed2xsai.h; sourceTree = "<group>"; };
|
||||
9499B5781AB242B200276D21 /* maxsthq2x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maxsthq2x.cpp; sourceTree = "<group>"; };
|
||||
9499B5791AB242B200276D21 /* maxsthq2x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maxsthq2x.h; sourceTree = "<group>"; };
|
||||
9499B57A1AB242B200276D21 /* maxsthq3x.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maxsthq3x.cpp; sourceTree = "<group>"; };
|
||||
9499B57B1AB242B200276D21 /* maxsthq3x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maxsthq3x.h; sourceTree = "<group>"; };
|
||||
9499B57C1AB242B200276D21 /* videolink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = videolink.h; sourceTree = "<group>"; };
|
||||
9499B57F1AB242B200276D21 /* gambatte.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gambatte.h; sourceTree = "<group>"; };
|
||||
9499B5801AB242B200276D21 /* gbint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gbint.h; sourceTree = "<group>"; };
|
||||
9499B5811AB242B200276D21 /* inputgetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inputgetter.h; sourceTree = "<group>"; };
|
||||
9499B5821AB242B200276D21 /* loadres.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loadres.h; sourceTree = "<group>"; };
|
||||
9499B5831AB242B200276D21 /* pakinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pakinfo.h; sourceTree = "<group>"; };
|
||||
9499B5841AB242B200276D21 /* SConstruct */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SConstruct; sourceTree = "<group>"; };
|
||||
9499B5861AB242B200276D21 /* bitmap_font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitmap_font.cpp; sourceTree = "<group>"; };
|
||||
9499B5871AB242B200276D21 /* bitmap_font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitmap_font.h; sourceTree = "<group>"; };
|
||||
9499B5881AB242B200276D21 /* counterdef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = counterdef.h; sourceTree = "<group>"; };
|
||||
@@ -181,13 +158,7 @@
|
||||
9499B58A1AB242B200276D21 /* cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpu.h; sourceTree = "<group>"; };
|
||||
9499B58C1AB242B200276D21 /* file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file.cpp; sourceTree = "<group>"; };
|
||||
9499B58D1AB242B200276D21 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = "<group>"; };
|
||||
9499B58E1AB242B200276D21 /* file_zip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_zip.cpp; sourceTree = "<group>"; };
|
||||
9499B58F1AB242B200276D21 /* stdfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdfile.h; sourceTree = "<group>"; };
|
||||
9499B5911AB242B200276D21 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = "<group>"; };
|
||||
9499B5921AB242B200276D21 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = "<group>"; };
|
||||
9499B5931AB242B200276D21 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = "<group>"; };
|
||||
9499B5941AB242B200276D21 /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = "<group>"; };
|
||||
9499B5951AB242B200276D21 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = "<group>"; };
|
||||
9499B5961AB242B200276D21 /* gambatte.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gambatte.cpp; sourceTree = "<group>"; };
|
||||
9499B5971AB242B200276D21 /* initstate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = initstate.cpp; sourceTree = "<group>"; };
|
||||
9499B5981AB242B200276D21 /* initstate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = initstate.h; sourceTree = "<group>"; };
|
||||
@@ -240,7 +211,6 @@
|
||||
9499B5CA1AB242B200276D21 /* ly_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ly_counter.h; sourceTree = "<group>"; };
|
||||
9499B5CB1AB242B200276D21 /* lyc_irq.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lyc_irq.cpp; sourceTree = "<group>"; };
|
||||
9499B5CC1AB242B200276D21 /* lyc_irq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lyc_irq.h; sourceTree = "<group>"; };
|
||||
9499B5CD1AB242B200276D21 /* m0_irq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m0_irq.h; sourceTree = "<group>"; };
|
||||
9499B5CE1AB242B200276D21 /* next_m0_time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = next_m0_time.cpp; sourceTree = "<group>"; };
|
||||
9499B5CF1AB242B200276D21 /* next_m0_time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = next_m0_time.h; sourceTree = "<group>"; };
|
||||
9499B5D01AB242B200276D21 /* ppu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ppu.cpp; sourceTree = "<group>"; };
|
||||
@@ -249,11 +219,11 @@
|
||||
9499B5D31AB242B200276D21 /* sprite_mapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite_mapper.h; sourceTree = "<group>"; };
|
||||
9499B5D41AB242B200276D21 /* video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = video.cpp; sourceTree = "<group>"; };
|
||||
9499B5D51AB242B200276D21 /* video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video.h; sourceTree = "<group>"; };
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
B5EC4D410E6312DF0046BD93 /* GBGameCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBGameCore.h; sourceTree = "<group>"; };
|
||||
B5EC4D420E6312DF0046BD93 /* GBGameCore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GBGameCore.mm; sourceTree = "<group>"; };
|
||||
B5F6D8A80E66914F001CA5D3 /* gameboy.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = gameboy.icns; sourceTree = "<group>"; };
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGBSystemResponderClient.h; path = ../OpenEmu/GameBoy/OEGBSystemResponderClient.h; sourceTree = "<group>"; };
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OEGBSystemResponderClient.h; path = ../OpenEmu/SystemPlugins/GameBoy/OEGBSystemResponderClient.h; sourceTree = "<group>"; };
|
||||
C6D120ED1711308C00E868A8 /* OpenEmuBase.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenEmuBase.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -273,7 +243,6 @@
|
||||
1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
942597C7151470210074E3A3 /* OpenEmuBase.framework */,
|
||||
B5350B7C0E62EC0800A0903A /* OpenGL.framework */,
|
||||
1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */,
|
||||
);
|
||||
@@ -307,6 +276,7 @@
|
||||
);
|
||||
name = Gambatte;
|
||||
sourceTree = "<group>";
|
||||
usesTabs = 0;
|
||||
};
|
||||
2A37F4ABFDCFA73011CA2CEA /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
@@ -314,6 +284,7 @@
|
||||
C6B947DE1364FD0C00A425F0 /* OEGBSystemResponderClient.h */,
|
||||
B5EC4D410E6312DF0046BD93 /* GBGameCore.h */,
|
||||
B5EC4D420E6312DF0046BD93 /* GBGameCore.mm */,
|
||||
8F14C4F829FF7217000D080B /* statesaver.cpp */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
@@ -345,26 +316,18 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B5421AB242B200276D21 /* common */ = {
|
||||
9499B5421AB242B200276D21 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B5431AB242B200276D21 /* adaptivesleep.cpp */,
|
||||
9499B5441AB242B200276D21 /* adaptivesleep.h */,
|
||||
9499B5451AB242B200276D21 /* array.h */,
|
||||
9499B5461AB242B200276D21 /* defined_ptr.h */,
|
||||
9499B5471AB242B200276D21 /* rateest.cpp */,
|
||||
9499B5481AB242B200276D21 /* rateest.h */,
|
||||
9499B5851AB242B200276D21 /* libgambatte */,
|
||||
9499B5491AB242B200276D21 /* resample */,
|
||||
9499B5651AB242B200276D21 /* ringbuffer.h */,
|
||||
9499B5661AB242B200276D21 /* scoped_ptr.h */,
|
||||
9499B5671AB242B200276D21 /* skipsched.cpp */,
|
||||
9499B5681AB242B200276D21 /* skipsched.h */,
|
||||
9499B5691AB242B200276D21 /* transfer_ptr.h */,
|
||||
9499B56A1AB242B200276D21 /* uncopyable.h */,
|
||||
9499B56B1AB242B200276D21 /* usec.h */,
|
||||
9499B56C1AB242B200276D21 /* videolink */,
|
||||
);
|
||||
path = common;
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B5491AB242B200276D21 /* resample */ = {
|
||||
@@ -372,14 +335,6 @@
|
||||
children = (
|
||||
9499B54A1AB242B200276D21 /* resampler.h */,
|
||||
9499B54B1AB242B200276D21 /* resamplerinfo.h */,
|
||||
9499B54C1AB242B200276D21 /* src */,
|
||||
);
|
||||
path = resample;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B54C1AB242B200276D21 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B54D1AB242B200276D21 /* blackmansinc.h */,
|
||||
9499B54E1AB242B200276D21 /* chainresampler.cpp */,
|
||||
9499B54F1AB242B200276D21 /* chainresampler.h */,
|
||||
@@ -405,62 +360,10 @@
|
||||
9499B5631AB242B200276D21 /* u48div.h */,
|
||||
9499B5641AB242B200276D21 /* upsampler.h */,
|
||||
);
|
||||
path = src;
|
||||
path = resample;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B56C1AB242B200276D21 /* videolink */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B56D1AB242B200276D21 /* rgb32conv.cpp */,
|
||||
9499B56E1AB242B200276D21 /* rgb32conv.h */,
|
||||
9499B56F1AB242B200276D21 /* vfilterinfo.cpp */,
|
||||
9499B5701AB242B200276D21 /* vfilterinfo.h */,
|
||||
9499B5711AB242B200276D21 /* vfilters */,
|
||||
9499B57C1AB242B200276D21 /* videolink.h */,
|
||||
);
|
||||
path = videolink;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B5711AB242B200276D21 /* vfilters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B5721AB242B200276D21 /* catrom2x.cpp */,
|
||||
9499B5731AB242B200276D21 /* catrom2x.h */,
|
||||
9499B5741AB242B200276D21 /* catrom3x.cpp */,
|
||||
9499B5751AB242B200276D21 /* catrom3x.h */,
|
||||
9499B5761AB242B200276D21 /* kreed2xsai.cpp */,
|
||||
9499B5771AB242B200276D21 /* kreed2xsai.h */,
|
||||
9499B5781AB242B200276D21 /* maxsthq2x.cpp */,
|
||||
9499B5791AB242B200276D21 /* maxsthq2x.h */,
|
||||
9499B57A1AB242B200276D21 /* maxsthq3x.cpp */,
|
||||
9499B57B1AB242B200276D21 /* maxsthq3x.h */,
|
||||
);
|
||||
path = vfilters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B57D1AB242B200276D21 /* libgambatte */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B57E1AB242B200276D21 /* include */,
|
||||
9499B5841AB242B200276D21 /* SConstruct */,
|
||||
9499B5851AB242B200276D21 /* src */,
|
||||
);
|
||||
path = libgambatte;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B57E1AB242B200276D21 /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B57F1AB242B200276D21 /* gambatte.h */,
|
||||
9499B5801AB242B200276D21 /* gbint.h */,
|
||||
9499B5811AB242B200276D21 /* inputgetter.h */,
|
||||
9499B5821AB242B200276D21 /* loadres.h */,
|
||||
9499B5831AB242B200276D21 /* pakinfo.h */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B5851AB242B200276D21 /* src */ = {
|
||||
9499B5851AB242B200276D21 /* libgambatte */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B5861AB242B200276D21 /* bitmap_font.cpp */,
|
||||
@@ -470,19 +373,24 @@
|
||||
9499B58A1AB242B200276D21 /* cpu.h */,
|
||||
9499B58B1AB242B200276D21 /* file */,
|
||||
9499B5961AB242B200276D21 /* gambatte.cpp */,
|
||||
9499B57F1AB242B200276D21 /* gambatte.h */,
|
||||
9499B5801AB242B200276D21 /* gbint.h */,
|
||||
9499B5971AB242B200276D21 /* initstate.cpp */,
|
||||
9499B5981AB242B200276D21 /* initstate.h */,
|
||||
9499B5811AB242B200276D21 /* inputgetter.h */,
|
||||
9499B5991AB242B200276D21 /* insertion_sort.h */,
|
||||
9499B59A1AB242B200276D21 /* interrupter.cpp */,
|
||||
9499B59B1AB242B200276D21 /* interrupter.h */,
|
||||
9499B59C1AB242B200276D21 /* interruptrequester.cpp */,
|
||||
9499B59D1AB242B200276D21 /* interruptrequester.h */,
|
||||
9499B59E1AB242B200276D21 /* loadres.cpp */,
|
||||
9499B5821AB242B200276D21 /* loadres.h */,
|
||||
9499B59F1AB242B200276D21 /* mem */,
|
||||
9499B5A81AB242B200276D21 /* memory.cpp */,
|
||||
9499B5A91AB242B200276D21 /* memory.h */,
|
||||
9499B5AA1AB242B200276D21 /* minkeeper.h */,
|
||||
9499B5AB1AB242B200276D21 /* osd_element.h */,
|
||||
9499B5831AB242B200276D21 /* pakinfo.h */,
|
||||
9499B5AC1AB242B200276D21 /* savestate.h */,
|
||||
9499B5AD1AB242B200276D21 /* sound */,
|
||||
9499B5BF1AB242B200276D21 /* sound.cpp */,
|
||||
@@ -497,7 +405,7 @@
|
||||
9499B5D41AB242B200276D21 /* video.cpp */,
|
||||
9499B5D51AB242B200276D21 /* video.h */,
|
||||
);
|
||||
path = src;
|
||||
path = libgambatte;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B58B1AB242B200276D21 /* file */ = {
|
||||
@@ -505,25 +413,12 @@
|
||||
children = (
|
||||
9499B58C1AB242B200276D21 /* file.cpp */,
|
||||
9499B58D1AB242B200276D21 /* file.h */,
|
||||
9499B58E1AB242B200276D21 /* file_zip.cpp */,
|
||||
8F14C4F729FF7204000D080B /* memfile.h */,
|
||||
9499B58F1AB242B200276D21 /* stdfile.h */,
|
||||
9499B5901AB242B200276D21 /* unzip */,
|
||||
);
|
||||
path = file;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B5901AB242B200276D21 /* unzip */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B5911AB242B200276D21 /* crypt.h */,
|
||||
9499B5921AB242B200276D21 /* ioapi.c */,
|
||||
9499B5931AB242B200276D21 /* ioapi.h */,
|
||||
9499B5941AB242B200276D21 /* unzip.c */,
|
||||
9499B5951AB242B200276D21 /* unzip.h */,
|
||||
);
|
||||
path = unzip;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9499B59F1AB242B200276D21 /* mem */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -571,7 +466,6 @@
|
||||
9499B5CA1AB242B200276D21 /* ly_counter.h */,
|
||||
9499B5CB1AB242B200276D21 /* lyc_irq.cpp */,
|
||||
9499B5CC1AB242B200276D21 /* lyc_irq.h */,
|
||||
9499B5CD1AB242B200276D21 /* m0_irq.h */,
|
||||
9499B5CE1AB242B200276D21 /* next_m0_time.cpp */,
|
||||
9499B5CF1AB242B200276D21 /* next_m0_time.h */,
|
||||
9499B5D01AB242B200276D21 /* ppu.cpp */,
|
||||
@@ -585,8 +479,7 @@
|
||||
B5A6D9310E617C4900622CCF /* Core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9499B5421AB242B200276D21 /* common */,
|
||||
9499B57D1AB242B200276D21 /* libgambatte */,
|
||||
9499B5421AB242B200276D21 /* src */,
|
||||
);
|
||||
name = Core;
|
||||
sourceTree = "<group>";
|
||||
@@ -617,15 +510,15 @@
|
||||
2A37F4A9FDCFA73011CA2CEA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 0700;
|
||||
LastUpgradeCheck = 1130;
|
||||
};
|
||||
buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "Gambatte" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 2A37F4AAFDCFA73011CA2CEA /* Gambatte */;
|
||||
projectDirPath = "";
|
||||
@@ -703,7 +596,7 @@
|
||||
9499B5F71AB242B300276D21 /* memory.cpp in Sources */,
|
||||
9499B5FF1AB242B300276D21 /* sound.cpp in Sources */,
|
||||
9499B6001AB242B300276D21 /* state_osd_elements.cpp in Sources */,
|
||||
9499B6011AB242B300276D21 /* statesaver.cpp in Sources */,
|
||||
8F14C4F929FF7217000D080B /* statesaver.cpp in Sources */,
|
||||
9499B6021AB242B300276D21 /* tima.cpp in Sources */,
|
||||
9499B6081AB242B300276D21 /* video.cpp in Sources */,
|
||||
9499B5F31AB242B300276D21 /* cartridge.cpp in Sources */,
|
||||
@@ -744,7 +637,7 @@
|
||||
089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
089C1660FE840EACC02AAC07 /* English */,
|
||||
089C1660FE840EACC02AAC07 /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -756,6 +649,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(PROJECT_DIR)/gambatte\"",
|
||||
@@ -777,6 +671,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(PROJECT_DIR)/gambatte\"",
|
||||
@@ -840,20 +735,32 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = NO;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = GL_SILENCE_DEPRECATION;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@@ -875,11 +782,21 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
@@ -888,7 +805,9 @@
|
||||
ENABLE_TESTABILITY = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = c99;
|
||||
GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = GL_SILENCE_DEPRECATION;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
||||
+5
-3
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.5.0.573</string>
|
||||
<string>0.5.1</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>OEGameCoreController</string>
|
||||
<key>OEGameCoreClass</key>
|
||||
@@ -32,6 +32,8 @@
|
||||
<integer>0</integer>
|
||||
<key>OEGameCoreSupportsCheatCode</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSupportsDisplayModeChange</key>
|
||||
<true/>
|
||||
<key>OEGameCoreSupportsRewinding</key>
|
||||
<true/>
|
||||
</dict>
|
||||
@@ -39,7 +41,7 @@
|
||||
<key>OEGameCorePlayerCount</key>
|
||||
<string>1</string>
|
||||
<key>OEProjectURL</key>
|
||||
<string>https://github.com/sinamas/gambatte</string>
|
||||
<string>https://gitlab.com/jgemu/gambatte</string>
|
||||
<key>OESystemIdentifiers</key>
|
||||
<array>
|
||||
<string>openemu.system.gb</string>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
Gambatte JG
|
||||
-----------
|
||||
Gambatte JG is an emulator for the Nintendo Game Boy/Game Boy Color.
|
||||
|
||||
This is a fork of the final public revision of Gambatte.
|
||||
|
||||
This repository lives at https://gitlab.com/jgemu/gambatte
|
||||
|
||||
Compiling
|
||||
---------
|
||||
Make sure you have The Jolly Good API's header files installed. If you did
|
||||
not install them, you will be required to include their path in CXXFLAGS.
|
||||
|
||||
GNU Make's default behaviour for compiling C++ sources is to use g++. If your
|
||||
platform of choice uses an unpatched GNU Make, you will need to override the
|
||||
CXX implicit variable if you wish to use a different compiler.
|
||||
|
||||
Options:
|
||||
USE_VENDORED_SOXR - Set non-zero to use vendored soxr
|
||||
|
||||
Linux:
|
||||
make
|
||||
|
||||
macOS:
|
||||
make
|
||||
|
||||
BSD:
|
||||
gmake
|
||||
|
||||
Windows (MSYS2):
|
||||
make
|
||||
|
||||
The build will be output to "gambatte/". This directory may be used as is
|
||||
locally by copying it to your local "cores" directory, or may be installed
|
||||
system-wide using the "install" target specified in the Makefile.
|
||||
|
||||
Settings
|
||||
--------
|
||||
palette = 0
|
||||
0 = Internal, 1 = Original Green, 2 = GB Pocket, 3 = Blue, 4 = Brown,
|
||||
5 = Dark Blue, 6 = Dark Brown, 7 = Dark Green, 8 = Grayscale, 9 = Green,
|
||||
10 = Inverted, 11 = Orange, 12 = Pastel Mix, 13 = Red, 14 = Yellow
|
||||
|
||||
system = 0
|
||||
0 = Auto (CGB), 1 = DMG, 2 = GBA-CGB
|
||||
|
||||
turbo_rate = 3
|
||||
N = Pulse every N frames
|
||||
|
||||
Copyright
|
||||
---------
|
||||
Gambatte JG (GPL-2.0-or-later)
|
||||
Copyright (c) 2007-2020 Sindre Aamås
|
||||
Copyright (c) 2020-2022 Rupert Carmichael
|
||||
|
||||
SoX Resampler Library (LGPL-2.1-or-later)
|
||||
Copyright (c) 2007-2018 Rob Sykes
|
||||
See source files in deps/soxr/ (https://sourceforge.net/projects/soxr/)
|
||||
@@ -1,52 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "adaptivesleep.h"
|
||||
|
||||
static usec_t absdiff(usec_t a, usec_t b) { return a < b ? b - a : a - b; }
|
||||
|
||||
usec_t AdaptiveSleep::sleepUntil(usec_t base, usec_t inc) {
|
||||
usec_t now = getusecs();
|
||||
usec_t diff = now - base;
|
||||
if (diff >= inc)
|
||||
return diff - inc;
|
||||
|
||||
diff = inc - diff;
|
||||
if (diff > oversleep_ + oversleepVar_) {
|
||||
diff -= oversleep_ + oversleepVar_;
|
||||
usecsleep(diff);
|
||||
usec_t const sleepTarget = now + diff;
|
||||
now = getusecs();
|
||||
|
||||
usec_t curOversleep = now - sleepTarget;
|
||||
if (curOversleep > usec_t(-1) / 2)
|
||||
curOversleep = 0;
|
||||
|
||||
oversleepVar_ = (oversleepVar_ * 15 + absdiff(curOversleep, oversleep_) + 8) >> 4;
|
||||
oversleep_ = (oversleep_ * 15 + curOversleep + 8) >> 4;
|
||||
noSleep_ = 60;
|
||||
} else if (--noSleep_ == 0) {
|
||||
noSleep_ = 60;
|
||||
oversleep_ = oversleepVar_ = 0;
|
||||
}
|
||||
|
||||
while (now - base < inc)
|
||||
now = getusecs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ADAPTIVE_SLEEP_H
|
||||
#define ADAPTIVE_SLEEP_H
|
||||
|
||||
#include "usec.h"
|
||||
|
||||
class AdaptiveSleep {
|
||||
public:
|
||||
AdaptiveSleep() : oversleep_(0), oversleepVar_(0), noSleep_(60) {}
|
||||
usec_t sleepUntil(usec_t base, usec_t inc);
|
||||
|
||||
private:
|
||||
usec_t oversleep_;
|
||||
usec_t oversleepVar_;
|
||||
unsigned noSleep_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,91 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rateest.h"
|
||||
#include <cstdlib>
|
||||
|
||||
void RateEst::SumQueue::push(std::ptrdiff_t const samples, usec_t const usecs) {
|
||||
q_.push_back(std::make_pair(samples, usecs));
|
||||
samples_ += samples;
|
||||
usecs_ += usecs;
|
||||
}
|
||||
|
||||
void RateEst::SumQueue::pop() {
|
||||
std::pair<std::ptrdiff_t, usec_t> const &f = q_.front();
|
||||
samples_ -= f.first;
|
||||
usecs_ -= f.second;
|
||||
q_.pop_front();
|
||||
}
|
||||
|
||||
static usec_t sampleUsecs(std::ptrdiff_t samples, long rate) {
|
||||
return usec_t((samples * 1000000.0f) / (rate ? rate : 1) + 0.5f);
|
||||
}
|
||||
|
||||
static long limit(long est, long const reference) {
|
||||
if (est > reference + (reference >> 6))
|
||||
est = reference + (reference >> 6);
|
||||
else if (est < reference - (reference >> 6))
|
||||
est = reference - (reference >> 6);
|
||||
|
||||
return est;
|
||||
}
|
||||
|
||||
RateEst::RateEst(long const nominalSampleRate, std::size_t const maxValidFeedPeriodSamples)
|
||||
: srate_(nominalSampleRate * est_scale)
|
||||
, reference_(srate_)
|
||||
, maxPeriod_(sampleUsecs(maxValidFeedPeriodSamples, nominalSampleRate))
|
||||
, last_(0)
|
||||
, t_(6000)
|
||||
, s_(nominalSampleRate * 6)
|
||||
, st_(s_ * t_)
|
||||
, t2_(t_ * t_)
|
||||
{
|
||||
}
|
||||
|
||||
void RateEst::feed(std::ptrdiff_t samplesIn, usec_t const now) {
|
||||
usec_t usecsIn = now - last_;
|
||||
|
||||
if (last_ && usecsIn < maxPeriod_) {
|
||||
sumq_.push(samplesIn, usecsIn);
|
||||
|
||||
while ((usecsIn = sumq_.usecs()) > 100000) {
|
||||
samplesIn = sumq_.samples();
|
||||
sumq_.pop();
|
||||
|
||||
long const srateIn = long(samplesIn * (1000000.0f * est_scale) / usecsIn);
|
||||
if (std::abs(srateIn - reference_) < reference_ >> 1) {
|
||||
s_ += samplesIn - sumq_.samples() ;
|
||||
t_ += ( usecsIn - sumq_.usecs() ) * 0.001;
|
||||
st_ += s_ * t_;
|
||||
t2_ += t_ * t_;
|
||||
|
||||
long est = long(st_ * (1000.0 * est_scale) / t2_ + 0.5);
|
||||
srate_ = limit((srate_ * 31 + est + 16) >> 5, reference_);
|
||||
|
||||
if (t_ > 8000) {
|
||||
s_ *= 3.0 / 4;
|
||||
t_ *= 3.0 / 4;
|
||||
st_ *= 9.0 / 16;
|
||||
t2_ *= 9.0 / 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_ = now;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RATEEST_H
|
||||
#define RATEEST_H
|
||||
|
||||
#include "usec.h"
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
class RateEst {
|
||||
public:
|
||||
RateEst() { *this = RateEst(0, 0); }
|
||||
RateEst(long nominalSampleRate, std::size_t maxValidFeedPeriodSamples);
|
||||
void resetLastFeedTimeStamp() { last_ = 0; }
|
||||
void feed(std::ptrdiff_t samples, usec_t usecsNow = getusecs());
|
||||
long result() const { return (srate_ + est_scale / 2) >> est_lshift; }
|
||||
|
||||
private:
|
||||
class SumQueue {
|
||||
public:
|
||||
SumQueue() : samples_(0), usecs_(0) {}
|
||||
std::ptrdiff_t samples() const { return samples_; }
|
||||
usec_t usecs() const { return usecs_; }
|
||||
void push(std::ptrdiff_t samples, usec_t usecs);
|
||||
void pop();
|
||||
|
||||
private:
|
||||
std::deque< std::pair<std::ptrdiff_t, usec_t> > q_;
|
||||
std::ptrdiff_t samples_;
|
||||
usec_t usecs_;
|
||||
};
|
||||
|
||||
enum { est_lshift = 5 };
|
||||
enum { est_scale = 1 << est_lshift };
|
||||
|
||||
SumQueue sumq_;
|
||||
long srate_;
|
||||
long reference_;
|
||||
usec_t maxPeriod_;
|
||||
usec_t last_;
|
||||
double t_, s_, st_, t2_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RINGBUFFER_H
|
||||
#define RINGBUFFER_H
|
||||
|
||||
#include "array.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
template<typename T>
|
||||
class RingBuffer {
|
||||
public:
|
||||
explicit RingBuffer(std::size_t size = 0)
|
||||
: endpos_(0), rpos_(0), wpos_(0)
|
||||
{
|
||||
reset(size);
|
||||
}
|
||||
|
||||
void reset(std::size_t size);
|
||||
|
||||
void clear() {
|
||||
wpos_ = rpos_ = 0;
|
||||
}
|
||||
|
||||
void fill(T value);
|
||||
void read(T *out, std::size_t num);
|
||||
void write(T const *in, std::size_t num);
|
||||
|
||||
std::size_t avail() const {
|
||||
return (wpos_ < rpos_ ? 0 : endpos_) + rpos_ - wpos_ - 1;
|
||||
}
|
||||
|
||||
std::size_t used() const {
|
||||
return (wpos_ < rpos_ ? endpos_ : 0) + wpos_ - rpos_;
|
||||
}
|
||||
|
||||
std::size_t size() const {
|
||||
return endpos_ - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
Array<T> buf_;
|
||||
std::size_t endpos_;
|
||||
std::size_t rpos_;
|
||||
std::size_t wpos_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::reset(std::size_t size) {
|
||||
endpos_ = size + 1;
|
||||
rpos_ = wpos_ = 0;
|
||||
buf_.reset(size ? endpos_ : 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::fill(T value) {
|
||||
std::fill(buf_.get(), buf_.get() + buf_.size(), value);
|
||||
rpos_ = 0;
|
||||
wpos_ = endpos_ - 1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::read(T *out, std::size_t num) {
|
||||
if (rpos_ + num > endpos_) {
|
||||
std::size_t const n = endpos_ - rpos_;
|
||||
std::memcpy(out, buf_ + rpos_, n * sizeof *out);
|
||||
rpos_ = 0;
|
||||
num -= n;
|
||||
out += n;
|
||||
}
|
||||
|
||||
std::memcpy(out, buf_ + rpos_, num * sizeof *out);
|
||||
if ((rpos_ += num) == endpos_)
|
||||
rpos_ = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RingBuffer<T>::write(T const *in, std::size_t num) {
|
||||
if (wpos_ + num > endpos_) {
|
||||
std::size_t const n = endpos_ - wpos_;
|
||||
std::memcpy(buf_ + wpos_, in, n * sizeof *buf_);
|
||||
wpos_ = 0;
|
||||
num -= n;
|
||||
in += n;
|
||||
}
|
||||
|
||||
std::memcpy(buf_ + wpos_, in, num * sizeof *buf_);
|
||||
if ((wpos_ += num) == endpos_)
|
||||
wpos_ = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "skipsched.h"
|
||||
|
||||
bool SkipSched::skipNext(bool skip) {
|
||||
if (skipped_) {
|
||||
if (skipped_ < skippedmax_ / 2)
|
||||
skip = true;
|
||||
else
|
||||
skipped_ = skip = 0;
|
||||
} else if (skip) {
|
||||
skippedmax_ += skippedmax_ / 2 < 8;
|
||||
} else if (skippedmax_ / 2)
|
||||
--skippedmax_;
|
||||
|
||||
skipped_ += skip;
|
||||
|
||||
return skip;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef SKIPSCHED_H
|
||||
#define SKIPSCHED_H
|
||||
|
||||
class SkipSched {
|
||||
public:
|
||||
SkipSched() : skipped_(0), skippedmax_(2 - 1) {}
|
||||
bool skipNext(bool wantskip);
|
||||
|
||||
private:
|
||||
unsigned skipped_;
|
||||
unsigned skippedmax_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,27 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef USEC_H
|
||||
#define USEC_H
|
||||
|
||||
typedef unsigned long usec_t;
|
||||
|
||||
usec_t getusecs();
|
||||
void usecsleep(usec_t usecs);
|
||||
|
||||
#endif
|
||||
@@ -1,199 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "rgb32conv.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
#include "videolink.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
static bool isBigEndian() {
|
||||
union {
|
||||
gambatte::uint_least32_t ul32;
|
||||
unsigned char uc[sizeof(gambatte::uint_least32_t)];
|
||||
} u;
|
||||
u.ul32 = -0x10000;
|
||||
return u.uc[0];
|
||||
}
|
||||
|
||||
class Rgb32ToUyvy {
|
||||
public:
|
||||
Rgb32ToUyvy();
|
||||
void operator()(gambatte::uint_least32_t *d, std::ptrdiff_t dstPitch,
|
||||
gambatte::uint_least32_t const *s, std::ptrdiff_t srcPitch,
|
||||
unsigned w, unsigned h);
|
||||
|
||||
private:
|
||||
struct CacheUnit {
|
||||
gambatte::uint_least32_t rgb32;
|
||||
gambatte::uint_least32_t uyvy;
|
||||
};
|
||||
|
||||
enum { cache_size = 0x100 };
|
||||
enum { cache_mask = cache_size - 1 };
|
||||
CacheUnit cache_[cache_size];
|
||||
};
|
||||
|
||||
Rgb32ToUyvy::Rgb32ToUyvy() {
|
||||
if (isBigEndian()) {
|
||||
CacheUnit c = { 0, 128ul << 24 | 16ul << 16 | 128u << 8 | 16 };
|
||||
std::fill(cache_, cache_ + cache_size, c);
|
||||
} else {
|
||||
CacheUnit c = { 0, 16ul << 24 | 128ul << 16 | 16 << 8 | 128 };
|
||||
std::fill(cache_, cache_ + cache_size, c);
|
||||
}
|
||||
}
|
||||
|
||||
void Rgb32ToUyvy::operator()(gambatte::uint_least32_t *dst,
|
||||
std::ptrdiff_t const dstPitch,
|
||||
gambatte::uint_least32_t const *src,
|
||||
std::ptrdiff_t const srcPitch,
|
||||
unsigned const w,
|
||||
unsigned h)
|
||||
{
|
||||
while (h--) {
|
||||
gambatte::uint_least32_t *d = dst;
|
||||
gambatte::uint_least32_t const *s = src;
|
||||
gambatte::uint_least32_t const *const sEnd = s + w - 1;
|
||||
while (s < sEnd) {
|
||||
if ((cache_[s[0] & cache_mask].rgb32 - s[0]) | (cache_[s[1] & cache_mask].rgb32 - s[1])) {
|
||||
cache_[s[0] & cache_mask].rgb32 = s[0];
|
||||
cache_[s[1] & cache_mask].rgb32 = s[1];
|
||||
|
||||
unsigned long const r = (s[0] >> 16 & 0x000000FF) | (s[1] & 0x00FF0000);
|
||||
unsigned long const g = (s[0] >> 8 & 0x000000FF) | (s[1] << 8 & 0x00FF0000);
|
||||
unsigned long const b = (s[0] & 0x000000FF) | (s[1] << 16 & 0x00FF0000);
|
||||
unsigned long const y = r * 66 + g * 129 + b * 25 + ( 16 * 256u + 128) * 0x00010001ul;
|
||||
unsigned long const u = b * 112 - r * 38 - g * 74 + (128 * 256u + 128) * 0x00010001ul;
|
||||
unsigned long const v = r * 112 - g * 94 - b * 18 + (128 * 256u + 128) * 0x00010001ul;
|
||||
if (isBigEndian()) {
|
||||
d[0] = cache_[s[0] & cache_mask].uyvy = (u << 16 & 0xFF000000)
|
||||
| (y << 8 & 0x00FF0000)
|
||||
| (v & 0x0000FF00)
|
||||
| (y >> 8 & 0x000000FF);
|
||||
d[1] = cache_[s[1] & cache_mask].uyvy = (u & 0xFF000000)
|
||||
| (y >> 8 & 0x00FF0000)
|
||||
| (v >> 16 & 0x0000FF00)
|
||||
| y >> 24 ;
|
||||
} else {
|
||||
d[0] = cache_[s[0] & cache_mask].uyvy = (y << 16 & 0xFF000000)
|
||||
| (v << 8 & 0x00FF0000)
|
||||
| (y & 0x0000FF00)
|
||||
| (u >> 8 & 0x000000FF);
|
||||
d[1] = cache_[s[1] & cache_mask].uyvy = (y & 0xFF000000)
|
||||
| (v >> 8 & 0x00FF0000)
|
||||
| (y >> 16 & 0x0000FF00)
|
||||
| u >> 24 ;
|
||||
}
|
||||
} else {
|
||||
gambatte::uint_least32_t const s0 = s[0], s1 = s[1];
|
||||
d[0] = cache_[s0 & cache_mask].uyvy;
|
||||
d[1] = cache_[s1 & cache_mask].uyvy;
|
||||
}
|
||||
|
||||
s += 2;
|
||||
d += 2;
|
||||
}
|
||||
|
||||
src += srcPitch;
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
static void rgb32ToRgb16(gambatte::uint_least16_t *d,
|
||||
std::ptrdiff_t const dstPitch,
|
||||
gambatte::uint_least32_t const *s,
|
||||
std::ptrdiff_t const srcPitch,
|
||||
unsigned const w,
|
||||
unsigned h)
|
||||
{
|
||||
do {
|
||||
std::ptrdiff_t i = -static_cast<std::ptrdiff_t>(w);
|
||||
s += w;
|
||||
d += w;
|
||||
|
||||
do {
|
||||
d[i] = (s[i] >> 8 & 0xF800) | (s[i] & 0xFC00) >> 5 | (s[i] & 0xFF) >> 3;
|
||||
} while (++i);
|
||||
|
||||
s += srcPitch - static_cast<std::ptrdiff_t>(w);
|
||||
d += dstPitch - static_cast<std::ptrdiff_t>(w);
|
||||
} while (--h);
|
||||
}
|
||||
|
||||
class Rgb32ToUyvyLink : public VideoLink {
|
||||
public:
|
||||
Rgb32ToUyvyLink(unsigned width, unsigned height)
|
||||
: inbuf_(static_cast<std::size_t>(width) * height)
|
||||
, width_(width)
|
||||
, height_(height)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void * inBuf() const { return inbuf_; }
|
||||
virtual std::ptrdiff_t inPitch() const { return width_; }
|
||||
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstPitch) {
|
||||
rgb32ToUyvy_(static_cast<gambatte::uint_least32_t *>(dst), dstPitch,
|
||||
inbuf_, width_, width_, height_);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleArray<gambatte::uint_least32_t> const inbuf_;
|
||||
Rgb32ToUyvy rgb32ToUyvy_;
|
||||
unsigned const width_;
|
||||
unsigned const height_;
|
||||
};
|
||||
|
||||
class Rgb32ToRgb16Link : public VideoLink {
|
||||
public:
|
||||
Rgb32ToRgb16Link(unsigned width, unsigned height)
|
||||
: inbuf_(static_cast<std::size_t>(width) * height)
|
||||
, width_(width)
|
||||
, height_(height)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void * inBuf() const { return inbuf_; }
|
||||
virtual std::ptrdiff_t inPitch() const { return width_; }
|
||||
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstPitch) {
|
||||
if (!inbuf_)
|
||||
return;
|
||||
|
||||
rgb32ToRgb16(static_cast<gambatte::uint_least16_t *>(dst), dstPitch,
|
||||
inbuf_, width_, width_, height_);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleArray<gambatte::uint_least32_t> const inbuf_;
|
||||
unsigned const width_;
|
||||
unsigned const height_;
|
||||
};
|
||||
|
||||
} // anon namespace
|
||||
|
||||
VideoLink * Rgb32Conv::create(PixelFormat pf, unsigned width, unsigned height) {
|
||||
switch (pf) {
|
||||
case RGB16: return new Rgb32ToRgb16Link(width, height);
|
||||
case UYVY: return new Rgb32ToUyvyLink(width, height);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef RGB32CONV_H
|
||||
#define RGB32CONV_H
|
||||
|
||||
class VideoLink;
|
||||
|
||||
class Rgb32Conv {
|
||||
public:
|
||||
enum PixelFormat { RGB32, RGB16, UYVY };
|
||||
static VideoLink * create(PixelFormat pf, unsigned width, unsigned height);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "vfilterinfo.h"
|
||||
#include "vfilters/catrom2x.h"
|
||||
#include "vfilters/catrom3x.h"
|
||||
#include "vfilters/kreed2xsai.h"
|
||||
#include "vfilters/maxsthq2x.h"
|
||||
#include "vfilters/maxsthq3x.h"
|
||||
|
||||
static VideoLink * createNone() { return 0; }
|
||||
|
||||
template<class T>
|
||||
static VideoLink * createT() { return new T; }
|
||||
|
||||
#define VFINFO(handle, Type) { handle, Type::out_width, Type::out_height, createT<Type> }
|
||||
|
||||
static VfilterInfo const vfinfos[] = {
|
||||
{ "None", VfilterInfo::in_width, VfilterInfo::in_height, createNone },
|
||||
VFINFO("Bicubic Catmull-Rom spline 2x", Catrom2x),
|
||||
VFINFO("Bicubic Catmull-Rom spline 3x", Catrom3x),
|
||||
VFINFO("Kreed's 2xSaI", Kreed2xSaI),
|
||||
VFINFO("MaxSt's hq2x", MaxStHq2x),
|
||||
VFINFO("MaxSt's hq3x", MaxStHq3x),
|
||||
};
|
||||
|
||||
std::size_t VfilterInfo::numVfilters() {
|
||||
return sizeof vfinfos / sizeof vfinfos[0];
|
||||
}
|
||||
|
||||
VfilterInfo const & VfilterInfo::get(std::size_t n) {
|
||||
return vfinfos[n];
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VFILTERINFO_H
|
||||
#define VFILTERINFO_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class VideoLink;
|
||||
|
||||
struct VfilterInfo {
|
||||
enum { in_width = 160 };
|
||||
enum { in_height = 144 };
|
||||
|
||||
char const *handle;
|
||||
unsigned outWidth;
|
||||
unsigned outHeight;
|
||||
VideoLink * (*create)();
|
||||
|
||||
static VfilterInfo const & get(std::size_t n);
|
||||
static std::size_t numVfilters();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,179 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "catrom2x.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
enum { in_width = VfilterInfo::in_width };
|
||||
enum { in_height = VfilterInfo::in_height };
|
||||
enum { in_pitch = in_width + 3 };
|
||||
|
||||
struct Colorsum {
|
||||
gambatte::uint_least32_t r, g, b;
|
||||
};
|
||||
|
||||
static void mergeColumns(gambatte::uint_least32_t *dest, Colorsum const *sums) {
|
||||
for (unsigned w = in_width; w--;) {
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r;
|
||||
gambatte::uint_least32_t gsum = sums[1].g;
|
||||
gambatte::uint_least32_t bsum = sums[1].b;
|
||||
|
||||
if (rsum >= 0x80000000) rsum = 0;
|
||||
if (gsum >= 0x80000000) gsum = 0;
|
||||
if (bsum >= 0x80000000) bsum = 0;
|
||||
|
||||
rsum <<= 12;
|
||||
rsum += 0x008000;
|
||||
gsum >>= 4;
|
||||
gsum += 0x0080;
|
||||
bsum += 0x0008;
|
||||
bsum >>= 4;
|
||||
|
||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
||||
|
||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
||||
}
|
||||
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
||||
|
||||
rsum -= sums[0].r;
|
||||
gsum -= sums[0].g;
|
||||
bsum -= sums[0].b;
|
||||
|
||||
rsum += sums[2].r * 9;
|
||||
gsum += sums[2].g * 9;
|
||||
bsum += sums[2].b * 9;
|
||||
|
||||
rsum -= sums[3].r;
|
||||
gsum -= sums[3].g;
|
||||
bsum -= sums[3].b;
|
||||
|
||||
if (rsum >= 0x80000000) rsum = 0;
|
||||
if (gsum >= 0x80000000) gsum = 0;
|
||||
if (bsum >= 0x80000000) bsum = 0;
|
||||
|
||||
rsum <<= 8;
|
||||
rsum += 0x008000;
|
||||
gsum >>= 8;
|
||||
gsum += 0x000080;
|
||||
bsum += 0x000080;
|
||||
bsum >>= 8;
|
||||
|
||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
||||
|
||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
||||
}
|
||||
|
||||
++sums;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter(gambatte::uint_least32_t *dline,
|
||||
std::ptrdiff_t const pitch,
|
||||
gambatte::uint_least32_t const *sline)
|
||||
{
|
||||
Colorsum sums[in_pitch];
|
||||
for (unsigned h = in_height; h--;) {
|
||||
{
|
||||
gambatte::uint_least32_t const *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = in_pitch;
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
sum->r = pixel >> 12 & 0x000FF0 ;
|
||||
pixel <<= 4;
|
||||
sum->g = pixel & 0x0FF000;
|
||||
sum->b = pixel & 0x000FF0;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
mergeColumns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
gambatte::uint_least32_t const *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = in_pitch;
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 9;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[-1 * in_pitch];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
pixel = s[1 * in_pitch];
|
||||
rsum += (pixel >> 16) * 9;
|
||||
gsum += (pixel & 0x00FF00) * 9;
|
||||
bsum += (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[2 * in_pitch];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
mergeColumns(dline, sums);
|
||||
dline += pitch;
|
||||
sline += in_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Catrom2x::Catrom2x()
|
||||
: buffer_((in_height + 3UL) * in_pitch)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void * Catrom2x::inBuf() const {
|
||||
return buffer_ + in_pitch + 1;
|
||||
}
|
||||
|
||||
std::ptrdiff_t Catrom2x::inPitch() const {
|
||||
return in_pitch;
|
||||
}
|
||||
|
||||
void Catrom2x::draw(void *dbuffer, std::ptrdiff_t pitch) {
|
||||
::filter(static_cast<gambatte::uint_least32_t *>(dbuffer), pitch, buffer_ + in_pitch);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CATROM2X_H
|
||||
#define CATROM2X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Catrom2x : public VideoLink {
|
||||
public:
|
||||
enum { out_width = VfilterInfo::in_width * 2 };
|
||||
enum { out_height = VfilterInfo::in_height * 2 };
|
||||
|
||||
Catrom2x();
|
||||
virtual void * inBuf() const;
|
||||
virtual std::ptrdiff_t inPitch() const;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch);
|
||||
|
||||
private:
|
||||
Array<gambatte::uint_least32_t> const buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,345 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "catrom3x.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
enum { in_width = VfilterInfo::in_width };
|
||||
enum { in_height = VfilterInfo::in_height };
|
||||
enum { in_pitch = in_width + 3 };
|
||||
|
||||
struct Colorsum {
|
||||
gambatte::uint_least32_t r, g, b;
|
||||
};
|
||||
|
||||
static void mergeColumns(gambatte::uint_least32_t *dest, Colorsum const *sums) {
|
||||
for (unsigned w = in_width; w--;) {
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r;
|
||||
gambatte::uint_least32_t gsum = sums[1].g;
|
||||
gambatte::uint_least32_t bsum = sums[1].b;
|
||||
|
||||
if (rsum >= 0x80000000) {
|
||||
rsum = 0;
|
||||
} else if (rsum > 6869) {
|
||||
rsum = 0xFF0000;
|
||||
} else {
|
||||
rsum *= 607;
|
||||
rsum <<= 2;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum >= 0x80000000) {
|
||||
gsum = 0;
|
||||
} else if (gsum > 1758567) {
|
||||
gsum = 0xFF00;
|
||||
} else {
|
||||
gsum *= 607;
|
||||
gsum >>= 14;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum >= 0x80000000) {
|
||||
bsum = 0;
|
||||
} else if (bsum > 6869) {
|
||||
bsum = 0xFF;
|
||||
} else {
|
||||
bsum *= 607;
|
||||
bsum += 8192;
|
||||
bsum >>= 14;
|
||||
}
|
||||
|
||||
/*rsum/=27;
|
||||
rsum<<=8;
|
||||
gsum/=27;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=27;
|
||||
bsum/=54;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 21;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 21;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 21;
|
||||
|
||||
rsum -= sums[0].r << 1;
|
||||
gsum -= sums[0].g << 1;
|
||||
bsum -= sums[0].b << 1;
|
||||
|
||||
rsum += sums[2].r * 9;
|
||||
gsum += sums[2].g * 9;
|
||||
bsum += sums[2].b * 9;
|
||||
|
||||
rsum -= sums[3].r;
|
||||
gsum -= sums[3].g;
|
||||
bsum -= sums[3].b;
|
||||
|
||||
if (rsum >= 0x80000000) {
|
||||
rsum = 0;
|
||||
} else if (rsum > 185578) {
|
||||
rsum = 0xFF0000;
|
||||
} else {
|
||||
rsum *= 719;
|
||||
rsum >>= 3;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum >= 0x80000000) {
|
||||
gsum = 0;
|
||||
} else if (gsum > 47508223) {
|
||||
gsum = 0x00FF00;
|
||||
} else {
|
||||
gsum >>= 8;
|
||||
gsum *= 719;
|
||||
gsum >>= 11;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum >= 0x80000000) {
|
||||
bsum = 0;
|
||||
} else if (bsum > 185578) {
|
||||
bsum = 0x0000FF;
|
||||
} else {
|
||||
bsum *= 719;
|
||||
bsum += 0x040000;
|
||||
bsum >>= 19;
|
||||
}
|
||||
|
||||
/*rsum/=729;
|
||||
rsum<<=8;
|
||||
gsum/=729;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=729;
|
||||
bsum/=1458;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
{
|
||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
||||
|
||||
rsum -= sums[0].r;
|
||||
gsum -= sums[0].g;
|
||||
bsum -= sums[0].b;
|
||||
|
||||
rsum += sums[2].r * 21;
|
||||
gsum += sums[2].g * 21;
|
||||
bsum += sums[2].b * 21;
|
||||
|
||||
rsum -= sums[3].r << 1;
|
||||
gsum -= sums[3].g << 1;
|
||||
bsum -= sums[3].b << 1;
|
||||
|
||||
if (rsum >= 0x80000000) {
|
||||
rsum = 0;
|
||||
} else if (rsum > 185578) {
|
||||
rsum = 0xFF0000;
|
||||
} else {
|
||||
rsum *= 719;
|
||||
rsum >>= 3;
|
||||
rsum += 0x008000;
|
||||
rsum &= 0xFF0000;
|
||||
}
|
||||
|
||||
if (gsum >= 0x80000000) {
|
||||
gsum = 0;
|
||||
} else if (gsum > 47508223) {
|
||||
gsum = 0xFF00;
|
||||
} else {
|
||||
gsum >>= 8;
|
||||
gsum *= 719;
|
||||
gsum >>= 11;
|
||||
gsum += 0x000080;
|
||||
gsum &= 0x00FF00;
|
||||
}
|
||||
|
||||
if (bsum >= 0x80000000) {
|
||||
bsum = 0;
|
||||
} else if (bsum > 185578) {
|
||||
bsum = 0x0000FF;
|
||||
} else {
|
||||
bsum *= 719;
|
||||
bsum += 0x040000;
|
||||
bsum >>= 19;
|
||||
}
|
||||
|
||||
/*rsum/=729;
|
||||
rsum<<=8;
|
||||
gsum/=729;
|
||||
gsum<<=5;
|
||||
bsum<<=4;
|
||||
bsum+=729;
|
||||
bsum/=1458;
|
||||
rsum+=0x008000;
|
||||
gsum+=0x000080;
|
||||
|
||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
||||
|
||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
||||
}
|
||||
|
||||
++sums;
|
||||
}
|
||||
}
|
||||
|
||||
static void filter(gambatte::uint_least32_t *dline,
|
||||
std::ptrdiff_t const pitch,
|
||||
gambatte::uint_least32_t const *sline)
|
||||
{
|
||||
Colorsum sums[in_pitch];
|
||||
for (unsigned h = in_height; h--;) {
|
||||
{
|
||||
gambatte::uint_least32_t const *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = in_pitch;
|
||||
while (n--) {
|
||||
unsigned long const pixel = *s;
|
||||
sum->r = (pixel >> 16) * 27;
|
||||
sum->g = (pixel & 0x00FF00) * 27;
|
||||
sum->b = (pixel & 0x0000FF) * 27;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
mergeColumns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
gambatte::uint_least32_t const *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = in_pitch;
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 21;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 21;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 21;
|
||||
|
||||
pixel = s[-1 * in_pitch];
|
||||
rsum -= (pixel >> 16) << 1;
|
||||
pixel <<= 1;
|
||||
gsum -= pixel & 0x01FE00;
|
||||
bsum -= pixel & 0x0001FE;
|
||||
|
||||
pixel = s[1 * in_pitch];
|
||||
rsum += (pixel >> 16) * 9;
|
||||
gsum += (pixel & 0x00FF00) * 9;
|
||||
bsum += (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[2 * in_pitch];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
mergeColumns(dline, sums);
|
||||
dline += pitch;
|
||||
|
||||
{
|
||||
gambatte::uint_least32_t const *s = sline;
|
||||
Colorsum *sum = sums;
|
||||
unsigned n = in_pitch;
|
||||
while (n--) {
|
||||
unsigned long pixel = *s;
|
||||
unsigned long rsum = (pixel >> 16) * 9;
|
||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
||||
|
||||
pixel = s[-1 * in_pitch];
|
||||
rsum -= pixel >> 16;
|
||||
gsum -= pixel & 0x00FF00;
|
||||
bsum -= pixel & 0x0000FF;
|
||||
|
||||
pixel = s[1 * in_pitch];
|
||||
rsum += (pixel >> 16) * 21;
|
||||
gsum += (pixel & 0x00FF00) * 21;
|
||||
bsum += (pixel & 0x0000FF) * 21;
|
||||
|
||||
pixel = s[2 * in_pitch];
|
||||
rsum -= (pixel >> 16) << 1;
|
||||
pixel <<= 1;
|
||||
gsum -= pixel & 0x01FE00;
|
||||
bsum -= pixel & 0x0001FE;
|
||||
|
||||
sum->r = rsum;
|
||||
sum->g = gsum;
|
||||
sum->b = bsum;
|
||||
|
||||
++s;
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
mergeColumns(dline, sums);
|
||||
dline += pitch;
|
||||
sline += in_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Catrom3x::Catrom3x()
|
||||
: buffer_((in_height + 3UL) * in_pitch)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void * Catrom3x::inBuf() const {
|
||||
return buffer_ + in_pitch + 1;
|
||||
}
|
||||
|
||||
std::ptrdiff_t Catrom3x::inPitch() const {
|
||||
return in_pitch;
|
||||
}
|
||||
|
||||
void Catrom3x::draw(void *dbuffer, std::ptrdiff_t pitch) {
|
||||
::filter(static_cast<gambatte::uint_least32_t *>(dbuffer), pitch, buffer_ + in_pitch);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef CATROM3X_H
|
||||
#define CATROM3X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Catrom3x : public VideoLink {
|
||||
public:
|
||||
enum { out_width = VfilterInfo::in_width * 3 };
|
||||
enum { out_height = VfilterInfo::in_height * 3 };
|
||||
|
||||
Catrom3x();
|
||||
virtual void * inBuf() const;
|
||||
virtual std::ptrdiff_t inPitch() const;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch);
|
||||
|
||||
private:
|
||||
Array<gambatte::uint_least32_t> const buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,233 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* Copyright (C) 1999 Derek Liauw Kie Fa (Kreed) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "kreed2xsai.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
static int getResult1(unsigned long const a,
|
||||
unsigned long const b,
|
||||
unsigned long const c,
|
||||
unsigned long const d)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int r = 0;
|
||||
|
||||
if (a == c) ++x;
|
||||
else if (b == c) ++y;
|
||||
|
||||
if (a == d) ++x;
|
||||
else if (b == d) ++y;
|
||||
|
||||
if (x <= 1) ++r;
|
||||
if (y <= 1) --r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int getResult2(unsigned long const a,
|
||||
unsigned long const b,
|
||||
unsigned long const c,
|
||||
unsigned long const d)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int r = 0;
|
||||
|
||||
if (a == c) ++x;
|
||||
else if (b == c) ++y;
|
||||
|
||||
if (a == d) ++x;
|
||||
else if (b == d) ++y;
|
||||
|
||||
if (x <= 1) --r;
|
||||
if (y <= 1) ++r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned long interpolate(unsigned long a, unsigned long b) {
|
||||
return (a + b - ((a ^ b) & 0x010101)) >> 1;
|
||||
}
|
||||
|
||||
static unsigned long qInterpolate(unsigned long const a,
|
||||
unsigned long const b,
|
||||
unsigned long const c,
|
||||
unsigned long const d)
|
||||
{
|
||||
unsigned long lowBits = ((a & 0x030303)
|
||||
+ (b & 0x030303)
|
||||
+ (c & 0x030303)
|
||||
+ (d & 0x030303)) & 0x030303;
|
||||
return (a + b + c + d - lowBits) >> 2;
|
||||
}
|
||||
|
||||
template<std::ptrdiff_t srcPitch, unsigned width, unsigned height>
|
||||
static void filter(gambatte::uint_least32_t *dstPtr,
|
||||
std::ptrdiff_t const dstPitch,
|
||||
gambatte::uint_least32_t const *srcPtr)
|
||||
{
|
||||
for (unsigned h = height; h--;) {
|
||||
gambatte::uint_least32_t const *bP = srcPtr;
|
||||
gambatte::uint_least32_t *dP = dstPtr;
|
||||
for (unsigned w = width; w--;) {
|
||||
unsigned long colorA, colorB, colorC, colorD,
|
||||
colorE, colorF, colorG, colorH,
|
||||
colorI, colorJ, colorK, colorL,
|
||||
colorM, colorN, colorO/*, colorP*/;
|
||||
|
||||
//---------------------------------------
|
||||
// Map of the pixels: I|E F|J
|
||||
// G|A B|K
|
||||
// H|C D|L
|
||||
// M|N O|P
|
||||
|
||||
colorI = *(bP - srcPitch - 1);
|
||||
colorE = *(bP - srcPitch );
|
||||
colorF = *(bP - srcPitch + 1);
|
||||
colorJ = *(bP - srcPitch + 2);
|
||||
|
||||
colorG = *(bP - 1);
|
||||
colorA = *(bP );
|
||||
colorB = *(bP + 1);
|
||||
colorK = *(bP + 2);
|
||||
|
||||
colorH = *(bP + srcPitch - 1);
|
||||
colorC = *(bP + srcPitch );
|
||||
colorD = *(bP + srcPitch + 1);
|
||||
colorL = *(bP + srcPitch + 2);
|
||||
|
||||
colorM = *(bP + srcPitch * 2 - 1);
|
||||
colorN = *(bP + srcPitch * 2 );
|
||||
colorO = *(bP + srcPitch * 2 + 1);
|
||||
// colorP = *(bP + srcPitch * 2 + 2);
|
||||
|
||||
unsigned long product0, product1, product2;
|
||||
if (colorA == colorD && colorB != colorC) {
|
||||
product0 = (colorA == colorE && colorB == colorL)
|
||||
|| (colorA == colorC && colorA == colorF
|
||||
&& colorB != colorE && colorB == colorJ)
|
||||
? colorA
|
||||
: interpolate(colorA, colorB);
|
||||
product1 = (colorA == colorG && colorC == colorO)
|
||||
|| (colorA == colorB && colorA == colorH
|
||||
&& colorG != colorC && colorC == colorM)
|
||||
? colorA
|
||||
: interpolate(colorA, colorC);
|
||||
product2 = colorA;
|
||||
} else if (colorB == colorC && colorA != colorD) {
|
||||
product0 = (colorB == colorF && colorA == colorH)
|
||||
|| (colorB == colorE && colorB == colorD
|
||||
&& colorA != colorF && colorA == colorI)
|
||||
? colorB
|
||||
: interpolate(colorA, colorB);
|
||||
product1 = (colorC == colorH && colorA == colorF)
|
||||
|| (colorC == colorG && colorC == colorD
|
||||
&& colorA != colorH && colorA == colorI)
|
||||
? colorC
|
||||
: interpolate(colorA, colorC);
|
||||
product2 = colorB;
|
||||
} else if (colorA == colorD && colorB == colorC) {
|
||||
if (colorA == colorB) {
|
||||
product0 = colorA;
|
||||
product1 = colorA;
|
||||
product2 = colorA;
|
||||
} else {
|
||||
product0 = interpolate(colorA, colorB);
|
||||
product1 = interpolate(colorA, colorC);
|
||||
|
||||
int r = 0;
|
||||
r += getResult1(colorA, colorB, colorG, colorE);
|
||||
r += getResult2(colorB, colorA, colorK, colorF);
|
||||
r += getResult2(colorB, colorA, colorH, colorN);
|
||||
r += getResult1(colorA, colorB, colorL, colorO);
|
||||
if (r > 0) {
|
||||
product2 = colorA;
|
||||
} else if (r < 0) {
|
||||
product2 = colorB;
|
||||
} else {
|
||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
||||
|
||||
if (colorA == colorC && colorA == colorF
|
||||
&& colorB != colorE && colorB == colorJ) {
|
||||
product0 = colorA;
|
||||
} else if (colorB == colorE && colorB == colorD
|
||||
&& colorA != colorF && colorA == colorI) {
|
||||
product0 = colorB;
|
||||
} else {
|
||||
product0 = interpolate(colorA, colorB);
|
||||
}
|
||||
|
||||
if (colorA == colorB && colorA == colorH
|
||||
&& colorG != colorC && colorC == colorM) {
|
||||
product1 = colorA;
|
||||
} else if (colorC == colorG && colorC == colorD
|
||||
&& colorA != colorH && colorA == colorI) {
|
||||
product1 = colorC;
|
||||
} else {
|
||||
product1 = interpolate(colorA, colorC);
|
||||
}
|
||||
}
|
||||
|
||||
*(dP ) = colorA;
|
||||
*(dP + 1) = product0;
|
||||
*(dP + dstPitch ) = product1;
|
||||
*(dP + dstPitch + 1) = product2;
|
||||
dP += 2;
|
||||
++bP;
|
||||
}
|
||||
|
||||
srcPtr += srcPitch;
|
||||
dstPtr += dstPitch * 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum { in_width = VfilterInfo::in_width };
|
||||
enum { in_height = VfilterInfo::in_height };
|
||||
enum { in_pitch = in_width + 3 };
|
||||
enum { buf_size = (in_height + 3ul) * in_pitch };
|
||||
enum { buf_offset = in_pitch + 1 };
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Kreed2xSaI::Kreed2xSaI()
|
||||
: buffer_(buf_size)
|
||||
{
|
||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
||||
}
|
||||
|
||||
void * Kreed2xSaI::inBuf() const {
|
||||
return buffer_ + buf_offset;
|
||||
}
|
||||
|
||||
std::ptrdiff_t Kreed2xSaI::inPitch() const {
|
||||
return in_pitch;
|
||||
}
|
||||
|
||||
void Kreed2xSaI::draw(void *dbuffer, std::ptrdiff_t dpitch) {
|
||||
::filter<in_pitch, in_width, in_height>(static_cast<gambatte::uint_least32_t *>(dbuffer),
|
||||
dpitch, buffer_ + buf_offset);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef KREED2XSAI_H
|
||||
#define KREED2XSAI_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class Kreed2xSaI : public VideoLink {
|
||||
public:
|
||||
enum { out_width = VfilterInfo::in_width * 2 };
|
||||
enum { out_height = VfilterInfo::in_height * 2 };
|
||||
|
||||
Kreed2xSaI();
|
||||
virtual void * inBuf() const;
|
||||
virtual std::ptrdiff_t inPitch() const;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch);
|
||||
|
||||
private:
|
||||
Array<gambatte::uint_least32_t> const buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MAXSTHQ2X_H
|
||||
#define MAXSTHQ2X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class MaxStHq2x : public VideoLink {
|
||||
public:
|
||||
enum { out_width = VfilterInfo::in_width * 2 };
|
||||
enum { out_height = VfilterInfo::in_height * 2 };
|
||||
|
||||
MaxStHq2x();
|
||||
virtual void * inBuf() const;
|
||||
virtual std::ptrdiff_t inPitch() const;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch);
|
||||
|
||||
private:
|
||||
SimpleArray<gambatte::uint_least32_t> const buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef MAXSTHQ3X_H
|
||||
#define MAXSTHQ3X_H
|
||||
|
||||
#include "../videolink.h"
|
||||
#include "../vfilterinfo.h"
|
||||
#include "array.h"
|
||||
#include "gbint.h"
|
||||
|
||||
class MaxStHq3x : public VideoLink {
|
||||
public:
|
||||
enum { out_width = VfilterInfo::in_width * 3 };
|
||||
enum { out_height = VfilterInfo::in_height * 3 };
|
||||
|
||||
MaxStHq3x();
|
||||
virtual void * inBuf() const;
|
||||
virtual std::ptrdiff_t inPitch() const;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch);
|
||||
|
||||
private:
|
||||
SimpleArray<gambatte::uint_least32_t> const buffer_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Sindre Aamås *
|
||||
* sinamas@users.sourceforge.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef VIDEOLINK_H
|
||||
#define VIDEOLINK_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
class VideoLink {
|
||||
public:
|
||||
virtual ~VideoLink() {}
|
||||
virtual void * inBuf() const = 0;
|
||||
virtual std::ptrdiff_t inPitch() const = 0;
|
||||
virtual void draw(void *dst, std::ptrdiff_t dstpitch) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
+506
-506
File diff suppressed because it is too large
Load Diff
@@ -1,56 +0,0 @@
|
||||
global_cflags = ARGUMENTS.get('CFLAGS', '-Wall -Wextra -O2 -fomit-frame-pointer')
|
||||
global_cxxflags = ARGUMENTS.get('CXXFLAGS', global_cflags + ' -fno-exceptions -fno-rtti')
|
||||
global_defines = ' -DHAVE_STDINT_H'
|
||||
vars = Variables()
|
||||
vars.Add('CC')
|
||||
vars.Add('CXX')
|
||||
|
||||
env = Environment(CPPPATH = ['src', 'include', '../common'],
|
||||
CFLAGS = global_cflags + global_defines,
|
||||
CXXFLAGS = global_cxxflags + global_defines,
|
||||
variables = vars)
|
||||
|
||||
sourceFiles = Split('''
|
||||
src/bitmap_font.cpp
|
||||
src/cpu.cpp
|
||||
src/gambatte.cpp
|
||||
src/initstate.cpp
|
||||
src/interrupter.cpp
|
||||
src/interruptrequester.cpp
|
||||
src/loadres.cpp
|
||||
src/memory.cpp
|
||||
src/sound.cpp
|
||||
src/state_osd_elements.cpp
|
||||
src/statesaver.cpp
|
||||
src/tima.cpp
|
||||
src/video.cpp
|
||||
src/mem/cartridge.cpp
|
||||
src/mem/memptrs.cpp
|
||||
src/mem/pakinfo.cpp
|
||||
src/mem/rtc.cpp
|
||||
src/sound/channel1.cpp
|
||||
src/sound/channel2.cpp
|
||||
src/sound/channel3.cpp
|
||||
src/sound/channel4.cpp
|
||||
src/sound/duty_unit.cpp
|
||||
src/sound/envelope_unit.cpp
|
||||
src/sound/length_counter.cpp
|
||||
src/video/ly_counter.cpp
|
||||
src/video/lyc_irq.cpp
|
||||
src/video/next_m0_time.cpp
|
||||
src/video/ppu.cpp
|
||||
src/video/sprite_mapper.cpp
|
||||
''')
|
||||
|
||||
conf = env.Configure()
|
||||
|
||||
if conf.CheckHeader('zlib.h'):
|
||||
sourceFiles.append('src/file/unzip/unzip.c')
|
||||
sourceFiles.append('src/file/unzip/ioapi.c')
|
||||
sourceFiles.append('src/file/file_zip.cpp')
|
||||
else:
|
||||
sourceFiles.append('src/file/file.cpp')
|
||||
|
||||
conf.Finish()
|
||||
|
||||
env.Library('gambatte', sourceFiles)
|
||||
@@ -1,222 +0,0 @@
|
||||
/***************************************************************************
|
||||
Copyright (C) 2007 by Nach
|
||||
http://nsrt.edgeemu.com
|
||||
|
||||
Copyright (C) 2007-2011 by sinamas <sinamas at users.sourceforge.net>
|
||||
sinamas@users.sourceforge.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
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 version 2 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
***************************************************************************/
|
||||
#include "stdfile.h"
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
namespace zlib {
|
||||
#include "unzip/unzip.h"
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ZipFile : public gambatte::File {
|
||||
private:
|
||||
std::size_t fsize, count;
|
||||
void *zipfile;
|
||||
bool zip_sub_open;
|
||||
|
||||
void zip(const char *filename);
|
||||
|
||||
public:
|
||||
ZipFile(const char *filename);
|
||||
virtual ~ZipFile();
|
||||
virtual void rewind();
|
||||
bool is_open() const;
|
||||
virtual void close();
|
||||
virtual std::size_t size() const { return fsize; };
|
||||
virtual void read(char *buffer, std::size_t amount);
|
||||
std::size_t gcount() const { return count; }
|
||||
virtual bool fail() const { return !is_open(); }
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
using namespace zlib;
|
||||
|
||||
static const unsigned int MAX_FILE_NAME = 512;
|
||||
|
||||
ZipFile::ZipFile(const char *filename) : fsize(0), count(0)
|
||||
{
|
||||
zip(filename);
|
||||
}
|
||||
|
||||
void ZipFile::zip(const char *filename)
|
||||
{
|
||||
zipfile = unzOpen(filename);
|
||||
if (zipfile)
|
||||
{
|
||||
zip_sub_open = false;
|
||||
|
||||
unz_file_info cFileInfo;
|
||||
char ourFile[MAX_FILE_NAME] = { '\n' };
|
||||
|
||||
for (int cFile = unzGoToFirstFile((unzFile)zipfile); cFile == UNZ_OK; cFile = unzGoToNextFile((unzFile)zipfile))
|
||||
{
|
||||
//Temporary char array for file name
|
||||
char cFileName[MAX_FILE_NAME];
|
||||
|
||||
//Gets info on current file, and places it in cFileInfo
|
||||
unzGetCurrentFileInfo((unzFile)zipfile, &cFileInfo, cFileName, MAX_FILE_NAME, 0, 0, 0, 0);
|
||||
|
||||
//Check for largest file which should be the ROM
|
||||
if ((size_t)cFileInfo.uncompressed_size > fsize)
|
||||
{
|
||||
strcpy(ourFile, cFileName);
|
||||
fsize = (size_t)cFileInfo.uncompressed_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourFile[0] != '\n')
|
||||
{
|
||||
//Sets current file to the file we liked before
|
||||
unzLocateFile((unzFile)zipfile, ourFile, 1);
|
||||
|
||||
if (unzOpenCurrentFile((unzFile)zipfile) == UNZ_OK)
|
||||
{
|
||||
zip_sub_open = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zip_sub_open)
|
||||
{
|
||||
unzClose((unzFile)zipfile);
|
||||
zipfile = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void ZipFile::rewind()
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
unzCloseCurrentFile((unzFile)zipfile);
|
||||
unzOpenCurrentFile((unzFile)zipfile);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZipFile::is_open() const
|
||||
{
|
||||
return(zipfile && zip_sub_open);
|
||||
}
|
||||
|
||||
void ZipFile::close()
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
unzOpenCurrentFile((unzFile)zipfile);
|
||||
unzClose((unzFile)zipfile);
|
||||
zipfile = 0;
|
||||
zip_sub_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipFile::read(char *buffer, size_t amount)
|
||||
{
|
||||
if (is_open())
|
||||
{
|
||||
count = (size_t)unzReadCurrentFile((unzFile)zipfile, buffer, amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class GzFile : public gambatte::File {
|
||||
public:
|
||||
explicit GzFile(char const *filename)
|
||||
: file_(gzopen(filename, "rb"))
|
||||
, fsize_(0)
|
||||
{
|
||||
if (file_) {
|
||||
char buf[256];
|
||||
int ret;
|
||||
|
||||
while ((ret = gzread(file_, buf, sizeof buf)) > 0)
|
||||
fsize_ += ret;
|
||||
|
||||
if (ret < 0) {
|
||||
close();
|
||||
fsize_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rewind();
|
||||
}
|
||||
|
||||
virtual ~GzFile() { close(); }
|
||||
|
||||
virtual void rewind() {
|
||||
if (file_ && gzrewind(file_) < 0)
|
||||
close();
|
||||
}
|
||||
|
||||
virtual std::size_t size() const { return fsize_; };
|
||||
|
||||
virtual void read(char *buffer, std::size_t amount) {
|
||||
if (file_ && gzread(file_, buffer, amount) < 0)
|
||||
close();
|
||||
}
|
||||
|
||||
virtual bool fail() const { return !file_; }
|
||||
|
||||
private:
|
||||
gzFile file_;
|
||||
std::size_t fsize_;
|
||||
|
||||
GzFile(GzFile const &);
|
||||
GzFile & operator=(GzFile const &);
|
||||
void close();
|
||||
};
|
||||
|
||||
void GzFile::close() {
|
||||
if (file_) {
|
||||
gzclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Avoid checking magic header values, because there are no values that cannot occur in a GB ROM.
|
||||
transfer_ptr<gambatte::File> gambatte::newFileInstance(std::string const &filepath) {
|
||||
std::size_t const extpos = filepath.rfind('.');
|
||||
|
||||
if (extpos != std::string::npos) {
|
||||
std::string const &ext = filepath.substr(extpos + 1);
|
||||
|
||||
if (ext.length() == 3 && std::tolower(ext[0]) == 'z'
|
||||
&& std::tolower(ext[1]) == 'i' && std::tolower(ext[2]) == 'p') {
|
||||
return transfer_ptr<File>(new ZipFile(filepath.c_str()));
|
||||
}
|
||||
|
||||
if (!ext.empty() && std::tolower(ext[ext.length() - 1]) == 'z')
|
||||
return transfer_ptr<File>(new GzFile(filepath.c_str()));
|
||||
}
|
||||
|
||||
return transfer_ptr<File>(new StdFile(filepath.c_str()));
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This code is a modified version of crypting code in Infozip distribution
|
||||
|
||||
The encryption/decryption parts of this source code (as opposed to the
|
||||
non-echoing password parts) were originally written in Europe. The
|
||||
whole source package can be freely distributed, including from the USA.
|
||||
(Prior to January 2000, re-export from the US was a violation of US law.)
|
||||
|
||||
This encryption code is a direct transcription of the algorithm from
|
||||
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
|
||||
file (appnote.txt) is distributed with the PKZIP program (even in the
|
||||
version without encryption capabilities).
|
||||
|
||||
If you don't need crypting in your application, just define symbols
|
||||
NOCRYPT and NOUNCRYPT.
|
||||
|
||||
This code support the "Traditional PKWARE Encryption".
|
||||
|
||||
The new AES encryption added on Zip format by Winzip (see the page
|
||||
http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
|
||||
Encryption is not supported.
|
||||
*/
|
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
|
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence
|
||||
*/
|
||||
static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
|
||||
* unpredictable manner on 16-bit systems; not a problem
|
||||
* with any known compiler so far, though */
|
||||
|
||||
temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
|
||||
return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Update the encryption keys with the next byte of plain text
|
||||
*/
|
||||
static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
|
||||
{
|
||||
(*(pkeys+0)) = CRC32((*(pkeys+0)), c);
|
||||
(*(pkeys+1)) += (*(pkeys+0)) & 0xff;
|
||||
(*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
|
||||
{
|
||||
register int keyshift = (int)((*(pkeys+1)) >> 24);
|
||||
(*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
*/
|
||||
static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
|
||||
{
|
||||
*(pkeys+0) = 305419896L;
|
||||
*(pkeys+1) = 591751049L;
|
||||
*(pkeys+2) = 878082192L;
|
||||
while (*passwd != '\0') {
|
||||
update_keys(pkeys,pcrc_32_tab,(int)*passwd);
|
||||
passwd++;
|
||||
}
|
||||
}
|
||||
|
||||
#define zdecode(pkeys,pcrc_32_tab,c) \
|
||||
(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
|
||||
|
||||
#define zencode(pkeys,pcrc_32_tab,c,t) \
|
||||
(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
|
||||
|
||||
#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
|
||||
|
||||
#define RAND_HEAD_LEN 12
|
||||
/* "last resort" source for second part of crypt seed pattern */
|
||||
# ifndef ZCR_SEED2
|
||||
# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
|
||||
# endif
|
||||
|
||||
static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
|
||||
const char *passwd; /* password string */
|
||||
unsigned char *buf; /* where to write header */
|
||||
int bufSize;
|
||||
unsigned long* pkeys;
|
||||
const unsigned long* pcrc_32_tab;
|
||||
unsigned long crcForCrypting;
|
||||
{
|
||||
int n; /* index in random header */
|
||||
int t; /* temporary */
|
||||
int c; /* random byte */
|
||||
unsigned char header[RAND_HEAD_LEN-2]; /* random header */
|
||||
static unsigned calls = 0; /* ensure different random header each time */
|
||||
|
||||
if (bufSize<RAND_HEAD_LEN)
|
||||
return 0;
|
||||
|
||||
/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
|
||||
* output of rand() to get less predictability, since rand() is
|
||||
* often poorly implemented.
|
||||
*/
|
||||
if (++calls == 1)
|
||||
{
|
||||
srand((unsigned)(time(NULL) ^ ZCR_SEED2));
|
||||
}
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
c = (rand() >> 7) & 0xff;
|
||||
header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
|
||||
}
|
||||
/* Encrypt random header (last two bytes is high word of crc) */
|
||||
init_keys(passwd, pkeys, pcrc_32_tab);
|
||||
for (n = 0; n < RAND_HEAD_LEN-2; n++)
|
||||
{
|
||||
buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
|
||||
}
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
|
||||
buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,177 +0,0 @@
|
||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zlib.h>
|
||||
#include "ioapi.h"
|
||||
|
||||
|
||||
|
||||
/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
|
||||
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func OF((
|
||||
voidpf opaque,
|
||||
const char* filename,
|
||||
int mode));
|
||||
|
||||
uLong ZCALLBACK fread_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
void* buf,
|
||||
uLong size));
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
const void* buf,
|
||||
uLong size));
|
||||
|
||||
long ZCALLBACK ftell_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
long ZCALLBACK fseek_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream,
|
||||
uLong offset,
|
||||
int origin));
|
||||
|
||||
int ZCALLBACK fclose_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
int ZCALLBACK ferror_file_func OF((
|
||||
voidpf opaque,
|
||||
voidpf stream));
|
||||
|
||||
|
||||
voidpf ZCALLBACK fopen_file_func (opaque, filename, mode)
|
||||
voidpf opaque;
|
||||
const char* filename;
|
||||
int mode;
|
||||
{
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
mode_fopen = "rb";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
mode_fopen = "r+b";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
mode_fopen = "wb";
|
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL))
|
||||
file = fopen(filename, mode_fopen);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fread_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
const void* buf;
|
||||
uLong size;
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK ftell_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
long ret;
|
||||
ret = ftell((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
uLong offset;
|
||||
int origin;
|
||||
{
|
||||
int fseek_origin=0;
|
||||
long ret;
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR :
|
||||
fseek_origin = SEEK_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END :
|
||||
fseek_origin = SEEK_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET :
|
||||
fseek_origin = SEEK_SET;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
ret = 0;
|
||||
fseek((FILE *)stream, offset, fseek_origin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK fclose_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = fclose((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ZCALLBACK ferror_file_func (opaque, stream)
|
||||
voidpf opaque;
|
||||
voidpf stream;
|
||||
{
|
||||
int ret;
|
||||
ret = ferror((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def)
|
||||
zlib_filefunc_def* pzlib_filefunc_def;
|
||||
{
|
||||
pzlib_filefunc_def->zopen_file = fopen_file_func;
|
||||
pzlib_filefunc_def->zread_file = fread_file_func;
|
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
|
||||
pzlib_filefunc_def->ztell_file = ftell_file_func;
|
||||
pzlib_filefunc_def->zseek_file = fseek_file_func;
|
||||
pzlib_filefunc_def->zclose_file = fclose_file_func;
|
||||
pzlib_filefunc_def->zerror_file = ferror_file_func;
|
||||
pzlib_filefunc_def->opaque = NULL;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
files using zlib + zip or unzip API
|
||||
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
*/
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#define _ZLIBIOAPI_H
|
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1)
|
||||
#define ZLIB_FILEFUNC_SEEK_END (2)
|
||||
#define ZLIB_FILEFUNC_SEEK_SET (0)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1)
|
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2)
|
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
|
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8)
|
||||
|
||||
|
||||
#ifndef ZCALLBACK
|
||||
|
||||
#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
|
||||
#define ZCALLBACK CALLBACK
|
||||
#else
|
||||
#define ZCALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
|
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
|
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
|
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
|
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
|
||||
|
||||
typedef struct zlib_filefunc_def_s
|
||||
{
|
||||
open_file_func zopen_file;
|
||||
read_file_func zread_file;
|
||||
write_file_func zwrite_file;
|
||||
tell_file_func ztell_file;
|
||||
seek_file_func zseek_file;
|
||||
close_file_func zclose_file;
|
||||
testerror_file_func zerror_file;
|
||||
voidpf opaque;
|
||||
} zlib_filefunc_def;
|
||||
|
||||
|
||||
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
|
||||
#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
|
||||
#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
|
||||
#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
|
||||
#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,358 +0,0 @@
|
||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.01e, February 12th, 2005
|
||||
|
||||
Copyright (C) 1998-2005 Gilles Vollant
|
||||
|
||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
||||
WinZip, InfoZip tools and compatible.
|
||||
|
||||
Multi volume ZipFile (span) are not supported.
|
||||
Encryption compatible with pkzip 2.04g only supported
|
||||
Old compressions used by old PKZip 1.x are not supported
|
||||
|
||||
|
||||
I WAIT FEEDBACK at mail info@winimage.com
|
||||
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
|
||||
|
||||
Condition of use and distribution are the same than zlib :
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* for more info about .ZIP format, see
|
||||
http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
|
||||
http://www.info-zip.org/pub/infozip/doc/
|
||||
PkWare has also a specification at :
|
||||
ftp://ftp.pkware.com/probdesc.zip
|
||||
*/
|
||||
|
||||
#ifndef _unz_H
|
||||
#define _unz_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIB_H
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef OF
|
||||
#define OF(args) args
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#include "ioapi.h"
|
||||
#endif
|
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */
|
||||
typedef struct TagunzFile__ { int unused; } unzFile__;
|
||||
typedef unzFile__ *unzFile;
|
||||
#else
|
||||
typedef voidp unzFile;
|
||||
#endif
|
||||
|
||||
|
||||
#define UNZ_OK (0)
|
||||
#define UNZ_END_OF_LIST_OF_FILE (-100)
|
||||
#define UNZ_ERRNO (Z_ERRNO)
|
||||
#define UNZ_EOF (0)
|
||||
#define UNZ_PARAMERROR (-102)
|
||||
#define UNZ_BADZIPFILE (-103)
|
||||
#define UNZ_INTERNALERROR (-104)
|
||||
#define UNZ_CRCERROR (-105)
|
||||
|
||||
/* tm_unz contain date/time info */
|
||||
typedef struct tm_unz_s
|
||||
{
|
||||
uInt tm_sec; /* seconds after the minute - [0,59] */
|
||||
uInt tm_min; /* minutes after the hour - [0,59] */
|
||||
uInt tm_hour; /* hours since midnight - [0,23] */
|
||||
uInt tm_mday; /* day of the month - [1,31] */
|
||||
uInt tm_mon; /* months since January - [0,11] */
|
||||
uInt tm_year; /* years - [1980..2044] */
|
||||
} tm_unz;
|
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */
|
||||
typedef struct unz_global_info_s
|
||||
{
|
||||
uLong number_entry; /* total number of entries in
|
||||
the central dir on this disk */
|
||||
uLong size_comment; /* size of the global comment of the zipfile */
|
||||
} unz_global_info;
|
||||
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_info_s
|
||||
{
|
||||
uLong version; /* version made by 2 bytes */
|
||||
uLong version_needed; /* version needed to extract 2 bytes */
|
||||
uLong flag; /* general purpose bit flag 2 bytes */
|
||||
uLong compression_method; /* compression method 2 bytes */
|
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
|
||||
uLong crc; /* crc-32 4 bytes */
|
||||
uLong compressed_size; /* compressed size 4 bytes */
|
||||
uLong uncompressed_size; /* uncompressed size 4 bytes */
|
||||
uLong size_filename; /* filename length 2 bytes */
|
||||
uLong size_file_extra; /* extra field length 2 bytes */
|
||||
uLong size_file_comment; /* file comment length 2 bytes */
|
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */
|
||||
uLong external_fa; /* external file attributes 4 bytes */
|
||||
|
||||
tm_unz tmu_date;
|
||||
} unz_file_info;
|
||||
|
||||
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
|
||||
const char* fileName2,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Compare two filename (fileName1,fileName2).
|
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
|
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
|
||||
or strcasecmp)
|
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
|
||||
(like 1 on Unix, 2 on Windows)
|
||||
*/
|
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen OF((const char *path));
|
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example,
|
||||
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
|
||||
"zlib/zlib113.zip".
|
||||
If the zipfile cannot be opened (file don't exist or in not valid), the
|
||||
return value is NULL.
|
||||
Else, the return value is a unzFile Handle, usable with other function
|
||||
of this unzip package.
|
||||
*/
|
||||
|
||||
extern unzFile ZEXPORT unzOpen2 OF((const char *path,
|
||||
zlib_filefunc_def* pzlib_filefunc_def));
|
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API
|
||||
for read/write the zip file (see ioapi.h)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzClose OF((unzFile file));
|
||||
/*
|
||||
Close a ZipFile opened with unzipOpen.
|
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
|
||||
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
|
||||
unz_global_info *pglobal_info));
|
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure.
|
||||
No preparation of the structure is needed
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
|
||||
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
|
||||
char *szComment,
|
||||
uLong uSizeBuf));
|
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer.
|
||||
uSizeBuf is the size of the szComment buffer.
|
||||
return the number of byte copied or an error code <0
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* Unzip package allow you browse the directory of the zipfile */
|
||||
|
||||
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the first file.
|
||||
return UNZ_OK if there is no problem
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the next file.
|
||||
return UNZ_OK if there is no problem
|
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzLocateFile OF((unzFile file,
|
||||
const char *szFileName,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Try locate the file szFileName in the zipfile.
|
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare
|
||||
|
||||
return value :
|
||||
UNZ_OK if the file is found. It becomes the current file.
|
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found
|
||||
*/
|
||||
|
||||
|
||||
/* ****************************************** */
|
||||
/* Ryan supplied functions */
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_pos_s
|
||||
{
|
||||
uLong pos_in_zip_directory; /* offset in zip file directory */
|
||||
uLong num_of_file; /* # of file */
|
||||
} unz_file_pos;
|
||||
|
||||
extern int ZEXPORT unzGetFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
extern int ZEXPORT unzGoToFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
|
||||
unz_file_info *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize));
|
||||
/*
|
||||
Get Info about the current file
|
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
|
||||
the current file
|
||||
if szFileName!=NULL, the filemane string will be copied in szFileName
|
||||
(fileNameBufferSize is the size of the buffer)
|
||||
if extraField!=NULL, the extra field information will be copied in extraField
|
||||
(extraFieldBufferSize is the size of the buffer).
|
||||
This is the Central-header version of the extra field
|
||||
if szComment!=NULL, the comment string of the file will be copied in szComment
|
||||
(commentBufferSize is the size of the buffer)
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
|
||||
const char* password));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
password is a crypting password
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw,
|
||||
const char* password));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
|
||||
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile
|
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read bytes from the current file (opened by unzOpenCurrentFile)
|
||||
buf contain buffer where data must be copied
|
||||
len the size of buf.
|
||||
|
||||
return the number of byte copied if somes bytes are copied
|
||||
return 0 if the end of file was reached
|
||||
return <0 with error code if there is an error
|
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
|
||||
*/
|
||||
|
||||
extern z_off_t ZEXPORT unztell OF((unzFile file));
|
||||
/*
|
||||
Give the current position in uncompressed data
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzeof OF((unzFile file));
|
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile)
|
||||
This is the local-header version of the extra field (sometimes, there is
|
||||
more info in the local-header version than in the central-header)
|
||||
|
||||
if buf==NULL, it return the size of the local extra field
|
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in
|
||||
buf.
|
||||
the return value is the number of bytes copied in buf, or (if <0)
|
||||
the error code
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* Get the current file offset */
|
||||
extern uLong ZEXPORT unzGetOffset (unzFile file);
|
||||
|
||||
/* Set the current file offset */
|
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _unz_H */
|
||||
@@ -1,158 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2007-2010 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
|
||||
#include "memptrs.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
MemPtrs::MemPtrs()
|
||||
: rmem_()
|
||||
, wmem_()
|
||||
, romdata_()
|
||||
, wramdata_()
|
||||
, vrambankptr_(0)
|
||||
, rsrambankptr_(0)
|
||||
, wsrambankptr_(0)
|
||||
, memchunk_(0)
|
||||
, rambankdata_(0)
|
||||
, wramdataend_(0)
|
||||
, oamDmaSrc_(oam_dma_src_off)
|
||||
{
|
||||
}
|
||||
|
||||
MemPtrs::~MemPtrs() {
|
||||
delete []memchunk_;
|
||||
}
|
||||
|
||||
void MemPtrs::reset(unsigned const rombanks, unsigned const rambanks, unsigned const wrambanks) {
|
||||
delete []memchunk_;
|
||||
memchunk_ = new unsigned char[
|
||||
0x4000
|
||||
+ rombanks * 0x4000ul
|
||||
+ 0x4000
|
||||
+ rambanks * 0x2000ul
|
||||
+ wrambanks * 0x1000ul
|
||||
+ 0x4000];
|
||||
|
||||
romdata_[0] = romdata();
|
||||
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
|
||||
wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
|
||||
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
|
||||
|
||||
std::memset(rdisabledRamw(), 0xFF, 0x2000);
|
||||
|
||||
oamDmaSrc_ = oam_dma_src_off;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
setRombank(1);
|
||||
setRambank(0, 0);
|
||||
setVrambank(0);
|
||||
setWrambank(1);
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank0(unsigned bank) {
|
||||
romdata_[0] = romdata() + bank * 0x4000ul;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank(unsigned bank) {
|
||||
romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRambank(unsigned const flags, unsigned const rambank) {
|
||||
unsigned char *srambankptr = 0;
|
||||
if (!(flags & rtc_en)) {
|
||||
srambankptr = rambankdata() != rambankdataend()
|
||||
? rambankdata_ + rambank * 0x2000ul - 0xA000
|
||||
: wdisabledRam() - 0xA000;
|
||||
}
|
||||
|
||||
rsrambankptr_ = (flags & read_en) && srambankptr != wdisabledRam() - 0xA000
|
||||
? srambankptr
|
||||
: rdisabledRamw() - 0xA000;
|
||||
wsrambankptr_ = flags & write_en ? srambankptr : wdisabledRam() - 0xA000;
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setWrambank(unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + (bank & 0x07 ? bank & 0x07 : 1) * 0x1000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setOamDmaSrc(OamDmaSrc oamDmaSrc) {
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::disconnectOamDmaAreas() {
|
||||
if (isCgb(*this)) {
|
||||
switch (oamDmaSrc_) {
|
||||
case oam_dma_src_rom: // fall through
|
||||
case oam_dma_src_sram:
|
||||
case oam_dma_src_invalid:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
break;
|
||||
case oam_dma_src_vram:
|
||||
break;
|
||||
case oam_dma_src_wram:
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case oam_dma_src_off:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (oamDmaSrc_) {
|
||||
case oam_dma_src_rom: // fall through
|
||||
case oam_dma_src_sram:
|
||||
case oam_dma_src_wram:
|
||||
case oam_dma_src_invalid:
|
||||
std::fill(rmem_, rmem_ + 8, static_cast<unsigned char *>(0));
|
||||
rmem_[0xB] = rmem_[0xA] = 0;
|
||||
wmem_[0xB] = wmem_[0xA] = 0;
|
||||
rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
|
||||
wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
|
||||
break;
|
||||
case oam_dma_src_vram:
|
||||
break;
|
||||
case oam_dma_src_off:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef LCDDEF_H
|
||||
#define LCDDEF_H
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum { lcdc_bgen = 0x01,
|
||||
lcdc_objen = 0x02,
|
||||
lcdc_obj2x = 0x04,
|
||||
lcdc_tdsel = 0x10,
|
||||
lcdc_we = 0x20,
|
||||
lcdc_en = 0x80 };
|
||||
|
||||
enum { lcdstat_lycflag = 0x04,
|
||||
lcdstat_m0irqen = 0x08,
|
||||
lcdstat_m1irqen = 0x10,
|
||||
lcdstat_m2irqen = 0x20,
|
||||
lcdstat_lycirqen = 0x40 };
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
#ifndef M0_IRQ_H
|
||||
#define M0_IRQ_H
|
||||
|
||||
#include "lcddef.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class M0Irq {
|
||||
public:
|
||||
M0Irq()
|
||||
: statReg_(0)
|
||||
, lycReg_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void lcdReset(unsigned statReg, unsigned lycReg) {
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void statRegChange(unsigned statReg,
|
||||
unsigned long nextM0IrqTime, unsigned long cc, bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 2U)
|
||||
statReg_ = statReg;
|
||||
}
|
||||
|
||||
void lycRegChange(unsigned lycReg,
|
||||
unsigned long nextM0IrqTime, unsigned long cc,
|
||||
bool ds, bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void doEvent(unsigned char *ifreg, unsigned ly, unsigned statReg, unsigned lycReg) {
|
||||
if (((statReg_ | statReg) & lcdstat_m0irqen)
|
||||
&& (!(statReg_ & lcdstat_lycirqen) || ly != lycReg_)) {
|
||||
*ifreg |= 2;
|
||||
}
|
||||
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void saveState(SaveState &state) const {
|
||||
state.ppu.m0lyc = lycReg_;
|
||||
}
|
||||
|
||||
void loadState(SaveState const &state) {
|
||||
lycReg_ = state.ppu.m0lyc;
|
||||
statReg_ = state.mem.ioamhram.get()[0x141];
|
||||
}
|
||||
|
||||
unsigned statReg() const { return statReg_; }
|
||||
|
||||
private:
|
||||
unsigned char statReg_;
|
||||
unsigned char lycReg_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
/*
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef BITMAP_FONT_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "cpu.h"
|
||||
@@ -23,7 +23,7 @@
|
||||
namespace gambatte {
|
||||
|
||||
CPU::CPU()
|
||||
: mem_(Interrupter(sp, pc_))
|
||||
: mem_(Interrupter(sp, pc_, opcode_, prefetched_))
|
||||
, cycleCounter_(0)
|
||||
, pc_(0x100)
|
||||
, sp(0xFFFE)
|
||||
@@ -38,7 +38,8 @@ CPU::CPU()
|
||||
, e(0xD8)
|
||||
, h(0x01)
|
||||
, l(0x4D)
|
||||
, skip_(false)
|
||||
, opcode_(0)
|
||||
, prefetched_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -99,7 +100,9 @@ void CPU::saveState(SaveState &state) {
|
||||
state.cpu.f = toF(hf2, cf, zf);
|
||||
state.cpu.h = h;
|
||||
state.cpu.l = l;
|
||||
state.cpu.skip = skip_;
|
||||
state.cpu.opcode = opcode_;
|
||||
state.cpu.prefetched = prefetched_;
|
||||
state.cpu.skip = false;
|
||||
}
|
||||
|
||||
void CPU::loadState(SaveState const &state) {
|
||||
@@ -118,7 +121,12 @@ void CPU::loadState(SaveState const &state) {
|
||||
cf = cfFromF(state.cpu.f);
|
||||
h = state.cpu.h & 0xFF;
|
||||
l = state.cpu.l & 0xFF;
|
||||
skip_ = state.cpu.skip;
|
||||
opcode_ = state.cpu.opcode;
|
||||
prefetched_ = state.cpu.prefetched;
|
||||
if (state.cpu.skip) {
|
||||
opcode_ = mem_.read(pc_, cycleCounter_);
|
||||
prefetched_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The main reasons for the use of macros is to more conveniently be able to tweak
|
||||
@@ -126,9 +134,9 @@ void CPU::loadState(SaveState const &state) {
|
||||
// time they were written GCC had a tendency to not be able to keep hot variables
|
||||
// in regs if you took an address/reference in an inline function.
|
||||
|
||||
#define bc() ( b << 8 | c )
|
||||
#define de() ( d << 8 | e )
|
||||
#define hl() ( h << 8 | l )
|
||||
#define bc() ( b * 0x100u | c )
|
||||
#define de() ( d * 0x100u | e )
|
||||
#define hl() ( h * 0x100u | l )
|
||||
|
||||
#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter); cycleCounter += 4; } while (0)
|
||||
#define PC_READ(dest) do { (dest) = mem_.read(pc, cycleCounter); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0)
|
||||
@@ -187,7 +195,7 @@ void CPU::loadState(SaveState const &state) {
|
||||
// Rotate 8-bit register right through CF, store old bit0 in CF, old CF value becomes bit7. Reset SF and HCF, Check ZF:
|
||||
#define rr_r(r) do { \
|
||||
unsigned const oldcf = cf & 0x100; \
|
||||
cf = (r) << 8; \
|
||||
cf = (r) * 0x100u; \
|
||||
(r) = zf = ((r) | oldcf) >> 1; \
|
||||
hf2 = 0; \
|
||||
} while (0)
|
||||
@@ -203,7 +211,7 @@ void CPU::loadState(SaveState const &state) {
|
||||
// sra r (8 cycles):
|
||||
// Shift 8-bit register right, store old bit0 in CF. bit7=old bit7. Reset SF and HCF, Check ZF:
|
||||
#define sra_r(r) do { \
|
||||
cf = (r) << 8; \
|
||||
cf = (r) * 0x100u; \
|
||||
zf = (r) >> 1; \
|
||||
(r) = zf | ((r) & 0x80); \
|
||||
hf2 = 0; \
|
||||
@@ -213,7 +221,7 @@ void CPU::loadState(SaveState const &state) {
|
||||
// Shift 8-bit register right, store old bit0 in CF. Reset SF and HCF, Check ZF:
|
||||
#define srl_r(r) do { \
|
||||
zf = (r); \
|
||||
cf = (r) << 8; \
|
||||
cf = (r) * 0x100u; \
|
||||
zf >>= 1; \
|
||||
(r) = zf; \
|
||||
hf2 = 0; \
|
||||
@@ -274,7 +282,7 @@ void CPU::loadState(SaveState const &state) {
|
||||
unsigned const hl = hl(); \
|
||||
unsigned val; \
|
||||
READ(val, hl); \
|
||||
val &= ~(1 << (n)); \
|
||||
val &= ~(1u << (n)); \
|
||||
WRITE(hl, val); \
|
||||
} while (0)
|
||||
|
||||
@@ -290,8 +298,8 @@ void CPU::loadState(SaveState const &state) {
|
||||
// push rr (16 cycles):
|
||||
// Push value of register pair onto stack:
|
||||
#define push_rr(r1, r2) do { \
|
||||
PUSH(r1, r2); \
|
||||
cycleCounter += 4; \
|
||||
PUSH(r1, r2); \
|
||||
} while (0)
|
||||
|
||||
// pop rr (12 cycles):
|
||||
@@ -474,8 +482,8 @@ void CPU::loadState(SaveState const &state) {
|
||||
// rst n (16 Cycles):
|
||||
// Push present address onto stack, jump to address n (one of 00h,08h,10h,18h,20h,28h,30h,38h):
|
||||
#define rst_n(n) do { \
|
||||
PUSH(pc >> 8, pc & 0xFF); \
|
||||
PC_MOD(n); \
|
||||
push_rr(pc >> 8, pc & 0xFF); \
|
||||
pc = (n); \
|
||||
} while (0)
|
||||
|
||||
// ret (16 cycles):
|
||||
@@ -486,6 +494,20 @@ void CPU::loadState(SaveState const &state) {
|
||||
PC_MOD(high << 8 | low); \
|
||||
} while (0)
|
||||
|
||||
namespace {
|
||||
|
||||
unsigned long freeze(Memory &mem, unsigned long cc) {
|
||||
mem.freeze(cc);
|
||||
if (cc < mem.nextEventTime()) {
|
||||
unsigned long cycles = mem.nextEventTime() - cc;
|
||||
cc += cycles + (-cycles & 3);
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CPU::process(unsigned long const cycles) {
|
||||
mem_.setEndtime(cycleCounter_, cycles);
|
||||
mem_.updateInput();
|
||||
@@ -498,17 +520,18 @@ void CPU::process(unsigned long const cycles) {
|
||||
|
||||
if (mem_.halted()) {
|
||||
if (cycleCounter < mem_.nextEventTime()) {
|
||||
unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cycles + (-cycles & 3);
|
||||
unsigned long cpu_cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cpu_cycles + (-cpu_cycles & 3);
|
||||
}
|
||||
} else while (cycleCounter < mem_.nextEventTime()) {
|
||||
unsigned char opcode;
|
||||
|
||||
PC_READ(opcode);
|
||||
|
||||
if (skip_) {
|
||||
pc = (pc - 1) & 0xFFFF;
|
||||
skip_ = false;
|
||||
if (!prefetched_) {
|
||||
PC_READ(opcode);
|
||||
} else {
|
||||
opcode = opcode_;
|
||||
cycleCounter += 4;
|
||||
prefetched_ = false;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
@@ -579,7 +602,7 @@ void CPU::process(unsigned long const cycles) {
|
||||
// rrca (4 cycles):
|
||||
// Rotate 8-bit register A right, store old bit0 in CF. Reset SF, HCF, ZF:
|
||||
case 0x0F:
|
||||
cf = a << 8 | a;
|
||||
cf = a * 0x100u | a;
|
||||
a = cf >> 1 & 0xFF;
|
||||
hf2 = 0;
|
||||
zf = 1;
|
||||
@@ -588,13 +611,11 @@ void CPU::process(unsigned long const cycles) {
|
||||
// stop (4 cycles):
|
||||
// Halt CPU and LCD display until button pressed:
|
||||
case 0x10:
|
||||
pc = (pc + 1) & 0xFFFF;
|
||||
|
||||
cycleCounter = mem_.stop(cycleCounter);
|
||||
|
||||
PC_READ(opcode_);
|
||||
cycleCounter = mem_.stop(cycleCounter - 4, prefetched_);
|
||||
if (cycleCounter < mem_.nextEventTime()) {
|
||||
unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cycles + (-cycles & 3);
|
||||
unsigned long cpu_cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cpu_cycles + (-cpu_cycles & 3);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -660,7 +681,7 @@ void CPU::process(unsigned long const cycles) {
|
||||
case 0x1F:
|
||||
{
|
||||
unsigned oldcf = cf & 0x100;
|
||||
cf = a << 8;
|
||||
cf = a * 0x100u;
|
||||
a = (a | oldcf) >> 1;
|
||||
}
|
||||
|
||||
@@ -994,21 +1015,17 @@ void CPU::process(unsigned long const cycles) {
|
||||
case 0x74: WRITE(hl(), h); break;
|
||||
case 0x75: WRITE(hl(), l); break;
|
||||
|
||||
// halt (4 cycles):
|
||||
// halt (4n cycles):
|
||||
case 0x76:
|
||||
if (!mem_.ime()
|
||||
&& ( mem_.ff_read(0x0F, cycleCounter)
|
||||
& mem_.ff_read(0xFF, cycleCounter) & 0x1F)) {
|
||||
if (mem_.isCgb())
|
||||
cycleCounter += 4;
|
||||
else
|
||||
skip_ = true;
|
||||
opcode_ = mem_.read(pc, cycleCounter);
|
||||
if (mem_.pendingIrqs(cycleCounter)) {
|
||||
prefetched_ = true;
|
||||
} else {
|
||||
mem_.halt();
|
||||
|
||||
prefetched_ = mem_.halt(cycleCounter);
|
||||
cycleCounter += 4 + 4 * !mem_.isCgb();
|
||||
if (cycleCounter < mem_.nextEventTime()) {
|
||||
unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cycles + (-cycles & 3);
|
||||
unsigned long cpu_cycles = mem_.nextEventTime() - cycleCounter;
|
||||
cycleCounter += cpu_cycles + (-cpu_cycles & 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1680,6 +1697,7 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xD3: // not specified. should freeze.
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
// call nc,nn (24;12 cycles):
|
||||
@@ -1747,6 +1765,7 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xDB: // not specified. should freeze.
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
// call z,nn (24;12 cycles):
|
||||
@@ -1797,8 +1816,8 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xE3: // not specified. should freeze.
|
||||
break;
|
||||
case 0xE4: // not specified. should freeze.
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
case 0xE5:
|
||||
@@ -1845,10 +1864,9 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xEB: // not specified. should freeze.
|
||||
break;
|
||||
case 0xEC: // not specified. should freeze.
|
||||
break;
|
||||
case 0xED: // not specified. should freeze.
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
case 0xEE:
|
||||
@@ -1898,6 +1916,7 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xF4: // not specified. should freeze.
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
@@ -1962,9 +1981,10 @@ void CPU::process(unsigned long const cycles) {
|
||||
break;
|
||||
|
||||
case 0xFC: // not specified. should freeze.
|
||||
break;
|
||||
case 0xFD: // not specified. should freeze
|
||||
cycleCounter = freeze(mem_, cycleCounter);
|
||||
break;
|
||||
|
||||
case 0xFE:
|
||||
{
|
||||
unsigned data;
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef CPU_H
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class File;
|
||||
|
||||
class CPU {
|
||||
public:
|
||||
CPU();
|
||||
@@ -53,8 +55,8 @@ public:
|
||||
mem_.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
LoadRes load(std::string const &romfile, bool forceDmg, bool multicartCompat) {
|
||||
return mem_.loadROM(romfile, forceDmg, multicartCompat);
|
||||
LoadRes load(File &file, std::string const &filename, bool forceDmg, bool multicartCompat) {
|
||||
return mem_.loadROM(file, filename, forceDmg, multicartCompat);
|
||||
}
|
||||
|
||||
bool loaded() const { return mem_.loaded(); }
|
||||
@@ -64,6 +66,10 @@ public:
|
||||
std::size_t fillSoundBuffer() { return mem_.fillSoundBuffer(cycleCounter_); }
|
||||
bool isCgb() const { return mem_.isCgb(); }
|
||||
|
||||
void setCgbColorCorrection(int optNum) {
|
||||
mem_.setCgbColorCorrection(optNum);
|
||||
}
|
||||
|
||||
void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
||||
mem_.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
@@ -78,7 +84,8 @@ private:
|
||||
unsigned short sp;
|
||||
unsigned hf1, hf2, zf, cf;
|
||||
unsigned char a_, b, c, d, e, /*f,*/ h, l;
|
||||
bool skip_;
|
||||
unsigned char opcode_;
|
||||
bool prefetched_;
|
||||
|
||||
void process(unsigned long cycles);
|
||||
};
|
||||
@@ -17,7 +17,7 @@ GNU General Public License version 2 for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
***************************************************************************/
|
||||
#include "stdfile.h"
|
||||
|
||||
@@ -17,7 +17,7 @@ GNU General Public License version 2 for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_FILE_H
|
||||
#define GAMBATTE_FILE_H
|
||||
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
Copyright (C) 2007 by Nach
|
||||
http://nsrt.edgeemu.com
|
||||
|
||||
Copyright (C) 2007-2011 by sinamas <sinamas at users.sourceforge.net>
|
||||
sinamas@users.sourceforge.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
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 version 2 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_MEMFILE_H
|
||||
#define GAMBATTE_MEMFILE_H
|
||||
|
||||
#include <string.h>
|
||||
#include "file.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class MemFile : public File {
|
||||
public:
|
||||
explicit MemFile(const void *data, size_t size)
|
||||
: data_(static_cast<const char*>(data))
|
||||
, size_(size)
|
||||
, offset_(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void read(char *buffer, size_t amount) {
|
||||
size_t remaining = size_ - offset_;
|
||||
size_t bytes_to_read = amount < remaining ? amount : remaining;
|
||||
memcpy(buffer, data_ + offset_, bytes_to_read);
|
||||
offset_ += bytes_to_read;
|
||||
}
|
||||
|
||||
virtual void rewind() { offset_ = 0; }
|
||||
virtual size_t size() const { return size_; };
|
||||
virtual bool fail() const { return false; }
|
||||
|
||||
private:
|
||||
const char *data_;
|
||||
size_t size_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ GNU General Public License version 2 for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
version 2 along with this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
***************************************************************************/
|
||||
#ifndef GAMBATTE_STD_FILE_H
|
||||
#define GAMBATTE_STD_FILE_H
|
||||
@@ -13,29 +13,36 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "file/file.h"
|
||||
#include "file/memfile.h"
|
||||
#include "gambatte.h"
|
||||
#include "cpu.h"
|
||||
#include "initstate.h"
|
||||
#include "savestate.h"
|
||||
#include "state_osd_elements.h"
|
||||
#include "statesaver.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
static std::string const itos(int i) {
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string to_string(int i) {
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string const statePath(std::string const &basePath, int stateNo) {
|
||||
return basePath + "_" + itos(stateNo) + ".gqs";
|
||||
std::string statePath(std::string const &basePath, int stateNo) {
|
||||
return basePath + '_' + to_string(stateNo) + ".gqs";
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
}
|
||||
|
||||
struct GB::Priv {
|
||||
CPU cpu;
|
||||
@@ -91,11 +98,24 @@ void GB::setSaveDir(std::string const &sdir) {
|
||||
p_->cpu.setSaveDir(sdir);
|
||||
}
|
||||
|
||||
LoadRes GB::load(std::string const &romfile, unsigned const flags) {
|
||||
LoadRes GB::load(const void *rom,
|
||||
size_t size,
|
||||
std::string const &filename,
|
||||
unsigned const flags) {
|
||||
MemFile file(rom, size);
|
||||
return load(file, filename, flags);
|
||||
}
|
||||
|
||||
LoadRes GB::load(std::string const &filename, unsigned const flags) {
|
||||
transfer_ptr<File> file = newFileInstance(filename);
|
||||
return load(*file, filename, flags);
|
||||
}
|
||||
|
||||
LoadRes GB::load(File &file, std::string const &filename, unsigned const flags) {
|
||||
if (p_->cpu.loaded())
|
||||
p_->cpu.saveSavedata();
|
||||
|
||||
LoadRes const loadres = p_->cpu.load(romfile,
|
||||
LoadRes const loadres = p_->cpu.load(file, filename,
|
||||
flags & FORCE_DMG,
|
||||
flags & MULTICART_COMPAT);
|
||||
if (loadres == LOADRES_OK) {
|
||||
@@ -126,10 +146,15 @@ void GB::saveSavedata() {
|
||||
p_->cpu.saveSavedata();
|
||||
}
|
||||
|
||||
void GB::setCgbColorCorrection(int optNum) {
|
||||
p_->cpu.setCgbColorCorrection(optNum);
|
||||
}
|
||||
|
||||
void GB::setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
||||
p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
|
||||
//> OpenEmu
|
||||
bool GB::serializeState(std::ostream &stream) {
|
||||
if (p_->cpu.loaded()) {
|
||||
SaveState state;
|
||||
@@ -137,31 +162,32 @@ bool GB::serializeState(std::ostream &stream) {
|
||||
p_->cpu.saveState(state);
|
||||
return StateSaver::serializeState(state, stream);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GB::deserializeState(std::istream &stream) {
|
||||
if (p_->cpu.loaded()) {
|
||||
p_->cpu.saveSavedata();
|
||||
|
||||
|
||||
SaveState state;
|
||||
p_->cpu.setStatePtrs(state);
|
||||
|
||||
|
||||
if (StateSaver::deserializeState(state, stream)) {
|
||||
p_->cpu.loadState(state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//< OpenEmu
|
||||
bool GB::loadState(std::string const &filepath) {
|
||||
if (p_->cpu.loaded()) {
|
||||
p_->cpu.saveSavedata();
|
||||
|
||||
SaveState state;
|
||||
SaveState state = SaveState();
|
||||
p_->cpu.setStatePtrs(state);
|
||||
|
||||
if (StateSaver::loadState(state, filepath)) {
|
||||
@@ -235,5 +261,3 @@ void GB::setGameGenie(std::string const &codes) {
|
||||
void GB::setGameShark(std::string const &codes) {
|
||||
p_->cpu.setGameShark(codes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef GAMBATTE_H
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class File;
|
||||
|
||||
enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 };
|
||||
|
||||
class GB {
|
||||
@@ -52,6 +54,17 @@ public:
|
||||
*/
|
||||
LoadRes load(std::string const &romfile, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* Load an in-memory ROM image.
|
||||
*
|
||||
* @param rom The ROM image data to load.
|
||||
* @param size The size of the ROM image, in bytes.
|
||||
* @param filename A filename, which is only used for naming save files.
|
||||
* @param flags ORed combination of LoadFlags.
|
||||
* @return 0 on success, negative value on failure.
|
||||
*/
|
||||
LoadRes load(const void *rom, size_t size, std::string const &filename, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* Emulates until at least 'samples' audio samples are produced in the
|
||||
* supplied audio buffer, or until a video frame has been drawn.
|
||||
@@ -89,6 +102,11 @@ public:
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @param optNum 0 <= palNum < 1
|
||||
*/
|
||||
void setCgbColorCorrection(int optNum);
|
||||
|
||||
/**
|
||||
* @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
|
||||
* @param colorNum 0 <= colorNum < 4
|
||||
@@ -111,18 +129,20 @@ public:
|
||||
bool isLoaded() const;
|
||||
|
||||
/** Writes persistent cartridge data to disk. Done implicitly on ROM close. */
|
||||
void saveSavedata();
|
||||
|
||||
void saveSavedata();
|
||||
|
||||
//> OpenEmu
|
||||
/** Serializes state data to 'stream'
|
||||
* @return success
|
||||
*/
|
||||
bool serializeState(std::ostream &stream);
|
||||
|
||||
|
||||
/** Deserializes state data from 'stream'.
|
||||
* @return success
|
||||
*/
|
||||
bool deserializeState(std::istream &stream);
|
||||
|
||||
//< OpenEmu
|
||||
/**
|
||||
* Saves emulator state to the state slot selected with selectState().
|
||||
* The data will be stored in the directory given by setSaveDir().
|
||||
@@ -191,6 +211,8 @@ public:
|
||||
void setGameShark(std::string const &codes);
|
||||
|
||||
private:
|
||||
LoadRes load(File &file, std::string const &filename, unsigned flags);
|
||||
|
||||
struct Priv;
|
||||
Priv *const p_;
|
||||
|
||||
@@ -13,23 +13,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef GAMBATTE_INT_H
|
||||
#define GAMBATTE_INT_H
|
||||
|
||||
#ifdef HAVE_CSTDINT
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace gambatte {
|
||||
using std::uint_least32_t;
|
||||
using std::uint_least16_t;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_STDINT_H)
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace gambatte {
|
||||
@@ -37,26 +26,4 @@ using ::uint_least32_t;
|
||||
using ::uint_least16_t;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace gambatte {
|
||||
#ifdef CHAR_LEAST_32
|
||||
typedef unsigned char uint_least32_t;
|
||||
#elif defined(SHORT_LEAST_32)
|
||||
typedef unsigned short uint_least32_t;
|
||||
#elif defined(INT_LEAST_32)
|
||||
typedef unsigned uint_least32_t;
|
||||
#else
|
||||
typedef unsigned long uint_least32_t;
|
||||
#endif
|
||||
|
||||
#ifdef CHAR_LEAST_16
|
||||
typedef unsigned char uint_least16_t;
|
||||
#else
|
||||
typedef unsigned short uint_least16_t;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -13,13 +13,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "initstate.h"
|
||||
#include "counterdef.h"
|
||||
#include "savestate.h"
|
||||
#include "sound/sound_unit.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
@@ -1178,6 +1179,8 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
|
||||
state.cpu.f = 0xB0;
|
||||
state.cpu.h = 0x01;
|
||||
state.cpu.l = 0x4D;
|
||||
state.cpu.opcode = 0x00;
|
||||
state.cpu.prefetched = false;
|
||||
state.cpu.skip = false;
|
||||
|
||||
std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.size());
|
||||
@@ -1192,11 +1195,14 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
|
||||
setInitialDmgIoamhram(state.mem.ioamhram.ptr);
|
||||
}
|
||||
|
||||
state.mem.ioamhram.ptr[0x104] = 0x1C;
|
||||
state.mem.ioamhram.ptr[0x104] = 0x00;
|
||||
state.mem.ioamhram.ptr[0x140] = 0x91;
|
||||
state.mem.ioamhram.ptr[0x144] = 0x00;
|
||||
|
||||
state.mem.divLastUpdate = 0;
|
||||
// DIV, TIMA, and the PSG frame sequencer are clocked by bits of the
|
||||
// cycle counter less divLastUpdate (equivalent to a counter that is
|
||||
// reset on DIV write).
|
||||
state.mem.divLastUpdate = -0x1C00;
|
||||
state.mem.timaLastUpdate = 0;
|
||||
state.mem.tmatime = disabled_time;
|
||||
state.mem.nextSerialtime = disabled_time;
|
||||
@@ -1208,13 +1214,13 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
|
||||
state.mem.dmaDestination = 0;
|
||||
state.mem.rambank = 0;
|
||||
state.mem.oamDmaPos = 0xFE;
|
||||
state.mem.haltHdmaState = 0;
|
||||
state.mem.IME = false;
|
||||
state.mem.halted = false;
|
||||
state.mem.enableRam = false;
|
||||
state.mem.rambankMode = false;
|
||||
state.mem.hdmaTransfer = false;
|
||||
|
||||
|
||||
for (int i = 0x00; i < 0x40; i += 0x02) {
|
||||
state.ppu.bgpData.ptr[i ] = 0xFF;
|
||||
state.ppu.bgpData.ptr[i + 1] = 0x7F;
|
||||
@@ -1261,11 +1267,12 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
|
||||
|
||||
// spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
state.spu.cycleCounter = (cgb ? 0x1E00 : 0x2400) | (state.cpu.cycleCounter >> 1 & 0x1FF);
|
||||
state.spu.lastUpdate = 0;
|
||||
|
||||
state.spu.ch1.sweep.counter = SoundUnit::counter_disabled;
|
||||
state.spu.ch1.sweep.shadow = 0;
|
||||
state.spu.ch1.sweep.nr0 = 0;
|
||||
state.spu.ch1.sweep.negging = false;
|
||||
state.spu.ch1.sweep.neg = false;
|
||||
if (cgb) {
|
||||
state.spu.ch1.duty.nextPosUpdate = (state.spu.cycleCounter & ~1ul) + 37 * 2;
|
||||
state.spu.ch1.duty.pos = 6;
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef INITSTATE_H
|
||||
Executable → Regular
+1
-1
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef GAMBATTE_INPUTGETTER_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef INSERTION_SORT_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "interrupter.h"
|
||||
@@ -21,21 +21,47 @@
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
Interrupter::Interrupter(unsigned short &sp, unsigned short &pc)
|
||||
Interrupter::Interrupter(unsigned short &sp, unsigned short &pc, unsigned char &opcode, bool &prefetched)
|
||||
: sp_(sp)
|
||||
, pc_(pc)
|
||||
, opcode_(opcode)
|
||||
, prefetched_(prefetched)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long Interrupter::interrupt(unsigned const address, unsigned long cc, Memory &memory) {
|
||||
cc += 8;
|
||||
void Interrupter::prefetch(unsigned long cc, Memory &mem) {
|
||||
if (!prefetched_) {
|
||||
opcode_ = mem.read(pc_, cc);
|
||||
pc_ = (pc_ + 1) & 0xFFFF;
|
||||
prefetched_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long Interrupter::interrupt(unsigned long cc, Memory &memory) {
|
||||
// undo prefetch (presumably unconditional on hw).
|
||||
if (prefetched_) {
|
||||
pc_ = (pc_ - 1) & 0xFFFF;
|
||||
prefetched_ = false;
|
||||
}
|
||||
cc += 12;
|
||||
sp_ = (sp_ - 1) & 0xFFFF;
|
||||
memory.write(sp_, pc_ >> 8, cc);
|
||||
cc += 4;
|
||||
|
||||
unsigned const pendingIrqs = memory.pendingIrqs(cc);
|
||||
unsigned const n = pendingIrqs & -pendingIrqs;
|
||||
unsigned address;
|
||||
if (n <= 4) {
|
||||
static unsigned char const lut[] = { 0x00, 0x40, 0x48, 0x48, 0x50 };
|
||||
address = lut[n];
|
||||
} else
|
||||
address = 0x50 + n;
|
||||
|
||||
sp_ = (sp_ - 1) & 0xFFFF;
|
||||
memory.write(sp_, pc_ & 0xFF, cc);
|
||||
memory.ackIrq(n, cc);
|
||||
pc_ = address;
|
||||
cc += 8;
|
||||
cc += 4;
|
||||
|
||||
if (address == 0x40 && !gsCodes_.empty())
|
||||
applyVblankCheats(cc, memory);
|
||||
@@ -52,6 +78,8 @@ void Interrupter::setGameShark(std::string const &codes) {
|
||||
gsCodes_.clear();
|
||||
|
||||
for (std::size_t pos = 0; pos < codes.length(); pos += code.length() + 1) {
|
||||
// OpenEmu
|
||||
//code = codes.substr(pos, codes.find(';', pos) - pos);
|
||||
code = codes.substr(pos, codes.find('+', pos) - pos);
|
||||
if (code.length() >= 8) {
|
||||
GsCode gs;
|
||||
@@ -68,6 +96,8 @@ void Interrupter::setGameShark(std::string const &codes) {
|
||||
|
||||
void Interrupter::applyVblankCheats(unsigned long const cc, Memory &memory) {
|
||||
for (std::size_t i = 0, size = gsCodes_.size(); i < size; ++i) {
|
||||
// OpenEmu
|
||||
//if (gsCodes_[i].type == 0x01)
|
||||
if (gsCodes_[i].type == 0x01 || gsCodes_[i].type == 0x91)
|
||||
memory.write(gsCodes_[i].address, gsCodes_[i].value, cc);
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef INTERRUPTER_H
|
||||
@@ -34,13 +34,16 @@ class Memory;
|
||||
|
||||
class Interrupter {
|
||||
public:
|
||||
Interrupter(unsigned short &sp, unsigned short &pc);
|
||||
unsigned long interrupt(unsigned address, unsigned long cycleCounter, Memory &memory);
|
||||
Interrupter(unsigned short &sp, unsigned short &pc, unsigned char &opcode, bool &prefetched);
|
||||
void prefetch(unsigned long cc, Memory &mem);
|
||||
unsigned long interrupt(unsigned long cycleCounter, Memory &memory);
|
||||
void setGameShark(std::string const &codes);
|
||||
|
||||
private:
|
||||
unsigned short &sp_;
|
||||
unsigned short &pc_;
|
||||
unsigned char &opcode_;
|
||||
bool &prefetched_;
|
||||
std::vector<GsCode> gsCodes_;
|
||||
|
||||
void applyVblankCheats(unsigned long cc, Memory &mem);
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "interruptrequester.h"
|
||||
@@ -89,9 +89,14 @@ void InterruptRequester::flagIrq(unsigned bit) {
|
||||
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
|
||||
}
|
||||
|
||||
void InterruptRequester::ackIrq(unsigned bit) {
|
||||
ifreg_ ^= bit;
|
||||
di();
|
||||
void InterruptRequester::flagIrq(unsigned bit, unsigned long cc) {
|
||||
unsigned const prevPending = pendingIrqs();
|
||||
ifreg_ |= bit;
|
||||
|
||||
if (!prevPending && pendingIrqs() && intFlags_.imeOrHalted()) {
|
||||
minIntTime_ = std::max(minIntTime_, cc);
|
||||
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
|
||||
}
|
||||
}
|
||||
|
||||
void InterruptRequester::setIereg(unsigned iereg) {
|
||||
@@ -114,4 +119,11 @@ void InterruptRequester::setIfreg(unsigned ifreg) {
|
||||
}
|
||||
}
|
||||
|
||||
void InterruptRequester::setMinIntTime(unsigned long cc) {
|
||||
minIntTime_ = cc;
|
||||
|
||||
if (eventTimes_.value(intevent_interrupts) < minIntTime_)
|
||||
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef INTERRUPT_REQUESTER_H
|
||||
@@ -51,9 +51,11 @@ public:
|
||||
void halt();
|
||||
void unhalt();
|
||||
void flagIrq(unsigned bit);
|
||||
void ackIrq(unsigned bit);
|
||||
void flagIrq(unsigned bit, unsigned long cc);
|
||||
void ackIrq(unsigned bit) { ifreg_ &= ~bit; }
|
||||
void setIereg(unsigned iereg);
|
||||
void setIfreg(unsigned ifreg);
|
||||
void setMinIntTime(unsigned long cc);
|
||||
|
||||
IntEventId minEventId() const { return static_cast<IntEventId>(eventTimes_.min()); }
|
||||
unsigned long minEventTime() const { return eventTimes_.minValue(); }
|
||||
@@ -69,9 +71,9 @@ private:
|
||||
bool halted() const { return flags_ & flag_halted; }
|
||||
bool imeOrHalted() const { return flags_; }
|
||||
void setIme() { flags_ |= flag_ime; }
|
||||
void unsetIme() { flags_ &= ~flag_ime; }
|
||||
void unsetIme() { flags_ &= ~(1u * flag_ime); }
|
||||
void setHalted() { flags_ |= flag_halted; }
|
||||
void unsetHalted() { flags_ &= ~flag_halted; }
|
||||
void unsetHalted() { flags_ &= ~(1u * flag_halted); }
|
||||
void set(bool ime, bool halted) { flags_ = halted * flag_halted + ime * flag_ime; }
|
||||
|
||||
private:
|
||||
@@ -13,28 +13,32 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "cartridge.h"
|
||||
#include "file/file.h"
|
||||
// OpenEmu
|
||||
//#include "file/file.h"
|
||||
#include "../file/file.h"
|
||||
#include "../savestate.h"
|
||||
#include "pakinfo_internal.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
static unsigned toMulti64Rombank(unsigned rombank) {
|
||||
unsigned toMulti64Rombank(unsigned rombank) {
|
||||
return (rombank >> 1 & 0x30) | (rombank & 0xF);
|
||||
}
|
||||
|
||||
class DefaultMbc : public Mbc {
|
||||
public:
|
||||
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
||||
return (addr< 0x4000) == (bank == 0);
|
||||
return (addr < 0x4000) == (bank == 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,12 +71,12 @@ private:
|
||||
bool enableRam_;
|
||||
};
|
||||
|
||||
static inline unsigned rambanks(MemPtrs const &memptrs) {
|
||||
return std::size_t(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
|
||||
inline unsigned rambanks(MemPtrs const &memptrs) {
|
||||
return (memptrs.rambankdataend() - memptrs.rambankdata()) / rambank_size();
|
||||
}
|
||||
|
||||
static inline unsigned rombanks(MemPtrs const &memptrs) {
|
||||
return std::size_t(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
|
||||
inline unsigned rombanks(MemPtrs const &memptrs) {
|
||||
return (memptrs.romdataend() - memptrs.romdata()) / rombank_size();
|
||||
}
|
||||
|
||||
class Mbc1 : public DefaultMbc {
|
||||
@@ -107,8 +111,7 @@ public:
|
||||
|
||||
break;
|
||||
case 3:
|
||||
// Pretty sure this should take effect immediately, but I have a policy not to change old behavior
|
||||
// unless I have something (eg. a verified test or a game) that justifies it.
|
||||
// Should this take effect immediately rather?
|
||||
rambankMode_ = data & 1;
|
||||
break;
|
||||
}
|
||||
@@ -448,22 +451,82 @@ private:
|
||||
unsigned char rambank_;
|
||||
bool enableRam_;
|
||||
|
||||
static unsigned adjustedRombank(unsigned bank) { return bank ? bank : 1; }
|
||||
|
||||
void setRambank() const {
|
||||
memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0,
|
||||
rambank_ & (rambanks(memptrs_) - 1));
|
||||
}
|
||||
|
||||
void setRombank() const { memptrs_.setRombank(adjustedRombank(rombank_) & (rombanks(memptrs_) - 1)); }
|
||||
void setRombank() const { memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1)); }
|
||||
};
|
||||
|
||||
static bool hasRtc(unsigned headerByte0x147) {
|
||||
std::string stripExtension(std::string const &str) {
|
||||
std::string::size_type const lastDot = str.find_last_of('.');
|
||||
std::string::size_type const lastSlash = str.find_last_of('/');
|
||||
|
||||
if (lastDot != std::string::npos && (lastSlash == std::string::npos || lastSlash < lastDot))
|
||||
return str.substr(0, lastDot);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string stripDir(std::string const &str) {
|
||||
std::string::size_type const lastSlash = str.find_last_of('/');
|
||||
if (lastSlash != std::string::npos)
|
||||
return str.substr(lastSlash + 1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void enforce8bit(unsigned char *data, std::size_t size) {
|
||||
if (static_cast<unsigned char>(0x100))
|
||||
while (size--)
|
||||
*data++ &= 0xFF;
|
||||
}
|
||||
|
||||
unsigned pow2ceil(unsigned n) {
|
||||
--n;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
bool presumedMulti64Mbc1(unsigned char const header[], unsigned rombanks) {
|
||||
return header[0x147] == 1 && header[0x149] == 0 && rombanks == 64;
|
||||
}
|
||||
|
||||
bool hasBattery(unsigned char headerByte0x147) {
|
||||
switch (headerByte0x147) {
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
case 0x09:
|
||||
case 0x0F:
|
||||
case 0x10:
|
||||
case 0x13:
|
||||
case 0x1B:
|
||||
case 0x1E:
|
||||
case 0xFF:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasRtc(unsigned headerByte0x147) {
|
||||
switch (headerByte0x147) {
|
||||
case 0x0F:
|
||||
case 0x10: return true;
|
||||
default: return false;
|
||||
case 0x10:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int asHex(char c) {
|
||||
return c >= 'A' ? c - 'A' + 0xA : c - '0';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -484,24 +547,6 @@ void Cartridge::loadState(SaveState const &state) {
|
||||
mbc_->loadState(state.mem);
|
||||
}
|
||||
|
||||
static std::string const stripExtension(std::string const &str) {
|
||||
std::string::size_type const lastDot = str.find_last_of('.');
|
||||
std::string::size_type const lastSlash = str.find_last_of('/');
|
||||
|
||||
if (lastDot != std::string::npos && (lastSlash == std::string::npos || lastSlash < lastDot))
|
||||
return str.substr(0, lastDot);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string const stripDir(std::string const &str) {
|
||||
std::string::size_type const lastSlash = str.find_last_of('/');
|
||||
if (lastSlash != std::string::npos)
|
||||
return str.substr(lastSlash + 1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string const Cartridge::saveBasePath() const {
|
||||
return saveDir_.empty()
|
||||
? defaultSaveBasePath_
|
||||
@@ -514,33 +559,12 @@ void Cartridge::setSaveDir(std::string const &dir) {
|
||||
saveDir_ += '/';
|
||||
}
|
||||
|
||||
static void enforce8bit(unsigned char *data, std::size_t size) {
|
||||
if (static_cast<unsigned char>(0x100))
|
||||
while (size--)
|
||||
*data++ &= 0xFF;
|
||||
}
|
||||
|
||||
static unsigned pow2ceil(unsigned n) {
|
||||
--n;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool presumedMulti64Mbc1(unsigned char const header[], unsigned rombanks) {
|
||||
return header[0x147] == 1 && header[0x149] == 0 && rombanks == 64;
|
||||
}
|
||||
|
||||
LoadRes Cartridge::loadROM(std::string const &romfile,
|
||||
LoadRes Cartridge::loadROM(File &file,
|
||||
std::string const &filename,
|
||||
bool const forceDmg,
|
||||
bool const multicartCompat)
|
||||
{
|
||||
scoped_ptr<File> const rom(newFileInstance(romfile));
|
||||
if (rom->fail())
|
||||
if (file.fail())
|
||||
return LOADRES_IO_ERROR;
|
||||
|
||||
enum Cartridgetype { type_plain,
|
||||
@@ -556,7 +580,7 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
||||
|
||||
{
|
||||
unsigned char header[0x150];
|
||||
rom->read(reinterpret_cast<char *>(header), sizeof header);
|
||||
file.read(reinterpret_cast<char *>(header), sizeof header);
|
||||
|
||||
switch (header[0x0147]) {
|
||||
case 0x00: type = type_plain; break;
|
||||
@@ -613,7 +637,7 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
||||
cgb = header[0x0143] >> 7 & (1 ^ forceDmg);
|
||||
}
|
||||
|
||||
std::size_t const filesize = rom->size();
|
||||
std::size_t const filesize = file.size();
|
||||
rombanks = std::max(pow2ceil(filesize / 0x4000), 2u);
|
||||
|
||||
defaultSaveBasePath_.clear();
|
||||
@@ -622,17 +646,17 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
||||
memptrs_.reset(rombanks, rambanks, cgb ? 8 : 2);
|
||||
rtc_.set(false, 0);
|
||||
|
||||
rom->rewind();
|
||||
rom->read(reinterpret_cast<char*>(memptrs_.romdata()), filesize / 0x4000 * 0x4000ul);
|
||||
file.rewind();
|
||||
file.read(reinterpret_cast<char*>(memptrs_.romdata()), filesize / 0x4000 * 0x4000ul);
|
||||
std::memset(memptrs_.romdata() + filesize / 0x4000 * 0x4000ul,
|
||||
0xFF,
|
||||
(rombanks - filesize / 0x4000) * 0x4000ul);
|
||||
enforce8bit(memptrs_.romdata(), rombanks * 0x4000ul);
|
||||
|
||||
if (rom->fail())
|
||||
if (file.fail())
|
||||
return LOADRES_IO_ERROR;
|
||||
|
||||
defaultSaveBasePath_ = stripExtension(romfile);
|
||||
defaultSaveBasePath_ = stripExtension(filename);
|
||||
|
||||
switch (type) {
|
||||
case type_plain: mbc_.reset(new Mbc0(memptrs_)); break;
|
||||
@@ -654,21 +678,6 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
||||
return LOADRES_OK;
|
||||
}
|
||||
|
||||
static bool hasBattery(unsigned char headerByte0x147) {
|
||||
switch (headerByte0x147) {
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
case 0x09:
|
||||
case 0x0F:
|
||||
case 0x10:
|
||||
case 0x13:
|
||||
case 0x1B:
|
||||
case 0x1E:
|
||||
case 0xFF: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::loadSavedata() {
|
||||
std::string const &sbp = saveBasePath();
|
||||
|
||||
@@ -713,10 +722,6 @@ void Cartridge::saveSavedata() {
|
||||
}
|
||||
}
|
||||
|
||||
static int asHex(char c) {
|
||||
return c >= 'A' ? c - 'A' + 0xA : c - '0';
|
||||
}
|
||||
|
||||
void Cartridge::applyGameGenie(std::string const &code) {
|
||||
if (6 < code.length()) {
|
||||
unsigned const val = (asHex(code[0]) << 4 | asHex(code[1])) & 0xFF;
|
||||
@@ -730,12 +735,12 @@ void Cartridge::applyGameGenie(std::string const &code) {
|
||||
cmp = ((cmp >> 2 | cmp << 6) ^ 0x45) & 0xFF;
|
||||
}
|
||||
|
||||
for (unsigned bank = 0; bank < std::size_t(memptrs_.romdataend() - memptrs_.romdata()) / 0x4000; ++bank) {
|
||||
for (unsigned bank = 0; bank < rombanks(memptrs_); ++bank) {
|
||||
if (mbc_->isAddressWithinAreaRombankCanBeMappedTo(addr, bank)
|
||||
&& (cmp > 0xFF || memptrs_.romdata()[bank * 0x4000ul + (addr & 0x3FFF)] == cmp)) {
|
||||
ggUndoList_.push_back(AddrData(bank * 0x4000ul + (addr & 0x3FFF),
|
||||
memptrs_.romdata()[bank * 0x4000ul + (addr & 0x3FFF)]));
|
||||
memptrs_.romdata()[bank * 0x4000ul + (addr & 0x3FFF)] = val;
|
||||
&& (cmp > 0xFF || memptrs_.romdata()[bank * rombank_size() + addr % rombank_size()] == cmp)) {
|
||||
ggUndoList_.push_back(AddrData(bank * rombank_size() + addr % rombank_size(),
|
||||
memptrs_.romdata()[bank * rombank_size() + addr % rombank_size()]));
|
||||
memptrs_.romdata()[bank * rombank_size() + addr % rombank_size()] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -753,6 +758,8 @@ void Cartridge::setGameGenie(std::string const &codes) {
|
||||
|
||||
std::string code;
|
||||
for (std::size_t pos = 0; pos < codes.length(); pos += code.length() + 1) {
|
||||
// OpenEmu
|
||||
//code = codes.substr(pos, codes.find(';', pos) - pos);
|
||||
code = codes.substr(pos, codes.find('+', pos) - pos);
|
||||
applyGameGenie(code);
|
||||
}
|
||||
@@ -769,5 +776,3 @@ PakInfo const Cartridge::pakInfo(bool const multipakCompat) const {
|
||||
|
||||
return PakInfo();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef CARTRIDGE_H
|
||||
@@ -24,11 +24,14 @@
|
||||
#include "rtc.h"
|
||||
#include "savestate.h"
|
||||
#include "scoped_ptr.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class File;
|
||||
|
||||
class Mbc {
|
||||
public:
|
||||
virtual ~Mbc() {}
|
||||
@@ -54,6 +57,7 @@ public:
|
||||
unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); }
|
||||
unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); }
|
||||
OamDmaSrc oamDmaSrc() const { return memptrs_.oamDmaSrc(); }
|
||||
bool isInOamDmaConflictArea(unsigned p) const { return memptrs_.isInOamDmaConflictArea(p); }
|
||||
void setVrambank(unsigned bank) { memptrs_.setVrambank(bank); }
|
||||
void setWrambank(unsigned bank) { memptrs_.setWrambank(bank); }
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs_.setOamDmaSrc(oamDmaSrc); }
|
||||
@@ -65,7 +69,7 @@ public:
|
||||
void saveSavedata();
|
||||
std::string const saveBasePath() const;
|
||||
void setSaveDir(std::string const &dir);
|
||||
LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
|
||||
LoadRes loadROM(File &file, std::string const &filename, bool forceDmg, bool multicartCompat);
|
||||
char const * romTitle() const { return reinterpret_cast<char const *>(memptrs_.romdata() + 0x134); }
|
||||
class PakInfo const pakInfo(bool multicartCompat) const;
|
||||
void setGameGenie(std::string const &codes);
|
||||
@@ -74,7 +78,7 @@ private:
|
||||
struct AddrData {
|
||||
unsigned long addr;
|
||||
unsigned char data;
|
||||
AddrData(unsigned long addr, unsigned data) : addr(addr), data(data) {}
|
||||
AddrData(unsigned long _addr, unsigned _data) : addr(_addr), data(_data) {}
|
||||
};
|
||||
|
||||
MemPtrs memptrs_;
|
||||
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// Copyright (C) 2007-2010 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "memptrs.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
template <OamDmaSrc src, bool cgb> struct OamDmaConflictMap;
|
||||
template <bool cgb> struct OamDmaConflictMap<oam_dma_src_rom, cgb> { enum { r = 0xFCFF }; };
|
||||
template <bool cgb> struct OamDmaConflictMap<oam_dma_src_sram, cgb> { enum { r = 0xFCFF }; };
|
||||
template <bool cgb> struct OamDmaConflictMap<oam_dma_src_vram, cgb> { enum { r = 0x0300 }; };
|
||||
template <bool cgb> struct OamDmaConflictMap<oam_dma_src_wram, cgb> { enum { r = cgb ? 0xF000 : 0xFCFF }; };
|
||||
template <bool cgb> struct OamDmaConflictMap<oam_dma_src_invalid, cgb> { enum { r = cgb ? 0xFCFF : 0x0000 }; };
|
||||
|
||||
template <bool cgb>
|
||||
bool isInOamDmaConflictArea(OamDmaSrc src, unsigned p)
|
||||
{
|
||||
static unsigned short const m[] = {
|
||||
OamDmaConflictMap<oam_dma_src_rom, cgb>::r,
|
||||
OamDmaConflictMap<oam_dma_src_sram, cgb>::r,
|
||||
OamDmaConflictMap<oam_dma_src_vram, cgb>::r,
|
||||
OamDmaConflictMap<oam_dma_src_wram, cgb>::r,
|
||||
OamDmaConflictMap<oam_dma_src_invalid, cgb>::r,
|
||||
0 };
|
||||
return p < mm_oam_begin && (m[src] >> (p >> 12) & 1);
|
||||
}
|
||||
|
||||
template <OamDmaSrc src, bool cgb>
|
||||
void disconnectOamDmaAreas(unsigned char const *(&rmem)[0x10], unsigned char *(&wmem)[0x10])
|
||||
{
|
||||
if (OamDmaConflictMap<src, cgb>::r & 0x00FF)
|
||||
std::fill_n(rmem, 8, static_cast<unsigned char *>(0));
|
||||
if (OamDmaConflictMap<src, cgb>::r & 0x0C00)
|
||||
rmem[0xB] = rmem[0xA] = wmem[0xB] = wmem[0xA] = 0;
|
||||
if (OamDmaConflictMap<src, cgb>::r & 0x7000)
|
||||
rmem[0xE] = rmem[0xD] = rmem[0xC] = wmem[0xE] = wmem[0xD] = wmem[0xC] = 0;
|
||||
}
|
||||
|
||||
template <bool cgb>
|
||||
void disconnectOamDmaAreas(unsigned char const *(&rmem)[0x10], unsigned char *(&wmem)[0x10],
|
||||
OamDmaSrc src)
|
||||
{
|
||||
switch (src) {
|
||||
case oam_dma_src_rom: disconnectOamDmaAreas<oam_dma_src_rom, cgb>(rmem, wmem); break;
|
||||
case oam_dma_src_sram: disconnectOamDmaAreas<oam_dma_src_sram, cgb>(rmem, wmem); break;
|
||||
case oam_dma_src_vram: disconnectOamDmaAreas<oam_dma_src_vram, cgb>(rmem, wmem); break;
|
||||
case oam_dma_src_wram: disconnectOamDmaAreas<oam_dma_src_wram, cgb>(rmem, wmem); break;
|
||||
case oam_dma_src_invalid: disconnectOamDmaAreas<oam_dma_src_invalid, cgb>(rmem, wmem); break;
|
||||
case oam_dma_src_off: break;
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace.
|
||||
|
||||
MemPtrs::MemPtrs()
|
||||
: rmem_()
|
||||
, wmem_()
|
||||
, romdata_()
|
||||
, wramdata_()
|
||||
, vrambankptr_(0)
|
||||
, rsrambankptr_(0)
|
||||
, wsrambankptr_(0)
|
||||
, rambankdata_(0)
|
||||
, wramdataend_(0)
|
||||
, oamDmaSrc_(oam_dma_src_off)
|
||||
{
|
||||
}
|
||||
|
||||
void MemPtrs::reset(unsigned const rombanks, unsigned const rambanks, unsigned const wrambanks) {
|
||||
int const num_disabled_ram_areas = 2;
|
||||
memchunk_.reset(
|
||||
pre_rom_pad_size()
|
||||
+ rombanks * rombank_size()
|
||||
+ max_num_vrambanks * vrambank_size()
|
||||
+ rambanks * rambank_size()
|
||||
+ wrambanks * wrambank_size()
|
||||
+ num_disabled_ram_areas * rambank_size());
|
||||
|
||||
romdata_[0] = romdata();
|
||||
rambankdata_ = romdata_[0] + rombanks * rombank_size() + max_num_vrambanks * vrambank_size();
|
||||
wramdata_[0] = rambankdata_ + rambanks * rambank_size();
|
||||
wramdataend_ = wramdata_[0] + wrambanks * wrambank_size();
|
||||
|
||||
std::fill_n(rdisabledRamw(), rambank_size(), 0xFF);
|
||||
|
||||
oamDmaSrc_ = oam_dma_src_off;
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - mm_wram_begin;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - mm_wram_mirror_begin;
|
||||
setRombank(1);
|
||||
setRambank(0, 0);
|
||||
setVrambank(0);
|
||||
setWrambank(1);
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank0(unsigned bank) {
|
||||
romdata_[0] = romdata() + bank * rombank_size();
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRombank(unsigned bank) {
|
||||
romdata_[1] = romdata() + bank * rombank_size() - mm_rom1_begin;
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setRambank(unsigned const flags, unsigned const rambank) {
|
||||
unsigned char *srambankptr = 0;
|
||||
if (!(flags & rtc_en)) {
|
||||
srambankptr = rambankdata() != rambankdataend()
|
||||
? rambankdata_ + rambank * rambank_size() - mm_sram_begin
|
||||
: wdisabledRam() - mm_sram_begin;
|
||||
}
|
||||
|
||||
rsrambankptr_ = (flags & read_en) && srambankptr != wdisabledRam() - mm_sram_begin
|
||||
? srambankptr
|
||||
: rdisabledRamw() - mm_sram_begin;
|
||||
wsrambankptr_ = flags & write_en
|
||||
? srambankptr
|
||||
: wdisabledRam() - mm_sram_begin;
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setWrambank(unsigned bank) {
|
||||
wramdata_[1] = wramdata_[0] + (bank & 0x07 ? bank & 0x07 : 1) * wrambank_size();
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - mm_wram1_begin;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::setOamDmaSrc(OamDmaSrc oamDmaSrc) {
|
||||
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
|
||||
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
|
||||
rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
|
||||
wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
|
||||
rmem_[0xC] = wmem_[0xC] = wramdata_[0] - mm_wram_begin;
|
||||
rmem_[0xD] = wmem_[0xD] = wramdata_[1] - mm_wram1_begin;
|
||||
rmem_[0xE] = wmem_[0xE] = wramdata_[0] - mm_wram_mirror_begin;
|
||||
|
||||
oamDmaSrc_ = oamDmaSrc;
|
||||
disconnectOamDmaAreas();
|
||||
}
|
||||
|
||||
void MemPtrs::disconnectOamDmaAreas() {
|
||||
return isCgb(*this)
|
||||
? ::disconnectOamDmaAreas<true>(rmem_, wmem_, oamDmaSrc_)
|
||||
: ::disconnectOamDmaAreas<false>(rmem_, wmem_, oamDmaSrc_);
|
||||
}
|
||||
|
||||
bool MemPtrs::isInOamDmaConflictArea(unsigned p) const
|
||||
{
|
||||
return isCgb(*this)
|
||||
? ::isInOamDmaConflictArea<true>(oamDmaSrc_, p)
|
||||
: ::isInOamDmaConflictArea<false>(oamDmaSrc_, p);
|
||||
}
|
||||
@@ -13,50 +13,71 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef MEMPTRS_H
|
||||
#define MEMPTRS_H
|
||||
|
||||
#include "array.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum OamDmaSrc { oam_dma_src_rom,
|
||||
oam_dma_src_sram,
|
||||
oam_dma_src_vram,
|
||||
oam_dma_src_wram,
|
||||
oam_dma_src_invalid,
|
||||
oam_dma_src_off, };
|
||||
enum OamDmaSrc {
|
||||
oam_dma_src_rom,
|
||||
oam_dma_src_sram,
|
||||
oam_dma_src_vram,
|
||||
oam_dma_src_wram,
|
||||
oam_dma_src_invalid,
|
||||
oam_dma_src_off };
|
||||
|
||||
enum {
|
||||
mm_rom_begin = 0x0000,
|
||||
mm_rom1_begin = 0x4000,
|
||||
mm_vram_begin = 0x8000,
|
||||
mm_sram_begin = 0xA000,
|
||||
mm_wram_begin = 0xC000,
|
||||
mm_wram1_begin = 0xD000,
|
||||
mm_wram_mirror_begin = 0xE000,
|
||||
mm_oam_begin = 0xFE00,
|
||||
mm_io_begin = 0xFF00,
|
||||
mm_hram_begin = 0xFF80 };
|
||||
|
||||
enum { max_num_vrambanks = 2 };
|
||||
inline std::size_t rambank_size() { return 0x2000; }
|
||||
inline std::size_t rombank_size() { return 0x4000; }
|
||||
inline std::size_t vrambank_size() { return 0x2000; }
|
||||
inline std::size_t wrambank_size() { return 0x1000; }
|
||||
|
||||
class MemPtrs {
|
||||
public:
|
||||
enum RamFlag { read_en = 1, write_en = 2, rtc_en = 4 };
|
||||
|
||||
MemPtrs();
|
||||
~MemPtrs();
|
||||
void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
|
||||
|
||||
unsigned char const * rmem(unsigned area) const { return rmem_[area]; }
|
||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * vramdataend() const { return rambankdata_; }
|
||||
unsigned char * romdata() const { return memchunk_ + 0x4000; }
|
||||
unsigned char * romdata() const { return memchunk_ + pre_rom_pad_size(); }
|
||||
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
||||
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||
unsigned char * wramdataend() const { return wramdataend_; }
|
||||
unsigned char * romdataend() const { return rambankdata_ - max_num_vrambanks * vrambank_size(); }
|
||||
unsigned char * vramdata() const { return romdataend(); }
|
||||
unsigned char * vramdataend() const { return rambankdata_; }
|
||||
unsigned char * rambankdata() const { return rambankdata_; }
|
||||
unsigned char * rambankdataend() const { return wramdata_[0]; }
|
||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||
unsigned char * wramdataend() const { return wramdataend_; }
|
||||
unsigned char const * rdisabledRam() const { return rdisabledRamw(); }
|
||||
unsigned char const * rsrambankptr() const { return rsrambankptr_; }
|
||||
unsigned char * wsrambankptr() const { return wsrambankptr_; }
|
||||
unsigned char * vrambankptr() const { return vrambankptr_; }
|
||||
OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
|
||||
bool isInOamDmaConflictArea(unsigned p) const;
|
||||
|
||||
void setRombank0(unsigned bank);
|
||||
void setRombank(unsigned bank);
|
||||
void setRambank(unsigned ramFlags, unsigned rambank);
|
||||
void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
|
||||
void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * vrambank_size() - mm_vram_begin; }
|
||||
void setWrambank(unsigned bank);
|
||||
void setOamDmaSrc(OamDmaSrc oamDmaSrc);
|
||||
|
||||
@@ -68,20 +89,21 @@ private:
|
||||
unsigned char *vrambankptr_;
|
||||
unsigned char *rsrambankptr_;
|
||||
unsigned char *wsrambankptr_;
|
||||
unsigned char *memchunk_;
|
||||
SimpleArray<unsigned char> memchunk_;
|
||||
unsigned char *rambankdata_;
|
||||
unsigned char *wramdataend_;
|
||||
OamDmaSrc oamDmaSrc_;
|
||||
|
||||
MemPtrs(MemPtrs const &);
|
||||
MemPtrs & operator=(MemPtrs const &);
|
||||
static std::size_t pre_rom_pad_size() { return mm_rom1_begin; }
|
||||
void disconnectOamDmaAreas();
|
||||
unsigned char * rdisabledRamw() const { return wramdataend_ ; }
|
||||
unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
|
||||
unsigned char * rdisabledRamw() const { return wramdataend_; }
|
||||
unsigned char * wdisabledRam() const { return wramdataend_ + rambank_size(); }
|
||||
};
|
||||
|
||||
inline bool isCgb(MemPtrs const &memptrs) {
|
||||
return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
|
||||
int const num_cgb_wrambanks = 8;
|
||||
std::size_t const wramsize = memptrs.wramdataend() - memptrs.wramdata(0);
|
||||
return wramsize == num_cgb_wrambanks * wrambank_size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "pakinfo_internal.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum { flag_multipak = 1, flag_header_checksum_ok = 2, };
|
||||
enum { flag_multipak = 1, flag_header_checksum_ok = 2 };
|
||||
|
||||
static bool isHeaderChecksumOk(unsigned const char header[]) {
|
||||
unsigned csum = 0;
|
||||
@@ -20,9 +21,10 @@ unsigned numRambanksFromH14x(unsigned char h147, unsigned char h149) {
|
||||
case 0x00: return isMbc2(h147) ? 1 : 0;
|
||||
case 0x01:
|
||||
case 0x02: return 1;
|
||||
default: case 0x03: return 4;
|
||||
case 0x04: return 16;
|
||||
case 0x05: return 8;
|
||||
}
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
PakInfo::PakInfo()
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "rtc.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef RTC_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "memory.h"
|
||||
@@ -21,23 +21,40 @@
|
||||
#include "savestate.h"
|
||||
#include "sound.h"
|
||||
#include "video.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace gambatte {
|
||||
#include <algorithm>
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
int const oam_size = 4 * lcd_num_oam_entries;
|
||||
|
||||
void decCycles(unsigned long &counter, unsigned long dec) {
|
||||
if (counter != disabled_time)
|
||||
counter -= dec;
|
||||
}
|
||||
|
||||
int serialCntFrom(unsigned long cyclesUntilDone, bool cgbFast) {
|
||||
return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
|
||||
}
|
||||
|
||||
} // unnamed namespace.
|
||||
|
||||
Memory::Memory(Interrupter const &interrupter)
|
||||
: getInput_(0)
|
||||
, divLastUpdate_(0)
|
||||
, lastOamDmaUpdate_(disabled_time)
|
||||
, lcd_(ioamhram_, 0, VideoInterruptRequester(intreq_))
|
||||
, interrupter_(interrupter)
|
||||
, dmaSource_(0)
|
||||
, dmaDestination_(0)
|
||||
, oamDmaPos_(0xFE)
|
||||
, oamDmaPos_(-2u & 0xFF)
|
||||
, oamDmaStartPos_(0)
|
||||
, serialCnt_(0)
|
||||
, blanklcd_(false)
|
||||
, haltHdmaState_(hdma_low)
|
||||
{
|
||||
intreq_.setEventTime<intevent_blit>(144 * 456ul);
|
||||
intreq_.setEventTime<intevent_blit>(1l * lcd_vres * lcd_cycles_per_line);
|
||||
intreq_.setEventTime<intevent_end>(0);
|
||||
}
|
||||
|
||||
@@ -51,17 +68,20 @@ void Memory::setStatePtrs(SaveState &state) {
|
||||
|
||||
unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
|
||||
cc = resetCounters(cc);
|
||||
ioamhram_[0x104] = 0;
|
||||
nontrivial_ff_read(0x05, cc);
|
||||
nontrivial_ff_read(0x0F, cc);
|
||||
nontrivial_ff_read(0x26, cc);
|
||||
|
||||
state.mem.divLastUpdate = divLastUpdate_;
|
||||
state.mem.nextSerialtime = intreq_.eventTime(intevent_serial);
|
||||
state.mem.unhaltTime = intreq_.eventTime(intevent_unhalt);
|
||||
state.mem.lastOamDmaUpdate = lastOamDmaUpdate_;
|
||||
state.mem.lastOamDmaUpdate = oamDmaStartPos_
|
||||
? lastOamDmaUpdate_ + ((oamDmaStartPos_ - oamDmaPos_) & 0xFF) * 4
|
||||
: lastOamDmaUpdate_;
|
||||
state.mem.dmaSource = dmaSource_;
|
||||
state.mem.dmaDestination = dmaDestination_;
|
||||
state.mem.oamDmaPos = oamDmaPos_;
|
||||
state.mem.haltHdmaState = haltHdmaState_;
|
||||
|
||||
intreq_.saveState(state);
|
||||
cart_.saveState(state);
|
||||
@@ -72,18 +92,13 @@ unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
|
||||
return cc;
|
||||
}
|
||||
|
||||
static int serialCntFrom(unsigned long cyclesUntilDone, bool cgbFast) {
|
||||
return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
|
||||
}
|
||||
|
||||
void Memory::loadState(SaveState const &state) {
|
||||
psg_.loadState(state);
|
||||
lcd_.loadState(state, state.mem.oamDmaPos < 0xA0 ? cart_.rdisabledRam() : ioamhram_);
|
||||
lcd_.loadState(state, state.mem.oamDmaPos < oam_size ? cart_.rdisabledRam() : ioamhram_);
|
||||
tima_.loadState(state, TimaInterruptRequester(intreq_));
|
||||
cart_.loadState(state);
|
||||
intreq_.loadState(state);
|
||||
|
||||
divLastUpdate_ = state.mem.divLastUpdate;
|
||||
intreq_.setEventTime<intevent_serial>(state.mem.nextSerialtime > state.cpu.cycleCounter
|
||||
? state.mem.nextSerialtime
|
||||
: state.cpu.cycleCounter);
|
||||
@@ -92,36 +107,42 @@ void Memory::loadState(SaveState const &state) {
|
||||
dmaSource_ = state.mem.dmaSource;
|
||||
dmaDestination_ = state.mem.dmaDestination;
|
||||
oamDmaPos_ = state.mem.oamDmaPos;
|
||||
oamDmaStartPos_ = 0;
|
||||
haltHdmaState_ = static_cast<HdmaState>(std::min(1u * state.mem.haltHdmaState, 1u * hdma_requested));
|
||||
serialCnt_ = intreq_.eventTime(intevent_serial) != disabled_time
|
||||
? serialCntFrom(intreq_.eventTime(intevent_serial) - state.cpu.cycleCounter,
|
||||
ioamhram_[0x102] & isCgb() * 2)
|
||||
: 8;
|
||||
? serialCntFrom(intreq_.eventTime(intevent_serial) - state.cpu.cycleCounter,
|
||||
ioamhram_[0x102] & isCgb() * 2)
|
||||
: 8;
|
||||
|
||||
cart_.setVrambank(ioamhram_[0x14F] & isCgb());
|
||||
cart_.setOamDmaSrc(oam_dma_src_off);
|
||||
cart_.setWrambank(isCgb() && (ioamhram_[0x170] & 0x07) ? ioamhram_[0x170] & 0x07 : 1);
|
||||
|
||||
if (lastOamDmaUpdate_ != disabled_time) {
|
||||
if (lastOamDmaUpdate_ > state.cpu.cycleCounter) {
|
||||
oamDmaStartPos_ = (oamDmaPos_ + (lastOamDmaUpdate_ - state.cpu.cycleCounter) / 4) & 0xFF;
|
||||
lastOamDmaUpdate_ = state.cpu.cycleCounter;
|
||||
}
|
||||
oamDmaInitSetup();
|
||||
|
||||
unsigned oamEventPos = oamDmaPos_ < 0xA0 ? 0xA0 : 0x100;
|
||||
unsigned oamEventPos = oamDmaPos_ < oam_size ? oam_size : oamDmaStartPos_;
|
||||
intreq_.setEventTime<intevent_oam>(
|
||||
lastOamDmaUpdate_ + (oamEventPos - oamDmaPos_) * 4);
|
||||
lastOamDmaUpdate_ + ((oamEventPos - oamDmaPos_) & 0xFF) * 4);
|
||||
}
|
||||
|
||||
intreq_.setEventTime<intevent_blit>(ioamhram_[0x140] & lcdc_en
|
||||
? lcd_.nextMode1IrqTime()
|
||||
: state.cpu.cycleCounter);
|
||||
? lcd_.nextMode1IrqTime()
|
||||
: state.cpu.cycleCounter);
|
||||
blanklcd_ = false;
|
||||
|
||||
if (!isCgb())
|
||||
std::memset(cart_.vramdata() + 0x2000, 0, 0x2000);
|
||||
std::fill_n(cart_.vramdata() + vrambank_size(), vrambank_size(), 0);
|
||||
}
|
||||
|
||||
void Memory::setEndtime(unsigned long cc, unsigned long inc) {
|
||||
if (intreq_.eventTime(intevent_blit) <= cc) {
|
||||
intreq_.setEventTime<intevent_blit>(intreq_.eventTime(intevent_blit)
|
||||
+ (70224 << isDoubleSpeed()));
|
||||
+ (lcd_cycles_per_frame << isDoubleSpeed()));
|
||||
}
|
||||
|
||||
intreq_.setEventTime<intevent_end>(cc + (inc << isDoubleSpeed()));
|
||||
@@ -132,11 +153,11 @@ void Memory::updateSerial(unsigned long const cc) {
|
||||
if (intreq_.eventTime(intevent_serial) <= cc) {
|
||||
ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << serialCnt_) - 1) & 0xFF;
|
||||
ioamhram_[0x102] &= 0x7F;
|
||||
intreq_.flagIrq(8, intreq_.eventTime(intevent_serial));
|
||||
intreq_.setEventTime<intevent_serial>(disabled_time);
|
||||
intreq_.flagIrq(8);
|
||||
} else {
|
||||
int const targetCnt = serialCntFrom(intreq_.eventTime(intevent_serial) - cc,
|
||||
ioamhram_[0x102] & isCgb() * 2);
|
||||
ioamhram_[0x102] & isCgb() * 2);
|
||||
ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << (serialCnt_ - targetCnt)) - 1) & 0xFF;
|
||||
serialCnt_ = targetCnt;
|
||||
}
|
||||
@@ -160,6 +181,11 @@ unsigned long Memory::event(unsigned long cc) {
|
||||
|
||||
switch (intreq_.minEventId()) {
|
||||
case intevent_unhalt:
|
||||
if ((lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) && haltHdmaState_ == hdma_low)
|
||||
|| haltHdmaState_ == hdma_requested) {
|
||||
flagHdmaReq(intreq_);
|
||||
}
|
||||
|
||||
intreq_.unhalt();
|
||||
intreq_.setEventTime<intevent_unhalt>(disabled_time);
|
||||
break;
|
||||
@@ -187,7 +213,7 @@ unsigned long Memory::event(unsigned long cc) {
|
||||
while (cc >= intreq_.minEventTime())
|
||||
cc = event(cc);
|
||||
} else
|
||||
blitTime += 70224 << isDoubleSpeed();
|
||||
blitTime += lcd_cycles_per_frame << isDoubleSpeed();
|
||||
|
||||
blanklcd_ = lcden ^ 1;
|
||||
intreq_.setEventTime<intevent_blit>(blitTime);
|
||||
@@ -197,77 +223,22 @@ unsigned long Memory::event(unsigned long cc) {
|
||||
updateSerial(cc);
|
||||
break;
|
||||
case intevent_oam:
|
||||
intreq_.setEventTime<intevent_oam>(lastOamDmaUpdate_ == disabled_time
|
||||
? static_cast<unsigned long>(disabled_time)
|
||||
: intreq_.eventTime(intevent_oam) + 0xA0 * 4);
|
||||
if (lastOamDmaUpdate_ != disabled_time) {
|
||||
unsigned const oamEventPos = oamDmaPos_ < oam_size ? oam_size : oamDmaStartPos_;
|
||||
intreq_.setEventTime<intevent_oam>(
|
||||
lastOamDmaUpdate_ + ((oamEventPos - oamDmaPos_) & 0xFF) * 4);
|
||||
} else
|
||||
intreq_.setEventTime<intevent_oam>(disabled_time);
|
||||
|
||||
break;
|
||||
case intevent_dma:
|
||||
{
|
||||
bool const doubleSpeed = isDoubleSpeed();
|
||||
unsigned dmaSrc = dmaSource_;
|
||||
unsigned dmaDest = dmaDestination_;
|
||||
unsigned dmaLength = ((ioamhram_[0x155] & 0x7F) + 0x1) * 0x10;
|
||||
unsigned length = hdmaReqFlagged(intreq_) ? 0x10 : dmaLength;
|
||||
|
||||
ackDmaReq(intreq_);
|
||||
|
||||
if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) {
|
||||
length = 0x10000 - dmaDest;
|
||||
ioamhram_[0x155] |= 0x80;
|
||||
}
|
||||
|
||||
dmaLength -= length;
|
||||
|
||||
if (!(ioamhram_[0x140] & lcdc_en))
|
||||
dmaLength = 0;
|
||||
|
||||
{
|
||||
unsigned long lOamDmaUpdate = lastOamDmaUpdate_;
|
||||
lastOamDmaUpdate_ = disabled_time;
|
||||
|
||||
while (length--) {
|
||||
unsigned const src = dmaSrc++ & 0xFFFF;
|
||||
unsigned const data = (src & 0xE000) == 0x8000 || src > 0xFDFF
|
||||
? 0xFF
|
||||
: read(src, cc);
|
||||
|
||||
cc += 2 << doubleSpeed;
|
||||
|
||||
if (cc - 3 > lOamDmaUpdate) {
|
||||
oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF;
|
||||
lOamDmaUpdate += 4;
|
||||
|
||||
if (oamDmaPos_ < 0xA0) {
|
||||
if (oamDmaPos_ == 0)
|
||||
startOamDma(lOamDmaUpdate - 1);
|
||||
|
||||
ioamhram_[src & 0xFF] = data;
|
||||
} else if (oamDmaPos_ == 0xA0) {
|
||||
endOamDma(lOamDmaUpdate - 1);
|
||||
lOamDmaUpdate = disabled_time;
|
||||
}
|
||||
}
|
||||
|
||||
nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cc);
|
||||
}
|
||||
|
||||
lastOamDmaUpdate_ = lOamDmaUpdate;
|
||||
}
|
||||
|
||||
cc += 4;
|
||||
|
||||
dmaSource_ = dmaSrc;
|
||||
dmaDestination_ = dmaDest;
|
||||
ioamhram_[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram_[0x155] & 0x80);
|
||||
|
||||
if ((ioamhram_[0x155] & 0x80) && lcd_.hdmaIsEnabled()) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc);
|
||||
|
||||
lcd_.disableHdma(cc);
|
||||
}
|
||||
interrupter_.prefetch(cc, *this);
|
||||
cc = dma(cc);
|
||||
if (haltHdmaState_ == hdma_requested) {
|
||||
haltHdmaState_ = hdma_low;
|
||||
intreq_.setMinIntTime(cc);
|
||||
cc -= 4;
|
||||
}
|
||||
|
||||
break;
|
||||
case intevent_tima:
|
||||
tima_.doIrqEvent(TimaInterruptRequester(intreq_));
|
||||
@@ -277,25 +248,25 @@ unsigned long Memory::event(unsigned long cc) {
|
||||
break;
|
||||
case intevent_interrupts:
|
||||
if (halted()) {
|
||||
if (isCgb())
|
||||
cc += 4;
|
||||
cc += 4 * (isCgb() || cc - intreq_.eventTime(intevent_interrupts) < 2);
|
||||
if (cc > lastOamDmaUpdate_)
|
||||
updateOamDma(cc);
|
||||
if ((lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) && haltHdmaState_ == hdma_low)
|
||||
|| haltHdmaState_ == hdma_requested) {
|
||||
flagHdmaReq(intreq_);
|
||||
}
|
||||
|
||||
intreq_.unhalt();
|
||||
intreq_.setEventTime<intevent_unhalt>(disabled_time);
|
||||
}
|
||||
if (cc >= intreq_.eventTime(intevent_video))
|
||||
lcd_.update(cc);
|
||||
if (cc >= intreq_.eventTime(intevent_dma))
|
||||
break;
|
||||
|
||||
if (ime()) {
|
||||
unsigned const pendingIrqs = intreq_.pendingIrqs();
|
||||
unsigned const n = pendingIrqs & -pendingIrqs;
|
||||
unsigned address;
|
||||
if (n <= 4) {
|
||||
static unsigned char const lut[] = { 0x40, 0x48, 0x48, 0x50 };
|
||||
address = lut[n-1];
|
||||
} else
|
||||
address = 0x50 + n;
|
||||
|
||||
intreq_.ackIrq(n);
|
||||
cc = interrupter_.interrupt(address, cc, *this);
|
||||
di();
|
||||
cc = interrupter_.interrupt(cc, *this);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -304,33 +275,169 @@ unsigned long Memory::event(unsigned long cc) {
|
||||
return cc;
|
||||
}
|
||||
|
||||
unsigned long Memory::stop(unsigned long cc) {
|
||||
cc += 4 + 4 * isDoubleSpeed();
|
||||
unsigned long Memory::dma(unsigned long cc) {
|
||||
bool const doubleSpeed = isDoubleSpeed();
|
||||
unsigned dmaSrc = dmaSource_;
|
||||
unsigned dmaDest = dmaDestination_;
|
||||
unsigned dmaLength = ((ioamhram_[0x155] & 0x7F) + 1) * 0x10;
|
||||
unsigned length = hdmaReqFlagged(intreq_) ? 0x10 : dmaLength;
|
||||
|
||||
if (ioamhram_[0x14D] & isCgb()) {
|
||||
psg_.generateSamples(cc, isDoubleSpeed());
|
||||
lcd_.speedChange(cc);
|
||||
ioamhram_[0x14D] ^= 0x81;
|
||||
intreq_.setEventTime<intevent_blit>(ioamhram_[0x140] & lcdc_en
|
||||
? lcd_.nextMode1IrqTime()
|
||||
: cc + (70224 << isDoubleSpeed()));
|
||||
|
||||
if (intreq_.eventTime(intevent_end) > cc) {
|
||||
intreq_.setEventTime<intevent_end>(cc
|
||||
+ ( isDoubleSpeed()
|
||||
? (intreq_.eventTime(intevent_end) - cc) << 1
|
||||
: (intreq_.eventTime(intevent_end) - cc) >> 1));
|
||||
}
|
||||
if (1ul * dmaDest + length >= 0x10000) {
|
||||
length = 0x10000 - dmaDest;
|
||||
ioamhram_[0x155] |= 0x80;
|
||||
}
|
||||
|
||||
dmaLength -= length;
|
||||
|
||||
if (!(ioamhram_[0x140] & lcdc_en))
|
||||
dmaLength = 0;
|
||||
|
||||
unsigned long lOamDmaUpdate = lastOamDmaUpdate_;
|
||||
lastOamDmaUpdate_ = disabled_time;
|
||||
|
||||
while (length--) {
|
||||
unsigned const src = dmaSrc++ & 0xFFFF;
|
||||
unsigned const data = (src & -vrambank_size()) == mm_vram_begin || src >= mm_oam_begin
|
||||
? 0xFF
|
||||
: read(src, cc);
|
||||
|
||||
cc += 2 + 2 * doubleSpeed;
|
||||
|
||||
if (cc - 3 > lOamDmaUpdate && !halted()) {
|
||||
oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF;
|
||||
lOamDmaUpdate += 4;
|
||||
if (oamDmaPos_ == oamDmaStartPos_)
|
||||
startOamDma(lOamDmaUpdate);
|
||||
|
||||
if (oamDmaPos_ < oam_size) {
|
||||
ioamhram_[src & 0xFF] = data;
|
||||
} else if (oamDmaPos_ == oam_size) {
|
||||
endOamDma(lOamDmaUpdate);
|
||||
if (oamDmaStartPos_ == 0)
|
||||
lOamDmaUpdate = disabled_time;
|
||||
}
|
||||
}
|
||||
|
||||
nontrivial_write(mm_vram_begin | dmaDest++ % vrambank_size(), data, cc);
|
||||
}
|
||||
|
||||
lastOamDmaUpdate_ = lOamDmaUpdate;
|
||||
ackDmaReq(intreq_);
|
||||
cc += 4;
|
||||
|
||||
dmaSource_ = dmaSrc;
|
||||
dmaDestination_ = dmaDest;
|
||||
ioamhram_[0x155] = halted()
|
||||
? ioamhram_[0x155] | 0x80
|
||||
: ((dmaLength / 0x10 - 1) & 0xFF) | (ioamhram_[0x155] & 0x80);
|
||||
|
||||
if ((ioamhram_[0x155] & 0x80) && lcd_.hdmaIsEnabled()) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc);
|
||||
|
||||
lcd_.disableHdma(cc);
|
||||
}
|
||||
|
||||
intreq_.halt();
|
||||
intreq_.setEventTime<intevent_unhalt>(cc + 0x20000 + isDoubleSpeed() * 8);
|
||||
return cc;
|
||||
}
|
||||
|
||||
static void decCycles(unsigned long &counter, unsigned long dec) {
|
||||
if (counter != disabled_time)
|
||||
counter -= dec;
|
||||
void Memory::freeze(unsigned long cc) {
|
||||
// permanently halt CPU.
|
||||
// simply halt and clear IE to avoid unhalt from occuring,
|
||||
// which avoids additional state to represent a "frozen" state.
|
||||
nontrivial_ff_write(0xFF, 0, cc);
|
||||
ackDmaReq(intreq_);
|
||||
intreq_.halt();
|
||||
}
|
||||
|
||||
bool Memory::halt(unsigned long cc) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc);
|
||||
|
||||
haltHdmaState_ = lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc)
|
||||
? hdma_high : hdma_low;
|
||||
bool const hdmaReq = hdmaReqFlagged(intreq_);
|
||||
if (hdmaReq)
|
||||
haltHdmaState_ = hdma_requested;
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc + 4);
|
||||
|
||||
ackDmaReq(intreq_);
|
||||
intreq_.halt();
|
||||
return hdmaReq;
|
||||
}
|
||||
|
||||
unsigned Memory::pendingIrqs(unsigned long cc) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc);
|
||||
|
||||
updateIrqs(cc);
|
||||
return intreq_.pendingIrqs();
|
||||
}
|
||||
|
||||
void Memory::ackIrq(unsigned bit, unsigned long cc) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc);
|
||||
|
||||
// TODO: adjust/extend IRQ assertion time rather than use the odd cc offsets?
|
||||
// NOTE: a minimum offset of 2 is required for the LCD due to implementation assumptions w.r.t. cc headroom.
|
||||
updateSerial(cc + 3 + isCgb());
|
||||
updateTimaIrq(cc + 2 + isCgb());
|
||||
lcd_.update(cc + 2);
|
||||
intreq_.ackIrq(bit);
|
||||
}
|
||||
|
||||
unsigned long Memory::stop(unsigned long cc, bool &skip) {
|
||||
// FIXME: this is incomplete.
|
||||
intreq_.setEventTime<intevent_unhalt>(cc + 0x20000 + 4);
|
||||
|
||||
// speed change.
|
||||
if (ioamhram_[0x14D] & isCgb()) {
|
||||
tima_.speedChange(TimaInterruptRequester(intreq_));
|
||||
// DIV reset.
|
||||
nontrivial_ff_write(0x04, 0, cc);
|
||||
haltHdmaState_ = lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc)
|
||||
? hdma_high : hdma_low;
|
||||
skip = hdmaReqFlagged(intreq_);
|
||||
if (skip && isDoubleSpeed())
|
||||
haltHdmaState_ = hdma_requested;
|
||||
unsigned long const cc_ = cc + 8 * !isDoubleSpeed();
|
||||
if (cc_ >= cc + 4) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc + 4);
|
||||
if (!skip || isDoubleSpeed())
|
||||
ackDmaReq(intreq_);
|
||||
intreq_.halt();
|
||||
}
|
||||
psg_.speedChange(cc_, isDoubleSpeed());
|
||||
lcd_.speedChange(cc_);
|
||||
ioamhram_[0x14D] ^= 0x81;
|
||||
// TODO: perhaps make this a bit nicer?
|
||||
intreq_.setEventTime<intevent_blit>(ioamhram_[0x140] & lcdc_en
|
||||
? lcd_.nextMode1IrqTime()
|
||||
: cc + (lcd_cycles_per_frame << isDoubleSpeed()));
|
||||
if (intreq_.eventTime(intevent_end) > cc_) {
|
||||
intreq_.setEventTime<intevent_end>(cc_
|
||||
+ (isDoubleSpeed()
|
||||
? (intreq_.eventTime(intevent_end) - cc_) * 2
|
||||
: (intreq_.eventTime(intevent_end) - cc_) / 2));
|
||||
}
|
||||
if (cc_ < cc + 4) {
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
updateOamDma(cc + 4);
|
||||
if (!skip || !isDoubleSpeed())
|
||||
ackDmaReq(intreq_);
|
||||
intreq_.halt();
|
||||
}
|
||||
// ensure that no updates with a previous cc occur.
|
||||
cc += 8;
|
||||
} else {
|
||||
// FIXME: test and implement stop correctly.
|
||||
skip = halt(cc);
|
||||
cc += 4;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
void Memory::decEventCycles(IntEventId eventId, unsigned long dec) {
|
||||
@@ -344,16 +451,9 @@ unsigned long Memory::resetCounters(unsigned long cc) {
|
||||
|
||||
updateIrqs(cc);
|
||||
|
||||
{
|
||||
unsigned long divinc = (cc - divLastUpdate_) >> 8;
|
||||
ioamhram_[0x104] = (ioamhram_[0x104] + divinc) & 0xFF;
|
||||
divLastUpdate_ += divinc << 8;
|
||||
}
|
||||
|
||||
unsigned long const dec = cc < 0x10000
|
||||
? 0
|
||||
: (cc & ~0x7FFFul) - 0x8000;
|
||||
decCycles(divLastUpdate_, dec);
|
||||
unsigned long const dec = cc < 0x20000
|
||||
? 0
|
||||
: (cc & -0x10000l) - 0x10000;
|
||||
decCycles(lastOamDmaUpdate_, dec);
|
||||
decEventCycles(intevent_serial, dec);
|
||||
decEventCycles(intevent_oam, dec);
|
||||
@@ -393,62 +493,64 @@ void Memory::updateOamDma(unsigned long const cc) {
|
||||
unsigned char const *const oamDmaSrc = oamDmaSrcPtr();
|
||||
unsigned cycles = (cc - lastOamDmaUpdate_) >> 2;
|
||||
|
||||
while (cycles--) {
|
||||
if (halted()) {
|
||||
lastOamDmaUpdate_ += 4 * cycles;
|
||||
} else while (cycles--) {
|
||||
oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF;
|
||||
lastOamDmaUpdate_ += 4;
|
||||
if (oamDmaPos_ == oamDmaStartPos_)
|
||||
startOamDma(lastOamDmaUpdate_);
|
||||
|
||||
if (oamDmaPos_ < 0xA0) {
|
||||
if (oamDmaPos_ == 0)
|
||||
startOamDma(lastOamDmaUpdate_ - 1);
|
||||
|
||||
if (oamDmaPos_ < oam_size) {
|
||||
ioamhram_[oamDmaPos_] = oamDmaSrc ? oamDmaSrc[oamDmaPos_] : cart_.rtcRead();
|
||||
} else if (oamDmaPos_ == 0xA0) {
|
||||
endOamDma(lastOamDmaUpdate_ - 1);
|
||||
lastOamDmaUpdate_ = disabled_time;
|
||||
break;
|
||||
} else if (oamDmaPos_ == oam_size) {
|
||||
endOamDma(lastOamDmaUpdate_);
|
||||
if (oamDmaStartPos_ == 0) {
|
||||
lastOamDmaUpdate_ = disabled_time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::oamDmaInitSetup() {
|
||||
if (ioamhram_[0x146] < 0xA0) {
|
||||
cart_.setOamDmaSrc(ioamhram_[0x146] < 0x80 ? oam_dma_src_rom : oam_dma_src_vram);
|
||||
} else if (ioamhram_[0x146] < 0xFE - isCgb() * 0x1E) {
|
||||
cart_.setOamDmaSrc(ioamhram_[0x146] < 0xC0 ? oam_dma_src_sram : oam_dma_src_wram);
|
||||
if (ioamhram_[0x146] < mm_sram_begin / 0x100) {
|
||||
cart_.setOamDmaSrc(ioamhram_[0x146] < mm_vram_begin / 0x100 ? oam_dma_src_rom : oam_dma_src_vram);
|
||||
} else if (ioamhram_[0x146] < 0x100 - isCgb() * 0x20) {
|
||||
cart_.setOamDmaSrc(ioamhram_[0x146] < mm_wram_begin / 0x100 ? oam_dma_src_sram : oam_dma_src_wram);
|
||||
} else
|
||||
cart_.setOamDmaSrc(oam_dma_src_invalid);
|
||||
}
|
||||
|
||||
static unsigned char const * oamDmaSrcZero() {
|
||||
static unsigned char zeroMem[0xA0];
|
||||
return zeroMem;
|
||||
}
|
||||
|
||||
unsigned char const * Memory::oamDmaSrcPtr() const {
|
||||
switch (cart_.oamDmaSrc()) {
|
||||
case oam_dma_src_rom:
|
||||
return cart_.romdata(ioamhram_[0x146] >> 6) + (ioamhram_[0x146] << 8);
|
||||
return cart_.romdata(ioamhram_[0x146] >> 6) + ioamhram_[0x146] * 0x100l;
|
||||
case oam_dma_src_sram:
|
||||
return cart_.rsrambankptr() ? cart_.rsrambankptr() + (ioamhram_[0x146] << 8) : 0;
|
||||
return cart_.rsrambankptr() ? cart_.rsrambankptr() + ioamhram_[0x146] * 0x100l : 0;
|
||||
case oam_dma_src_vram:
|
||||
return cart_.vrambankptr() + (ioamhram_[0x146] << 8);
|
||||
return cart_.vrambankptr() + ioamhram_[0x146] * 0x100l;
|
||||
case oam_dma_src_wram:
|
||||
return cart_.wramdata(ioamhram_[0x146] >> 4 & 1) + (ioamhram_[0x146] << 8 & 0xFFF);
|
||||
return cart_.wramdata(ioamhram_[0x146] >> 4 & 1) + (ioamhram_[0x146] * 0x100l & 0xFFF);
|
||||
case oam_dma_src_invalid:
|
||||
case oam_dma_src_off:
|
||||
break;
|
||||
}
|
||||
|
||||
return ioamhram_[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart_.rdisabledRam();
|
||||
return cart_.rdisabledRam();
|
||||
}
|
||||
|
||||
void Memory::startOamDma(unsigned long cc) {
|
||||
oamDmaPos_ = 0;
|
||||
oamDmaStartPos_ = 0;
|
||||
lcd_.oamChange(cart_.rdisabledRam(), cc);
|
||||
}
|
||||
|
||||
void Memory::endOamDma(unsigned long cc) {
|
||||
oamDmaPos_ = 0xFE;
|
||||
cart_.setOamDmaSrc(oam_dma_src_off);
|
||||
if (oamDmaStartPos_ == 0) {
|
||||
oamDmaPos_ = -2u & 0xFF;
|
||||
cart_.setOamDmaSrc(oam_dma_src_off);
|
||||
}
|
||||
lcd_.oamChange(ioamhram_, cc);
|
||||
}
|
||||
|
||||
@@ -465,13 +567,7 @@ unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
|
||||
updateSerial(cc);
|
||||
break;
|
||||
case 0x04:
|
||||
{
|
||||
unsigned long divcycles = (cc - divLastUpdate_) >> 8;
|
||||
ioamhram_[0x104] = (ioamhram_[0x104] + divcycles) & 0xFF;
|
||||
divLastUpdate_ += divcycles << 8;
|
||||
}
|
||||
|
||||
break;
|
||||
return (cc - tima_.divLastUpdate()) >> 8 & 0xFF;
|
||||
case 0x05:
|
||||
ioamhram_[0x105] = tima_.tima(cc);
|
||||
break;
|
||||
@@ -520,47 +616,28 @@ unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
|
||||
return ioamhram_[p + 0x100];
|
||||
}
|
||||
|
||||
static bool isInOamDmaConflictArea(OamDmaSrc const oamDmaSrc, unsigned const p, bool const cgb) {
|
||||
struct Area { unsigned short areaUpper, exceptAreaLower, exceptAreaWidth, pad; };
|
||||
|
||||
static Area const cgbAreas[] = {
|
||||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
{ 0xA000, 0x0000, 0x8000, 0 },
|
||||
{ 0xFE00, 0x0000, 0xC000, 0 },
|
||||
{ 0xC000, 0x8000, 0x2000, 0 },
|
||||
{ 0x0000, 0x0000, 0x0000, 0 }
|
||||
};
|
||||
|
||||
static Area const dmgAreas[] = {
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0xA000, 0x0000, 0x8000, 0 },
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0xFE00, 0x8000, 0x2000, 0 },
|
||||
{ 0x0000, 0x0000, 0x0000, 0 }
|
||||
};
|
||||
|
||||
Area const *a = cgb ? cgbAreas : dmgAreas;
|
||||
return p < a[oamDmaSrc].areaUpper
|
||||
&& p - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
|
||||
}
|
||||
|
||||
unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
|
||||
if (p < 0xFF80) {
|
||||
if (p < mm_hram_begin) {
|
||||
if (lastOamDmaUpdate_ != disabled_time) {
|
||||
updateOamDma(cc);
|
||||
|
||||
if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0)
|
||||
return ioamhram_[oamDmaPos_];
|
||||
if (cart_.isInOamDmaConflictArea(p) && oamDmaPos_ < oam_size) {
|
||||
int const r = isCgb() && cart_.oamDmaSrc() != oam_dma_src_wram && p >= mm_wram_begin
|
||||
? cart_.wramdata(ioamhram_[0x146] >> 4 & 1)[p & 0xFFF]
|
||||
: ioamhram_[oamDmaPos_];
|
||||
if (isCgb() && cart_.oamDmaSrc() == oam_dma_src_vram)
|
||||
ioamhram_[oamDmaPos_] = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (p < 0xC000) {
|
||||
if (p < 0x8000)
|
||||
if (p < mm_wram_begin) {
|
||||
if (p < mm_vram_begin)
|
||||
return cart_.romdata(p >> 14)[p];
|
||||
|
||||
if (p < 0xA000) {
|
||||
if (!lcd_.vramAccessible(cc))
|
||||
if (p < mm_sram_begin) {
|
||||
if (!lcd_.vramReadable(cc))
|
||||
return 0xFF;
|
||||
|
||||
return cart_.vrambankptr()[p];
|
||||
@@ -572,18 +649,18 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
|
||||
return cart_.rtcRead();
|
||||
}
|
||||
|
||||
if (p < 0xFE00)
|
||||
if (p < mm_oam_begin)
|
||||
return cart_.wramdata(p >> 12 & 1)[p & 0xFFF];
|
||||
|
||||
long const ffp = long(p) - 0xFF00;
|
||||
long const ffp = static_cast<long>(p) - mm_io_begin;
|
||||
if (ffp >= 0)
|
||||
return nontrivial_ff_read(ffp, cc);
|
||||
|
||||
if (!lcd_.oamReadable(cc) || oamDmaPos_ < 0xA0)
|
||||
if (!lcd_.oamReadable(cc) || oamDmaPos_ < oam_size)
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return ioamhram_[p - 0xFE00];
|
||||
return ioamhram_[p - mm_oam_begin];
|
||||
}
|
||||
|
||||
void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long const cc) {
|
||||
@@ -604,19 +681,27 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
case 0x02:
|
||||
updateSerial(cc);
|
||||
serialCnt_ = 8;
|
||||
|
||||
if ((data & 0x81) == 0x81) {
|
||||
intreq_.setEventTime<intevent_serial>(data & isCgb() * 2
|
||||
? (cc & ~0x07ul) + 0x010 * 8
|
||||
: (cc & ~0xFFul) + 0x200 * 8);
|
||||
? cc - (cc - tima_.divLastUpdate()) % 8 + 0x10 * serialCnt_
|
||||
: cc - (cc - tima_.divLastUpdate()) % 0x100 + 0x200 * serialCnt_);
|
||||
} else
|
||||
intreq_.setEventTime<intevent_serial>(disabled_time);
|
||||
|
||||
data |= 0x7E - isCgb() * 2;
|
||||
break;
|
||||
case 0x04:
|
||||
ioamhram_[0x104] = 0;
|
||||
divLastUpdate_ = cc;
|
||||
if (intreq_.eventTime(intevent_serial) != disabled_time
|
||||
&& intreq_.eventTime(intevent_serial) > cc) {
|
||||
unsigned long const t = intreq_.eventTime(intevent_serial);
|
||||
unsigned long const n = ioamhram_[0x102] & isCgb() * 2
|
||||
? t + (cc - t) % 8 - 2 * ((cc - t) & 4)
|
||||
: t + (cc - t) % 0x100 - 2 * ((cc - t) & 0x80);
|
||||
intreq_.setEventTime<intevent_serial>(std::max(cc, n));
|
||||
}
|
||||
psg_.generateSamples(cc, isDoubleSpeed());
|
||||
psg_.divReset(isDoubleSpeed());
|
||||
tima_.divReset(cc, TimaInterruptRequester(intreq_));
|
||||
return;
|
||||
case 0x05:
|
||||
tima_.setTima(data, cc, TimaInterruptRequester(intreq_));
|
||||
@@ -629,7 +714,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
tima_.setTac(data, cc, TimaInterruptRequester(intreq_));
|
||||
break;
|
||||
case 0x0F:
|
||||
updateIrqs(cc);
|
||||
updateIrqs(cc + 1 + isDoubleSpeed());
|
||||
intreq_.setIfreg(0xE0 | data);
|
||||
return;
|
||||
case 0x10:
|
||||
@@ -671,7 +756,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
return;
|
||||
|
||||
psg_.generateSamples(cc, isDoubleSpeed());
|
||||
psg_.setNr14(data);
|
||||
psg_.setNr14(data, isDoubleSpeed());
|
||||
data |= 0xBF;
|
||||
break;
|
||||
case 0x16:
|
||||
@@ -705,7 +790,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
return;
|
||||
|
||||
psg_.generateSamples(cc, isDoubleSpeed());
|
||||
psg_.setNr24(data);
|
||||
psg_.setNr24(data, isDoubleSpeed());
|
||||
data |= 0xBF;
|
||||
break;
|
||||
case 0x1A:
|
||||
@@ -799,7 +884,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
|
||||
psg_.setEnabled(false);
|
||||
} else {
|
||||
psg_.reset();
|
||||
psg_.reset(isDoubleSpeed());
|
||||
psg_.setEnabled(true);
|
||||
}
|
||||
}
|
||||
@@ -828,8 +913,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
case 0x40:
|
||||
if (ioamhram_[0x140] != data) {
|
||||
if ((ioamhram_[0x140] ^ data) & lcdc_en) {
|
||||
unsigned const lyc = lcd_.getStat(ioamhram_[0x145], cc)
|
||||
& lcdstat_lycflag;
|
||||
unsigned const stat = data & lcdc_en ? ioamhram_[0x141] : lcd_.getStat(ioamhram_[0x145], cc);
|
||||
bool const hdmaEnabled = lcd_.hdmaIsEnabled();
|
||||
|
||||
lcd_.lcdcChange(data, cc);
|
||||
@@ -837,14 +921,16 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
ioamhram_[0x141] &= 0xF8;
|
||||
|
||||
if (data & lcdc_en) {
|
||||
if (ioamhram_[0x141] & lcdstat_lycirqen && ioamhram_[0x145] == 0 && !(stat & lcdstat_lycflag))
|
||||
intreq_.flagIrq(2);
|
||||
|
||||
intreq_.setEventTime<intevent_blit>(blanklcd_
|
||||
? lcd_.nextMode1IrqTime()
|
||||
: lcd_.nextMode1IrqTime()
|
||||
+ (70224 << isDoubleSpeed()));
|
||||
: lcd_.nextMode1IrqTime() + (lcd_cycles_per_frame << isDoubleSpeed()));
|
||||
} else {
|
||||
ioamhram_[0x141] |= lyc;
|
||||
ioamhram_[0x141] |= stat & lcdstat_lycflag;
|
||||
intreq_.setEventTime<intevent_blit>(
|
||||
cc + (456 * 4 << isDoubleSpeed()));
|
||||
cc + (lcd_cycles_per_line * 4 << isDoubleSpeed()));
|
||||
|
||||
if (hdmaEnabled)
|
||||
flagHdmaReq(intreq_);
|
||||
@@ -858,6 +944,10 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
return;
|
||||
case 0x41:
|
||||
lcd_.lcdstatChange(data, cc);
|
||||
if (!(ioamhram_[0x140] & lcdc_en) && (ioamhram_[0x141] & lcdstat_lycflag)
|
||||
&& (~ioamhram_[0x141] & lcdstat_lycirqen & (isCgb() ? data : -1))) {
|
||||
intreq_.flagIrq(2);
|
||||
}
|
||||
data = (ioamhram_[0x141] & 0x87) | (data & 0x78);
|
||||
break;
|
||||
case 0x42:
|
||||
@@ -870,11 +960,9 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
lcd_.lycRegChange(data, cc);
|
||||
break;
|
||||
case 0x46:
|
||||
if (lastOamDmaUpdate_ != disabled_time)
|
||||
endOamDma(cc);
|
||||
|
||||
lastOamDmaUpdate_ = cc;
|
||||
intreq_.setEventTime<intevent_oam>(cc + 8);
|
||||
oamDmaStartPos_ = (oamDmaPos_ + 2) & 0xFF;
|
||||
intreq_.setEventTime<intevent_oam>(std::min(intreq_.eventTime(intevent_oam), cc + 8));
|
||||
ioamhram_[0x146] = data;
|
||||
oamDmaInitSetup();
|
||||
return;
|
||||
@@ -959,8 +1047,8 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
if (isCgb()) {
|
||||
unsigned index = ioamhram_[0x168] & 0x3F;
|
||||
lcd_.cgbBgColorChange(index, data, cc);
|
||||
ioamhram_[0x168] = (ioamhram_[0x168] & ~0x3F)
|
||||
| ((index + (ioamhram_[0x168] >> 7)) & 0x3F);
|
||||
ioamhram_[0x168] = (ioamhram_[0x168] & ~0x3Fu)
|
||||
| ((index + (ioamhram_[0x168] >> 7)) & 0x3F);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -973,8 +1061,8 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
||||
if (isCgb()) {
|
||||
unsigned index = ioamhram_[0x16A] & 0x3F;
|
||||
lcd_.cgbSpColorChange(index, data, cc);
|
||||
ioamhram_[0x16A] = (ioamhram_[0x16A] & ~0x3F)
|
||||
| ((index + (ioamhram_[0x16A] >> 7)) & 0x3F);
|
||||
ioamhram_[0x16A] = (ioamhram_[0x16A] & ~0x3Fu)
|
||||
| ((index + (ioamhram_[0x16A] >> 7)) & 0x3F);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1016,42 +1104,53 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
|
||||
if (lastOamDmaUpdate_ != disabled_time) {
|
||||
updateOamDma(cc);
|
||||
|
||||
if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0) {
|
||||
ioamhram_[oamDmaPos_] = data;
|
||||
if (cart_.isInOamDmaConflictArea(p) && oamDmaPos_ < oam_size) {
|
||||
if (isCgb()) {
|
||||
if (p < mm_wram_begin)
|
||||
ioamhram_[oamDmaPos_] = cart_.oamDmaSrc() != oam_dma_src_vram ? data : 0;
|
||||
else if (cart_.oamDmaSrc() != oam_dma_src_wram)
|
||||
cart_.wramdata(ioamhram_[0x146] >> 4 & 1)[p & 0xFFF] = data;
|
||||
} else {
|
||||
ioamhram_[oamDmaPos_] = cart_.oamDmaSrc() == oam_dma_src_wram
|
||||
? ioamhram_[oamDmaPos_] & data
|
||||
: data;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (p < 0xFE00) {
|
||||
if (p < 0xA000) {
|
||||
if (p < 0x8000) {
|
||||
if (p < mm_oam_begin) {
|
||||
if (p < mm_sram_begin) {
|
||||
if (p < mm_vram_begin) {
|
||||
cart_.mbcWrite(p, data);
|
||||
} else if (lcd_.vramAccessible(cc)) {
|
||||
} else if (lcd_.vramWritable(cc)) {
|
||||
lcd_.vramChange(cc);
|
||||
cart_.vrambankptr()[p] = data;
|
||||
}
|
||||
} else if (p < 0xC000) {
|
||||
} else if (p < mm_wram_begin) {
|
||||
if (cart_.wsrambankptr())
|
||||
cart_.wsrambankptr()[p] = data;
|
||||
else
|
||||
cart_.rtcWrite(data);
|
||||
} else
|
||||
cart_.wramdata(p >> 12 & 1)[p & 0xFFF] = data;
|
||||
} else if (p - 0xFF80u >= 0x7Fu) {
|
||||
long const ffp = long(p) - 0xFF00;
|
||||
} else if (p - mm_hram_begin >= 0x7Fu) {
|
||||
long const ffp = static_cast<long>(p) - mm_io_begin;
|
||||
if (ffp < 0) {
|
||||
if (lcd_.oamWritable(cc) && oamDmaPos_ >= 0xA0 && (p < 0xFEA0 || isCgb())) {
|
||||
if (lcd_.oamWritable(cc) && oamDmaPos_ >= oam_size
|
||||
&& (p < mm_oam_begin + oam_size || isCgb())) {
|
||||
lcd_.oamChange(cc);
|
||||
ioamhram_[p - 0xFE00] = data;
|
||||
ioamhram_[p - mm_oam_begin] = data;
|
||||
}
|
||||
} else
|
||||
nontrivial_ff_write(ffp, data, cc);
|
||||
} else
|
||||
ioamhram_[p - 0xFE00] = data;
|
||||
ioamhram_[p - mm_oam_begin] = data;
|
||||
}
|
||||
|
||||
LoadRes Memory::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
|
||||
if (LoadRes const fail = cart_.loadROM(romfile, forceDmg, multicartCompat))
|
||||
LoadRes Memory::loadROM(File &file, std::string const &filename, bool const forceDmg, bool const multicartCompat) {
|
||||
if (LoadRes const fail = cart_.loadROM(file, filename, forceDmg, multicartCompat))
|
||||
return fail;
|
||||
|
||||
psg_.init(cart_.isCgb());
|
||||
@@ -1065,5 +1164,3 @@ std::size_t Memory::fillSoundBuffer(unsigned long cc) {
|
||||
psg_.generateSamples(cc, isDoubleSpeed());
|
||||
return psg_.fillBuffer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef MEMORY_H
|
||||
@@ -28,8 +28,9 @@
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class InputGetter;
|
||||
class File;
|
||||
class FilterInfo;
|
||||
class InputGetter;
|
||||
|
||||
class Memory {
|
||||
public:
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
lcd_.setOsdElement(osdElement);
|
||||
}
|
||||
|
||||
unsigned long stop(unsigned long cycleCounter);
|
||||
unsigned long stop(unsigned long cycleCounter, bool &skip);
|
||||
bool isCgb() const { return lcd_.isCgb(); }
|
||||
bool ime() const { return intreq_.ime(); }
|
||||
bool halted() const { return intreq_.halted(); }
|
||||
@@ -62,9 +63,12 @@ public:
|
||||
return (cc - intreq_.eventTime(intevent_blit)) >> isDoubleSpeed();
|
||||
}
|
||||
|
||||
void halt() { intreq_.halt(); }
|
||||
void freeze(unsigned long cc);
|
||||
bool halt(unsigned long cc);
|
||||
void ei(unsigned long cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
|
||||
void di() { intreq_.di(); }
|
||||
unsigned pendingIrqs(unsigned long cc);
|
||||
void ackIrq(unsigned bit, unsigned long cc);
|
||||
|
||||
unsigned ff_read(unsigned p, unsigned long cc) {
|
||||
return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100];
|
||||
@@ -90,7 +94,7 @@ public:
|
||||
|
||||
unsigned long event(unsigned long cycleCounter);
|
||||
unsigned long resetCounters(unsigned long cycleCounter);
|
||||
LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
|
||||
LoadRes loadROM(File &file, std::string const &filename, bool forceDmg, bool multicartCompat);
|
||||
void setSaveDir(std::string const &dir) { cart_.setSaveDir(dir); }
|
||||
void setInputGetter(InputGetter *getInput) { getInput_ = getInput; }
|
||||
void setEndtime(unsigned long cc, unsigned long inc);
|
||||
@@ -101,6 +105,10 @@ public:
|
||||
lcd_.setVideoBuffer(videoBuf, pitch);
|
||||
}
|
||||
|
||||
void setCgbColorCorrection(int optNum) {
|
||||
lcd_.setCgbColorCorrection(optNum);
|
||||
}
|
||||
|
||||
void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
||||
lcd_.setDmgPaletteColor(palNum, colorNum, rgb32);
|
||||
}
|
||||
@@ -113,7 +121,6 @@ private:
|
||||
Cartridge cart_;
|
||||
unsigned char ioamhram_[0x200];
|
||||
InputGetter *getInput_;
|
||||
unsigned long divLastUpdate_;
|
||||
unsigned long lastOamDmaUpdate_;
|
||||
InterruptRequester intreq_;
|
||||
Tima tima_;
|
||||
@@ -123,8 +130,10 @@ private:
|
||||
unsigned short dmaSource_;
|
||||
unsigned short dmaDestination_;
|
||||
unsigned char oamDmaPos_;
|
||||
unsigned char oamDmaStartPos_;
|
||||
unsigned char serialCnt_;
|
||||
bool blanklcd_;
|
||||
enum HdmaState { hdma_low, hdma_high, hdma_requested } haltHdmaState_;
|
||||
|
||||
void decEventCycles(IntEventId eventId, unsigned long dec);
|
||||
void oamDmaInitSetup();
|
||||
@@ -132,6 +141,7 @@ private:
|
||||
void startOamDma(unsigned long cycleCounter);
|
||||
void endOamDma(unsigned long cycleCounter);
|
||||
unsigned char const * oamDmaSrcPtr() const;
|
||||
unsigned long dma(unsigned long cc);
|
||||
unsigned nontrivial_ff_read(unsigned p, unsigned long cycleCounter);
|
||||
unsigned nontrivial_read(unsigned p, unsigned long cycleCounter);
|
||||
void nontrivial_ff_write(unsigned p, unsigned data, unsigned long cycleCounter);
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef MINKEEPER_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef OSD_ELEMENT_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SAVESTATE_H
|
||||
@@ -54,7 +54,9 @@ struct SaveState {
|
||||
unsigned char f;
|
||||
unsigned char h;
|
||||
unsigned char l;
|
||||
bool skip;
|
||||
unsigned char opcode;
|
||||
unsigned char /*bool*/ prefetched;
|
||||
unsigned char /*bool*/ skip;
|
||||
} cpu;
|
||||
|
||||
struct Mem {
|
||||
@@ -74,11 +76,12 @@ struct SaveState {
|
||||
unsigned short dmaDestination;
|
||||
unsigned char rambank;
|
||||
unsigned char oamDmaPos;
|
||||
bool IME;
|
||||
bool halted;
|
||||
bool enableRam;
|
||||
bool rambankMode;
|
||||
bool hdmaTransfer;
|
||||
unsigned char haltHdmaState;
|
||||
unsigned char /*bool*/ IME;
|
||||
unsigned char /*bool*/ halted;
|
||||
unsigned char /*bool*/ enableRam;
|
||||
unsigned char /*bool*/ rambankMode;
|
||||
unsigned char /*bool*/ hdmaTransfer;
|
||||
} mem;
|
||||
|
||||
struct PPU {
|
||||
@@ -112,8 +115,8 @@ struct SaveState {
|
||||
unsigned char oldWy;
|
||||
unsigned char winDrawState;
|
||||
unsigned char wscx;
|
||||
bool weMaster;
|
||||
bool pendingLcdstatIrq;
|
||||
unsigned char /*bool*/ weMaster;
|
||||
unsigned char /*bool*/ pendingLcdstatIrq;
|
||||
} ppu;
|
||||
|
||||
struct SPU {
|
||||
@@ -121,7 +124,7 @@ struct SaveState {
|
||||
unsigned long nextPosUpdate;
|
||||
unsigned char nr3;
|
||||
unsigned char pos;
|
||||
bool high;
|
||||
unsigned char /*bool*/ high;
|
||||
};
|
||||
|
||||
struct Env {
|
||||
@@ -139,13 +142,13 @@ struct SaveState {
|
||||
unsigned long counter;
|
||||
unsigned short shadow;
|
||||
unsigned char nr0;
|
||||
bool negging;
|
||||
unsigned char /*bool*/ neg;
|
||||
} sweep;
|
||||
Duty duty;
|
||||
Env env;
|
||||
LCounter lcounter;
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
unsigned char /*bool*/ master;
|
||||
} ch1;
|
||||
|
||||
struct {
|
||||
@@ -153,7 +156,7 @@ struct SaveState {
|
||||
Env env;
|
||||
LCounter lcounter;
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
unsigned char /*bool*/ master;
|
||||
} ch2;
|
||||
|
||||
struct {
|
||||
@@ -165,7 +168,7 @@ struct SaveState {
|
||||
unsigned char nr4;
|
||||
unsigned char wavePos;
|
||||
unsigned char sampleBuf;
|
||||
bool master;
|
||||
unsigned char /*bool*/ master;
|
||||
} ch3;
|
||||
|
||||
struct {
|
||||
@@ -176,10 +179,11 @@ struct SaveState {
|
||||
Env env;
|
||||
LCounter lcounter;
|
||||
unsigned char nr4;
|
||||
bool master;
|
||||
unsigned char /*bool*/ master;
|
||||
} ch4;
|
||||
|
||||
unsigned long cycleCounter;
|
||||
unsigned char lastUpdate;
|
||||
} spu;
|
||||
|
||||
struct RTC {
|
||||
@@ -190,7 +194,7 @@ struct SaveState {
|
||||
unsigned char dataH;
|
||||
unsigned char dataM;
|
||||
unsigned char dataS;
|
||||
bool lastLatchData;
|
||||
unsigned char /*bool*/ lastLatchData;
|
||||
} rtc;
|
||||
};
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "sound.h"
|
||||
#include "savestate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
@@ -43,12 +44,13 @@ Clock) clock timer on transition to step.
|
||||
|
||||
*/
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
PSG::PSG()
|
||||
: buffer_(0)
|
||||
, bufferPos_(0)
|
||||
, lastUpdate_(0)
|
||||
, cycleCounter_(0)
|
||||
, soVol_(0)
|
||||
, rsum_(0x8000) // initialize to 0x8000 to prevent borrows from high word, xor away later
|
||||
, enabled_(false)
|
||||
@@ -60,11 +62,41 @@ void PSG::init(bool cgb) {
|
||||
ch3_.init(cgb);
|
||||
}
|
||||
|
||||
void PSG::reset() {
|
||||
void PSG::reset(bool ds) {
|
||||
int const divOffset = lastUpdate_ & ds;
|
||||
unsigned long const cc = cycleCounter_ + divOffset;
|
||||
// cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
cycleCounter_ = (cc & 0xFFF) + 2 * (~(cc + 1 + !ds) & 0x800);
|
||||
lastUpdate_ = ((lastUpdate_ + 3) & -4) - !ds;
|
||||
ch1_.reset();
|
||||
ch2_.reset();
|
||||
ch3_.reset();
|
||||
ch4_.reset();
|
||||
ch4_.reset(cycleCounter_);
|
||||
}
|
||||
|
||||
void PSG::divReset(bool ds) {
|
||||
int const divOffset = lastUpdate_ & ds;
|
||||
unsigned long const cc = cycleCounter_ + divOffset;
|
||||
cycleCounter_ = (cc & -0x1000) + 2 * (cc & 0x800) - divOffset;
|
||||
ch1_.resetCc(cc - divOffset, cycleCounter_);
|
||||
ch2_.resetCc(cc - divOffset, cycleCounter_);
|
||||
ch3_.resetCc(cc - divOffset, cycleCounter_);
|
||||
ch4_.resetCc(cc - divOffset, cycleCounter_);
|
||||
}
|
||||
|
||||
void PSG::speedChange(unsigned long const cpuCc, bool const ds) {
|
||||
generateSamples(cpuCc, ds);
|
||||
lastUpdate_ -= ds;
|
||||
// correct for cycles since DIV reset (if any).
|
||||
if (!ds) {
|
||||
unsigned long const cc = cycleCounter_;
|
||||
unsigned const divCycles = cc & 0xFFF;
|
||||
cycleCounter_ = cc - divCycles / 2 - lastUpdate_ % 2;
|
||||
ch1_.resetCc(cc, cycleCounter_);
|
||||
ch2_.resetCc(cc, cycleCounter_);
|
||||
ch3_.resetCc(cc, cycleCounter_);
|
||||
ch4_.resetCc(cc, cycleCounter_);
|
||||
}
|
||||
}
|
||||
|
||||
void PSG::setStatePtrs(SaveState &state) {
|
||||
@@ -72,10 +104,12 @@ void PSG::setStatePtrs(SaveState &state) {
|
||||
}
|
||||
|
||||
void PSG::saveState(SaveState &state) {
|
||||
ch1_.saveState(state);
|
||||
ch2_.saveState(state);
|
||||
state.spu.cycleCounter = cycleCounter_;
|
||||
state.spu.lastUpdate = (lastUpdate_ + 1) % 4;
|
||||
ch1_.saveState(state, cycleCounter_);
|
||||
ch2_.saveState(state, cycleCounter_);
|
||||
ch3_.saveState(state);
|
||||
ch4_.saveState(state);
|
||||
ch4_.saveState(state, cycleCounter_);
|
||||
}
|
||||
|
||||
void PSG::loadState(SaveState const &state) {
|
||||
@@ -84,23 +118,26 @@ void PSG::loadState(SaveState const &state) {
|
||||
ch3_.loadState(state);
|
||||
ch4_.loadState(state);
|
||||
|
||||
lastUpdate_ = state.cpu.cycleCounter;
|
||||
cycleCounter_ = state.spu.cycleCounter;
|
||||
lastUpdate_ = state.cpu.cycleCounter - (1 - state.spu.lastUpdate) % 4u;
|
||||
setSoVolume(state.mem.ioamhram.get()[0x124]);
|
||||
mapSo(state.mem.ioamhram.get()[0x125]);
|
||||
enabled_ = state.mem.ioamhram.get()[0x126] >> 7 & 1;
|
||||
}
|
||||
|
||||
void PSG::accumulateChannels(unsigned long const cycles) {
|
||||
inline void PSG::accumulateChannels(unsigned long const cycles) {
|
||||
unsigned long const cc = cycleCounter_;
|
||||
uint_least32_t *const buf = buffer_ + bufferPos_;
|
||||
std::memset(buf, 0, cycles * sizeof *buf);
|
||||
ch1_.update(buf, soVol_, cycles);
|
||||
ch2_.update(buf, soVol_, cycles);
|
||||
ch3_.update(buf, soVol_, cycles);
|
||||
ch4_.update(buf, soVol_, cycles);
|
||||
ch1_.update(buf, soVol_, cc, cc + cycles);
|
||||
ch2_.update(buf, soVol_, cc, cc + cycles);
|
||||
ch3_.update(buf, soVol_, cc, cc + cycles);
|
||||
ch4_.update(buf, soVol_, cc, cc + cycles);
|
||||
cycleCounter_ = (cc + cycles) % SoundUnit::counter_max;
|
||||
}
|
||||
|
||||
void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpeed) {
|
||||
unsigned long const cycles = (cycleCounter - lastUpdate_) >> (1 + doubleSpeed);
|
||||
void PSG::generateSamples(unsigned long const cpuCc, bool const doubleSpeed) {
|
||||
unsigned long const cycles = (cpuCc - lastUpdate_) >> (1 + doubleSpeed);
|
||||
lastUpdate_ += cycles << (1 + doubleSpeed);
|
||||
|
||||
if (cycles)
|
||||
@@ -175,10 +212,10 @@ void PSG::setSoVolume(unsigned nr50) {
|
||||
|
||||
void PSG::mapSo(unsigned nr51) {
|
||||
unsigned long so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul();
|
||||
ch1_.setSo((so & 0x00010001) * 0xFFFF);
|
||||
ch2_.setSo((so >> 1 & 0x00010001) * 0xFFFF);
|
||||
ch1_.setSo((so & 0x00010001) * 0xFFFF, cycleCounter_);
|
||||
ch2_.setSo((so >> 1 & 0x00010001) * 0xFFFF, cycleCounter_);
|
||||
ch3_.setSo((so >> 2 & 0x00010001) * 0xFFFF);
|
||||
ch4_.setSo((so >> 3 & 0x00010001) * 0xFFFF);
|
||||
ch4_.setSo((so >> 3 & 0x00010001) * 0xFFFF, cycleCounter_);
|
||||
}
|
||||
|
||||
unsigned PSG::getStatus() const {
|
||||
@@ -187,5 +224,3 @@ unsigned PSG::getStatus() const {
|
||||
| ch3_.isActive() << 2
|
||||
| ch4_.isActive() << 3;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_H
|
||||
@@ -30,13 +30,15 @@ class PSG {
|
||||
public:
|
||||
PSG();
|
||||
void init(bool cgb);
|
||||
void reset();
|
||||
void reset(bool ds);
|
||||
void divReset(bool ds);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state);
|
||||
void loadState(SaveState const &state);
|
||||
|
||||
void generateSamples(unsigned long cycleCounter, bool doubleSpeed);
|
||||
void resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed);
|
||||
void speedChange(unsigned long cc, bool doubleSpeed);
|
||||
std::size_t fillBuffer();
|
||||
void setBuffer(uint_least32_t *buf) { buffer_ = buf; bufferPos_ = 0; }
|
||||
|
||||
@@ -44,28 +46,28 @@ public:
|
||||
void setEnabled(bool value) { enabled_ = value; }
|
||||
|
||||
void setNr10(unsigned data) { ch1_.setNr0(data); }
|
||||
void setNr11(unsigned data) { ch1_.setNr1(data); }
|
||||
void setNr12(unsigned data) { ch1_.setNr2(data); }
|
||||
void setNr13(unsigned data) { ch1_.setNr3(data); }
|
||||
void setNr14(unsigned data) { ch1_.setNr4(data); }
|
||||
void setNr11(unsigned data) { ch1_.setNr1(data, cycleCounter_); }
|
||||
void setNr12(unsigned data) { ch1_.setNr2(data, cycleCounter_); }
|
||||
void setNr13(unsigned data) { ch1_.setNr3(data, cycleCounter_); }
|
||||
void setNr14(unsigned data, bool ds) { ch1_.setNr4(data, cycleCounter_, !(lastUpdate_ & ds)); }
|
||||
|
||||
void setNr21(unsigned data) { ch2_.setNr1(data); }
|
||||
void setNr22(unsigned data) { ch2_.setNr2(data); }
|
||||
void setNr23(unsigned data) { ch2_.setNr3(data); }
|
||||
void setNr24(unsigned data) { ch2_.setNr4(data); }
|
||||
void setNr21(unsigned data) { ch2_.setNr1(data, cycleCounter_); }
|
||||
void setNr22(unsigned data) { ch2_.setNr2(data, cycleCounter_); }
|
||||
void setNr23(unsigned data) { ch2_.setNr3(data, cycleCounter_); }
|
||||
void setNr24(unsigned data, bool ds) { ch2_.setNr4(data, cycleCounter_, !(lastUpdate_ & ds)); }
|
||||
|
||||
void setNr30(unsigned data) { ch3_.setNr0(data); }
|
||||
void setNr31(unsigned data) { ch3_.setNr1(data); }
|
||||
void setNr31(unsigned data) { ch3_.setNr1(data, cycleCounter_); }
|
||||
void setNr32(unsigned data) { ch3_.setNr2(data); }
|
||||
void setNr33(unsigned data) { ch3_.setNr3(data); }
|
||||
void setNr34(unsigned data) { ch3_.setNr4(data); }
|
||||
unsigned waveRamRead(unsigned index) const { return ch3_.waveRamRead(index); }
|
||||
void waveRamWrite(unsigned index, unsigned data) { ch3_.waveRamWrite(index, data); }
|
||||
void setNr34(unsigned data) { ch3_.setNr4(data, cycleCounter_); }
|
||||
unsigned waveRamRead(unsigned index) const { return ch3_.waveRamRead(index, cycleCounter_); }
|
||||
void waveRamWrite(unsigned index, unsigned data) { ch3_.waveRamWrite(index, data, cycleCounter_); }
|
||||
|
||||
void setNr41(unsigned data) { ch4_.setNr1(data); }
|
||||
void setNr42(unsigned data) { ch4_.setNr2(data); }
|
||||
void setNr43(unsigned data) { ch4_.setNr3(data); }
|
||||
void setNr44(unsigned data) { ch4_.setNr4(data); }
|
||||
void setNr41(unsigned data) { ch4_.setNr1(data, cycleCounter_); }
|
||||
void setNr42(unsigned data) { ch4_.setNr2(data, cycleCounter_); }
|
||||
void setNr43(unsigned data) { ch4_.setNr3(data, cycleCounter_); }
|
||||
void setNr44(unsigned data) { ch4_.setNr4(data, cycleCounter_); }
|
||||
|
||||
void setSoVolume(unsigned nr50);
|
||||
void mapSo(unsigned nr51);
|
||||
@@ -79,6 +81,7 @@ private:
|
||||
uint_least32_t *buffer_;
|
||||
std::size_t bufferPos_;
|
||||
unsigned long lastUpdate_;
|
||||
unsigned long cycleCounter_;
|
||||
unsigned long soVol_;
|
||||
uint_least32_t rsum_;
|
||||
bool enabled_;
|
||||
@@ -13,34 +13,33 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "channel1.h"
|
||||
#include "psgdef.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit)
|
||||
: disableMaster_(disabler)
|
||||
, dutyUnit_(dutyUnit)
|
||||
, shadow_(0)
|
||||
, nr0_(0)
|
||||
, negging_(false)
|
||||
, neg_(false)
|
||||
, cgb_(false)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned Channel1::SweepUnit::calcFreq() {
|
||||
unsigned freq = shadow_ >> (nr0_ & 0x07);
|
||||
|
||||
if (nr0_ & 0x08) {
|
||||
freq = shadow_ - freq;
|
||||
negging_ = true;
|
||||
} else
|
||||
freq = shadow_ + freq;
|
||||
|
||||
unsigned const freq = nr0_ & psg_nr10_neg
|
||||
? shadow_ - (shadow_ >> (nr0_ & psg_nr10_rsh))
|
||||
: shadow_ + (shadow_ >> (nr0_ & psg_nr10_rsh));
|
||||
if (nr0_ & psg_nr10_neg)
|
||||
neg_ = true;
|
||||
if (freq & 2048)
|
||||
disableMaster_();
|
||||
|
||||
@@ -48,12 +47,12 @@ unsigned Channel1::SweepUnit::calcFreq() {
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::event() {
|
||||
unsigned long const period = nr0_ >> 4 & 0x07;
|
||||
unsigned long const period = (nr0_ & psg_nr10_time) / (1u * psg_nr10_time & -psg_nr10_time);
|
||||
|
||||
if (period) {
|
||||
unsigned const freq = calcFreq();
|
||||
|
||||
if (!(freq & 2048) && (nr0_ & 0x07)) {
|
||||
if (!(freq & 2048) && nr0_ & psg_nr10_rsh) {
|
||||
shadow_ = freq;
|
||||
dutyUnit_.setFreq(freq, counter_);
|
||||
calcFreq();
|
||||
@@ -65,25 +64,25 @@ void Channel1::SweepUnit::event() {
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::nr0Change(unsigned newNr0) {
|
||||
if (negging_ && !(newNr0 & 0x08))
|
||||
if (neg_ && !(newNr0 & psg_nr10_neg))
|
||||
disableMaster_();
|
||||
|
||||
nr0_ = newNr0;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::nr4Init(unsigned long const cc) {
|
||||
negging_ = false;
|
||||
neg_ = false;
|
||||
shadow_ = dutyUnit_.freq();
|
||||
|
||||
unsigned const period = nr0_ >> 4 & 0x07;
|
||||
unsigned const shift = nr0_ & 0x07;
|
||||
unsigned const period = (nr0_ & psg_nr10_time) / (1u * psg_nr10_time & -psg_nr10_time);
|
||||
unsigned const rsh = nr0_ & psg_nr10_rsh;
|
||||
|
||||
if (period | shift)
|
||||
if (period | rsh)
|
||||
counter_ = ((((cc + 2 + cgb_ * 2) >> 14) + (period ? period : 8)) << 14) + 2;
|
||||
else
|
||||
counter_ = counter_disabled;
|
||||
|
||||
if (shift)
|
||||
if (rsh)
|
||||
calcFreq();
|
||||
}
|
||||
|
||||
@@ -95,14 +94,14 @@ void Channel1::SweepUnit::saveState(SaveState &state) const {
|
||||
state.spu.ch1.sweep.counter = counter_;
|
||||
state.spu.ch1.sweep.shadow = shadow_;
|
||||
state.spu.ch1.sweep.nr0 = nr0_;
|
||||
state.spu.ch1.sweep.negging = negging_;
|
||||
state.spu.ch1.sweep.neg = neg_;
|
||||
}
|
||||
|
||||
void Channel1::SweepUnit::loadState(SaveState const &state) {
|
||||
counter_ = std::max(state.spu.ch1.sweep.counter, state.spu.cycleCounter);
|
||||
shadow_ = state.spu.ch1.sweep.shadow;
|
||||
nr0_ = state.spu.ch1.sweep.nr0;
|
||||
negging_ = state.spu.ch1.sweep.negging;
|
||||
neg_ = state.spu.ch1.sweep.neg;
|
||||
}
|
||||
|
||||
Channel1::Channel1()
|
||||
@@ -112,7 +111,6 @@ Channel1::Channel1()
|
||||
, envelopeUnit_(staticOutputTest_)
|
||||
, sweepUnit_(disableMaster_, dutyUnit_)
|
||||
, nextEventUnit_(0)
|
||||
, cycleCounter_(0)
|
||||
, soMask_(0)
|
||||
, prevOut_(0)
|
||||
, nr4_(0)
|
||||
@@ -134,52 +132,48 @@ void Channel1::setNr0(unsigned data) {
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr1(unsigned data) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cycleCounter_);
|
||||
dutyUnit_.nr1Change(data, cycleCounter_);
|
||||
void Channel1::setNr1(unsigned data, unsigned long cc) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cc);
|
||||
dutyUnit_.nr1Change(data, cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr2(unsigned data) {
|
||||
void Channel1::setNr2(unsigned data, unsigned long cc) {
|
||||
if (envelopeUnit_.nr2Change(data))
|
||||
disableMaster_();
|
||||
else
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr3(unsigned data) {
|
||||
dutyUnit_.nr3Change(data, cycleCounter_);
|
||||
void Channel1::setNr3(unsigned data, unsigned long cc) {
|
||||
dutyUnit_.nr3Change(data, cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setNr4(unsigned const data) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
|
||||
void Channel1::setNr4(unsigned data, unsigned long cc, unsigned long ref) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cc);
|
||||
dutyUnit_.nr4Change(data, cc, ref);
|
||||
nr4_ = data;
|
||||
dutyUnit_.nr4Change(data, cycleCounter_);
|
||||
|
||||
if (data & 0x80) { // init-bit
|
||||
nr4_ &= 0x7F;
|
||||
master_ = !envelopeUnit_.nr4Init(cycleCounter_);
|
||||
sweepUnit_.nr4Init(cycleCounter_);
|
||||
staticOutputTest_(cycleCounter_);
|
||||
if (nr4_ & psg_nr4_init) {
|
||||
nr4_ -= psg_nr4_init;
|
||||
master_ = !envelopeUnit_.nr4Init(cc);
|
||||
sweepUnit_.nr4Init(cc);
|
||||
staticOutputTest_(cc);
|
||||
}
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::setSo(unsigned long soMask) {
|
||||
void Channel1::setSo(unsigned long soMask, unsigned long cc) {
|
||||
soMask_ = soMask;
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel1::reset() {
|
||||
// cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
cycleCounter_ &= 0xFFF;
|
||||
cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
|
||||
|
||||
dutyUnit_.reset();
|
||||
envelopeUnit_.reset();
|
||||
sweepUnit_.reset();
|
||||
@@ -190,13 +184,12 @@ void Channel1::init(bool cgb) {
|
||||
sweepUnit_.init(cgb);
|
||||
}
|
||||
|
||||
void Channel1::saveState(SaveState &state) {
|
||||
void Channel1::saveState(SaveState &state, unsigned long cc) {
|
||||
sweepUnit_.saveState(state);
|
||||
dutyUnit_.saveState(state.spu.ch1.duty, cycleCounter_);
|
||||
dutyUnit_.saveState(state.spu.ch1.duty, cc);
|
||||
envelopeUnit_.saveState(state.spu.ch1.env);
|
||||
lengthCounter_.saveState(state.spu.ch1.lcounter);
|
||||
|
||||
state.spu.cycleCounter = cycleCounter_;
|
||||
state.spu.ch1.nr4 = nr4_;
|
||||
state.spu.ch1.master = master_;
|
||||
}
|
||||
@@ -204,59 +197,50 @@ void Channel1::saveState(SaveState &state) {
|
||||
void Channel1::loadState(SaveState const &state) {
|
||||
sweepUnit_.loadState(state);
|
||||
dutyUnit_.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111],
|
||||
state.spu.ch1.nr4, state.spu.cycleCounter);
|
||||
state.spu.ch1.nr4, state.spu.cycleCounter);
|
||||
envelopeUnit_.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112],
|
||||
state.spu.cycleCounter);
|
||||
state.spu.cycleCounter);
|
||||
lengthCounter_.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter_ = state.spu.cycleCounter;
|
||||
nr4_ = state.spu.ch1.nr4;
|
||||
master_ = state.spu.ch1.master;
|
||||
}
|
||||
|
||||
void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
||||
void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) {
|
||||
unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
||||
unsigned long const outLow = outBase * (0 - 15ul);
|
||||
unsigned long const endCycles = cycleCounter_ + cycles;
|
||||
unsigned long const outLow = outBase * -15;
|
||||
|
||||
for (;;) {
|
||||
while (cc < end) {
|
||||
unsigned long const outHigh = master_
|
||||
? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
|
||||
: outLow;
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
||||
? outBase * (envelopeUnit_.getVolume() * 2l - 15)
|
||||
: outLow;
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), end);
|
||||
unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (dutyUnit_.counter() <= nextMajorEvent) {
|
||||
*buf = out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += dutyUnit_.counter() - cycleCounter_;
|
||||
cycleCounter_ = dutyUnit_.counter();
|
||||
|
||||
buf += dutyUnit_.counter() - cc;
|
||||
cc = dutyUnit_.counter();
|
||||
dutyUnit_.event();
|
||||
out = dutyUnit_.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
if (cycleCounter_ < nextMajorEvent) {
|
||||
if (cc < nextMajorEvent) {
|
||||
*buf = out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += nextMajorEvent - cycleCounter_;
|
||||
cycleCounter_ = nextMajorEvent;
|
||||
buf += nextMajorEvent - cc;
|
||||
cc = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit_->counter() == nextMajorEvent) {
|
||||
nextEventUnit_->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cycleCounter_ >= SoundUnit::counter_max) {
|
||||
dutyUnit_.resetCounters(cycleCounter_);
|
||||
lengthCounter_.resetCounters(cycleCounter_);
|
||||
envelopeUnit_.resetCounters(cycleCounter_);
|
||||
sweepUnit_.resetCounters(cycleCounter_);
|
||||
cycleCounter_ -= SoundUnit::counter_max;
|
||||
if (cc >= SoundUnit::counter_max) {
|
||||
dutyUnit_.resetCounters(cc);
|
||||
lengthCounter_.resetCounters(cc);
|
||||
envelopeUnit_.resetCounters(cc);
|
||||
sweepUnit_.resetCounters(cc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_CHANNEL1_H
|
||||
@@ -34,16 +34,17 @@ class Channel1 {
|
||||
public:
|
||||
Channel1();
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void setNr1(unsigned data, unsigned long cc);
|
||||
void setNr2(unsigned data, unsigned long cc);
|
||||
void setNr3(unsigned data, unsigned long cc);
|
||||
void setNr4(unsigned data, unsigned long cc, unsigned long ref);
|
||||
void setSo(unsigned long soMask, unsigned long cc);
|
||||
bool isActive() const { return master_; }
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cc, unsigned long end);
|
||||
void reset();
|
||||
void resetCc(unsigned long cc, unsigned long ncc) { dutyUnit_.resetCc(cc, ncc); }
|
||||
void init(bool cgb);
|
||||
void saveState(SaveState &state);
|
||||
void saveState(SaveState &state, unsigned long cc);
|
||||
void loadState(SaveState const &state);
|
||||
|
||||
private:
|
||||
@@ -63,7 +64,7 @@ private:
|
||||
DutyUnit &dutyUnit_;
|
||||
unsigned short shadow_;
|
||||
unsigned char nr0_;
|
||||
bool negging_;
|
||||
bool neg_;
|
||||
bool cgb_;
|
||||
|
||||
unsigned calcFreq();
|
||||
@@ -78,7 +79,6 @@ private:
|
||||
EnvelopeUnit envelopeUnit_;
|
||||
SweepUnit sweepUnit_;
|
||||
SoundUnit *nextEventUnit_;
|
||||
unsigned long cycleCounter_;
|
||||
unsigned long soMask_;
|
||||
unsigned long prevOut_;
|
||||
unsigned char nr4_;
|
||||
@@ -13,21 +13,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "channel2.h"
|
||||
#include "psgdef.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
Channel2::Channel2()
|
||||
: staticOutputTest_(*this, dutyUnit_)
|
||||
, disableMaster_(master_, dutyUnit_)
|
||||
, lengthCounter_(disableMaster_, 0x3F)
|
||||
, envelopeUnit_(staticOutputTest_)
|
||||
, cycleCounter_(0)
|
||||
, soMask_(0)
|
||||
, prevOut_(0)
|
||||
, nr4_(0)
|
||||
@@ -42,58 +43,54 @@ void Channel2::setEvent() {
|
||||
nextEventUnit = &lengthCounter_;
|
||||
}
|
||||
|
||||
void Channel2::setNr1(unsigned data) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cycleCounter_);
|
||||
dutyUnit_.nr1Change(data, cycleCounter_);
|
||||
void Channel2::setNr1(unsigned data, unsigned long cc) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cc);
|
||||
dutyUnit_.nr1Change(data, cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr2(unsigned data) {
|
||||
void Channel2::setNr2(unsigned data, unsigned long cc) {
|
||||
if (envelopeUnit_.nr2Change(data))
|
||||
disableMaster_();
|
||||
else
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr3(unsigned data) {
|
||||
dutyUnit_.nr3Change(data, cycleCounter_);
|
||||
void Channel2::setNr3(unsigned data, unsigned long cc) {
|
||||
dutyUnit_.nr3Change(data, cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setNr4(unsigned const data) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
|
||||
void Channel2::setNr4(unsigned data, unsigned long cc, unsigned long ref) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cc);
|
||||
nr4_ = data;
|
||||
|
||||
if (data & 0x80) { // init-bit
|
||||
nr4_ &= 0x7F;
|
||||
master_ = !envelopeUnit_.nr4Init(cycleCounter_);
|
||||
staticOutputTest_(cycleCounter_);
|
||||
if (nr4_ & psg_nr4_init) {
|
||||
nr4_ -= psg_nr4_init;
|
||||
master_ = !envelopeUnit_.nr4Init(cc);
|
||||
staticOutputTest_(cc);
|
||||
}
|
||||
|
||||
dutyUnit_.nr4Change(data, cycleCounter_);
|
||||
dutyUnit_.nr4Change(data, cc, ref);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::setSo(unsigned long soMask) {
|
||||
void Channel2::setSo(unsigned long soMask, unsigned long cc) {
|
||||
soMask_ = soMask;
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::reset() {
|
||||
// cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
cycleCounter_ &= 0xFFF;
|
||||
cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
|
||||
|
||||
dutyUnit_.reset();
|
||||
envelopeUnit_.reset();
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel2::saveState(SaveState &state) {
|
||||
dutyUnit_.saveState(state.spu.ch2.duty, cycleCounter_);
|
||||
void Channel2::saveState(SaveState &state, unsigned long cc) {
|
||||
dutyUnit_.saveState(state.spu.ch2.duty, cc);
|
||||
envelopeUnit_.saveState(state.spu.ch2.env);
|
||||
lengthCounter_.saveState(state.spu.ch2.lcounter);
|
||||
|
||||
@@ -103,58 +100,49 @@ void Channel2::saveState(SaveState &state) {
|
||||
|
||||
void Channel2::loadState(SaveState const &state) {
|
||||
dutyUnit_.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116],
|
||||
state.spu.ch2.nr4, state.spu.cycleCounter);
|
||||
state.spu.ch2.nr4, state.spu.cycleCounter);
|
||||
envelopeUnit_.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117],
|
||||
state.spu.cycleCounter);
|
||||
state.spu.cycleCounter);
|
||||
lengthCounter_.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter_ = state.spu.cycleCounter;
|
||||
nr4_ = state.spu.ch2.nr4;
|
||||
master_ = state.spu.ch2.master;
|
||||
}
|
||||
|
||||
void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
||||
void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) {
|
||||
unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
||||
unsigned long const outLow = outBase * (0 - 15ul);
|
||||
unsigned long const endCycles = cycleCounter_ + cycles;
|
||||
unsigned long const outLow = outBase * -15;
|
||||
|
||||
for (;;) {
|
||||
while (cc < end) {
|
||||
unsigned long const outHigh = master_
|
||||
? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
|
||||
: outLow;
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit->counter(), endCycles);
|
||||
? outBase * (envelopeUnit_.getVolume() * 2l - 15)
|
||||
: outLow;
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit->counter(), end);
|
||||
unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (dutyUnit_.counter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += dutyUnit_.counter() - cycleCounter_;
|
||||
cycleCounter_ = dutyUnit_.counter();
|
||||
|
||||
buf += dutyUnit_.counter() - cc;
|
||||
cc = dutyUnit_.counter();
|
||||
dutyUnit_.event();
|
||||
out = dutyUnit_.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
|
||||
if (cycleCounter_ < nextMajorEvent) {
|
||||
if (cc < nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += nextMajorEvent - cycleCounter_;
|
||||
cycleCounter_ = nextMajorEvent;
|
||||
buf += nextMajorEvent - cc;
|
||||
cc = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit->counter() == nextMajorEvent) {
|
||||
nextEventUnit->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cycleCounter_ >= SoundUnit::counter_max) {
|
||||
dutyUnit_.resetCounters(cycleCounter_);
|
||||
lengthCounter_.resetCounters(cycleCounter_);
|
||||
envelopeUnit_.resetCounters(cycleCounter_);
|
||||
cycleCounter_ -= SoundUnit::counter_max;
|
||||
if (cc >= SoundUnit::counter_max) {
|
||||
dutyUnit_.resetCounters(cc);
|
||||
lengthCounter_.resetCounters(cc);
|
||||
envelopeUnit_.resetCounters(cc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_CHANNEL2_H
|
||||
@@ -32,15 +32,16 @@ struct SaveState;
|
||||
class Channel2 {
|
||||
public:
|
||||
Channel2();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data);
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void setNr1(unsigned data, unsigned long cc);
|
||||
void setNr2(unsigned data, unsigned long cc);
|
||||
void setNr3(unsigned data, unsigned long cc);
|
||||
void setNr4(unsigned data, unsigned long cc, unsigned long ref);
|
||||
void setSo(unsigned long soMask, unsigned long cc);
|
||||
bool isActive() const { return master_; }
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cc, unsigned long end);
|
||||
void reset();
|
||||
void saveState(SaveState &state);
|
||||
void resetCc(unsigned long cc, unsigned long ncc) { dutyUnit_.resetCc(cc, ncc); }
|
||||
void saveState(SaveState &state, unsigned long cc);
|
||||
void loadState(SaveState const &state);
|
||||
|
||||
private:
|
||||
@@ -52,7 +53,6 @@ private:
|
||||
DutyUnit dutyUnit_;
|
||||
EnvelopeUnit envelopeUnit_;
|
||||
SoundUnit *nextEventUnit;
|
||||
unsigned long cycleCounter_;
|
||||
unsigned long soMask_;
|
||||
unsigned long prevOut_;
|
||||
unsigned char nr4_;
|
||||
@@ -13,24 +13,29 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "channel3.h"
|
||||
#include "psgdef.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
static inline unsigned toPeriod(unsigned nr3, unsigned nr4) {
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
unsigned toPeriod(unsigned nr3, unsigned nr4) {
|
||||
return 0x800 - ((nr4 << 8 & 0x700) | nr3);
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
}
|
||||
|
||||
Channel3::Channel3()
|
||||
: disableMaster_(master_, waveCounter_)
|
||||
, lengthCounter_(disableMaster_, 0xFF)
|
||||
, cycleCounter_(0)
|
||||
, soMask_(0)
|
||||
, prevOut_(0)
|
||||
, waveCounter_(SoundUnit::counter_disabled)
|
||||
@@ -47,25 +52,22 @@ Channel3::Channel3()
|
||||
}
|
||||
|
||||
void Channel3::setNr0(unsigned data) {
|
||||
nr0_ = data & 0x80;
|
||||
|
||||
if (!(data & 0x80))
|
||||
nr0_ = data & psg_nr4_init;
|
||||
if (!nr0_)
|
||||
disableMaster_();
|
||||
}
|
||||
|
||||
void Channel3::setNr2(unsigned data) {
|
||||
rshift_ = (data >> 5 & 3U) - 1;
|
||||
if (rshift_ > 3)
|
||||
rshift_ = 4;
|
||||
rshift_ = std::min((data >> 5 & 3) - 1, 4u);
|
||||
}
|
||||
|
||||
void Channel3::setNr4(unsigned const data) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
|
||||
nr4_ = data & 0x7F;
|
||||
void Channel3::setNr4(unsigned const data, unsigned long const cc) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cc);
|
||||
nr4_ = data & ~(1u * psg_nr4_init);
|
||||
|
||||
if (data & nr0_/* & 0x80*/) {
|
||||
if (!cgb_ && waveCounter_ == cycleCounter_ + 1) {
|
||||
unsigned const pos = ((wavePos_ + 1) & 0x1F) >> 1;
|
||||
if (data & nr0_) {
|
||||
if (!cgb_ && waveCounter_ == cc + 1) {
|
||||
int const pos = (wavePos_ + 1) / 2 % sizeof waveRam_;
|
||||
|
||||
if (pos < 4)
|
||||
waveRam_[0] = waveRam_[pos];
|
||||
@@ -75,7 +77,7 @@ void Channel3::setNr4(unsigned const data) {
|
||||
|
||||
master_ = true;
|
||||
wavePos_ = 0;
|
||||
lastReadTime_ = waveCounter_ = cycleCounter_ + toPeriod(nr3_, data) + 3;
|
||||
lastReadTime_ = waveCounter_ = cc + toPeriod(nr3_, data) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,13 +86,15 @@ void Channel3::setSo(unsigned long soMask) {
|
||||
}
|
||||
|
||||
void Channel3::reset() {
|
||||
// cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
cycleCounter_ &= 0xFFF;
|
||||
cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
|
||||
|
||||
sampleBuf_ = 0;
|
||||
}
|
||||
|
||||
void Channel3::resetCc(unsigned long cc, unsigned long newCc) {
|
||||
lastReadTime_ -= cc - newCc;
|
||||
if (waveCounter_ != SoundUnit::counter_disabled)
|
||||
waveCounter_ -= cc - newCc;
|
||||
}
|
||||
|
||||
void Channel3::init(bool cgb) {
|
||||
cgb_ = cgb;
|
||||
}
|
||||
@@ -114,16 +118,15 @@ void Channel3::saveState(SaveState &state) const {
|
||||
void Channel3::loadState(SaveState const &state) {
|
||||
lengthCounter_.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter_ = state.spu.cycleCounter;
|
||||
waveCounter_ = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter);
|
||||
lastReadTime_ = state.spu.ch3.lastReadTime;
|
||||
nr3_ = state.spu.ch3.nr3;
|
||||
nr4_ = state.spu.ch3.nr4;
|
||||
wavePos_ = state.spu.ch3.wavePos & 0x1F;
|
||||
wavePos_ = state.spu.ch3.wavePos % (2 * sizeof waveRam_);
|
||||
sampleBuf_ = state.spu.ch3.sampleBuf;
|
||||
master_ = state.spu.ch3.master;
|
||||
|
||||
nr0_ = state.mem.ioamhram.get()[0x11A] & 0x80;
|
||||
nr0_ = state.mem.ioamhram.get()[0x11A] & psg_nr4_init;
|
||||
setNr2(state.mem.ioamhram.get()[0x11C]);
|
||||
}
|
||||
|
||||
@@ -134,78 +137,78 @@ void Channel3::updateWaveCounter(unsigned long const cc) {
|
||||
|
||||
lastReadTime_ = waveCounter_ + periods * period;
|
||||
waveCounter_ = lastReadTime_ + period;
|
||||
|
||||
wavePos_ += periods + 1;
|
||||
wavePos_ &= 0x1F;
|
||||
|
||||
sampleBuf_ = waveRam_[wavePos_ >> 1];
|
||||
wavePos_ = (wavePos_ + periods + 1) % (2 * sizeof waveRam_);
|
||||
sampleBuf_ = waveRam_[wavePos_ / 2];
|
||||
}
|
||||
}
|
||||
|
||||
void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
||||
unsigned long const outBase = nr0_/* & 0x80*/ ? soBaseVol & soMask_ : 0;
|
||||
void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) {
|
||||
unsigned long const outBase = nr0_ ? soBaseVol & soMask_ : 0;
|
||||
|
||||
if (outBase && rshift_ != 4) {
|
||||
unsigned long const endCycles = cycleCounter_ + cycles;
|
||||
|
||||
for (;;) {
|
||||
while (std::min(waveCounter_, lengthCounter_.counter()) <= end) {
|
||||
unsigned pos = wavePos_;
|
||||
unsigned const period = toPeriod(nr3_, nr4_), rsh = rshift_;
|
||||
unsigned long const nextMajorEvent =
|
||||
std::min(lengthCounter_.counter(), endCycles);
|
||||
std::min(lengthCounter_.counter(), end);
|
||||
unsigned long cnt = waveCounter_, prevOut = prevOut_;
|
||||
unsigned long out = master_
|
||||
? ((sampleBuf_ >> (~wavePos_ << 2 & 4) & 0xF) >> rshift_) * 2 - 15ul
|
||||
: 0 - 15ul;
|
||||
? ((pos % 2 ? sampleBuf_ & 0xF : sampleBuf_ >> 4) >> rsh) * 2l - 15
|
||||
: -15;
|
||||
out *= outBase;
|
||||
|
||||
while (waveCounter_ <= nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += waveCounter_ - cycleCounter_;
|
||||
cycleCounter_ = waveCounter_;
|
||||
|
||||
lastReadTime_ = waveCounter_;
|
||||
waveCounter_ += toPeriod(nr3_, nr4_);
|
||||
++wavePos_;
|
||||
wavePos_ &= 0x1F;
|
||||
sampleBuf_ = waveRam_[wavePos_ >> 1];
|
||||
out = ((sampleBuf_ >> (~wavePos_ << 2 & 4) & 0xF) >> rshift_) * 2 - 15ul;
|
||||
while (cnt <= nextMajorEvent) {
|
||||
*buf += out - prevOut;
|
||||
prevOut = out;
|
||||
buf += cnt - cc;
|
||||
cc = cnt;
|
||||
cnt += period;
|
||||
++pos;
|
||||
unsigned const s = waveRam_[pos / 2 % sizeof waveRam_];
|
||||
out = ((pos % 2 ? s & 0xF : s >> 4) >> rsh) * 2l - 15;
|
||||
out *= outBase;
|
||||
}
|
||||
|
||||
if (cycleCounter_ < nextMajorEvent) {
|
||||
if (cnt != waveCounter_) {
|
||||
wavePos_ = pos % (2 * sizeof waveRam_);
|
||||
sampleBuf_ = waveRam_[wavePos_ / 2];
|
||||
prevOut_ = prevOut;
|
||||
waveCounter_ = cnt;
|
||||
lastReadTime_ = cc;
|
||||
}
|
||||
if (cc < nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += nextMajorEvent - cycleCounter_;
|
||||
cycleCounter_ = nextMajorEvent;
|
||||
buf += nextMajorEvent - cc;
|
||||
cc = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (lengthCounter_.counter() == nextMajorEvent) {
|
||||
if (lengthCounter_.counter() == nextMajorEvent)
|
||||
lengthCounter_.event();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (cc < end) {
|
||||
unsigned long out = master_
|
||||
? ((wavePos_ % 2 ? sampleBuf_ & 0xF : sampleBuf_ >> 4) >> rshift_) * 2l - 15
|
||||
: -15;
|
||||
out *= outBase;
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
cc = end;
|
||||
}
|
||||
} else {
|
||||
unsigned long const out = outBase * (0 - 15ul);
|
||||
unsigned long const out = outBase * -15;
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
cycleCounter_ += cycles;
|
||||
|
||||
while (lengthCounter_.counter() <= cycleCounter_) {
|
||||
cc = end;
|
||||
while (lengthCounter_.counter() <= cc) {
|
||||
updateWaveCounter(lengthCounter_.counter());
|
||||
lengthCounter_.event();
|
||||
}
|
||||
|
||||
updateWaveCounter(cycleCounter_);
|
||||
updateWaveCounter(cc);
|
||||
}
|
||||
|
||||
if (cycleCounter_ >= SoundUnit::counter_max) {
|
||||
lengthCounter_.resetCounters(cycleCounter_);
|
||||
|
||||
if (cc >= SoundUnit::counter_max) {
|
||||
lengthCounter_.resetCounters(cc);
|
||||
lastReadTime_ -= SoundUnit::counter_max;
|
||||
if (waveCounter_ != SoundUnit::counter_disabled)
|
||||
waveCounter_ -= SoundUnit::counter_max;
|
||||
|
||||
lastReadTime_ -= SoundUnit::counter_max;
|
||||
cycleCounter_ -= SoundUnit::counter_max;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_CHANNEL3_H
|
||||
@@ -31,36 +31,38 @@ class Channel3 {
|
||||
public:
|
||||
Channel3();
|
||||
bool isActive() const { return master_; }
|
||||
bool isCgb() const { return cgb_; }
|
||||
void reset();
|
||||
void resetCc(unsigned long cc, unsigned long newCc);
|
||||
void init(bool cgb);
|
||||
void setStatePtrs(SaveState &state);
|
||||
void saveState(SaveState &state) const;
|
||||
void loadState(const SaveState &state);
|
||||
void loadState(SaveState const &state);
|
||||
void setNr0(unsigned data);
|
||||
void setNr1(unsigned data) { lengthCounter_.nr1Change(data, nr4_, cycleCounter_); }
|
||||
void setNr1(unsigned data, unsigned long cc) { lengthCounter_.nr1Change(data, nr4_, cc); }
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { nr3_ = data; }
|
||||
void setNr4(unsigned data);
|
||||
void setNr4(unsigned data, unsigned long cc);
|
||||
void setSo(unsigned long soMask);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cc, unsigned long end);
|
||||
|
||||
unsigned waveRamRead(unsigned index) const {
|
||||
unsigned waveRamRead(unsigned index, unsigned long cc) const {
|
||||
if (master_) {
|
||||
if (!cgb_ && cycleCounter_ != lastReadTime_)
|
||||
if (!cgb_ && cc != lastReadTime_)
|
||||
return 0xFF;
|
||||
|
||||
index = wavePos_ >> 1;
|
||||
index = wavePos_ / 2;
|
||||
}
|
||||
|
||||
return waveRam_[index];
|
||||
}
|
||||
|
||||
void waveRamWrite(unsigned index, unsigned data) {
|
||||
void waveRamWrite(unsigned index, unsigned data, unsigned long cc) {
|
||||
if (master_) {
|
||||
if (!cgb_ && cycleCounter_ != lastReadTime_)
|
||||
if (!cgb_ && cc != lastReadTime_)
|
||||
return;
|
||||
|
||||
index = wavePos_ >> 1;
|
||||
index = wavePos_ / 2;
|
||||
}
|
||||
|
||||
waveRam_[index] = data;
|
||||
@@ -83,7 +85,6 @@ private:
|
||||
unsigned char waveRam_[0x10];
|
||||
Ch3MasterDisabler disableMaster_;
|
||||
LengthCounter lengthCounter_;
|
||||
unsigned long cycleCounter_;
|
||||
unsigned long soMask_;
|
||||
unsigned long prevOut_;
|
||||
unsigned long waveCounter_;
|
||||
@@ -13,16 +13,22 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "channel4.h"
|
||||
#include "psgdef.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static unsigned long toPeriod(unsigned const nr3) {
|
||||
unsigned s = (nr3 >> 4) + 3;
|
||||
unsigned r = nr3 & 7;
|
||||
using namespace gambatte;
|
||||
|
||||
namespace {
|
||||
|
||||
unsigned long toPeriod(unsigned const nr3) {
|
||||
unsigned s = nr3 / (1u * psg_nr43_s & -psg_nr43_s) + 3;
|
||||
unsigned r = nr3 & psg_nr43_r;
|
||||
|
||||
if (!r) {
|
||||
r = 1;
|
||||
@@ -32,7 +38,7 @@ static unsigned long toPeriod(unsigned const nr3) {
|
||||
return r << s;
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
}
|
||||
|
||||
Channel4::Lfsr::Lfsr()
|
||||
: backupCounter_(counter_disabled)
|
||||
@@ -48,16 +54,16 @@ void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
|
||||
unsigned long periods = (cc - backupCounter_) / period + 1;
|
||||
backupCounter_ += periods * period;
|
||||
|
||||
if (master_ && nr3_ < 0xE0) {
|
||||
if (nr3_ & 8) {
|
||||
if (master_ && nr3_ < 0xE * (1u * psg_nr43_s & -psg_nr43_s)) {
|
||||
if (nr3_ & psg_nr43_7biten) {
|
||||
while (periods > 6) {
|
||||
unsigned const xored = (reg_ << 1 ^ reg_) & 0x7E;
|
||||
reg_ = (reg_ >> 6 & ~0x7E) | xored | xored << 8;
|
||||
reg_ = (reg_ >> 6 & ~0x7Eu) | xored | xored << 8;
|
||||
periods -= 6;
|
||||
}
|
||||
|
||||
unsigned const xored = ((reg_ ^ reg_ >> 1) << (7 - periods)) & 0x7F;
|
||||
reg_ = (reg_ >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
|
||||
reg_ = (reg_ >> periods & ~(0x80u - (0x80 >> periods))) | xored | xored << 8;
|
||||
} else {
|
||||
while (periods > 15) {
|
||||
reg_ = reg_ ^ reg_ >> 1;
|
||||
@@ -76,13 +82,13 @@ void Channel4::Lfsr::reviveCounter(unsigned long cc) {
|
||||
}
|
||||
|
||||
inline void Channel4::Lfsr::event() {
|
||||
if (nr3_ < 0xE0) {
|
||||
if (nr3_ < 0xE * (1u * psg_nr43_s & -psg_nr43_s)) {
|
||||
unsigned const shifted = reg_ >> 1;
|
||||
unsigned const xored = (reg_ ^ shifted) & 1;
|
||||
reg_ = shifted | xored << 14;
|
||||
|
||||
if (nr3_ & 8)
|
||||
reg_ = (reg_ & ~0x40) | xored << 6;
|
||||
if (nr3_ & psg_nr43_7biten)
|
||||
reg_ = (reg_ & ~0x40u) | xored << 6;
|
||||
}
|
||||
|
||||
counter_ += toPeriod(nr3_);
|
||||
@@ -108,10 +114,15 @@ void Channel4::Lfsr::reset(unsigned long cc) {
|
||||
backupCounter_ = cc + toPeriod(nr3_);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::resetCounters(unsigned long oldCc) {
|
||||
updateBackupCounter(oldCc);
|
||||
backupCounter_ -= counter_max;
|
||||
SoundUnit::resetCounters(oldCc);
|
||||
void Channel4::Lfsr::resetCc(unsigned long cc, unsigned long newCc) {
|
||||
updateBackupCounter(cc);
|
||||
backupCounter_ -= cc - newCc;
|
||||
if (counter_ != counter_disabled)
|
||||
counter_ -= cc - newCc;
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::resetCounters(unsigned long cc) {
|
||||
resetCc(cc, cc - counter_max);
|
||||
}
|
||||
|
||||
void Channel4::Lfsr::saveState(SaveState &state, unsigned long cc) {
|
||||
@@ -133,7 +144,6 @@ Channel4::Channel4()
|
||||
, lengthCounter_(disableMaster_, 0x3F)
|
||||
, envelopeUnit_(staticOutputTest_)
|
||||
, nextEventUnit_(0)
|
||||
, cycleCounter_(0)
|
||||
, soMask_(0)
|
||||
, prevOut_(0)
|
||||
, nr4_(0)
|
||||
@@ -148,55 +158,50 @@ void Channel4::setEvent() {
|
||||
nextEventUnit_ = &lengthCounter_;
|
||||
}
|
||||
|
||||
void Channel4::setNr1(unsigned data) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cycleCounter_);
|
||||
void Channel4::setNr1(unsigned data, unsigned long cc) {
|
||||
lengthCounter_.nr1Change(data, nr4_, cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setNr2(unsigned data) {
|
||||
void Channel4::setNr2(unsigned data, unsigned long cc) {
|
||||
if (envelopeUnit_.nr2Change(data))
|
||||
disableMaster_();
|
||||
else
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setNr4(unsigned const data) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
|
||||
void Channel4::setNr4(unsigned const data, unsigned long const cc) {
|
||||
lengthCounter_.nr4Change(nr4_, data, cc);
|
||||
nr4_ = data;
|
||||
|
||||
if (data & 0x80) { // init-bit
|
||||
nr4_ &= 0x7F;
|
||||
master_ = !envelopeUnit_.nr4Init(cycleCounter_);
|
||||
|
||||
if (nr4_ & psg_nr4_init) {
|
||||
nr4_ -= psg_nr4_init;
|
||||
master_ = !envelopeUnit_.nr4Init(cc);
|
||||
if (master_)
|
||||
lfsr_.nr4Init(cycleCounter_);
|
||||
lfsr_.nr4Init(cc);
|
||||
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
}
|
||||
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::setSo(unsigned long soMask) {
|
||||
void Channel4::setSo(unsigned long soMask, unsigned long cc) {
|
||||
soMask_ = soMask;
|
||||
staticOutputTest_(cycleCounter_);
|
||||
staticOutputTest_(cc);
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::reset() {
|
||||
// cycleCounter >> 12 & 7 represents the frame sequencer position.
|
||||
cycleCounter_ &= 0xFFF;
|
||||
cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
|
||||
|
||||
lfsr_.reset(cycleCounter_);
|
||||
void Channel4::reset(unsigned long cc) {
|
||||
lfsr_.reset(cc);
|
||||
envelopeUnit_.reset();
|
||||
setEvent();
|
||||
}
|
||||
|
||||
void Channel4::saveState(SaveState &state) {
|
||||
lfsr_.saveState(state, cycleCounter_);
|
||||
void Channel4::saveState(SaveState &state, unsigned long cc) {
|
||||
lfsr_.saveState(state, cc);
|
||||
envelopeUnit_.saveState(state.spu.ch4.env);
|
||||
lengthCounter_.saveState(state.spu.ch4.lcounter);
|
||||
|
||||
@@ -207,54 +212,48 @@ void Channel4::saveState(SaveState &state) {
|
||||
void Channel4::loadState(SaveState const &state) {
|
||||
lfsr_.loadState(state);
|
||||
envelopeUnit_.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121],
|
||||
state.spu.cycleCounter);
|
||||
state.spu.cycleCounter);
|
||||
lengthCounter_.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
|
||||
|
||||
cycleCounter_ = state.spu.cycleCounter;
|
||||
nr4_ = state.spu.ch4.nr4;
|
||||
master_ = state.spu.ch4.master;
|
||||
}
|
||||
|
||||
void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
||||
void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) {
|
||||
unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
||||
unsigned long const outLow = outBase * (0 - 15ul);
|
||||
unsigned long const endCycles = cycleCounter_ + cycles;
|
||||
unsigned long const outLow = outBase * -15;
|
||||
|
||||
for (;;) {
|
||||
unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
||||
while (cc < end) {
|
||||
unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2l - 15);
|
||||
unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), end);
|
||||
unsigned long out = lfsr_.isHighState() ? outHigh : outLow;
|
||||
|
||||
while (lfsr_.counter() <= nextMajorEvent) {
|
||||
if (lfsr_.counter() <= nextMajorEvent) {
|
||||
Lfsr lfsr = lfsr_;
|
||||
while (lfsr.counter() <= nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += lfsr.counter() - cc;
|
||||
cc = lfsr.counter();
|
||||
lfsr.event();
|
||||
out = lfsr.isHighState() ? outHigh : outLow;
|
||||
}
|
||||
lfsr_ = lfsr;
|
||||
}
|
||||
if (cc < nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += lfsr_.counter() - cycleCounter_;
|
||||
cycleCounter_ = lfsr_.counter();
|
||||
|
||||
lfsr_.event();
|
||||
out = lfsr_.isHighState() ? outHigh : outLow;
|
||||
buf += nextMajorEvent - cc;
|
||||
cc = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (cycleCounter_ < nextMajorEvent) {
|
||||
*buf += out - prevOut_;
|
||||
prevOut_ = out;
|
||||
buf += nextMajorEvent - cycleCounter_;
|
||||
cycleCounter_ = nextMajorEvent;
|
||||
}
|
||||
|
||||
if (nextEventUnit_->counter() == nextMajorEvent) {
|
||||
nextEventUnit_->event();
|
||||
setEvent();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cycleCounter_ >= SoundUnit::counter_max) {
|
||||
lengthCounter_.resetCounters(cycleCounter_);
|
||||
lfsr_.resetCounters(cycleCounter_);
|
||||
envelopeUnit_.resetCounters(cycleCounter_);
|
||||
cycleCounter_ -= SoundUnit::counter_max;
|
||||
if (cc >= SoundUnit::counter_max) {
|
||||
lengthCounter_.resetCounters(cc);
|
||||
lfsr_.resetCounters(cc);
|
||||
envelopeUnit_.resetCounters(cc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_CHANNEL4_H
|
||||
@@ -32,15 +32,16 @@ struct SaveState;
|
||||
class Channel4 {
|
||||
public:
|
||||
Channel4();
|
||||
void setNr1(unsigned data);
|
||||
void setNr2(unsigned data);
|
||||
void setNr3(unsigned data) { lfsr_.nr3Change(data, cycleCounter_); }
|
||||
void setNr4(unsigned data);
|
||||
void setSo(unsigned long soMask);
|
||||
void setNr1(unsigned data, unsigned long cc);
|
||||
void setNr2(unsigned data, unsigned long cc);
|
||||
void setNr3(unsigned data, unsigned long cc) { lfsr_.nr3Change(data, cc); }
|
||||
void setNr4(unsigned data, unsigned long cc);
|
||||
void setSo(unsigned long soMask, unsigned long cc);
|
||||
bool isActive() const { return master_; }
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
||||
void reset();
|
||||
void saveState(SaveState &state);
|
||||
void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cc, unsigned long end);
|
||||
void reset(unsigned long cc);
|
||||
void resetCc(unsigned long cc, unsigned long newCc) { lfsr_.resetCc(cc, newCc); }
|
||||
void saveState(SaveState &state, unsigned long cc);
|
||||
void loadState(SaveState const &state);
|
||||
|
||||
private:
|
||||
@@ -53,6 +54,7 @@ private:
|
||||
void nr3Change(unsigned newNr3, unsigned long cc);
|
||||
void nr4Init(unsigned long cc);
|
||||
void reset(unsigned long cc);
|
||||
void resetCc(unsigned long cc, unsigned long newCc);
|
||||
void saveState(SaveState &state, unsigned long cc);
|
||||
void loadState(SaveState const &state);
|
||||
void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; }
|
||||
@@ -85,7 +87,6 @@ private:
|
||||
EnvelopeUnit envelopeUnit_;
|
||||
Lfsr lfsr_;
|
||||
SoundUnit *nextEventUnit_;
|
||||
unsigned long cycleCounter_;
|
||||
unsigned long soMask_;
|
||||
unsigned long prevOut_;
|
||||
unsigned char nr4_;
|
||||
@@ -13,21 +13,29 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "duty_unit.h"
|
||||
#include "psgdef.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static inline bool toOutState(unsigned duty, unsigned pos) {
|
||||
return 0x7EE18180 >> (duty * 8 + pos) & 1;
|
||||
namespace {
|
||||
|
||||
int const duty_pattern_len = 8;
|
||||
|
||||
bool toOutState(unsigned duty, unsigned pos) {
|
||||
return 0x7EE18180 >> (duty * duty_pattern_len + pos) & 1;
|
||||
}
|
||||
|
||||
static inline unsigned toPeriod(unsigned freq) {
|
||||
unsigned toPeriod(unsigned freq) {
|
||||
return (2048 - freq) * 2;
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
}
|
||||
|
||||
using namespace gambatte;
|
||||
|
||||
DutyUnit::DutyUnit()
|
||||
: nextPosUpdate_(counter_disabled)
|
||||
@@ -44,27 +52,26 @@ void DutyUnit::updatePos(unsigned long const cc) {
|
||||
if (cc >= nextPosUpdate_) {
|
||||
unsigned long const inc = (cc - nextPosUpdate_) / period_ + 1;
|
||||
nextPosUpdate_ += period_ * inc;
|
||||
pos_ += inc;
|
||||
pos_ &= 7;
|
||||
pos_ = (pos_ + inc) % duty_pattern_len;
|
||||
high_ = toOutState(duty_, pos_);
|
||||
}
|
||||
}
|
||||
|
||||
void DutyUnit::setCounter() {
|
||||
static unsigned char const nextStateDistance[4 * 8] = {
|
||||
7, 6, 5, 4, 3, 2, 1, 1,
|
||||
1, 6, 5, 4, 3, 2, 1, 2,
|
||||
1, 4, 3, 2, 1, 4, 3, 2,
|
||||
1, 6, 5, 4, 3, 2, 1, 2
|
||||
static unsigned char const nextStateDistance[][duty_pattern_len] = {
|
||||
{ 7, 6, 5, 4, 3, 2, 1, 1 },
|
||||
{ 1, 6, 5, 4, 3, 2, 1, 2 },
|
||||
{ 1, 4, 3, 2, 1, 4, 3, 2 },
|
||||
{ 1, 6, 5, 4, 3, 2, 1, 2 }
|
||||
};
|
||||
|
||||
if (enableEvents_ && nextPosUpdate_ != counter_disabled) {
|
||||
unsigned const npos = (pos_ + 1) & 7;
|
||||
unsigned const npos = (pos_ + 1) % duty_pattern_len;
|
||||
counter_ = nextPosUpdate_;
|
||||
inc_ = nextStateDistance[duty_ * 8 + npos];
|
||||
inc_ = nextStateDistance[duty_][npos];
|
||||
if (toOutState(duty_, npos) == high_) {
|
||||
counter_ += period_ * inc_;
|
||||
inc_ = nextStateDistance[duty_ * 8 + ((npos + inc_) & 7)];
|
||||
inc_ = nextStateDistance[duty_][(npos + inc_) % duty_pattern_len];
|
||||
}
|
||||
} else
|
||||
counter_ = counter_disabled;
|
||||
@@ -77,16 +84,16 @@ void DutyUnit::setFreq(unsigned newFreq, unsigned long cc) {
|
||||
}
|
||||
|
||||
void DutyUnit::event() {
|
||||
static unsigned char const inc[] = {
|
||||
1, 7,
|
||||
2, 6,
|
||||
4, 4,
|
||||
6, 2,
|
||||
static unsigned char const inc[][2] = {
|
||||
{ 1, 7 },
|
||||
{ 2, 6 },
|
||||
{ 4, 4 },
|
||||
{ 6, 2 }
|
||||
};
|
||||
|
||||
high_ ^= true;
|
||||
counter_ += inc_ * period_;
|
||||
inc_ = inc[duty_ * 2 + high_];
|
||||
inc_ = inc[duty_][high_];
|
||||
}
|
||||
|
||||
void DutyUnit::nr1Change(unsigned newNr1, unsigned long cc) {
|
||||
@@ -99,11 +106,11 @@ void DutyUnit::nr3Change(unsigned newNr3, unsigned long cc) {
|
||||
setFreq((freq() & 0x700) | newNr3, cc);
|
||||
}
|
||||
|
||||
void DutyUnit::nr4Change(unsigned const newNr4, unsigned long const cc) {
|
||||
void DutyUnit::nr4Change(unsigned const newNr4, unsigned long const cc, unsigned long const ref) {
|
||||
setFreq((newNr4 << 8 & 0x700) | (freq() & 0xFF), cc);
|
||||
|
||||
if (newNr4 & 0x80) {
|
||||
nextPosUpdate_ = (cc & ~1ul) + period_ + 4;
|
||||
if (newNr4 & psg_nr4_init) {
|
||||
nextPosUpdate_ = cc - (cc - ref) % 2 + period_ + 4;
|
||||
setCounter();
|
||||
}
|
||||
}
|
||||
@@ -115,6 +122,15 @@ void DutyUnit::reset() {
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::resetCc(unsigned long cc, unsigned long newCc) {
|
||||
if (nextPosUpdate_ == counter_disabled)
|
||||
return;
|
||||
|
||||
updatePos(cc);
|
||||
nextPosUpdate_ -= cc - newCc;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
|
||||
updatePos(cc);
|
||||
setCounter();
|
||||
@@ -127,7 +143,7 @@ void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
|
||||
void DutyUnit::loadState(SaveState::SPU::Duty const &dstate,
|
||||
unsigned const nr1, unsigned const nr4, unsigned long const cc) {
|
||||
nextPosUpdate_ = std::max(dstate.nextPosUpdate, cc);
|
||||
pos_ = dstate.pos & 7;
|
||||
pos_ = dstate.pos % duty_pattern_len;
|
||||
high_ = dstate.high;
|
||||
duty_ = nr1 >> 6;
|
||||
period_ = toPeriod((nr4 << 8 & 0x700) | dstate.nr3);
|
||||
@@ -135,13 +151,8 @@ void DutyUnit::loadState(SaveState::SPU::Duty const &dstate,
|
||||
setCounter();
|
||||
}
|
||||
|
||||
void DutyUnit::resetCounters(unsigned long const oldCc) {
|
||||
if (nextPosUpdate_ == counter_disabled)
|
||||
return;
|
||||
|
||||
updatePos(oldCc);
|
||||
nextPosUpdate_ -= counter_max;
|
||||
setCounter();
|
||||
void DutyUnit::resetCounters(unsigned long cc) {
|
||||
resetCc(cc, cc - counter_max);
|
||||
}
|
||||
|
||||
void DutyUnit::killCounter() {
|
||||
@@ -154,5 +165,3 @@ void DutyUnit::reviveCounter(unsigned long const cc) {
|
||||
enableEvents_ = true;
|
||||
setCounter();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef DUTY_UNIT_H
|
||||
@@ -33,8 +33,9 @@ public:
|
||||
bool isHighState() const { return high_; }
|
||||
void nr1Change(unsigned newNr1, unsigned long cc);
|
||||
void nr3Change(unsigned newNr3, unsigned long cc);
|
||||
void nr4Change(unsigned newNr4, unsigned long cc);
|
||||
void nr4Change(unsigned newNr4, unsigned long cc, unsigned long ref);
|
||||
void reset();
|
||||
void resetCc(unsigned long cc, unsigned long newCc);
|
||||
void saveState(SaveState::SPU::Duty &dstate, unsigned long cc);
|
||||
void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned long cc);
|
||||
void killCounter();
|
||||
@@ -13,13 +13,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "envelope_unit.h"
|
||||
#include "psgdef.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent_;
|
||||
|
||||
@@ -46,16 +48,16 @@ void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, un
|
||||
}
|
||||
|
||||
void EnvelopeUnit::event() {
|
||||
unsigned long const period = nr2_ & 7;
|
||||
unsigned long const period = nr2_ & psg_nr2_step;
|
||||
|
||||
if (period) {
|
||||
unsigned newVol = volume_;
|
||||
if (nr2_ & 8)
|
||||
if (nr2_ & psg_nr2_inc)
|
||||
++newVol;
|
||||
else
|
||||
--newVol;
|
||||
|
||||
if (newVol < 0x10U) {
|
||||
if (newVol < 0x10) {
|
||||
volume_ = newVol;
|
||||
if (volume_ < 2)
|
||||
volOnOffEvent_(counter_);
|
||||
@@ -68,29 +70,27 @@ void EnvelopeUnit::event() {
|
||||
}
|
||||
|
||||
bool EnvelopeUnit::nr2Change(unsigned const newNr2) {
|
||||
if (!(nr2_ & 7) && counter_ != counter_disabled)
|
||||
if (!(nr2_ & psg_nr2_step) && counter_ != counter_disabled)
|
||||
++volume_;
|
||||
else if (!(nr2_ & 8))
|
||||
else if (!(nr2_ & psg_nr2_inc))
|
||||
volume_ += 2;
|
||||
|
||||
if ((nr2_ ^ newNr2) & 8)
|
||||
if ((nr2_ ^ newNr2) & psg_nr2_inc)
|
||||
volume_ = 0x10 - volume_;
|
||||
|
||||
volume_ &= 0xF;
|
||||
nr2_ = newNr2;
|
||||
return !(newNr2 & 0xF8);
|
||||
return !(newNr2 & (psg_nr2_initvol | psg_nr2_inc));
|
||||
}
|
||||
|
||||
bool EnvelopeUnit::nr4Init(unsigned long const cc) {
|
||||
unsigned long period = nr2_ & 7 ? nr2_ & 7 : 8;
|
||||
unsigned long period = nr2_ & psg_nr2_step ? nr2_ & psg_nr2_step : 8;
|
||||
|
||||
if (((cc + 2) & 0x7000) == 0x0000)
|
||||
++period;
|
||||
|
||||
counter_ = cc - ((cc - 0x1000) & 0x7FFF) + period * 0x8000;
|
||||
|
||||
volume_ = nr2_ >> 4;
|
||||
return !(nr2_ & 0xF8);
|
||||
}
|
||||
|
||||
volume_ = nr2_ / (1u * psg_nr2_initvol & -psg_nr2_initvol);
|
||||
return !(nr2_ & (psg_nr2_initvol | psg_nr2_inc));
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef ENVELOPE_UNIT_H
|
||||
+19
-24
@@ -13,14 +13,16 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "length_counter.h"
|
||||
#include "master_disabler.h"
|
||||
#include "psgdef.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gambatte {
|
||||
using namespace gambatte;
|
||||
|
||||
LengthCounter::LengthCounter(MasterDisabler &disabler, unsigned const mask)
|
||||
: disableMaster_(disabler)
|
||||
@@ -38,35 +40,30 @@ void LengthCounter::event() {
|
||||
|
||||
void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned long const cc) {
|
||||
lengthCounter_ = (~newNr1 & lengthMask_) + 1;
|
||||
counter_ = nr4 & 0x40
|
||||
? ((cc >> 13) + lengthCounter_) << 13
|
||||
: static_cast<unsigned long>(counter_disabled);
|
||||
counter_ = nr4 & psg_nr4_lcen
|
||||
? ((cc >> 13) + lengthCounter_) << 13
|
||||
: 1 * counter_disabled;
|
||||
}
|
||||
|
||||
void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned long const cc) {
|
||||
if (counter_ != counter_disabled)
|
||||
lengthCounter_ = (counter_ >> 13) - (cc >> 13);
|
||||
|
||||
{
|
||||
unsigned dec = 0;
|
||||
|
||||
if (newNr4 & 0x40) {
|
||||
dec = ~cc >> 12 & 1;
|
||||
|
||||
if (!(oldNr4 & 0x40) && lengthCounter_) {
|
||||
if (!(lengthCounter_ -= dec))
|
||||
disableMaster_();
|
||||
}
|
||||
unsigned dec = 0;
|
||||
if (newNr4 & psg_nr4_lcen) {
|
||||
dec = ~cc >> 12 & 1;
|
||||
if (!(oldNr4 & psg_nr4_lcen) && lengthCounter_) {
|
||||
if (!(lengthCounter_ -= dec))
|
||||
disableMaster_();
|
||||
}
|
||||
|
||||
if ((newNr4 & 0x80) && !lengthCounter_)
|
||||
lengthCounter_ = lengthMask_ + 1 - dec;
|
||||
}
|
||||
|
||||
if ((newNr4 & 0x40) && lengthCounter_)
|
||||
counter_ = ((cc >> 13) + lengthCounter_) << 13;
|
||||
else
|
||||
counter_ = counter_disabled;
|
||||
if (newNr4 & psg_nr4_init && !lengthCounter_)
|
||||
lengthCounter_ = lengthMask_ + 1 - dec;
|
||||
|
||||
counter_ = newNr4 & psg_nr4_lcen && lengthCounter_
|
||||
? ((cc >> 13) + lengthCounter_) << 13
|
||||
: 1 * counter_disabled;
|
||||
}
|
||||
|
||||
void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const {
|
||||
@@ -78,5 +75,3 @@ void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned l
|
||||
counter_ = std::max(lstate.counter, cc);
|
||||
lengthCounter_ = lstate.lengthCounter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef LENGTH_COUNTER_H
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef MASTER_DISABLER_H
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef PSGDEF_H
|
||||
#define PSGDEF_H
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
enum {
|
||||
psg_nr10_rsh = 0x07,
|
||||
psg_nr10_neg = 0x08,
|
||||
psg_nr10_time = 0x70
|
||||
};
|
||||
|
||||
enum {
|
||||
psg_nr2_step = 0x07,
|
||||
psg_nr2_inc = 0x08,
|
||||
psg_nr2_initvol = 0xF0
|
||||
};
|
||||
|
||||
enum {
|
||||
psg_nr43_r = 0x07,
|
||||
psg_nr43_7biten = 0x08,
|
||||
psg_nr43_s = 0xF0
|
||||
};
|
||||
|
||||
enum {
|
||||
psg_nr4_lcen = 0x40,
|
||||
psg_nr4_init = 0x80
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SOUND_UNIT_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user