gnuboy: initial 1.0.3 import (last official release)
This commit is contained in:
commit
29076d4cef
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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 Library 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
|
||||
|
||||
Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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 Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
GNUBOY INSTALLATION
|
||||
|
||||
|
||||
*NIX SYSTEMS
|
||||
|
||||
One or more of the following is required to compile on *nix: X, SDL,
|
||||
svgalib, or Linux fbcon. Since basically everyone has X, this should
|
||||
not be a problem. Please note that the SDL and fbcon ports are the
|
||||
most functional, however. In the future, Sun console may also be
|
||||
supported.
|
||||
|
||||
The best and easiest way to build gnuboy for *nix is with the
|
||||
configure script:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
By default, heavy optimization and asm cpu and graphics cores will be
|
||||
used if available on your platform. For information on compiletime
|
||||
options related to performance and debugging, type:
|
||||
|
||||
./configure --help
|
||||
|
||||
Alternatively, if you don't like the GNU configure script, you may
|
||||
copy the Makefile.nix to Makefile and edit it by hand to work with
|
||||
your system. Make sure you uncomment -DIS_LITTLE_ENDIAN if your cpu is
|
||||
little endian. Please note that not everything is supported when
|
||||
compiling this way, and that it should only be done as a last resort.
|
||||
The generic Makefile.nix may be removed in the future since it's extra
|
||||
work to maintain.
|
||||
|
||||
Running make should produce the binaries xgnuboy, fbgnuboy, sgnuboy
|
||||
and/or sdlgnuboy, depending on the availability of the various
|
||||
interface libraries on your host. The install target will install
|
||||
these to $(prefix)/bin, where prefix is specified to configure in the
|
||||
usual way. The default prefix is of course /usr/local/.
|
||||
|
||||
Binary packages may be available for some platforms, but they are
|
||||
usually not quite up to date, and are not built or supported by the
|
||||
gnuboy team.
|
||||
|
||||
Binary package maintainers should be aware that, by default, gnuboy
|
||||
will be built with optimizations specific to the exact host cpu it's
|
||||
being compiled on, and may not work on older models. If you want your
|
||||
binaries to work with older systems too, run configure with the
|
||||
--disable-arch option to disable architecture specific compiler flags.
|
||||
|
||||
|
||||
WINDOWS
|
||||
|
||||
Mingw32 and the SDL development files are required to compile gnuboy
|
||||
for Windows. They may be obtained from www.mingw.org and
|
||||
www.libsdl.org, respectively.
|
||||
|
||||
Just copy Makefile.mingw32 to Makefile and run make. When done, put
|
||||
the resulting gnuboy.exe wherever you wish to install it.
|
||||
|
||||
Precompiled binaries are also available for Windows; check the site
|
||||
from which you obtained gnuboy to see if it provides copies.
|
||||
|
||||
|
||||
DOS
|
||||
|
||||
You'll need djgpp to use the included Makefile. Theoretically it
|
||||
shouldn't be hard to port the dos-specific modules to work with other
|
||||
compilers, but I see no reason why it should be necessary.
|
||||
|
||||
Since all DOS systems are basically alike, just copy Makefile.dos to
|
||||
Makefile and type "make" to compile gnuboy. No configuration should be
|
||||
necessary. If you do have build problems, let us know.
|
||||
|
||||
After compiling, place gnuboy.exe wherever you want.
|
||||
|
||||
Precompiled binaries are also available for DOS; check the site from
|
||||
which you obtained gnuboy to see if it provides copies.
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
|
||||
AS = $(CC)
|
||||
LD = $(CC)
|
||||
|
||||
CFLAGS = -O3 -fstrength-reduce -fomit-frame-pointer -I./asm/i386
|
||||
ASFLAGS = -x assembler-with-cpp
|
||||
LDFLAGS = -s
|
||||
|
||||
THIN_NAMES = tl_main tl_log tl_timer tl_key tl_mouse tl_joy tl_dpp tl_event \
|
||||
tl_bmp tl_vesa tl_vga tl_video tl_sb tl_sound tl_int
|
||||
THIN_OBJS = $(THIN_NAMES:%=sys/thinlib/lib/%.o)
|
||||
|
||||
SYS_DEFS = -DIS_LITTLE_ENDIAN -DALLOW_UNALIGNED_IO -DALT_PATH_SEP -DUSE_ASM
|
||||
|
||||
SYS_INCS = -I./sys/dos -I./sys/thinlib/lib
|
||||
SYS_OBJS = sys/dos/dos.o sys/thinlib/thinlib.o sys/thinlib/keymap.o $(THIN_OBJS) \
|
||||
asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.o
|
||||
|
||||
all: gnuboy.exe
|
||||
|
||||
include Rules
|
||||
|
||||
gnuboy.exe: $(OBJS) $(SYS_OBJS)
|
||||
$(LD) $(CFLAGS) $(LDFLAGS) $(OBJS) $(SYS_OBJS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f gnuboy.exe gmon.out *.o sys/*.o sys/dos/*.o sys/pc/*.o asm/i386/*.o \
|
||||
sys/thinlib/*.o sys/thinlib/*.exe sys/thinlib/*.o
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
|
||||
CC = @CC@
|
||||
LD = $(CC)
|
||||
AS = $(CC)
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = $(CFLAGS) @LDFLAGS@
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
TARGETS = @TARGETS@
|
||||
|
||||
ASM_OBJS = @ASM_OBJS@
|
||||
|
||||
SYS_DEFS = @DEFS@ @ENDIAN@ @ASM@ @SYS_DEFS@
|
||||
SYS_OBJS = sys/nix/nix.o $(ASM_OBJS)
|
||||
SYS_INCS = -I/usr/local/include @XINCS@ -I./sys/nix
|
||||
|
||||
FB_OBJS = @FB_OBJS@ @JOY@ @SOUND@
|
||||
FB_LIBS =
|
||||
|
||||
SVGA_OBJS = sys/svga/svgalib.o sys/pc/keymap.o @JOY@ @SOUND@
|
||||
SVGA_LIBS = -L/usr/local/lib -lvga
|
||||
|
||||
SDL_OBJS = sys/sdl/sdl.o sys/sdl/keymap.o
|
||||
SDL_LIBS = @SDL_LIBS@
|
||||
SDL_CFLAGS = @SDL_CFLAGS@
|
||||
|
||||
X11_OBJS = sys/x11/xlib.o sys/x11/keymap.o @JOY@ @SOUND@
|
||||
X11_LIBS = @XLIBS@ -lX11 -lXext
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
include Rules
|
||||
|
||||
fbgnuboy: $(OBJS) $(SYS_OBJS) $(FB_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(FB_OBJS) -o $@ $(FB_LIBS)
|
||||
|
||||
sgnuboy: $(OBJS) $(SYS_OBJS) $(SVGA_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SVGA_OBJS) -o $@ $(SVGA_LIBS)
|
||||
|
||||
sdlgnuboy: $(OBJS) $(SYS_OBJS) $(SDL_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS)
|
||||
|
||||
sys/sdl/sdl.o: sys/sdl/sdl.c
|
||||
$(MYCC) $(SDL_CFLAGS) -c $< -o $@
|
||||
|
||||
sys/sdl/keymap.o: sys/sdl/keymap.c
|
||||
$(MYCC) $(SDL_CFLAGS) -c $< -o $@
|
||||
|
||||
xgnuboy: $(OBJS) $(SYS_OBJS) $(X11_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(X11_OBJS) -o $@ $(X11_LIBS)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d $(bindir)
|
||||
$(INSTALL) -m 755 $(TARGETS) $(bindir)
|
||||
|
||||
clean:
|
||||
rm -f *gnuboy gmon.out *.o sys/*.o sys/*/*.o asm/*/*.o
|
||||
|
||||
distclean: clean
|
||||
rm -f config.* sys/nix/config.h Makefile
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# Makefile.nix
|
||||
#
|
||||
# This is a *bare minimum* makefile for building gnuboy on *nix systems.
|
||||
# If you have trouble with the configure script you can try using this,
|
||||
# but *please* try the configure script first. This file is mostly
|
||||
# unmaintained and may break.
|
||||
#
|
||||
# If you *do* insist on using this makefile, you at least need to check
|
||||
# SYS_DEFS below and uncomment -DIS_LITTLE_ENDIAN if your system is
|
||||
# little endian. Also, you may want to enable the OSS sound module if
|
||||
# your system supports it.
|
||||
#
|
||||
|
||||
prefix = /usr/local
|
||||
bindir = /bin
|
||||
|
||||
CC = gcc
|
||||
AS = $(CC)
|
||||
LD = $(CC)
|
||||
INSTALL = /bin/install -c
|
||||
|
||||
CFLAGS = -O3
|
||||
LDFLAGS =
|
||||
ASFLAGS =
|
||||
|
||||
SYS_DEFS = #-DIS_LITTLE_ENDIAN
|
||||
ASM_OBJS =
|
||||
#SND_OBJS = sys/oss/oss.o
|
||||
SND_OBJS = sys/dummy/nosound.o
|
||||
JOY_OBJS = sys/dummy/nojoy.o
|
||||
|
||||
TARGETS = xgnuboy
|
||||
|
||||
SYS_OBJS = sys/nix/nix.o $(ASM_OBJS) $(SND_OBJS) $(JOY_OBJS)
|
||||
SYS_INCS = -I/usr/local/include -I/usr/X11R6/include -I./sys/nix
|
||||
|
||||
X11_OBJS = sys/x11/xlib.o sys/x11/keymap.o
|
||||
X11_LIBS = -L/usr/X11R6/lib -lX11 -lXext
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
include Rules
|
||||
|
||||
xgnuboy: $(OBJS) $(SYS_OBJS) $(X11_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(X11_OBJS) -o $@ $(X11_LIBS)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -m 755 $(TARGETS) $(prefix)$(bindir)
|
||||
|
||||
clean:
|
||||
rm -f *gnuboy gmon.out *.o sys/*.o sys/*/*.o asm/*/*.o
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
CC = gcc
|
||||
AS = $(CC)
|
||||
LD = $(CC)
|
||||
|
||||
CFLAGS = -O3 -I./asm/i386 -Dmain=SDL_main
|
||||
LDFLAGS = -s -lmingw32 -lSDLmain -lSDL
|
||||
ASFLAGS = -x assembler-with-cpp
|
||||
|
||||
SYS_DEFS = -DIS_LITTLE_ENDIAN -DALT_PATH_SEP -DUSE_ASM
|
||||
ASM_OBJS = asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.o
|
||||
#SND_OBJS = sys/dummy/nosound.o
|
||||
|
||||
SYS_OBJS = $(ASM_OBJS) $(SND_OBJS) sys/windows/windows.o sys/windows/resource.o
|
||||
SYS_INCS = -I./sys/windows
|
||||
|
||||
SDL_OBJS = sys/sdl/sdl.o sys/sdl/keymap.o
|
||||
SDL_LIBS = -lSDL
|
||||
|
||||
all: gnuboy
|
||||
|
||||
include Rules
|
||||
|
||||
%.o: %.rc
|
||||
windres -o $@ $<
|
||||
|
||||
gnuboy: $(OBJS) $(SYS_OBJS) $(SDL_OBJS)
|
||||
$(LD) $(LDFLAGS) $(OBJS) $(SYS_OBJS) $(SDL_OBJS) -o $@ $(SDL_LIBS)
|
||||
|
||||
clean:
|
||||
rm -f gnuboy.exe *.o sys/*.o sys/*/*.o asm/*/*.o
|
|
@ -0,0 +1,199 @@
|
|||
|
||||
GNUBOY README
|
||||
|
||||
|
||||
INTRO
|
||||
|
||||
Welcome to gnuboy, one of the few pieces of Free Software to emulate
|
||||
the Game Boy handheld game console. Written in ANSI C with a few
|
||||
optional assembler optimizations for particular cpus, gnuboy supports
|
||||
a wide range of host systems, and has been tested successfully on:
|
||||
|
||||
GNU/Linux
|
||||
FreeBSD
|
||||
OpenBSD
|
||||
BeOS
|
||||
Linux/390 (IBM S/390 Mainframe)
|
||||
SunOS/Sun Ultra60
|
||||
IRIX/SGI O2
|
||||
IRIX/SGI Indy
|
||||
AIX/Unknown
|
||||
DR-DOS
|
||||
MS-DOS
|
||||
Windows DOS box
|
||||
Windows 9x/NT/2k
|
||||
|
||||
Additionally, gnuboy should run on any other *nix variants that have
|
||||
ANSI C compilers and that are remotely POSIX compliant. As gnuboy is
|
||||
Free Software, you're welcome to fix any problems you encounter
|
||||
building it for a particular system, or to port it to entirely new
|
||||
systems.
|
||||
|
||||
|
||||
EMULATION
|
||||
|
||||
gnuboy emulates nearly all aspects of the (Color) Gameboy, including
|
||||
all of the following and much more:
|
||||
|
||||
Full GBZ80 instruction set.
|
||||
Scanline-based LCD engine.
|
||||
Ten sprites per scanline limit.
|
||||
Support for all CGB graphics extensions.
|
||||
Sprite DMA, HDMA, and GDMA.
|
||||
All four sound channels including digital samples.
|
||||
MBC1, MBC2, MBC3 (including clock), and MBC5 mappers.
|
||||
Wave pattern memory corruption when sound channel 3 is played.
|
||||
Pad, timer, divide counter, and other basic hardware registers.
|
||||
CGB double-speed CPU mode.
|
||||
|
||||
Aspects not emulated at this time include:
|
||||
|
||||
* Serial IO (link cable).
|
||||
Undocumented 'extra' ram in OAM space on Gameboy Color.
|
||||
All Super Gameboy extensions.
|
||||
* GBC, HuC1, and HuC3 IR ports.
|
||||
* Obscure mappers such as TAMA5.
|
||||
Sorting sprites by X coordinate in DMG mode.
|
||||
HALT instruction skipping in DMG mode.
|
||||
CPU stalls during HDMA and GDMA.
|
||||
|
||||
Only the two marked by * are known to affect the playability of
|
||||
actual games or demos; the rest are just listed for completeness'
|
||||
sake.
|
||||
|
||||
|
||||
FEATURES
|
||||
|
||||
In addition to basic emulation, gnuboy provides the following
|
||||
features:
|
||||
|
||||
Highly flexible keybinding and configuration subsystem.
|
||||
State saving and loading at any point.
|
||||
Very precise timing/synchronization, preserved across save/load.
|
||||
Joystick support on Linux, DOS, and all SDL-based ports.
|
||||
Fully customizable palettes for DMG games.
|
||||
Screen scaling by a factor of 2, 3, or 4 in all ports.
|
||||
Hardware-based screen scaling on platforms where it's available.
|
||||
Debug traces to stdout.
|
||||
Dynamic palette allocation when run in 256-color modes...
|
||||
OR simulated 3/3/2 bits per channel in 256-color modes.
|
||||
|
||||
For information on configuring and using these features, see the
|
||||
additional documentation in the "docs" directory.
|
||||
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Out of over 300 results reported by testers, all games are known to
|
||||
work perfectly on gnuboy with the following exceptions:
|
||||
|
||||
Fighting Phoenix (Japanese) may or may not work since it uses the
|
||||
HuC1 memory controller, which is not implemented properly. There has
|
||||
been no report either way so far.
|
||||
|
||||
Pocket Bomberman (Japanese version, which uses HuC1) runs, but can
|
||||
be made to crash if the player jumps into the ceiling in the first
|
||||
level. It's not clear whether this bug is MBC-related, something
|
||||
else, or an actual bug in the original game.
|
||||
|
||||
Monster Go! Go! Go! (Japanese) is unplayable. The cause of the
|
||||
problem is not fully known, but it's either a very bad dump or it's
|
||||
using some sort of specialized MBC that's not documented.
|
||||
|
||||
Final Fantasy Adventure has visual problems with the fade between
|
||||
screens. Does not affect gameplay.
|
||||
|
||||
Bubble Bobble 2 has some minor tile glitches right before gameplay
|
||||
actually begins. Cause unknown. Does not affect gameplay.
|
||||
|
||||
Alone in the Dark is reported to have minor visual glitches. I
|
||||
haven't seen it myself so I can't judge their severity.
|
||||
|
||||
Both new Zelda games are reported to have a visual glitch at the
|
||||
beginning of the game, and on certain other screens. I haven't seen
|
||||
the problem myself, but supposedly it impacts gameplay to some
|
||||
extent.
|
||||
|
||||
Please report any other incompatibilities discovered directly to
|
||||
gnuboy@unix-fu.org, so that they can be documented and hopefully
|
||||
fixed.
|
||||
|
||||
|
||||
FUTURE / WISHLIST
|
||||
|
||||
Here's a brief list of what may appear in gnuboy in the future:
|
||||
|
||||
Screenshots.
|
||||
Integrated debugger.
|
||||
Super Gameboy support.
|
||||
Serial link over the internet.
|
||||
Serial link to a real Gameboy with a custom cable.
|
||||
Configurable color filters to provide more authentic LCD look.
|
||||
Custom colorization of DMG games on a per-tile basis.
|
||||
Support for more colorspaces in the hardware scaler.
|
||||
Recording audio.
|
||||
GBS player built from the same source tree.
|
||||
Full recording and playback of emulation.
|
||||
So-called "high level emulation" of certain typical dumb loops.
|
||||
|
||||
Features that are not likely to appear soon or at all include:
|
||||
|
||||
Rumble support - this would be nice, but SDL doesn't seem to support
|
||||
force-feedback yet. We'll see about it in the long-term though.
|
||||
|
||||
Eagle/2xSaI/etc. - probably not feasible since these libraries don't
|
||||
appear to be compatible with the terms of the GPL. We might work on
|
||||
our own interpolation engine eventually, but that's low priority.
|
||||
|
||||
GUI/GUI-like features - such things are best handled by external
|
||||
front-ends. We might eventually add a mechanism for external
|
||||
programs to communicate with gnuboy and reconfigure it while it's
|
||||
running, however.
|
||||
|
||||
Plugins - NO! The way I see it, plugins are just an attempt to work
|
||||
around the GPL. In any case, even if you are adding plugin support
|
||||
yourself, you are bound by the terms of the GPL when linking ANY
|
||||
code to gnuboy, including dynamic-linked modules. However we'd
|
||||
rather not deal with this mess to begin with.
|
||||
|
||||
Compressed ROMs/Saves - this one is very iffy. On most systems, this
|
||||
is redundant; *nix users can just pipe the rom through a
|
||||
decompression program, and Windows users can just double-click or
|
||||
drag files from their favorite GUI unzipper program. Linking to zlib
|
||||
isn't really acceptable since it's massively bloated and we don't
|
||||
want to include it with gnuboy or add external dependencies. We may,
|
||||
however, write our own tiny decompressor to use at some point.
|
||||
|
||||
Ideas and suggestions for other features are welcome, but won't
|
||||
necessarily be used. You're of course also free to add features
|
||||
yourself, and if they fit well into the main tree they may eventually
|
||||
get included in the official release. See the file HACKING for more
|
||||
details on modifying and/or contributing.
|
||||
|
||||
|
||||
THANKS
|
||||
|
||||
Thanks goes out to everyone who's expressed interest in gnuboy by
|
||||
writing -- users, porters, authors of other emulators, and so forth.
|
||||
Apologies if we don't get a personal response out to everyone, but
|
||||
either way, consider your feedback appreciated.
|
||||
|
||||
|
||||
EPILOGUE
|
||||
|
||||
OK, that looks like about it. More to come, stick around...
|
||||
|
||||
|
||||
|
||||
-Laguna <laguna@aerifal.cx>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
include Version
|
||||
|
||||
OBJS = lcd.o refresh.o lcdc.o palette.o cpu.o mem.o rtc.o hw.o sound.o \
|
||||
events.o keytable.o \
|
||||
loader.o save.o debug.o emu.o main.o \
|
||||
rccmds.o rckeys.o rcvars.o rcfile.o exports.o \
|
||||
split.o path.o inflate.o
|
||||
|
||||
INCS = -I.
|
||||
|
||||
MYCC = $(CC) $(CFLAGS) $(INCS) $(SYS_INCS) $(SYS_DEFS)
|
||||
MYAS = $(AS) $(ASFLAGS) $(INCS) $(SYS_INCS) $(SYS_DEFS)
|
||||
|
||||
main.o: Version
|
||||
|
||||
.c.o:
|
||||
$(MYCC) -c $< -o $@
|
||||
|
||||
.s.o:
|
||||
$(MYAS) -c $< -o $@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
|
||||
#ifndef __ASM_H__
|
||||
#define __ASM_H__
|
||||
|
||||
|
||||
|
||||
#define ASM_CPU_EMULATE
|
||||
#define ASM_CPU_STEP
|
||||
|
||||
#define ASM_REFRESH_1
|
||||
#define ASM_REFRESH_2
|
||||
#define ASM_REFRESH_3
|
||||
#define ASM_REFRESH_4
|
||||
|
||||
#define ASM_REFRESH_1_2X
|
||||
#define ASM_REFRESH_2_2X
|
||||
#define ASM_REFRESH_4_2X
|
||||
|
||||
#define ASM_REFRESH_1_3X
|
||||
#define ASM_REFRESH_2_3X
|
||||
#define ASM_REFRESH_4_3X
|
||||
|
||||
#define ASM_REFRESH_4_4X
|
||||
|
||||
#define ASM_UPDATEPATPIX
|
||||
|
||||
#define ASM_BG_SCAN_COLOR
|
||||
|
||||
|
||||
|
||||
#endif /* __ASM_H__ */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
|
||||
#define cpu _cpu
|
||||
#define hw _hw
|
||||
#define ram _ram
|
||||
#define mbc _mbc
|
||||
#define lcd _lcd
|
||||
#define scan _scan
|
||||
#define patpix _patpix
|
||||
#define anydirty _anydirty
|
||||
#define patdirty _patdirty
|
||||
#define cpu_emulate _cpu_emulate
|
||||
#define cpu_step _cpu_step
|
||||
#define lcdc_trans _lcdc_trans
|
||||
#define debug_trace _debug_trace
|
||||
#define updatepatpix _updatepatpix
|
||||
#define debug_disassemble _debug_disassemble
|
||||
#define bg_scan_color _bg_scan_color
|
||||
#define refresh_1 _refresh_1
|
||||
#define refresh_2 _refresh_2
|
||||
#define refresh_3 _refresh_3
|
||||
#define refresh_4 _refresh_4
|
||||
#define refresh_1_2x _refresh_1_2x
|
||||
#define refresh_2_2x _refresh_2_2x
|
||||
#define refresh_3_2x _refresh_3_2x
|
||||
#define refresh_4_2x _refresh_4_2x
|
||||
#define refresh_1_3x _refresh_1_3x
|
||||
#define refresh_2_3x _refresh_2_3x
|
||||
#define refresh_3_3x _refresh_3_3x
|
||||
#define refresh_4_3x _refresh_4_3x
|
||||
#define refresh_1_4x _refresh_1_4x
|
||||
#define refresh_2_4x _refresh_2_4x
|
||||
#define refresh_3_4x _refresh_3_4x
|
||||
#define refresh_4_4x _refresh_4_4x
|
||||
#define mem_read _mem_read
|
||||
#define mem_write _mem_write
|
||||
#define cpu_idle _cpu_idle
|
||||
#define die _die
|
||||
#define printf _printf
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,290 @@
|
|||
|
||||
#include "asmnames.h"
|
||||
|
||||
.set vram, lcd
|
||||
.set buf, scan+512
|
||||
.set pal1, scan+768
|
||||
.set pal2, scan+896
|
||||
.set pal4, scan+1024
|
||||
|
||||
.set bg, scan
|
||||
.set buf, scan+512
|
||||
.set u, scan+1792+24
|
||||
.set v, scan+1792+28
|
||||
.set wx, scan+1792+32
|
||||
|
||||
.data
|
||||
.balign 4
|
||||
|
||||
|
||||
.text
|
||||
.balign 32
|
||||
|
||||
debug: .string "%08x\n"
|
||||
|
||||
.macro _print arg=0
|
||||
pushf
|
||||
pusha
|
||||
movl \arg, %eax
|
||||
pushl %eax
|
||||
pushl $debug
|
||||
call printf
|
||||
addl $8, %esp
|
||||
popa
|
||||
popf
|
||||
.endm
|
||||
|
||||
.macro _patexpand k=0
|
||||
movw (%esi,%ecx,2), %ax
|
||||
andl $(0x0101<<\k), %eax
|
||||
addb $0xff, %al
|
||||
sbbb %bl, %bl
|
||||
addb $0xff, %ah
|
||||
sbbb %bh, %bh
|
||||
andl $0x0201, %ebx
|
||||
orb %bh, %bl
|
||||
movb %bl, patpix+7-\k(%ebp,%ecx,8)
|
||||
.endm
|
||||
|
||||
.macro _fastswap k=0
|
||||
movl patpix+(16*\k)(%ebp), %eax
|
||||
movl patpix+4+(16*\k)(%ebp), %ebx
|
||||
movl patpix+8+(16*\k)(%ebp), %ecx
|
||||
movl patpix+12+(16*\k)(%ebp), %edx
|
||||
bswap %eax
|
||||
bswap %ebx
|
||||
bswap %ecx
|
||||
bswap %edx
|
||||
movl %eax, patpix+1024*64+4+(16*\k)(%ebp)
|
||||
movl %ebx, patpix+1024*64+(16*\k)(%ebp)
|
||||
movl %ecx, patpix+1024*64+12+(16*\k)(%ebp)
|
||||
movl %edx, patpix+1024*64+8+(16*\k)(%ebp)
|
||||
.endm
|
||||
|
||||
|
||||
|
||||
.globl updatepatpix
|
||||
updatepatpix:
|
||||
movb anydirty, %al
|
||||
testb %al, %al
|
||||
jnz .Lupdatepatpix
|
||||
ret
|
||||
|
||||
.Lupdatepatpix:
|
||||
pushl %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
|
||||
movl $895, %edi
|
||||
.Lmainloop:
|
||||
cmpl $511, %edi
|
||||
jnz .Lnoskip
|
||||
movl $383, %edi
|
||||
.Lnoskip:
|
||||
movb patdirty(%edi), %al
|
||||
testb %al, %al
|
||||
jnz .Lpatdirty
|
||||
decl %edi
|
||||
jnl .Lmainloop
|
||||
jmp .Lend
|
||||
.Lpatdirty:
|
||||
movb $0, %al
|
||||
movb %al, patdirty(%edi)
|
||||
movl %edi, %eax
|
||||
movl $vram, %esi
|
||||
shll $4, %eax
|
||||
addl %eax, %esi
|
||||
|
||||
movl $7, %ecx
|
||||
movl %edi, %ebp
|
||||
shll $6, %ebp
|
||||
.Lexpandline:
|
||||
_patexpand 0
|
||||
_patexpand 1
|
||||
_patexpand 2
|
||||
_patexpand 3
|
||||
_patexpand 4
|
||||
_patexpand 5
|
||||
_patexpand 6
|
||||
_patexpand 7
|
||||
decl %ecx
|
||||
jnl .Lexpandline
|
||||
|
||||
_fastswap 0
|
||||
_fastswap 1
|
||||
_fastswap 2
|
||||
_fastswap 3
|
||||
|
||||
movl patpix(%ebp), %eax
|
||||
movl patpix+4(%ebp), %ebx
|
||||
movl patpix+8(%ebp), %ecx
|
||||
movl patpix+12(%ebp), %edx
|
||||
movl %eax, patpix+2048*64+56(%ebp)
|
||||
movl %ebx, patpix+2048*64+60(%ebp)
|
||||
movl %ecx, patpix+2048*64+48(%ebp)
|
||||
movl %edx, patpix+2048*64+52(%ebp)
|
||||
movl patpix+16(%ebp), %eax
|
||||
movl patpix+20(%ebp), %ebx
|
||||
movl patpix+24(%ebp), %ecx
|
||||
movl patpix+28(%ebp), %edx
|
||||
movl %eax, patpix+2048*64+40(%ebp)
|
||||
movl %ebx, patpix+2048*64+44(%ebp)
|
||||
movl %ecx, patpix+2048*64+32(%ebp)
|
||||
movl %edx, patpix+2048*64+36(%ebp)
|
||||
movl patpix+32(%ebp), %eax
|
||||
movl patpix+36(%ebp), %ebx
|
||||
movl patpix+40(%ebp), %ecx
|
||||
movl patpix+44(%ebp), %edx
|
||||
movl %eax, patpix+2048*64+24(%ebp)
|
||||
movl %ebx, patpix+2048*64+28(%ebp)
|
||||
movl %ecx, patpix+2048*64+16(%ebp)
|
||||
movl %edx, patpix+2048*64+20(%ebp)
|
||||
movl patpix+48(%ebp), %eax
|
||||
movl patpix+52(%ebp), %ebx
|
||||
movl patpix+56(%ebp), %ecx
|
||||
movl patpix+60(%ebp), %edx
|
||||
movl %eax, patpix+2048*64+8(%ebp)
|
||||
movl %ebx, patpix+2048*64+12(%ebp)
|
||||
movl %ecx, patpix+2048*64(%ebp)
|
||||
movl %edx, patpix+2048*64+4(%ebp)
|
||||
|
||||
movl patpix+1024*64(%ebp), %eax
|
||||
movl patpix+1024*64+4(%ebp), %ebx
|
||||
movl patpix+1024*64+8(%ebp), %ecx
|
||||
movl patpix+1024*64+12(%ebp), %edx
|
||||
movl %eax, patpix+3072*64+56(%ebp)
|
||||
movl %ebx, patpix+3072*64+60(%ebp)
|
||||
movl %ecx, patpix+3072*64+48(%ebp)
|
||||
movl %edx, patpix+3072*64+52(%ebp)
|
||||
movl patpix+1024*64+16(%ebp), %eax
|
||||
movl patpix+1024*64+20(%ebp), %ebx
|
||||
movl patpix+1024*64+24(%ebp), %ecx
|
||||
movl patpix+1024*64+28(%ebp), %edx
|
||||
movl %eax, patpix+3072*64+40(%ebp)
|
||||
movl %ebx, patpix+3072*64+44(%ebp)
|
||||
movl %ecx, patpix+3072*64+32(%ebp)
|
||||
movl %edx, patpix+3072*64+36(%ebp)
|
||||
movl patpix+1024*64+32(%ebp), %eax
|
||||
movl patpix+1024*64+36(%ebp), %ebx
|
||||
movl patpix+1024*64+40(%ebp), %ecx
|
||||
movl patpix+1024*64+44(%ebp), %edx
|
||||
movl %eax, patpix+3072*64+24(%ebp)
|
||||
movl %ebx, patpix+3072*64+28(%ebp)
|
||||
movl %ecx, patpix+3072*64+16(%ebp)
|
||||
movl %edx, patpix+3072*64+20(%ebp)
|
||||
movl patpix+1024*64+48(%ebp), %eax
|
||||
movl patpix+1024*64+52(%ebp), %ebx
|
||||
movl patpix+1024*64+56(%ebp), %ecx
|
||||
movl patpix+1024*64+60(%ebp), %edx
|
||||
movl %eax, patpix+3072*64+8(%ebp)
|
||||
movl %ebx, patpix+3072*64+12(%ebp)
|
||||
movl %ecx, patpix+3072*64(%ebp)
|
||||
movl %edx, patpix+3072*64+4(%ebp)
|
||||
|
||||
decl %edi
|
||||
jnl .Lmainloop
|
||||
.Lend:
|
||||
movb $0, %al
|
||||
movb %al, anydirty
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
|
||||
|
||||
.globl bg_scan_color
|
||||
bg_scan_color:
|
||||
movb wx, %ch
|
||||
cmpb $0, %ch
|
||||
jb .Lbsc_done_nopop
|
||||
pushl %ebx
|
||||
pushl %ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
movl v, %eax
|
||||
movl $bg, %esi
|
||||
movl $buf, %edi
|
||||
leal patpix(,%eax,8), %ebp
|
||||
movl (%esi), %eax
|
||||
movl u, %ebx
|
||||
shll $6, %eax
|
||||
movb $-8, %cl
|
||||
addl %ebx, %eax
|
||||
addb %bl, %cl
|
||||
movb 4(%esi), %bl
|
||||
addl $8, %esi
|
||||
addb %cl, %ch
|
||||
.Lbsc_preloop:
|
||||
movb (%ebp,%eax), %dl
|
||||
incl %eax
|
||||
orb %bl, %dl
|
||||
movb %dl, (%edi)
|
||||
incl %edi
|
||||
incb %cl
|
||||
jnz .Lbsc_preloop
|
||||
cmpb $0, %ch
|
||||
jb .Lbsc_done
|
||||
subb $8, %ch
|
||||
.Lbsc_loop:
|
||||
movl (%esi), %eax
|
||||
movl 4(%esi), %edx
|
||||
shll $6, %eax
|
||||
movb %dl, %dh
|
||||
addl $8, %esi
|
||||
movl %edx, %ebx
|
||||
rorl $16, %edx
|
||||
orl %edx, %ebx
|
||||
movl (%ebp,%eax), %edx
|
||||
orl %ebx, %edx
|
||||
movl %edx, (%edi)
|
||||
movl 4(%ebp,%eax), %edx
|
||||
orl %ebx, %edx
|
||||
movl %edx, 4(%edi)
|
||||
addl $8, %edi
|
||||
subb $8, %ch
|
||||
jae .Lbsc_loop
|
||||
addb $8, %ch
|
||||
jz .Lbsc_done
|
||||
movl (%esi), %eax
|
||||
shll $6, %eax
|
||||
movb 4(%esi), %bl
|
||||
.Lbsc_postloop:
|
||||
movb (%ebp,%eax), %dl
|
||||
incl %eax
|
||||
orb %bl, %dl
|
||||
movb %dl, (%edi)
|
||||
incl %edi
|
||||
decb %ch
|
||||
jnz .Lbsc_postloop
|
||||
.Lbsc_done:
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
popl %ebx
|
||||
.Lbsc_done_nopop:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
|
||||
|
||||
#include "asmnames.h"
|
||||
|
||||
.text
|
||||
|
||||
.macro _enter
|
||||
pushl %ebx
|
||||
pushl %ebp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
movl 20(%esp), %edi
|
||||
movl 24(%esp), %esi
|
||||
movl 28(%esp), %ebp
|
||||
movl 32(%esp), %ecx
|
||||
xorl %eax, %eax
|
||||
xorl %ebx, %ebx
|
||||
.endm
|
||||
|
||||
.macro _leave
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebp
|
||||
popl %ebx
|
||||
ret
|
||||
.endm
|
||||
|
||||
|
||||
.globl refresh_1
|
||||
refresh_1:
|
||||
_enter
|
||||
subl $4, %esi
|
||||
subl $4, %edi
|
||||
shrl $2, %ecx
|
||||
.Lrefresh_1:
|
||||
movb 2(%esi,%ecx,4), %al
|
||||
movb 3(%esi,%ecx,4), %bl
|
||||
movb (%ebp, %eax), %dl
|
||||
movb (%esi,%ecx,4), %al
|
||||
movb (%ebp, %ebx), %dh
|
||||
movb 1(%esi,%ecx,4), %bl
|
||||
rorl $16, %edx
|
||||
movb (%ebp, %eax), %dl
|
||||
movb (%ebp, %ebx), %dh
|
||||
movl %edx, (%edi,%ecx,4)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_1
|
||||
_leave
|
||||
|
||||
.globl refresh_2
|
||||
refresh_2:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
subl $4, %edi
|
||||
shrl $1, %ecx
|
||||
.Lrefresh_2:
|
||||
movb 1(%esi,%ecx,2), %al
|
||||
movb (%esi,%ecx,2), %bl
|
||||
movw (%ebp,%eax,2), %dx
|
||||
rorl $16, %edx
|
||||
movw (%ebp,%ebx,2), %dx
|
||||
movl %edx, (%edi,%ecx,4)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_2
|
||||
_leave
|
||||
|
||||
.globl refresh_3
|
||||
refresh_3:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
leal (%ecx,%ecx,2), %edx
|
||||
shrl $1, %ecx
|
||||
addl %edx, %edi
|
||||
.Lrefresh_3:
|
||||
movb (%esi,%ecx,2), %al
|
||||
subl $6, %edi
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movl (%ebp,%eax,4), %edx
|
||||
movb %dl, (%edi)
|
||||
movb 2(%ebp,%eax,4), %dl
|
||||
movb %dh, 1(%edi)
|
||||
movb %dl, 2(%edi)
|
||||
movl (%ebp,%ebx,4), %edx
|
||||
movb %dl, 3(%edi)
|
||||
movb 2(%ebp,%ebx,4), %dl
|
||||
movb %dh, 4(%edi)
|
||||
movb %dl, 5(%edi)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_3
|
||||
_leave
|
||||
|
||||
.globl refresh_4
|
||||
refresh_4:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
subl $8, %edi
|
||||
shrl $1, %ecx
|
||||
.Lrefresh_4:
|
||||
movb (%esi,%ecx,2), %al
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movl (%ebp,%eax,4), %edx
|
||||
movl %edx, (%edi,%ecx,8)
|
||||
movl (%ebp,%ebx,4), %edx
|
||||
movl %edx, 4(%edi,%ecx,8)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_4
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
.globl refresh_1_2x
|
||||
refresh_1_2x:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
subl $4, %edi
|
||||
shrl $1, %ecx
|
||||
.Lrefresh_1_2x:
|
||||
movb 1(%esi,%ecx,2), %al
|
||||
movb (%esi,%ecx,2), %bl
|
||||
movb (%ebp,%eax), %al
|
||||
movb %al, %dl
|
||||
movb %al, %dh
|
||||
movb (%ebp,%ebx), %bl
|
||||
rorl $16, %edx
|
||||
movb %bl, %dl
|
||||
movb %bl, %dh
|
||||
movl %edx, (%edi,%ecx,4)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_1_2x
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
|
||||
.globl refresh_2_2x
|
||||
refresh_2_2x:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
subl $8, %edi
|
||||
shrl $1, %ecx
|
||||
.Lrefresh_2_2x:
|
||||
movb (%esi,%ecx,2), %al
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movw (%ebp,%eax,2), %dx
|
||||
rorl $16, %edx
|
||||
movw (%ebp,%eax,2), %dx
|
||||
movl %edx, (%edi,%ecx,8)
|
||||
movw (%ebp,%ebx,2), %dx
|
||||
rorl $16, %edx
|
||||
movw (%ebp,%ebx,2), %dx
|
||||
movl %edx, 4(%edi,%ecx,8)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_2_2x
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
.globl refresh_4_2x
|
||||
refresh_4_2x:
|
||||
_enter
|
||||
subl $2, %esi
|
||||
subl $16, %edi
|
||||
.Lrefresh_4_2x:
|
||||
movb (%esi,%ecx), %al
|
||||
movb 1(%esi,%ecx), %bl
|
||||
movl (%ebp,%eax,4), %edx
|
||||
movl %edx, (%edi,%ecx,8)
|
||||
movl %edx, 4(%edi,%ecx,8)
|
||||
movl (%ebp,%ebx,4), %edx
|
||||
movl %edx, 8(%edi,%ecx,8)
|
||||
movl %edx, 12(%edi,%ecx,8)
|
||||
subl $2, %ecx
|
||||
jnz .Lrefresh_4_2x
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
|
||||
.globl refrsh_1_3x
|
||||
refresh_1_3x:
|
||||
_enter
|
||||
leal (%ecx,%ecx,2), %edx
|
||||
shrl $1, %ecx
|
||||
addl %edx, %edi
|
||||
subl $2, %esi
|
||||
.Lrefresh_1_3x:
|
||||
movb (%esi,%ecx,2), %al
|
||||
subl $6, %edi
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movb (%ebp,%eax,2), %dl
|
||||
movb %dl, (%edi)
|
||||
movb %dl, 1(%edi)
|
||||
movb %dl, 2(%edi)
|
||||
movb (%ebp,%ebx,2), %dl
|
||||
movb %dl, 3(%edi)
|
||||
movb %dl, 4(%edi)
|
||||
movb %dl, 5(%edi)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_1_3x
|
||||
_leave
|
||||
|
||||
|
||||
.globl refresh_2_3x
|
||||
refresh_2_3x:
|
||||
_enter
|
||||
shll $1, %ecx
|
||||
addl %ecx, %edi
|
||||
addl %ecx, %edi
|
||||
addl %ecx, %edi
|
||||
shrl $2, %ecx
|
||||
subl $2, %esi
|
||||
.Lrefresh_2_3x:
|
||||
movb (%esi,%ecx,2), %al
|
||||
subl $12, %edi
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movw (%ebp,%eax,2), %dx
|
||||
movw %dx, (%edi)
|
||||
movw %dx, 2(%edi)
|
||||
movw %dx, 4(%edi)
|
||||
movw (%ebp,%ebx,2), %dx
|
||||
movw %dx, 6(%edi)
|
||||
movw %dx, 8(%edi)
|
||||
movw %dx, 10(%edi)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_2_3x
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
.globl refresh_4_3x
|
||||
refresh_4_3x:
|
||||
_enter
|
||||
shll $2, %ecx
|
||||
addl %ecx, %edi
|
||||
addl %ecx, %edi
|
||||
addl %ecx, %edi
|
||||
shrl $3, %ecx
|
||||
subl $2, %esi
|
||||
.Lrefresh_4_3x:
|
||||
movb (%esi,%ecx,2), %al
|
||||
subl $24, %edi
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movl (%ebp,%eax,4), %edx
|
||||
movl %edx, (%edi)
|
||||
movl %edx, 4(%edi)
|
||||
movl %edx, 8(%edi)
|
||||
movl (%ebp,%ebx,4), %edx
|
||||
movl %edx, 12(%edi)
|
||||
movl %edx, 16(%edi)
|
||||
movl %edx, 20(%edi)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_4_3x
|
||||
_leave
|
||||
|
||||
|
||||
.globl refresh_4_4x
|
||||
refresh_4_4x:
|
||||
_enter
|
||||
shll $4, %ecx
|
||||
addl %ecx, %edi
|
||||
shrl $5, %ecx
|
||||
subl $2, %esi
|
||||
.Lrefresh_4_4x:
|
||||
movb (%esi,%ecx,2), %al
|
||||
subl $32, %edi
|
||||
movb 1(%esi,%ecx,2), %bl
|
||||
movl (%ebp,%eax,4), %edx
|
||||
movl %edx, (%edi)
|
||||
movl %edx, 4(%edi)
|
||||
movl %edx, 8(%edi)
|
||||
movl %edx, 12(%edi)
|
||||
movl (%ebp,%ebx,4), %edx
|
||||
movl %edx, 16(%edi)
|
||||
movl %edx, 20(%edi)
|
||||
movl %edx, 24(%edi)
|
||||
movl %edx, 28(%edi)
|
||||
decl %ecx
|
||||
jnz .Lrefresh_4_4x
|
||||
_leave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,259 @@
|
|||
|
||||
AC_INIT(cpu.c)
|
||||
|
||||
CFLAGS="$CFLAGS"
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
|
||||
|
||||
test "$cross_compiling" = "yes" || AC_C_BIGENDIAN
|
||||
test "$ac_cv_c_bigendian" = "no" && ENDIAN="-DIS_LITTLE_ENDIAN"
|
||||
|
||||
|
||||
|
||||
AC_CHECK_FUNCS(usleep, ,[
|
||||
AC_CHECK_FUNCS(select, ,[
|
||||
AC_MSG_ERROR(your system must support either usleep or select)
|
||||
])])
|
||||
|
||||
|
||||
|
||||
|
||||
LIBS="$LIBS -L/usr/local/lib -L/usr/X11R6/lib"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AC_ARG_WITH(fb, [ --with-fb build framebuffer device interface], [], [with_fb=yes])
|
||||
AC_ARG_WITH(svgalib, [ --with-svgalib build Linux svgalib interface], [], [with_svgalib=yes])
|
||||
AC_ARG_WITH(sdl, [ --with-sdl build SDL interface], [], [with_sdl=yes])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SOUND=""
|
||||
JOY=""
|
||||
|
||||
case `uname -s` in
|
||||
Linux)
|
||||
SYS_DEFS=-DIS_LINUX
|
||||
AC_CHECK_HEADERS(sys/soundcard.h, [SOUND=sys/oss/oss.o])
|
||||
AC_CHECK_HEADERS(linux/joystick.h, [JOY=sys/linux/joy.o])
|
||||
test "$with_fb" = "no" || AC_CHECK_HEADERS(linux/fb.h, [with_fb=linux])
|
||||
;;
|
||||
FreeBSD)
|
||||
SYS_DEFS=-DIS_FBSD
|
||||
AC_CHECK_HEADERS(machine/soundcard.h, [SOUND=sys/oss/oss.o])
|
||||
;;
|
||||
OpenBSD)
|
||||
SYS_DEFS=-DIS_OBSD
|
||||
AC_CHECK_HEADERS(soundcard.h, [SOUND=sys/oss/oss.o])
|
||||
;;
|
||||
esac
|
||||
|
||||
test "$SOUND" || SOUND=sys/dummy/nosound.o
|
||||
test "$JOY" || JOY=sys/dummy/nojoy.o
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case "$with_fb" in
|
||||
linux) FB_OBJS="sys/linux/fbdev.o sys/linux/kb.o sys/pc/keymap.o" ;;
|
||||
*) FB_OBJS="" ; with_fb=no ;;
|
||||
esac
|
||||
|
||||
if test "$with_svgalib" != "no" ; then
|
||||
AC_CHECK_LIB(vga, vga_init, [
|
||||
AC_CHECK_HEADERS(vga.h vgakeyboard.h, ,[
|
||||
AC_MSG_WARN(svgalib found but headers are missing!!)
|
||||
with_svgalib=no
|
||||
])], [with_svgalib=no])
|
||||
fi
|
||||
|
||||
if test "$with_sdl" != "no" ; then
|
||||
AC_CHECK_PROG(SDL_CONFIG, sdl-config, yes)
|
||||
if test "$SDL_CONFIG" ; then
|
||||
SDL_LIBS="`sdl-config --libs`"
|
||||
SDL_CFLAGS="`sdl-config --cflags`"
|
||||
old_incs="$INCS"
|
||||
INCS="$INCS $SDL_CFLAGS"
|
||||
AC_CHECK_LIB(SDL, SDL_Init, [
|
||||
AC_CHECK_HEADERS(SDL/SDL.h, ,[
|
||||
AC_MSG_WARN(SDL found but headers are missing!!)
|
||||
with_sdl=no
|
||||
])], [with_sdl=no], $SDL_LIBS)
|
||||
INCS="$old_incs"
|
||||
else
|
||||
with_sdl=no
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PATH_X
|
||||
|
||||
if test "$no_x" != "yes" ; then
|
||||
with_x=yes
|
||||
AC_CHECK_LIB(Xext, XShmCreateImage)
|
||||
AC_CHECK_HEADERS(sys/ipc.h sys/shm.h X11/extensions/XShm.h)
|
||||
test "$x_includes" && XINCS="-I$x_includes"
|
||||
test "$x_libraries" && XLIBS="-L$x_libraries"
|
||||
else
|
||||
with_x=no
|
||||
fi
|
||||
|
||||
|
||||
|
||||
test "$with_x" = "no" || TARGETS="$TARGETS xgnuboy"
|
||||
test "$with_fb" = "no" || TARGETS="$TARGETS fbgnuboy"
|
||||
test "$with_svgalib" = "no" || TARGETS="$TARGETS sgnuboy"
|
||||
test "$with_sdl" = "no" || TARGETS="$TARGETS sdlgnuboy"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AC_ARG_ENABLE(warnings, [ --enable-warnings enable selected compiler warnings], [], [enable_warnings=yes])
|
||||
AC_ARG_ENABLE(debug, [ --enable-debug include debugging symbols], [])
|
||||
AC_ARG_ENABLE(profile, [ --enable-profile enable performance profiling], [])
|
||||
AC_ARG_ENABLE(arch, [ --enable-arch compile for specific host cpu architecture], [], [enable_arch=yes])
|
||||
AC_ARG_ENABLE(optimize, [ --enable-optimize=LEVEL select optimization level (full,low,none)], [], [enable_optimize=yes])
|
||||
AC_ARG_ENABLE(asm, [ --enable-asm use hand-optimized asm cores], [], [enable_asm=yes])
|
||||
|
||||
|
||||
if test "$enable_warnings" = yes ; then
|
||||
case "$CC" in *gcc*)
|
||||
AC_MSG_RESULT(enabling selected compiler warnings)
|
||||
CFLAGS="$CFLAGS -ansi -pedantic -Wall -Wno-implicit -Wno-long-long" ;;
|
||||
*)
|
||||
AC_MSG_RESULT(disabling warnings for non-gcc compiler) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test "$enable_debug" = yes ; then
|
||||
AC_MSG_RESULT(including debugging symbols)
|
||||
CFLAGS="$CFLAGS -g"
|
||||
fi
|
||||
|
||||
if test "$enable_profile" = yes ; then
|
||||
AC_MSG_RESULT(enabling performance profiling)
|
||||
CFLAGS="$CFLAGS -pg"
|
||||
fi
|
||||
|
||||
if test "$enable_arch" = yes ; then
|
||||
if test `uname -s` = Linux -a -f /proc/cpuinfo ; then
|
||||
case `grep "model name" /proc/cpuinfo` in
|
||||
*AMD-K6*) enable_arch=k6 ;;
|
||||
*Pentium*Pro*|*Pentium\ I*|*Klamath*) enable_arch=i686 ;;
|
||||
*Pentium*|*586*) enable_arch=i586 ;;
|
||||
*486*) enable_arch=i486 ;;
|
||||
*386*) enable_arch=i386 ;;
|
||||
*) enable_arch=no ;;
|
||||
esac
|
||||
else
|
||||
enable_arch=no
|
||||
#case `uname -m` in
|
||||
#i686) enable_arch=i686 ;;
|
||||
#i586) enable_arch=i586 ;;
|
||||
#i486) enable_arch=i486 ;;
|
||||
#i386) enable_arch=i386 ;;
|
||||
#*) enable_arch=no ;;
|
||||
#esac
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
case `$CC --version` in
|
||||
|
||||
2.9*|3.*)
|
||||
|
||||
case "$enable_arch" in
|
||||
k6|i686|i586|i486|i386) CFLAGS="$CFLAGS -march=$enable_arch" ;;
|
||||
no) ;;
|
||||
*) AC_MSG_WARN(unknown architecture $enable_arch) ;;
|
||||
esac ;;
|
||||
|
||||
*)
|
||||
|
||||
case "$enable_arch" in
|
||||
k6|i686|i586) AC_MSG_WARN(your compiler is too old to support $enable_arch optimizations) ;;
|
||||
i486) CFLAGS="$CFLAGS -m486" ;;
|
||||
i386) CFLAGS="$CFLAGS -m386" ;;
|
||||
no) ;;
|
||||
*) AC_MSG_WARN(unknown architecture $enable_arch) ;;
|
||||
esac ;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
case "$enable_optimize" in
|
||||
yes|full)
|
||||
AC_MSG_RESULT(producing heavily optimized code)
|
||||
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
|
||||
case `uname -m` in
|
||||
i?86) CFLAGS="$CFLAGS -DALLOW_UNALIGNED_IO" ;;
|
||||
esac
|
||||
|
||||
#case `$CC --version` in
|
||||
#2.9*|3.*)
|
||||
CFLAGS="$CFLAGS -fstrength-reduce -fthread-jumps \
|
||||
-fcse-follow-jumps -fcse-skip-blocks -frerun-cse-after-loop \
|
||||
-fexpensive-optimizations -fforce-mem -fforce-addr"
|
||||
#;;
|
||||
#*)
|
||||
#AC_MSG_WARN(your compiler is too old for fancy optimizations)
|
||||
#;;
|
||||
#esac
|
||||
|
||||
if test "$enable_debug" != yes -a "$enable_profile" != yes ; then
|
||||
CFLAGS="$CFLAGS -fomit-frame-pointer"
|
||||
LDFLAGS="$LDFLAGS -s"
|
||||
fi ;;
|
||||
|
||||
low)
|
||||
|
||||
AC_MSG_RESULT(using minimal optimizations)
|
||||
CFLAGS="$CFLAGS -O3" ;;
|
||||
|
||||
esac
|
||||
|
||||
if test "$enable_asm" = yes ; then
|
||||
case `uname -m` in
|
||||
i?86)
|
||||
AC_MSG_RESULT(using optimized i386 cores)
|
||||
ASM="-DUSE_ASM -I./asm/i386" ; ASM_OBJS="asm/i386/cpu.o asm/i386/lcd.o asm/i386/refresh.s" ;;
|
||||
*)
|
||||
AC_MSG_RESULT(no optimized asm core available for `uname -m`) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
AC_SUBST(SYS_DEFS)
|
||||
AC_SUBST(ENDIAN)
|
||||
AC_SUBST(SOUND)
|
||||
AC_SUBST(JOY)
|
||||
AC_SUBST(ASM)
|
||||
AC_SUBST(ASM_OBJS)
|
||||
AC_SUBST(FB_OBJS)
|
||||
AC_SUBST(SDL_CFLAGS)
|
||||
AC_SUBST(SDL_LIBS)
|
||||
AC_SUBST(TARGETS)
|
||||
AC_SUBST(XINCS)
|
||||
AC_SUBST(XLIBS)
|
||||
|
||||
AC_CONFIG_HEADER(sys/nix/config.h)
|
||||
AC_OUTPUT(Makefile)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,878 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "regs.h"
|
||||
#include "hw.h"
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "fastmem.h"
|
||||
#include "cpuregs.h"
|
||||
#include "cpucore.h"
|
||||
|
||||
#ifdef USE_ASM
|
||||
#include "asm.h"
|
||||
#endif
|
||||
|
||||
|
||||
struct cpu cpu;
|
||||
|
||||
|
||||
|
||||
|
||||
#define ZFLAG(n) ( (n) ? 0 : FZ )
|
||||
|
||||
|
||||
#define PUSH(w) ( (SP -= 2), (writew(xSP, (w))) )
|
||||
#define POP(w) ( ((w) = readw(xSP)), (SP += 2) )
|
||||
|
||||
|
||||
#define FETCH_OLD ( mbc.rmap[PC>>12] \
|
||||
? mbc.rmap[PC>>12][PC++] \
|
||||
: mem_read(PC++) )
|
||||
|
||||
#define FETCH (readb(PC++))
|
||||
|
||||
|
||||
#define INC(r) { ((r)++); \
|
||||
F = (F & (FL|FC)) | incflag_table[(r)]; }
|
||||
|
||||
#define DEC(r) { ((r)--); \
|
||||
F = (F & (FL|FC)) | decflag_table[(r)]; }
|
||||
|
||||
#define INCW(r) ( (r)++ )
|
||||
|
||||
#define DECW(r) ( (r)-- )
|
||||
|
||||
#define ADD(n) { \
|
||||
W(acc) = (un16)A + (un16)(n); \
|
||||
F = (ZFLAG(LB(acc))) \
|
||||
| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
|
||||
| (HB(acc) << 4); \
|
||||
A = LB(acc); }
|
||||
|
||||
#define ADC(n) { \
|
||||
W(acc) = (un16)A + (un16)(n) + (un16)((F&FC)>>4); \
|
||||
F = (ZFLAG(LB(acc))) \
|
||||
| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
|
||||
| (HB(acc) << 4); \
|
||||
A = LB(acc); }
|
||||
|
||||
#define ADDW(n) { \
|
||||
DW(acc) = (un32)HL + (un32)(n); \
|
||||
F = (F & (FZ)) \
|
||||
| (FH & ((H ^ ((n)>>8) ^ HB(acc)) << 1)) \
|
||||
| (acc.b[HI][LO] << 4); \
|
||||
HL = W(acc); }
|
||||
|
||||
#define ADDSP(n) { \
|
||||
DW(acc) = (un32)SP + (un32)(n8)(n); \
|
||||
F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \
|
||||
| (acc.b[HI][LO] << 4); \
|
||||
SP = W(acc); }
|
||||
|
||||
#define LDHLSP(n) { \
|
||||
DW(acc) = (un32)SP + (un32)(n8)(n); \
|
||||
F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \
|
||||
| (acc.b[HI][LO] << 4); \
|
||||
HL = W(acc); }
|
||||
|
||||
#define CP(n) { \
|
||||
W(acc) = (un16)A - (un16)(n); \
|
||||
F = FN \
|
||||
| (ZFLAG(LB(acc))) \
|
||||
| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
|
||||
| ((un8)(-(n8)HB(acc)) << 4); }
|
||||
|
||||
#define SUB(n) { CP((n)); A = LB(acc); }
|
||||
|
||||
#define SBC(n) { \
|
||||
W(acc) = (un16)A - (un16)(n) - (un16)((F&FC)>>4); \
|
||||
F = FN \
|
||||
| (ZFLAG((n8)LB(acc))) \
|
||||
| (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
|
||||
| ((un8)(-(n8)HB(acc)) << 4); \
|
||||
A = LB(acc); }
|
||||
|
||||
#define AND(n) { A &= (n); \
|
||||
F = ZFLAG(A) | FH; }
|
||||
|
||||
#define XOR(n) { A ^= (n); \
|
||||
F = ZFLAG(A); }
|
||||
|
||||
#define OR(n) { A |= (n); \
|
||||
F = ZFLAG(A); }
|
||||
|
||||
#define RLCA(r) { (r) = ((r)>>7) | ((r)<<1); \
|
||||
F = (((r)&0x01)<<4); }
|
||||
|
||||
#define RRCA(r) { (r) = ((r)<<7) | ((r)>>1); \
|
||||
F = (((r)&0x80)>>3); }
|
||||
|
||||
#define RLA(r) { \
|
||||
LB(acc) = (((r)&0x80)>>3); \
|
||||
(r) = ((r)<<1) | ((F&FC)>>4); \
|
||||
F = LB(acc); }
|
||||
|
||||
#define RRA(r) { \
|
||||
LB(acc) = (((r)&0x01)<<4); \
|
||||
(r) = ((r)>>1) | ((F&FC)<<3); \
|
||||
F = LB(acc); }
|
||||
|
||||
#define RLC(r) { RLCA(r); F |= ZFLAG(r); }
|
||||
#define RRC(r) { RRCA(r); F |= ZFLAG(r); }
|
||||
#define RL(r) { RLA(r); F |= ZFLAG(r); }
|
||||
#define RR(r) { RRA(r); F |= ZFLAG(r); }
|
||||
|
||||
#define SLA(r) { \
|
||||
LB(acc) = (((r)&0x80)>>3); \
|
||||
(r) <<= 1; \
|
||||
F = ZFLAG((r)) | LB(acc); }
|
||||
|
||||
#define SRA(r) { \
|
||||
LB(acc) = (((r)&0x01)<<4); \
|
||||
(r) = (un8)(((n8)(r))>>1); \
|
||||
F = ZFLAG((r)) | LB(acc); }
|
||||
|
||||
#define SRL(r) { \
|
||||
LB(acc) = (((r)&0x01)<<4); \
|
||||
(r) >>= 1; \
|
||||
F = ZFLAG((r)) | LB(acc); }
|
||||
|
||||
#define CPL(r) { \
|
||||
(r) = ~(r); \
|
||||
F |= (FH|FN); }
|
||||
|
||||
#define SCF { F = (F & (FZ)) | FC; }
|
||||
|
||||
#define CCF { F = (F & (FZ|FC)) ^ FC; }
|
||||
|
||||
#define DAA { \
|
||||
A += (LB(acc) = daa_table[((((int)F)&0x70)<<4) | A]); \
|
||||
F = (F & (FN)) | ZFLAG(A) | daa_carry_table[LB(acc)>>2]; }
|
||||
|
||||
#define SWAP(r) { \
|
||||
(r) = swap_table[(r)]; \
|
||||
F = ZFLAG((r)); }
|
||||
|
||||
#define BIT(n,r) { F = (F & FC) | ZFLAG(((r) & (1 << (n)))) | FH; }
|
||||
#define RES(n,r) { (r) &= ~(1 << (n)); }
|
||||
#define SET(n,r) { (r) |= (1 << (n)); }
|
||||
|
||||
#define CB_REG_CASES(r, n) \
|
||||
case 0x00|(n): RLC(r); break; \
|
||||
case 0x08|(n): RRC(r); break; \
|
||||
case 0x10|(n): RL(r); break; \
|
||||
case 0x18|(n): RR(r); break; \
|
||||
case 0x20|(n): SLA(r); break; \
|
||||
case 0x28|(n): SRA(r); break; \
|
||||
case 0x30|(n): SWAP(r); break; \
|
||||
case 0x38|(n): SRL(r); break; \
|
||||
case 0x40|(n): BIT(0, r); break; \
|
||||
case 0x48|(n): BIT(1, r); break; \
|
||||
case 0x50|(n): BIT(2, r); break; \
|
||||
case 0x58|(n): BIT(3, r); break; \
|
||||
case 0x60|(n): BIT(4, r); break; \
|
||||
case 0x68|(n): BIT(5, r); break; \
|
||||
case 0x70|(n): BIT(6, r); break; \
|
||||
case 0x78|(n): BIT(7, r); break; \
|
||||
case 0x80|(n): RES(0, r); break; \
|
||||
case 0x88|(n): RES(1, r); break; \
|
||||
case 0x90|(n): RES(2, r); break; \
|
||||
case 0x98|(n): RES(3, r); break; \
|
||||
case 0xA0|(n): RES(4, r); break; \
|
||||
case 0xA8|(n): RES(5, r); break; \
|
||||
case 0xB0|(n): RES(6, r); break; \
|
||||
case 0xB8|(n): RES(7, r); break; \
|
||||
case 0xC0|(n): SET(0, r); break; \
|
||||
case 0xC8|(n): SET(1, r); break; \
|
||||
case 0xD0|(n): SET(2, r); break; \
|
||||
case 0xD8|(n): SET(3, r); break; \
|
||||
case 0xE0|(n): SET(4, r); break; \
|
||||
case 0xE8|(n): SET(5, r); break; \
|
||||
case 0xF0|(n): SET(6, r); break; \
|
||||
case 0xF8|(n): SET(7, r); break;
|
||||
|
||||
|
||||
#define ALU_CASES(base, imm, op, label) \
|
||||
case (imm): b = FETCH; goto label; \
|
||||
case (base): b = B; goto label; \
|
||||
case (base)+1: b = C; goto label; \
|
||||
case (base)+2: b = D; goto label; \
|
||||
case (base)+3: b = E; goto label; \
|
||||
case (base)+4: b = H; goto label; \
|
||||
case (base)+5: b = L; goto label; \
|
||||
case (base)+6: b = readb(HL); goto label; \
|
||||
case (base)+7: b = A; \
|
||||
label: op(b); break;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define JR ( PC += 1+(n8)readb(PC) )
|
||||
#define JP ( PC = readw(PC) )
|
||||
|
||||
#define CALL ( PUSH(PC+2), JP )
|
||||
|
||||
#define NOJR ( clen--, PC++ )
|
||||
#define NOJP ( clen--, PC+=2 )
|
||||
#define NOCALL ( clen-=3, PC+=2 )
|
||||
#define NORET ( clen-=3 )
|
||||
|
||||
#define RST(n) { PUSH(PC); PC = (n); }
|
||||
|
||||
#define RET ( POP(PC) )
|
||||
|
||||
#define EI ( IMA = 1 )
|
||||
#define DI ( cpu.halt = IMA = IME = 0 )
|
||||
|
||||
|
||||
|
||||
#define PRE_INT ( DI, PUSH(PC) )
|
||||
#define THROW_INT(n) ( (IF &= ~(1<<(n))), (PC = 0x40+((n)<<3)) )
|
||||
|
||||
|
||||
|
||||
|
||||
void cpu_reset()
|
||||
{
|
||||
cpu.speed = 0;
|
||||
cpu.halt = 0;
|
||||
cpu.div = 0;
|
||||
cpu.tim = 0;
|
||||
cpu.lcdc = 40;
|
||||
|
||||
IME = 0;
|
||||
IMA = 0;
|
||||
|
||||
PC = 0x0100;
|
||||
SP = 0xFFFE;
|
||||
AF = 0x01B0;
|
||||
BC = 0x0013;
|
||||
DE = 0x00D8;
|
||||
HL = 0x014D;
|
||||
|
||||
if (hw.cgb) A = 0x11;
|
||||
if (hw.gba) B = 0x01;
|
||||
}
|
||||
|
||||
|
||||
void div_advance(int cnt)
|
||||
{
|
||||
cpu.div += (cnt<<1);
|
||||
if (cpu.div >= 256)
|
||||
{
|
||||
R_DIV += (cpu.div >> 8);
|
||||
cpu.div &= 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_advance(int cnt)
|
||||
{
|
||||
int unit, tima;
|
||||
|
||||
if (!(R_TAC & 0x04)) return;
|
||||
|
||||
unit = ((-R_TAC) & 3) << 1;
|
||||
cpu.tim += (cnt<<unit);
|
||||
|
||||
if (cpu.tim >= 512)
|
||||
{
|
||||
tima = R_TIMA + (cpu.tim >> 9);
|
||||
cpu.tim &= 0x1ff;
|
||||
if (tima >= 256)
|
||||
{
|
||||
hw_interrupt(IF_TIMER, IF_TIMER);
|
||||
hw_interrupt(0, IF_TIMER);
|
||||
}
|
||||
while (tima >= 256)
|
||||
tima = tima - 256 + R_TMA;
|
||||
R_TIMA = tima;
|
||||
}
|
||||
}
|
||||
|
||||
void lcdc_advance(int cnt)
|
||||
{
|
||||
cpu.lcdc -= cnt;
|
||||
if (cpu.lcdc <= 0) lcdc_trans();
|
||||
}
|
||||
|
||||
void sound_advance(int cnt)
|
||||
{
|
||||
cpu.snd += cnt;
|
||||
}
|
||||
|
||||
void cpu_timers(int cnt)
|
||||
{
|
||||
div_advance(cnt << cpu.speed);
|
||||
timer_advance(cnt << cpu.speed);
|
||||
lcdc_advance(cnt);
|
||||
sound_advance(cnt);
|
||||
}
|
||||
|
||||
int cpu_idle(int max)
|
||||
{
|
||||
int cnt, unit;
|
||||
|
||||
if (!(cpu.halt && IME)) return 0;
|
||||
if (R_IF & R_IE)
|
||||
{
|
||||
cpu.halt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure we don't miss lcdc status events! */
|
||||
if ((R_IE & (IF_VBLANK | IF_STAT)) && (max > cpu.lcdc))
|
||||
max = cpu.lcdc;
|
||||
|
||||
/* If timer interrupt cannot happen, this is very simple! */
|
||||
if (!((R_IE & IF_TIMER) && (R_TAC & 0x04)))
|
||||
{
|
||||
cpu_timers(max);
|
||||
return max;
|
||||
}
|
||||
|
||||
/* Figure out when the next timer interrupt will happen */
|
||||
unit = ((-R_TAC) & 3) << 1;
|
||||
cnt = (511 - cpu.tim + (1<<unit)) >> unit;
|
||||
cnt += (255 - R_TIMA) << (9 - unit);
|
||||
|
||||
if (max < cnt)
|
||||
cnt = max;
|
||||
|
||||
cpu_timers(cnt);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
#ifndef ASM_CPU_EMULATE
|
||||
|
||||
extern int debug_trace;
|
||||
|
||||
int cpu_emulate(int cycles)
|
||||
{
|
||||
int i;
|
||||
byte op, cbop;
|
||||
int clen;
|
||||
static union reg acc;
|
||||
static byte b;
|
||||
static word w;
|
||||
|
||||
i = cycles;
|
||||
next:
|
||||
if ((clen = cpu_idle(i)))
|
||||
{
|
||||
i -= clen;
|
||||
if (i > 0) goto next;
|
||||
return cycles-i;
|
||||
}
|
||||
|
||||
if (IME && (IF & IE))
|
||||
{
|
||||
PRE_INT;
|
||||
switch ((byte)(IF & IE))
|
||||
{
|
||||
case 0x01: case 0x03: case 0x05: case 0x07:
|
||||
case 0x09: case 0x0B: case 0x0D: case 0x0F:
|
||||
case 0x11: case 0x13: case 0x15: case 0x17:
|
||||
case 0x19: case 0x1B: case 0x1D: case 0x1F:
|
||||
THROW_INT(0); break;
|
||||
case 0x02: case 0x06: case 0x0A: case 0x0E:
|
||||
case 0x12: case 0x16: case 0x1A: case 0x1E:
|
||||
THROW_INT(1); break;
|
||||
case 0x04: case 0x0C: case 0x14: case 0x1C:
|
||||
THROW_INT(2); break;
|
||||
case 0x08: case 0x18:
|
||||
THROW_INT(3); break;
|
||||
case 0x10:
|
||||
THROW_INT(4); break;
|
||||
}
|
||||
}
|
||||
IME = IMA;
|
||||
|
||||
if (debug_trace) debug_disassemble(PC, 1);
|
||||
op = FETCH;
|
||||
clen = cycles_table[op];
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case 0x00: /* NOP */
|
||||
case 0x40: /* LD B,B */
|
||||
case 0x49: /* LD C,C */
|
||||
case 0x52: /* LD D,D */
|
||||
case 0x5B: /* LD E,E */
|
||||
case 0x64: /* LD H,H */
|
||||
case 0x6D: /* LD L,L */
|
||||
case 0x7F: /* LD A,A */
|
||||
break;
|
||||
|
||||
case 0x41: /* LD B,C */
|
||||
B = C; break;
|
||||
case 0x42: /* LD B,D */
|
||||
B = D; break;
|
||||
case 0x43: /* LD B,E */
|
||||
B = E; break;
|
||||
case 0x44: /* LD B,H */
|
||||
B = H; break;
|
||||
case 0x45: /* LD B,L */
|
||||
B = L; break;
|
||||
case 0x46: /* LD B,(HL) */
|
||||
B = readb(xHL); break;
|
||||
case 0x47: /* LD B,A */
|
||||
B = A; break;
|
||||
|
||||
case 0x48: /* LD C,B */
|
||||
C = B; break;
|
||||
case 0x4A: /* LD C,D */
|
||||
C = D; break;
|
||||
case 0x4B: /* LD C,E */
|
||||
C = E; break;
|
||||
case 0x4C: /* LD C,H */
|
||||
C = H; break;
|
||||
case 0x4D: /* LD C,L */
|
||||
C = L; break;
|
||||
case 0x4E: /* LD C,(HL) */
|
||||
C = readb(xHL); break;
|
||||
case 0x4F: /* LD C,A */
|
||||
C = A; break;
|
||||
|
||||
case 0x50: /* LD D,B */
|
||||
D = B; break;
|
||||
case 0x51: /* LD D,C */
|
||||
D = C; break;
|
||||
case 0x53: /* LD D,E */
|
||||
D = E; break;
|
||||
case 0x54: /* LD D,H */
|
||||
D = H; break;
|
||||
case 0x55: /* LD D,L */
|
||||
D = L; break;
|
||||
case 0x56: /* LD D,(HL) */
|
||||
D = readb(xHL); break;
|
||||
case 0x57: /* LD D,A */
|
||||
D = A; break;
|
||||
|
||||
case 0x58: /* LD E,B */
|
||||
E = B; break;
|
||||
case 0x59: /* LD E,C */
|
||||
E = C; break;
|
||||
case 0x5A: /* LD E,D */
|
||||
E = D; break;
|
||||
case 0x5C: /* LD E,H */
|
||||
E = H; break;
|
||||
case 0x5D: /* LD E,L */
|
||||
E = L; break;
|
||||
case 0x5E: /* LD E,(HL) */
|
||||
E = readb(xHL); break;
|
||||
case 0x5F: /* LD E,A */
|
||||
E = A; break;
|
||||
|
||||
case 0x60: /* LD H,B */
|
||||
H = B; break;
|
||||
case 0x61: /* LD H,C */
|
||||
H = C; break;
|
||||
case 0x62: /* LD H,D */
|
||||
H = D; break;
|
||||
case 0x63: /* LD H,E */
|
||||
H = E; break;
|
||||
case 0x65: /* LD H,L */
|
||||
H = L; break;
|
||||
case 0x66: /* LD H,(HL) */
|
||||
H = readb(xHL); break;
|
||||
case 0x67: /* LD H,A */
|
||||
H = A; break;
|
||||
|
||||
case 0x68: /* LD L,B */
|
||||
L = B; break;
|
||||
case 0x69: /* LD L,C */
|
||||
L = C; break;
|
||||
case 0x6A: /* LD L,D */
|
||||
L = D; break;
|
||||
case 0x6B: /* LD L,E */
|
||||
L = E; break;
|
||||
case 0x6C: /* LD L,H */
|
||||
L = H; break;
|
||||
case 0x6E: /* LD L,(HL) */
|
||||
L = readb(xHL); break;
|
||||
case 0x6F: /* LD L,A */
|
||||
L = A; break;
|
||||
|
||||
case 0x70: /* LD (HL),B */
|
||||
b = B; goto __LD_HL;
|
||||
case 0x71: /* LD (HL),C */
|
||||
b = C; goto __LD_HL;
|
||||
case 0x72: /* LD (HL),D */
|
||||
b = D; goto __LD_HL;
|
||||
case 0x73: /* LD (HL),E */
|
||||
b = E; goto __LD_HL;
|
||||
case 0x74: /* LD (HL),H */
|
||||
b = H; goto __LD_HL;
|
||||
case 0x75: /* LD (HL),L */
|
||||
b = L; goto __LD_HL;
|
||||
case 0x77: /* LD (HL),A */
|
||||
b = A;
|
||||
__LD_HL:
|
||||
writeb(xHL,b);
|
||||
break;
|
||||
|
||||
case 0x78: /* LD A,B */
|
||||
A = B; break;
|
||||
case 0x79: /* LD A,C */
|
||||
A = C; break;
|
||||
case 0x7A: /* LD A,D */
|
||||
A = D; break;
|
||||
case 0x7B: /* LD A,E */
|
||||
A = E; break;
|
||||
case 0x7C: /* LD A,H */
|
||||
A = H; break;
|
||||
case 0x7D: /* LD A,L */
|
||||
A = L; break;
|
||||
case 0x7E: /* LD A,(HL) */
|
||||
A = readb(xHL); break;
|
||||
|
||||
case 0x01: /* LD BC,imm */
|
||||
BC = readw(xPC); PC += 2; break;
|
||||
case 0x11: /* LD DE,imm */
|
||||
DE = readw(xPC); PC += 2; break;
|
||||
case 0x21: /* LD HL,imm */
|
||||
HL = readw(xPC); PC += 2; break;
|
||||
case 0x31: /* LD SP,imm */
|
||||
SP = readw(xPC); PC += 2; break;
|
||||
|
||||
case 0x02: /* LD (BC),A */
|
||||
writeb(xBC, A); break;
|
||||
case 0x0A: /* LD A,(BC) */
|
||||
A = readb(xBC); break;
|
||||
case 0x12: /* LD (DE),A */
|
||||
writeb(xDE, A); break;
|
||||
case 0x1A: /* LD A,(DE) */
|
||||
A = readb(xDE); break;
|
||||
|
||||
case 0x22: /* LDI (HL),A */
|
||||
writeb(xHL, A); HL++; break;
|
||||
case 0x2A: /* LDI A,(HL) */
|
||||
A = readb(xHL); HL++; break;
|
||||
case 0x32: /* LDD (HL),A */
|
||||
writeb(xHL, A); HL--; break;
|
||||
case 0x3A: /* LDD A,(HL) */
|
||||
A = readb(xHL); HL--; break;
|
||||
|
||||
case 0x06: /* LD B,imm */
|
||||
B = FETCH; break;
|
||||
case 0x0E: /* LD C,imm */
|
||||
C = FETCH; break;
|
||||
case 0x16: /* LD D,imm */
|
||||
D = FETCH; break;
|
||||
case 0x1E: /* LD E,imm */
|
||||
E = FETCH; break;
|
||||
case 0x26: /* LD H,imm */
|
||||
H = FETCH; break;
|
||||
case 0x2E: /* LD L,imm */
|
||||
L = FETCH; break;
|
||||
case 0x36: /* LD (HL),imm */
|
||||
b = FETCH; writeb(xHL, b); break;
|
||||
case 0x3E: /* LD A,imm */
|
||||
A = FETCH; break;
|
||||
|
||||
case 0x08: /* LD (imm),SP */
|
||||
writew(readw(xPC), SP); PC += 2; break;
|
||||
case 0xEA: /* LD (imm),A */
|
||||
writeb(readw(xPC), A); PC += 2; break;
|
||||
|
||||
case 0xE0: /* LDH (imm),A */
|
||||
writehi(FETCH, A); break;
|
||||
case 0xE2: /* LDH (C),A */
|
||||
writehi(C, A); break;
|
||||
case 0xF0: /* LDH A,(imm) */
|
||||
A = readhi(FETCH); break;
|
||||
case 0xF2: /* LDH A,(C) (undocumented) */
|
||||
A = readhi(C); break;
|
||||
|
||||
|
||||
case 0xF8: /* LD HL,SP+imm */
|
||||
b = FETCH; LDHLSP(b); break;
|
||||
case 0xF9: /* LD SP,HL */
|
||||
SP = HL; break;
|
||||
case 0xFA: /* LD A,(imm) */
|
||||
A = readb(readw(xPC)); PC += 2; break;
|
||||
|
||||
ALU_CASES(0x80, 0xC6, ADD, __ADD)
|
||||
ALU_CASES(0x88, 0xCE, ADC, __ADC)
|
||||
ALU_CASES(0x90, 0xD6, SUB, __SUB)
|
||||
ALU_CASES(0x98, 0xDE, SBC, __SBC)
|
||||
ALU_CASES(0xA0, 0xE6, AND, __AND)
|
||||
ALU_CASES(0xA8, 0xEE, XOR, __XOR)
|
||||
ALU_CASES(0xB0, 0xF6, OR, __OR)
|
||||
ALU_CASES(0xB8, 0xFE, CP, __CP)
|
||||
|
||||
case 0x09: /* ADD HL,BC */
|
||||
w = BC; goto __ADDW;
|
||||
case 0x19: /* ADD HL,DE */
|
||||
w = DE; goto __ADDW;
|
||||
case 0x39: /* ADD HL,SP */
|
||||
w = SP; goto __ADDW;
|
||||
case 0x29: /* ADD HL,HL */
|
||||
w = HL;
|
||||
__ADDW:
|
||||
ADDW(w);
|
||||
break;
|
||||
|
||||
case 0x04: /* INC B */
|
||||
INC(B); break;
|
||||
case 0x0C: /* INC C */
|
||||
INC(C); break;
|
||||
case 0x14: /* INC D */
|
||||
INC(D); break;
|
||||
case 0x1C: /* INC E */
|
||||
INC(E); break;
|
||||
case 0x24: /* INC H */
|
||||
INC(H); break;
|
||||
case 0x2C: /* INC L */
|
||||
INC(L); break;
|
||||
case 0x34: /* INC (HL) */
|
||||
b = readb(xHL);
|
||||
INC(b);
|
||||
writeb(xHL, b);
|
||||
break;
|
||||
case 0x3C: /* INC A */
|
||||
INC(A); break;
|
||||
|
||||
case 0x03: /* INC BC */
|
||||
INCW(BC); break;
|
||||
case 0x13: /* INC DE */
|
||||
INCW(DE); break;
|
||||
case 0x23: /* INC HL */
|
||||
INCW(HL); break;
|
||||
case 0x33: /* INC SP */
|
||||
INCW(SP); break;
|
||||
|
||||
case 0x05: /* DEC B */
|
||||
DEC(B); break;
|
||||
case 0x0D: /* DEC C */
|
||||
DEC(C); break;
|
||||
case 0x15: /* DEC D */
|
||||
DEC(D); break;
|
||||
case 0x1D: /* DEC E */
|
||||
DEC(E); break;
|
||||
case 0x25: /* DEC H */
|
||||
DEC(H); break;
|
||||
case 0x2D: /* DEC L */
|
||||
DEC(L); break;
|
||||
case 0x35: /* DEC (HL) */
|
||||
b = readb(xHL);
|
||||
DEC(b);
|
||||
writeb(xHL, b);
|
||||
break;
|
||||
case 0x3D: /* DEC A */
|
||||
DEC(A); break;
|
||||
|
||||
case 0x0B: /* DEC BC */
|
||||
DECW(BC); break;
|
||||
case 0x1B: /* DEC DE */
|
||||
DECW(DE); break;
|
||||
case 0x2B: /* DEC HL */
|
||||
DECW(HL); break;
|
||||
case 0x3B: /* DEC SP */
|
||||
DECW(SP); break;
|
||||
|
||||
case 0x07: /* RLCA */
|
||||
RLCA(A); break;
|
||||
case 0x0F: /* RRCA */
|
||||
RRCA(A); break;
|
||||
case 0x17: /* RLA */
|
||||
RLA(A); break;
|
||||
case 0x1F: /* RRA */
|
||||
RRA(A); break;
|
||||
|
||||
case 0x27: /* DAA */
|
||||
DAA; break;
|
||||
case 0x2F: /* CPL */
|
||||
CPL(A); break;
|
||||
|
||||
case 0x18: /* JR */
|
||||
__JR:
|
||||
JR; break;
|
||||
case 0x20: /* JR NZ */
|
||||
if (!(F&FZ)) goto __JR; NOJR; break;
|
||||
case 0x28: /* JR Z */
|
||||
if (F&FZ) goto __JR; NOJR; break;
|
||||
case 0x30: /* JR NC */
|
||||
if (!(F&FC)) goto __JR; NOJR; break;
|
||||
case 0x38: /* JR C */
|
||||
if (F&FC) goto __JR; NOJR; break;
|
||||
|
||||
case 0xC3: /* JP */
|
||||
__JP:
|
||||
JP; break;
|
||||
case 0xC2: /* JP NZ */
|
||||
if (!(F&FZ)) goto __JP; NOJP; break;
|
||||
case 0xCA: /* JP Z */
|
||||
if (F&FZ) goto __JP; NOJP; break;
|
||||
case 0xD2: /* JP NC */
|
||||
if (!(F&FC)) goto __JP; NOJP; break;
|
||||
case 0xDA: /* JP C */
|
||||
if (F&FC) goto __JP; NOJP; break;
|
||||
case 0xE9: /* JP HL */
|
||||
PC = HL; break;
|
||||
|
||||
case 0xC9: /* RET */
|
||||
__RET:
|
||||
RET; break;
|
||||
case 0xC0: /* RET NZ */
|
||||
if (!(F&FZ)) goto __RET; NORET; break;
|
||||
case 0xC8: /* RET Z */
|
||||
if (F&FZ) goto __RET; NORET; break;
|
||||
case 0xD0: /* RET NC */
|
||||
if (!(F&FC)) goto __RET; NORET; break;
|
||||
case 0xD8: /* RET C */
|
||||
if (F&FC) goto __RET; NORET; break;
|
||||
case 0xD9: /* RETI */
|
||||
IME = IMA = 1; goto __RET;
|
||||
|
||||
case 0xCD: /* CALL */
|
||||
__CALL:
|
||||
CALL; break;
|
||||
case 0xC4: /* CALL NZ */
|
||||
if (!(F&FZ)) goto __CALL; NOCALL; break;
|
||||
case 0xCC: /* CALL Z */
|
||||
if (F&FZ) goto __CALL; NOCALL; break;
|
||||
case 0xD4: /* CALL NC */
|
||||
if (!(F&FC)) goto __CALL; NOCALL; break;
|
||||
case 0xDC: /* CALL C */
|
||||
if (F&FC) goto __CALL; NOCALL; break;
|
||||
|
||||
case 0xC7: /* RST 0 */
|
||||
b = 0x00; goto __RST;
|
||||
case 0xCF: /* RST 8 */
|
||||
b = 0x08; goto __RST;
|
||||
case 0xD7: /* RST 10 */
|
||||
b = 0x10; goto __RST;
|
||||
case 0xDF: /* RST 18 */
|
||||
b = 0x18; goto __RST;
|
||||
case 0xE7: /* RST 20 */
|
||||
b = 0x20; goto __RST;
|
||||
case 0xEF: /* RST 28 */
|
||||
b = 0x28; goto __RST;
|
||||
case 0xF7: /* RST 30 */
|
||||
b = 0x30; goto __RST;
|
||||
case 0xFF: /* RST 38 */
|
||||
b = 0x38;
|
||||
__RST:
|
||||
RST(b); break;
|
||||
|
||||
case 0xC1: /* POP BC */
|
||||
POP(BC); break;
|
||||
case 0xC5: /* PUSH BC */
|
||||
PUSH(BC); break;
|
||||
case 0xD1: /* POP DE */
|
||||
POP(DE); break;
|
||||
case 0xD5: /* PUSH DE */
|
||||
PUSH(DE); break;
|
||||
case 0xE1: /* POP HL */
|
||||
POP(HL); break;
|
||||
case 0xE5: /* PUSH HL */
|
||||
PUSH(HL); break;
|
||||
case 0xF1: /* POP AF */
|
||||
POP(AF); break;
|
||||
case 0xF5: /* PUSH AF */
|
||||
PUSH(AF); break;
|
||||
|
||||
case 0xE8: /* ADD SP,imm */
|
||||
b = FETCH; ADDSP(b); break;
|
||||
|
||||
case 0xF3: /* DI */
|
||||
DI; break;
|
||||
case 0xFB: /* EI */
|
||||
EI; break;
|
||||
|
||||
case 0x37: /* SCF */
|
||||
SCF; break;
|
||||
case 0x3F: /* CCF */
|
||||
CCF; break;
|
||||
|
||||
case 0x10: /* STOP */
|
||||
PC++;
|
||||
if (R_KEY1 & 1)
|
||||
{
|
||||
cpu.speed = cpu.speed ^ 1;
|
||||
R_KEY1 = (R_KEY1 & 0x7E) | (cpu.speed << 7);
|
||||
break;
|
||||
}
|
||||
/* NOTE - we do not implement dmg STOP whatsoever */
|
||||
break;
|
||||
|
||||
case 0x76: /* HALT */
|
||||
cpu.halt = 1;
|
||||
break;
|
||||
|
||||
case 0xCB: /* CB prefix */
|
||||
cbop = FETCH;
|
||||
clen = cb_cycles_table[cbop];
|
||||
switch (cbop)
|
||||
{
|
||||
CB_REG_CASES(B, 0);
|
||||
CB_REG_CASES(C, 1);
|
||||
CB_REG_CASES(D, 2);
|
||||
CB_REG_CASES(E, 3);
|
||||
CB_REG_CASES(H, 4);
|
||||
CB_REG_CASES(L, 5);
|
||||
CB_REG_CASES(A, 7);
|
||||
default:
|
||||
b = readb(xHL);
|
||||
switch(cbop)
|
||||
{
|
||||
CB_REG_CASES(b, 6);
|
||||
}
|
||||
if ((cbop & 0xC0) != 0x40) /* exclude BIT */
|
||||
writeb(xHL, b);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
die(
|
||||
"invalid opcode 0x%02X at address 0x%04X, rombank = %d\n",
|
||||
op, (PC-1) & 0xffff, mbc.rombank);
|
||||
break;
|
||||
}
|
||||
|
||||
clen <<= 1;
|
||||
div_advance(clen);
|
||||
timer_advance(clen);
|
||||
clen >>= cpu.speed;
|
||||
lcdc_advance(clen);
|
||||
sound_advance(clen);
|
||||
|
||||
i -= clen;
|
||||
if (i > 0) goto next;
|
||||
return cycles-i;
|
||||
}
|
||||
|
||||
#endif /* ASM_CPU_EMULATE */
|
||||
|
||||
|
||||
#ifndef ASM_CPU_STEP
|
||||
|
||||
int cpu_step(int max)
|
||||
{
|
||||
int cnt;
|
||||
if ((cnt = cpu_idle(max))) return cnt;
|
||||
return cpu_emulate(1);
|
||||
}
|
||||
|
||||
#endif /* ASM_CPU_STEP */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
#ifndef __CPU_H__
|
||||
#define __CPU_H__
|
||||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
union reg
|
||||
{
|
||||
byte b[2][2];
|
||||
word w[2];
|
||||
un32 d; /* padding for alignment, carry */
|
||||
};
|
||||
|
||||
struct cpu
|
||||
{
|
||||
union reg pc, sp, bc, de, hl, af;
|
||||
int ime, ima;
|
||||
int speed;
|
||||
int halt;
|
||||
int div, tim;
|
||||
int lcdc;
|
||||
int snd;
|
||||
};
|
||||
|
||||
extern struct cpu cpu;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
const static byte cycles_table[256] =
|
||||
{
|
||||
1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1,
|
||||
1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
3, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
3, 3, 2, 2, 1, 3, 3, 3, 3, 2, 2, 2, 1, 1, 2, 1,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
|
||||
|
||||
5, 3, 4, 4, 6, 4, 2, 4, 5, 4, 4, 1, 6, 6, 2, 4,
|
||||
5, 3, 4, 0, 6, 4, 2, 4, 5, 4, 4, 0, 6, 0, 2, 4,
|
||||
3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4,
|
||||
3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4,
|
||||
};
|
||||
|
||||
const static byte cb_cycles_table[256] =
|
||||
{
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
|
||||
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
const static byte zflag_table[256] =
|
||||
{
|
||||
FZ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const static byte incflag_table[256] =
|
||||
{
|
||||
FZ|FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
FH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const static byte decflag_table[256] =
|
||||
{
|
||||
FZ|FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH,
|
||||
FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN, FN|FH
|
||||
};
|
||||
|
||||
const static byte swap_table[256] =
|
||||
{
|
||||
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
|
||||
0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
|
||||
0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
|
||||
0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
|
||||
0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
|
||||
0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
|
||||
0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
|
||||
0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
|
||||
0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
|
||||
0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
|
||||
0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
|
||||
0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
|
||||
0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
|
||||
0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
|
||||
0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
|
||||
0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF,
|
||||
};
|
||||
|
||||
const static byte daa_table[4096] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
|
||||
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
|
||||
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
|
||||
};
|
||||
|
||||
const static byte daa_carry_table[64] =
|
||||
{
|
||||
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
|
||||
00, 00, 00, 00, 00, 00, 00, 00, FC, FC, 00, 00, 00, 00, 00, 00,
|
||||
FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC,
|
||||
FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, 00, FC,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
|
||||
#ifndef __CPUREGS_H__
|
||||
|
||||
#define __CPUREGS_H__
|
||||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define LB(r) ((r).b[LO][LO])
|
||||
#define HB(r) ((r).b[LO][HI])
|
||||
#define W(r) ((r).w[LO])
|
||||
#define DW(r) ((r).d)
|
||||
|
||||
#define A HB(cpu.af)
|
||||
#define F LB(cpu.af)
|
||||
#define B HB(cpu.bc)
|
||||
#define C LB(cpu.bc)
|
||||
#define D HB(cpu.de)
|
||||
#define E LB(cpu.de)
|
||||
#define H HB(cpu.hl)
|
||||
#define L LB(cpu.hl)
|
||||
|
||||
#define AF W(cpu.af)
|
||||
#define BC W(cpu.bc)
|
||||
#define DE W(cpu.de)
|
||||
#define HL W(cpu.hl)
|
||||
|
||||
#define PC W(cpu.pc)
|
||||
#define SP W(cpu.sp)
|
||||
|
||||
#define xAF DW(cpu.af)
|
||||
#define xBC DW(cpu.bc)
|
||||
#define xDE DW(cpu.de)
|
||||
#define xHL DW(cpu.hl)
|
||||
|
||||
#define xPC DW(cpu.pc)
|
||||
#define xSP DW(cpu.sp)
|
||||
|
||||
#define IMA cpu.ima
|
||||
#define IME cpu.ime
|
||||
#define IF R_IF
|
||||
#define IE R_IE
|
||||
|
||||
#define FZ 0x80
|
||||
#define FN 0x40
|
||||
#define FH 0x20
|
||||
#define FC 0x10
|
||||
#define FL 0x0F /* low unused portion of flags */
|
||||
|
||||
|
||||
#endif /* __CPUREGS_H__ */
|
||||
|
||||
|
|
@ -0,0 +1,689 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "fastmem.h"
|
||||
#include "regs.h"
|
||||
#include "rc.h"
|
||||
|
||||
#include "cpuregs.h"
|
||||
|
||||
|
||||
static char *mnemonic_table[256] =
|
||||
{
|
||||
"NOP",
|
||||
"LD BC,%w",
|
||||
"LD (BC),A",
|
||||
"INC BC",
|
||||
"INC B",
|
||||
"DEC B",
|
||||
"LD B,%b",
|
||||
"RLCA",
|
||||
"LD (%w),SP",
|
||||
"ADD HL,BC",
|
||||
"LD A,(BC)",
|
||||
"DEC BC",
|
||||
"INC C",
|
||||
"DEC C",
|
||||
"LD C,%b",
|
||||
"RRCA",
|
||||
"STOP",
|
||||
"LD DE,%w",
|
||||
"LD (DE),A",
|
||||
"INC DE",
|
||||
"INC D",
|
||||
"DEC D",
|
||||
"LD D,%b",
|
||||
"RLA",
|
||||
"JR %o",
|
||||
"ADD HL,DE",
|
||||
"LD A,(DE)",
|
||||
"DEC DE",
|
||||
"INC E",
|
||||
"DEC E",
|
||||
"LD E,%b",
|
||||
"RRA",
|
||||
"JR NZ,%o",
|
||||
"LD HL,%w",
|
||||
"LD (HLI),A",
|
||||
"INC HL",
|
||||
"INC H",
|
||||
"DEC H",
|
||||
"LD H,%b",
|
||||
"DAA",
|
||||
"JR Z,%o",
|
||||
"ADD HL,HL",
|
||||
"LD A,(HLI)",
|
||||
"DEC HL",
|
||||
"INC L",
|
||||
"DEC L",
|
||||
"LD L,%b",
|
||||
"CPL",
|
||||
"JR NC,%o",
|
||||
"LD SP,%w",
|
||||
"LD (HLD),A",
|
||||
"INC SP",
|
||||
"INC (HL)",
|
||||
"DEC (HL)",
|
||||
"LD (HL),%b",
|
||||
"SCF",
|
||||
"JR C,%o",
|
||||
"ADD HL,SP",
|
||||
"LD A,(HLD)",
|
||||
"DEC SP",
|
||||
"INC A",
|
||||
"DEC A",
|
||||
"LD A,%b",
|
||||
"CCF",
|
||||
"LD B,B",
|
||||
"LD B,C",
|
||||
"LD B,D",
|
||||
"LD B,E",
|
||||
"LD B,H",
|
||||
"LD B,L",
|
||||
"LD B,(HL)",
|
||||
"LD B,A",
|
||||
"LD C,B",
|
||||
"LD C,C",
|
||||
"LD C,D",
|
||||
"LD C,E",
|
||||
"LD C,H",
|
||||
"LD C,L",
|
||||
"LD C,(HL)",
|
||||
"LD C,A",
|
||||
"LD D,B",
|
||||
"LD D,C",
|
||||
"LD D,D",
|
||||
"LD D,E",
|
||||
"LD D,H",
|
||||
"LD D,L",
|
||||
"LD D,(HL)",
|
||||
"LD D,A",
|
||||
"LD E,B",
|
||||
"LD E,C",
|
||||
"LD E,D",
|
||||
"LD E,E",
|
||||
"LD E,H",
|
||||
"LD E,L",
|
||||
"LD E,(HL)",
|
||||
"LD E,A",
|
||||
"LD H,B",
|
||||
"LD H,C",
|
||||
"LD H,D",
|
||||
"LD H,E",
|
||||
"LD H,H",
|
||||
"LD H,L",
|
||||
"LD H,(HL)",
|
||||
"LD H,A",
|
||||
"LD L,B",
|
||||
"LD L,C",
|
||||
"LD L,D",
|
||||
"LD L,E",
|
||||
"LD L,H",
|
||||
"LD L,L",
|
||||
"LD L,(HL)",
|
||||
"LD L,A",
|
||||
"LD (HL),B",
|
||||
"LD (HL),C",
|
||||
"LD (HL),D",
|
||||
"LD (HL),E",
|
||||
"LD (HL),H",
|
||||
"LD (HL),L",
|
||||
"HALT",
|
||||
"LD (HL),A",
|
||||
"LD A,B",
|
||||
"LD A,C",
|
||||
"LD A,D",
|
||||
"LD A,E",
|
||||
"LD A,H",
|
||||
"LD A,L",
|
||||
"LD A,(HL)",
|
||||
"LD A,A",
|
||||
"ADD A,B",
|
||||
"ADD A,C",
|
||||
"ADD A,D",
|
||||
"ADD A,E",
|
||||
"ADD A,H",
|
||||
"ADD A,L",
|
||||
"ADD A,(HL)",
|
||||
"ADD A,A",
|
||||
"ADC A,B",
|
||||
"ADC A,C",
|
||||
"ADC A,D",
|
||||
"ADC A,E",
|
||||
"ADC A,H",
|
||||
"ADC A,L",
|
||||
"ADC A,(HL)",
|
||||
"ADC A",
|
||||
"SUB B",
|
||||
"SUB C",
|
||||
"SUB D",
|
||||
"SUB E",
|
||||
"SUB H",
|
||||
"SUB L",
|
||||
"SUB (HL)",
|
||||
"SUB A",
|
||||
"SBC A,B",
|
||||
"SBC A,C",
|
||||
"SBC A,D",
|
||||
"SBC A,E",
|
||||
"SBC A,H",
|
||||
"SBC A,L",
|
||||
"SBC A,(HL)",
|
||||
"SBC A,A",
|
||||
"AND B",
|
||||
"AND C",
|
||||
"AND D",
|
||||
"AND E",
|
||||
"AND H",
|
||||
"AND L",
|
||||
"AND (HL)",
|
||||
"AND A",
|
||||
"XOR B",
|
||||
"XOR C",
|
||||
"XOR D",
|
||||
"XOR E",
|
||||
"XOR H",
|
||||
"XOR L",
|
||||
"XOR (HL)",
|
||||
"XOR A",
|
||||
"OR B",
|
||||
"OR C",
|
||||
"OR D",
|
||||
"OR E",
|
||||
"OR H",
|
||||
"OR L",
|
||||
"OR (HL)",
|
||||
"OR A",
|
||||
"CP B",
|
||||
"CP C",
|
||||
"CP D",
|
||||
"CP E",
|
||||
"CP H",
|
||||
"CP L",
|
||||
"CP (HL)",
|
||||
"CP A",
|
||||
"RET NZ",
|
||||
"POP BC",
|
||||
"JP NZ,%w",
|
||||
"JP %w",
|
||||
"CALL NZ,%w",
|
||||
"PUSH BC",
|
||||
"ADD A,%b",
|
||||
"RST 0h",
|
||||
"RET Z",
|
||||
"RET",
|
||||
"JP Z,%w",
|
||||
NULL,
|
||||
"CALL Z,%w",
|
||||
"CALL %w",
|
||||
"ADC A,%b",
|
||||
"RST 8h",
|
||||
"RET NC",
|
||||
"POP DE",
|
||||
"JP NC,%w",
|
||||
NULL,
|
||||
"CALL NC,%w",
|
||||
"PUSH DE",
|
||||
"SUB %b",
|
||||
"RST 10h",
|
||||
"RET C",
|
||||
"RETI",
|
||||
"JP C,%w",
|
||||
NULL,
|
||||
"CALL C,%w",
|
||||
NULL,
|
||||
"SBC A,%b",
|
||||
"RST 18h",
|
||||
"LD (FF00+%b),A",
|
||||
"POP HL",
|
||||
"LD (FF00+C),A",
|
||||
NULL,
|
||||
NULL,
|
||||
"PUSH HL",
|
||||
"AND %b",
|
||||
"RST 20h",
|
||||
"ADD SP,%o",
|
||||
"JP HL",
|
||||
"LD (%w),A",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"XOR %b",
|
||||
"RST 28h",
|
||||
"LD A,(FF00+%b)",
|
||||
"POP AF",
|
||||
"LD A,(FF00+C)",
|
||||
"DI",
|
||||
NULL,
|
||||
"PUSH AF",
|
||||
"OR %b",
|
||||
"RST 30h",
|
||||
"LD HL,SP%o",
|
||||
"LD SP,HL",
|
||||
"LD A,(%w)",
|
||||
"EI",
|
||||
NULL,
|
||||
NULL,
|
||||
"CP %b",
|
||||
"RST 38h"
|
||||
};
|
||||
|
||||
static char *cb_mnemonic_table[256] =
|
||||
{
|
||||
"RLC B",
|
||||
"RLC C",
|
||||
"RLC D",
|
||||
"RLC E",
|
||||
"RLC H",
|
||||
"RLC L",
|
||||
"RLC (HL)",
|
||||
"RLC A",
|
||||
"RRC B",
|
||||
"RRC C",
|
||||
"RRC D",
|
||||
"RRC E",
|
||||
"RRC H",
|
||||
"RRC L",
|
||||
"RRC (HL)",
|
||||
"RRC A",
|
||||
"RL B",
|
||||
"RL C",
|
||||
"RL D",
|
||||
"RL E",
|
||||
"RL H",
|
||||
"RL L",
|
||||
"RL (HL)",
|
||||
"RL A",
|
||||
"RR B",
|
||||
"RR C",
|
||||
"RR D",
|
||||
"RR E",
|
||||
"RR H",
|
||||
"RR L",
|
||||
"RR (HL)",
|
||||
"RR A",
|
||||
"SLA B",
|
||||
"SLA C",
|
||||
"SLA D",
|
||||
"SLA E",
|
||||
"SLA H",
|
||||
"SLA L",
|
||||
"SLA (HL)",
|
||||
"SLA A",
|
||||
"SRA B",
|
||||
"SRA C",
|
||||
"SRA D",
|
||||
"SRA E",
|
||||
"SRA H",
|
||||
"SRA L",
|
||||
"SRA (HL)",
|
||||
"SRA A",
|
||||
"SWAP B",
|
||||
"SWAP C",
|
||||
"SWAP D",
|
||||
"SWAP E",
|
||||
"SWAP H",
|
||||
"SWAP L",
|
||||
"SWAP (HL)",
|
||||
"SWAP A",
|
||||
"SRL B",
|
||||
"SRL C",
|
||||
"SRL D",
|
||||
"SRL E",
|
||||
"SRL H",
|
||||
"SRL L",
|
||||
"SRL (HL)",
|
||||
"SRL A",
|
||||
"BIT 0,B",
|
||||
"BIT 0,C",
|
||||
"BIT 0,D",
|
||||
"BIT 0,E",
|
||||
"BIT 0,H",
|
||||
"BIT 0,L",
|
||||
"BIT 0,(HL)",
|
||||
"BIT 0,A",
|
||||
"BIT 1,B",
|
||||
"BIT 1,C",
|
||||
"BIT 1,D",
|
||||
"BIT 1,E",
|
||||
"BIT 1,H",
|
||||
"BIT 1,L",
|
||||
"BIT 1,(HL)",
|
||||
"BIT 1,A",
|
||||
"BIT 2,B",
|
||||
"BIT 2,C",
|
||||
"BIT 2,D",
|
||||
"BIT 2,E",
|
||||
"BIT 2,H",
|
||||
"BIT 2,L",
|
||||
"BIT 2,(HL)",
|
||||
"BIT 2,A",
|
||||
"BIT 3,B",
|
||||
"BIT 3,C",
|
||||
"BIT 3,D",
|
||||
"BIT 3,E",
|
||||
"BIT 3,H",
|
||||
"BIT 3,L",
|
||||
"BIT 3,(HL)",
|
||||
"BIT 3,A",
|
||||
"BIT 4,B",
|
||||
"BIT 4,C",
|
||||
"BIT 4,D",
|
||||
"BIT 4,E",
|
||||
"BIT 4,H",
|
||||
"BIT 4,L",
|
||||
"BIT 4,(HL)",
|
||||
"BIT 4,A",
|
||||
"BIT 5,B",
|
||||
"BIT 5,C",
|
||||
"BIT 5,D",
|
||||
"BIT 5,E",
|
||||
"BIT 5,H",
|
||||
"BIT 5,L",
|
||||
"BIT 5,(HL)",
|
||||
"BIT 5,A",
|
||||
"BIT 6,B",
|
||||
"BIT 6,C",
|
||||
"BIT 6,D",
|
||||
"BIT 6,E",
|
||||
"BIT 6,H",
|
||||
"BIT 6,L",
|
||||
"BIT 6,(HL)",
|
||||
"BIT 6,A",
|
||||
"BIT 7,B",
|
||||
"BIT 7,C",
|
||||
"BIT 7,D",
|
||||
"BIT 7,E",
|
||||
"BIT 7,H",
|
||||
"BIT 7,L",
|
||||
"BIT 7,(HL)",
|
||||
"BIT 7,A",
|
||||
"RES 0,B",
|
||||
"RES 0,C",
|
||||
"RES 0,D",
|
||||
"RES 0,E",
|
||||
"RES 0,H",
|
||||
"RES 0,L",
|
||||
"RES 0,(HL)",
|
||||
"RES 0,A",
|
||||
"RES 1,B",
|
||||
"RES 1,C",
|
||||
"RES 1,D",
|
||||
"RES 1,E",
|
||||
"RES 1,H",
|
||||
"RES 1,L",
|
||||
"RES 1,(HL)",
|
||||
"RES 1,A",
|
||||
"RES 2,B",
|
||||
"RES 2,C",
|
||||
"RES 2,D",
|
||||
"RES 2,E",
|
||||
"RES 2,H",
|
||||
"RES 2,L",
|
||||
"RES 2,(HL)",
|
||||
"RES 2,A",
|
||||
"RES 3,B",
|
||||
"RES 3,C",
|
||||
"RES 3,D",
|
||||
"RES 3,E",
|
||||
"RES 3,H",
|
||||
"RES 3,L",
|
||||
"RES 3,(HL)",
|
||||
"RES 3,A",
|
||||
"RES 4,B",
|
||||
"RES 4,C",
|
||||
"RES 4,D",
|
||||
"RES 4,E",
|
||||
"RES 4,H",
|
||||
"RES 4,L",
|
||||
"RES 4,(HL)",
|
||||
"RES 4,A",
|
||||
"RES 5,B",
|
||||
"RES 5,C",
|
||||
"RES 5,D",
|
||||
"RES 5,E",
|
||||
"RES 5,H",
|
||||
"RES 5,L",
|
||||
"RES 5,(HL)",
|
||||
"RES 5,A",
|
||||
"RES 6,B",
|
||||
"RES 6,C",
|
||||
"RES 6,D",
|
||||
"RES 6,E",
|
||||
"RES 6,H",
|
||||
"RES 6,L",
|
||||
"RES 6,(HL)",
|
||||
"RES 6,A",
|
||||
"RES 7,B",
|
||||
"RES 7,C",
|
||||
"RES 7,D",
|
||||
"RES 7,E",
|
||||
"RES 7,H",
|
||||
"RES 7,L",
|
||||
"RES 7,(HL)",
|
||||
"RES 7,A",
|
||||
"SET 0,B",
|
||||
"SET 0,C",
|
||||
"SET 0,D",
|
||||
"SET 0,E",
|
||||
"SET 0,H",
|
||||
"SET 0,L",
|
||||
"SET 0,(HL)",
|
||||
"SET 0,A",
|
||||
"SET 1,B",
|
||||
"SET 1,C",
|
||||
"SET 1,D",
|
||||
"SET 1,E",
|
||||
"SET 1,H",
|
||||
"SET 1,L",
|
||||
"SET 1,(HL)",
|
||||
"SET 1,A",
|
||||
"SET 2,B",
|
||||
"SET 2,C",
|
||||
"SET 2,D",
|
||||
"SET 2,E",
|
||||
"SET 2,H",
|
||||
"SET 2,L",
|
||||
"SET 2,(HL)",
|
||||
"SET 2,A",
|
||||
"SET 3,B",
|
||||
"SET 3,C",
|
||||
"SET 3,D",
|
||||
"SET 3,E",
|
||||
"SET 3,H",
|
||||
"SET 3,L",
|
||||
"SET 3,(HL)",
|
||||
"SET 3,A",
|
||||
"SET 4,B",
|
||||
"SET 4,C",
|
||||
"SET 4,D",
|
||||
"SET 4,E",
|
||||
"SET 4,H",
|
||||
"SET 4,L",
|
||||
"SET 4,(HL)",
|
||||
"SET 4,A",
|
||||
"SET 5,B",
|
||||
"SET 5,C",
|
||||
"SET 5,D",
|
||||
"SET 5,E",
|
||||
"SET 5,H",
|
||||
"SET 5,L",
|
||||
"SET 5,(HL)",
|
||||
"SET 5,A",
|
||||
"SET 6,B",
|
||||
"SET 6,C",
|
||||
"SET 6,D",
|
||||
"SET 6,E",
|
||||
"SET 6,H",
|
||||
"SET 6,L",
|
||||
"SET 6,(HL)",
|
||||
"SET 6,A",
|
||||
"SET 7,B",
|
||||
"SET 7,C",
|
||||
"SET 7,D",
|
||||
"SET 7,E",
|
||||
"SET 7,H",
|
||||
"SET 7,L",
|
||||
"SET 7,(HL)",
|
||||
"SET 7,A"
|
||||
};
|
||||
|
||||
static byte operand_count[256] =
|
||||
{
|
||||
1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
|
||||
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
|
||||
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1,
|
||||
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 1, 2, 1,
|
||||
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
|
||||
2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1
|
||||
};
|
||||
|
||||
|
||||
/* replace with a real interactive debugger eventually... */
|
||||
|
||||
int debug_trace = 0;
|
||||
|
||||
rcvar_t debug_exports[] =
|
||||
{
|
||||
RCV_BOOL("trace", &debug_trace),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
void debug_disassemble(addr a, int c)
|
||||
{
|
||||
static int i, j, k;
|
||||
static byte code;
|
||||
static byte ops[3];
|
||||
static int opaddr;
|
||||
static char mnemonic[256];
|
||||
static char *pattern;
|
||||
|
||||
if (!debug_trace) return;
|
||||
while (c > 0)
|
||||
{
|
||||
k = 0;
|
||||
opaddr = a;
|
||||
code = ops[k++] = readb(a); a++;
|
||||
if (code != 0xCB)
|
||||
{
|
||||
pattern = mnemonic_table[code];
|
||||
if (!pattern)
|
||||
pattern = "***INVALID***";
|
||||
}
|
||||
else
|
||||
{
|
||||
code = ops[k++] = readb(a); a++;
|
||||
pattern = cb_mnemonic_table[code];
|
||||
}
|
||||
i = j = 0;
|
||||
while (pattern[i])
|
||||
{
|
||||
if (pattern[i] == '%')
|
||||
{
|
||||
switch (pattern[++i])
|
||||
{
|
||||
case 'B':
|
||||
case 'b':
|
||||
ops[k] = readb(a); a++;
|
||||
j += sprintf(mnemonic + j,
|
||||
"%02Xh", ops[k++]);
|
||||
break;
|
||||
case 'W':
|
||||
case 'w':
|
||||
ops[k] = readb(a); a++;
|
||||
ops[k+1] = readb(a); a++;
|
||||
j += sprintf(mnemonic + j, "%04Xh",
|
||||
((ops[k+1] << 8) | ops[k]));
|
||||
k += 2;
|
||||
break;
|
||||
case 'O':
|
||||
case 'o':
|
||||
ops[k] = readb(a); a++;
|
||||
j += sprintf(mnemonic + j, "%+d",
|
||||
(n8)(ops[k++]));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mnemonic[j++] = pattern[i++];
|
||||
}
|
||||
}
|
||||
mnemonic[j] = 0;
|
||||
printf("%04X ", opaddr);
|
||||
switch (operand_count[ops[0]]) {
|
||||
case 1:
|
||||
printf("%02X ", ops[0]);
|
||||
break;
|
||||
case 2:
|
||||
printf("%02X %02X ", ops[0], ops[1]);
|
||||
break;
|
||||
case 3:
|
||||
printf("%02X %02X %02X ", ops[0], ops[1], ops[2]);
|
||||
break;
|
||||
}
|
||||
printf("%-16.16s", mnemonic);
|
||||
printf(
|
||||
" SP=%04X.%04X BC=%04X.%02X.%02X DE=%04X.%02X "
|
||||
"HL=%04X.%02X A=%02X F=%02X %c%c%c%c%c",
|
||||
SP, readw(SP),
|
||||
BC, readb(BC), readb(0xFF00 | C),
|
||||
DE, readb(DE),
|
||||
HL, readb(HL), A,
|
||||
F, (IME ? 'I' : '-'),
|
||||
((F & 0x80) ? 'Z' : '-'),
|
||||
((F & 0x40) ? 'N' : '-'),
|
||||
((F & 0x20) ? 'H' : '-'),
|
||||
((F & 0x10) ? 'C' : '-')
|
||||
);
|
||||
printf(
|
||||
" IE=%02X IF=%02X LCDC=%02X STAT=%02X LY=%02X LYC=%02X",
|
||||
R_IE, R_IF, R_LCDC, R_STAT, R_LY, R_LYC
|
||||
);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
|
||||
#ifndef __DEFS_H__
|
||||
#define __DEFS_H__
|
||||
|
||||
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define LO 0
|
||||
#define HI 1
|
||||
#else
|
||||
#define LO 1
|
||||
#define HI 0
|
||||
#endif
|
||||
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef unsigned char un8;
|
||||
typedef unsigned short un16;
|
||||
typedef unsigned int un32;
|
||||
|
||||
typedef signed char n8;
|
||||
typedef signed short n16;
|
||||
typedef signed int n32;
|
||||
|
||||
typedef un16 word;
|
||||
typedef word addr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,322 @@
|
|||
|
||||
GNUBOY CHANGES FILE -- detailed list of all changes made
|
||||
|
||||
Each release is labelled with the date it appeared; unreleased
|
||||
versions are listed without a date stamp for purely historical
|
||||
reasons. When checking what's changed since the last release, be
|
||||
sure to look over intermediate unreleased versions as well.
|
||||
|
||||
For an easy-to-read user-oriented list of major changes in each
|
||||
release, please refer to the file WHATSNEW.
|
||||
|
||||
|
||||
1.0.3
|
||||
fixed a typo in the SDL keymap file that kept . from working
|
||||
added support for binding keys to the ' key
|
||||
fixed bug related in nix.c's sys_checkdir that made it always demand writable
|
||||
fixed loader.c since it depended on this bug
|
||||
removed the literal newlines inside the copyright string in main.c
|
||||
removed some parentheses in save.c's macros
|
||||
(these were perfectly valid but caused problems with a broken compiler, lcc)
|
||||
added return-type prototypes for strdup since it's not always in string.h
|
||||
(many of the above were old bugfixes sent in by Damian M Gryski)
|
||||
added slow, primitive support for gzipped rom files
|
||||
(thanks to David Madore for the portable inflate code taken from his quine)
|
||||
various minor source cleanups
|
||||
more preliminary work on the fast register/himem io routines (not used yet)
|
||||
fixed HuC3 emulation, according to TGB's sources
|
||||
added hacks to work around HuC3's IR port not being implemented
|
||||
(Robopon Sun and Star now seem to run fine)
|
||||
fixed a few sound inconsistencies after loading a savestate
|
||||
various fixes to keybinding system and X11 keymap
|
||||
integrated Jonathan Gevaryahu's color filter
|
||||
added "gbamode" rcvar to unlock gba-only features in some cgb games
|
||||
(this has NOTHING to do with gba emulation!)
|
||||
fixed DMG sprite sorting code! it's now enabled by default
|
||||
reverted mistaken CGB wave pattern "fix" in 1.0.2
|
||||
don't always reset sound positions on sound init (is this correct?)
|
||||
|
||||
1.0.2 (2001-09-18)
|
||||
fixed bugs in rc_setvar calls in sys_initpath
|
||||
fixed multiple definition of cpu struct in cpu.h
|
||||
corrected behavior of ch1 sweep function when freq is written during sweep
|
||||
emulated wave pattern corruption to fool "emulator-detectors"
|
||||
updated savestate code to handle these changes, incremented minor version
|
||||
(this should not affect compatibility with old savestates)
|
||||
fixed major bugs in sound channel 4
|
||||
perfected channel 4 output sequence to sound like a real Gameboy
|
||||
(much thanks goes out to Lord Nightmare for all his hard work on this!)
|
||||
default channel 3 square wave is no longer 4 octaves too high
|
||||
make DI cancel pending HALT...is this correct? (fixes Konami Collection #1)
|
||||
fixed reversed stereo channels
|
||||
tweaked frequency cutoff points that prevent aliasing
|
||||
corrected default wave pattern (noise) when running in dmg mode
|
||||
fixed sound reset bug that messed up pitch after pausing in Bubble Ghost
|
||||
added new sample palettes
|
||||
fixed major interrupt/HALT bug that kept Amazing Penguin from running
|
||||
fixed sound channel 3 length regiser (info in gbspec.txt is bogus)
|
||||
tweaked volume of channel 4
|
||||
removed FFL3 tile glitch from the known bugs in the README
|
||||
(it was caused by a bad dump and/or hacked rom, not a bug in gnuboy)
|
||||
added emulation of DMG STAT register write bug (causes interrupt)
|
||||
(this fixes Legend of Zerd and perhaps one or two other games)
|
||||
|
||||
1.0.1 (2001-07-09)
|
||||
fixed problem in "make install" if dest dir doesn't exist
|
||||
cleaned up some compiler warnings
|
||||
fixed a problem with --bindir= not working in the autoconf process
|
||||
renamed several things from mingw32 to just plain windows
|
||||
fixed lots of keys that were still missing on the SDL port
|
||||
|
||||
1.0.0 (2001-06-29)
|
||||
renamed Makefile.mingw32 to Makefile.win to be 8.3 filename friendly
|
||||
finally fixed up configure to work around broken gcc 2.96 on Redhat 7, et al
|
||||
added lots of new documentation
|
||||
added autoconf option to disable cpu-specific code generation
|
||||
minor improvements to matroxfb hardware scaling code
|
||||
cleaned up some old deprecated variables
|
||||
|
||||
0.9.15
|
||||
various preparations for 1.0 release
|
||||
cleaned up nix.c to remove old code and prevent errors on some systems
|
||||
fixed Makefile.nix to be usable but minimal
|
||||
|
||||
0.9.14
|
||||
changed default dmg palette to be less yellow
|
||||
changed default keybindings not to use modifier keys
|
||||
moved vid_begin to after doevents in emu.c
|
||||
(this should fix alt+enter fullscreen toggle not working on windows)
|
||||
changed --help, etc to use stdout rather than stderr
|
||||
auto-loading config files on a per-rom basis
|
||||
|
||||
0.9.13 (2001-04-09)
|
||||
added matroxfb YUV scaling support
|
||||
moved lcd_refreshline from the 3->0 stat change to the 2->3 one
|
||||
(this fixes a slight visual glitch in Alleyway)
|
||||
experimental: no LYC=LY interrupt during VBLANK...?
|
||||
fixed emulation bug (RL/RR) in asm cpu core that broke Montezuma's Return
|
||||
fixed some minor bugs in the matrox scaler register settings
|
||||
fixed SWAP (HL) instruction in the asm core (fixes Pokemon Yellow)
|
||||
added more assembly language scalers for performance
|
||||
|
||||
0.9.12 (2001-04-02)
|
||||
started adding HuC3 MBC support
|
||||
removed some code that was accidentally left in that broke dos/win builds
|
||||
fixed a bug in SDL joystick support -- thanks Ralf Hoffmann
|
||||
unused bits in VBK register should be 1, not 0 -- this broke Binary Chaos
|
||||
fixed bug that kept dmg palette from restoring properly after loading savestate
|
||||
integrated hardware YUV scaling w/SDL thanks to Magnus Damm
|
||||
SDL code now turns off fb.enabled when window is iconified
|
||||
HDMA timing correction back in 0.9.6 broke Wacky Races; it's disabled for now
|
||||
|
||||
0.9.11 (2001-04-01)
|
||||
fixed bug that kept video mode setting from working with svgalib
|
||||
implemented program counter skip after STOP instruction (konami collections)
|
||||
fixed SDL hardware surface support -- thanks Dave Kiddell
|
||||
also fixed another bug in gnuboy graphics code related to that problem
|
||||
removed sdl_hwsurface rcvar (no longer needed)
|
||||
changed SDL code to use SDL_Flip rather than SDL_UpdateRect - much faster
|
||||
most ports now can auto-choose screen size for given scale if no vmode is given
|
||||
optional shm sync skipping for x11 -- boost performance but looses frames
|
||||
lots of new scaling stuff
|
||||
allow HDMA while LCDC is off -- fixes Worms Armageddon
|
||||
correct initial values for HDMA regs -- fixes first hang in Turok 3
|
||||
major timer fixes!! fixes second hang in Turok 3
|
||||
|
||||
0.9.10 (2001-03-26)
|
||||
hopefully fixed issue with X header locations affecting some users
|
||||
rewrote refresh_* functions to be faster and more flexible
|
||||
added scale-by-two versions of the above, including super-fast asm versions
|
||||
implemented primitive but fully functional scale-by-two mode
|
||||
added vmode rcvar to set the video mode
|
||||
disabled dmg sprite sorting by default because it doesn't seem to work right
|
||||
removed deprecated rcvars from various display modules
|
||||
heavily updated README
|
||||
changed VBLANK timings slightly - seems to fix Daedalian Opus
|
||||
enlarged OSS dma output buffer slightly; this may reduce occurance of underruns
|
||||
cleaned up all warnings
|
||||
fixed bug that prevented reading from OAM
|
||||
fixed all compiler warnings except implicit functions
|
||||
found and fixed a few minor bugs in the process
|
||||
added spacebar to SDL keymap
|
||||
up to 16 joystick buttons are now supported w/linux and SDL
|
||||
added sdl_hwsurface rcvar to turn hardware surface back on
|
||||
added static palette mode
|
||||
quick and dirty hack to make super rc pro-am work
|
||||
fixed bug that made OAM unreadable
|
||||
|
||||
0.9.9 (2001-03-23)
|
||||
removed some unused code from mingw32.c, fixed some bugs there too
|
||||
fixed a bad sound bug in sdl.c
|
||||
eliminated sound pops at startup with SDL
|
||||
eliminaed compiletime error about SDL_DISABLE on SDL ver < 1.1.8
|
||||
integrated new fully-thinlib-based DOS code from Matthew Conte
|
||||
added surface locking to SDL code; maybe this will fix windows+fullscreen?
|
||||
fixed serious bug in savestate loading (call mem_updatemap on load)
|
||||
new asm -- significant speed boosts for color games on older machines
|
||||
removed SDL_HWSURFACE from SDL code - this should fix fullscreen on windows
|
||||
disabled surface locking calls for now
|
||||
properly initialize default path on DOS
|
||||
added SDL_ANYFORMAT to SDL flags so we can natively support all color depths
|
||||
|
||||
0.9.8 (2001-03-07)
|
||||
enabled support for dmg sprite sorting; not sure it works yet
|
||||
added "sprsort" rcvar to toggle this since it's usually not needed
|
||||
fixed a potential crash that could happen if sound init failed on dos
|
||||
added native SDL sound support
|
||||
fixed lots of bugs in the SDL port
|
||||
removed stupid sys_realtime() function in favor of the simple ANSI C time()
|
||||
roms can now be loaded from stdin by specifying - as the rom name
|
||||
removed lots of useless bloat from system interface modules
|
||||
take advantage of ANSI atexit() to simplify termination logic
|
||||
hide mouse cursor with SDL
|
||||
SDL fullscreen mode
|
||||
optional alt+enter fullscreen toggle for SDL
|
||||
SDL rcvars sdl_fullscreen and sdl_altenter to control these features
|
||||
changed bswapl to bswap in asm to make it work on mingw32
|
||||
added ram size code 05 for 4 banks, this seems to make Pokemon Crystal work
|
||||
backed out hack for Altered Space and W&W because it broke other games
|
||||
new code to make them work, hopefully this time it's right
|
||||
now we give an error on unknown rom/ram size to prevent crashing
|
||||
integrated Windows port by mewse
|
||||
|
||||
0.9.7 (2001-02-27)
|
||||
added support for mono sound
|
||||
initial work on implementing sound blaster output on dos
|
||||
fixed envelope bug that made notes trail off (or amplify) too fast
|
||||
integrated dos sound support contributed by Matthew Conte using his thinlib
|
||||
added Matthew Conte to CREDITS
|
||||
tried to fix strange occasional keyboard misbehavior on dos
|
||||
build stripped binaries by default if debugging and profiling are off
|
||||
|
||||
0.9.6
|
||||
updated the INSTALL file
|
||||
fixed something stupid that broke building SDL joystick support on non-Linux
|
||||
added Mattias Wadman to the CREDITS
|
||||
fixed VBLANK timing slightly; now altered space and wizards & warriors work
|
||||
reverted change; it breaks other games
|
||||
new trick that might fix things...
|
||||
fixed bug in command line parsing that kept --savename=- from working
|
||||
fixed warning in oss.c
|
||||
fixed an old bug in HDMA/HBLANK that only recently became apparent
|
||||
vesa support on dos is now working!
|
||||
|
||||
0.9.5 (2001-02-22)
|
||||
added Ralf to the CREDITS, apologies for the prior omission
|
||||
show name from rom header in window title on X11 and SDL
|
||||
fixed bug that made highcolor screen flicker
|
||||
(this used to glitch sfalpha, but for some reason its ok now)
|
||||
updated README
|
||||
fixed cap on sound 3 frequency to eliminate bogus beeps
|
||||
began work on optimizing memory io in the C code
|
||||
updated HACKING slightly
|
||||
got new fast memory io functions integrated!
|
||||
moved all of high memory (registers, wave pattern, stack) to one array
|
||||
(eventually this will make memory io faster)
|
||||
changed savestate format, but old saves should still load fine
|
||||
(hopefully new format makes more sense)
|
||||
began implementing fast access to high memory
|
||||
discovered that low bits of the flags register don't exist
|
||||
optimized instruction emulation accordingly
|
||||
a few optimizations to the outer asm cpu loop
|
||||
fixed off-by-one error in C graphics code that made far right column blank
|
||||
added slow, experimental 24bpp (packed, unaligned) video support
|
||||
improved the configure script, now --without-* works
|
||||
use sdl-config instead of explicit -lpthread to support more systems
|
||||
removed stupid section directives from the asm
|
||||
got the asm cores working on dos!
|
||||
oss sound support *might* work on freebsd and openbsd now
|
||||
SDL joystick code has been integrated, but I haven't tested it
|
||||
fixed bug in new savestate code
|
||||
added David Lau to the CREDITS (SDL joystick support)
|
||||
GNU make should no longer be required to compile
|
||||
|
||||
0.9.4 (2001-02-18)
|
||||
various changes to lots of the system interface organization
|
||||
separation of linux fb and keyboard handling code into two modules
|
||||
integrated linux joystick support contributed by Ralf Hoffmann
|
||||
dummy joystick code for systems without real support yet
|
||||
fixed HDMA; now DKC runs perfectly
|
||||
|
||||
0.9.3
|
||||
explicit link of SDL target with -lpthread, tell me if this causes problems
|
||||
better cpu detection in configure script
|
||||
more big fixes in sweep, and now it's actually tested, so it SHOULD work (!)
|
||||
implemented default wave ram pattern
|
||||
added linux fbcon display support - very functional
|
||||
fix to allow new custom palette to take effect after loading dmg savestates
|
||||
|
||||
0.9.2 (2001-02-12)
|
||||
mbc3 rtc support, including save and resync across sessions
|
||||
updated README
|
||||
implemented sound channel 4
|
||||
fixed yet another bug in sweep (!!)
|
||||
fixed nasty aliasing when sound frequency was higher than sample rate permits
|
||||
finally, all sound registers can be adjusted while sound is being produced
|
||||
made it so the proper shutdown functions actually get called on exit
|
||||
added SDL port by Damian M Gryski, should be auto-detected by configure
|
||||
added Damian to the CREDITS file
|
||||
cleaned up sound code to minimize the amount of state data kept
|
||||
added sound and rtc status to savestates; this won't break old saves
|
||||
changed lots of lookup tables to const
|
||||
|
||||
0.9.1 (2001-02-11)
|
||||
fixed yet another critical bug in sweep
|
||||
fixed STAT interrupt bug
|
||||
added support for changing more sound params while sound is active
|
||||
fixed yet another major bug in envelope for channel 2
|
||||
fixed bug in HDMA, but DKC still fails
|
||||
updated README, HACKING
|
||||
made samplerate and sound (on/off) configurable rcvars
|
||||
changed command line parsing to make setting bools more intuitive
|
||||
added --showvars to list all available rcvars
|
||||
|
||||
0.9.0
|
||||
fixed bugs in sweep and envelope functions
|
||||
added sound channel 3
|
||||
|
||||
0.8.5
|
||||
various minor optimizations in the C code
|
||||
same in the i386 asm cpu core
|
||||
initial work on sound framework
|
||||
oss sound output for use on *nix
|
||||
dummy sound output for use on systems without sound
|
||||
sound channels 1 and 2
|
||||
|
||||
0.8.4 (2001-02-06)
|
||||
updated README to cover new features
|
||||
fixed off-by-one-line visual error introduced in 0.8.2
|
||||
gbspec.txt is wrong, ram size code 0 != no ram, big suprise... (!)
|
||||
workaround for undocumented 512 byte ram size, won't necessarily work
|
||||
changes in saved state format
|
||||
slight improvements to asm cpu core
|
||||
cleaned up HDMA code
|
||||
removed outdated comments
|
||||
more changes to lcdc/cpu timing interaction, fixing harmless bugs
|
||||
this may slightly impact performance, i'll compensate later
|
||||
hopefully fixed bug in svgalib interface that corrupted console on exit
|
||||
updated HACKING to reflect new code, detail more internals
|
||||
workaround for a bug that would never happen but could lock the emulator
|
||||
fixed another visual glitch introduced in 0.8.2
|
||||
optimized i386 cpu.s to keep PC in a register at all times
|
||||
|
||||
0.8.3
|
||||
changed install dir from $prefix/games to $prefix/bin
|
||||
fixed major bug in ramsize lookup table (!)
|
||||
updated HACKING to note that it's outdated
|
||||
implemented saved states!
|
||||
|
||||
0.8.2 (2001-02-03)
|
||||
rewrote lcdc state behavior completely, fixed lots of compat issues
|
||||
implemented serial io failure for roms that need it, fixed more compat
|
||||
now, mk1, sml2, and alleyway are all fixed!
|
||||
additions to input.h and keytable.c to allow future joystick support
|
||||
|
||||
0.8.1
|
||||
fixed stupid timer interrupt bug in asm cpu core
|
||||
renamed screen to fb so as not to conflict with allegro symbol names
|
||||
|
||||
0.8.0 (2001-02-01)
|
||||
initial release
|
||||
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
|
||||
GUIDE TO CONFIGURING GNUBOY
|
||||
|
||||
|
||||
[ P A R T I ]
|
||||
OVERVIEW
|
||||
|
||||
There are two major ways of configuring the way gnuboy behaves at
|
||||
runtime: setting the values of variables, and binding commands to keys
|
||||
and joystick buttons. Each can be done either on the command line, or
|
||||
from a config (rc) file.
|
||||
|
||||
If you don't want to read all this detailed info, look at the sample
|
||||
rc files provided, then browse back through this file to clarify
|
||||
anything that seems confusing. You might also skip down to Part II if
|
||||
you're already familiar with the syntax of gnuboy rc files and such;
|
||||
the second part explains the configurable variables which you can play
|
||||
with.
|
||||
|
||||
|
||||
WHAT HAPPENS AT STARTUP
|
||||
|
||||
When gnuboy is started, it first processes gnuboy.rc, the primary
|
||||
configuration file. On *nix systems, gnuboy will initially look for
|
||||
its rc files in ~/.gnuboy, or if that fails, the present working
|
||||
directory. On DOS and Windows, the current directory will be searched
|
||||
first, followed by the directory containing the gnuboy executable.
|
||||
|
||||
After finishing with gnuboy.rc, gnuboy next looks for an rc file with
|
||||
the same base name as the rom to be loaded. For example, if the name
|
||||
of the rom is mygame.gb, gnuboy will process mygame.rc, if it exists.
|
||||
This allows you to configure different preferences on a per-rom
|
||||
basis. The locations searched for the rom-specific rc file are the
|
||||
same as those searched for gnuboy.rc, unless gnuboy.rc has changed the
|
||||
search path (see below for more info).
|
||||
|
||||
Finally, options on the command line are processed. The command line
|
||||
will override any settings in the auto-loaded rc files. This is a good
|
||||
place for options that you just want to use occasionally, but not on a
|
||||
regular basis.
|
||||
|
||||
After all of the above is finished, gnuboy loads the rom and starts
|
||||
emulation.
|
||||
|
||||
|
||||
RC FILES
|
||||
|
||||
The rc files gnuboy uses are plain text files, with one command on
|
||||
each line. Lines that start with # are treated as comments, that is to
|
||||
say they are ignored, and blank lines are ignored as well.
|
||||
|
||||
There are three major types of commands.
|
||||
|
||||
|
||||
RC FILES -- SETTING VARIABLES
|
||||
|
||||
First of all, there is the "set" command, which is used for setting
|
||||
the values of variables. For example,
|
||||
|
||||
set scale 2
|
||||
|
||||
will set the screen scaling factor to 2. If you need to include a
|
||||
space in the value of a variable, you can do something like this:
|
||||
|
||||
set savename "I like spaces in my filenames"
|
||||
|
||||
and then your save files will be named something like:
|
||||
|
||||
I like spaces in my filenames.sav
|
||||
I like spaces in my filenames.000
|
||||
I like spaces in my filenames.001
|
||||
I like spaces in my filenames.002
|
||||
etc.
|
||||
|
||||
Finally, some variables allow multiple numbers to be given. For
|
||||
example, to set the video mode to 640x480, 16bpp, you might do
|
||||
something like this:
|
||||
|
||||
set vmode 640 480 16
|
||||
|
||||
Observe that each number is separate, and there are no quotation marks
|
||||
used.
|
||||
|
||||
|
||||
RC FILES -- KEYBINDINGS
|
||||
|
||||
Next, we have commands that deal with key and joystick bindings. These
|
||||
are fairly simple.
|
||||
|
||||
The "unbindall" command removes all existing keybindings -- be
|
||||
careful! -- and its main use is for people who want to redefine their
|
||||
keyboard controls entirely and throw away the defaults. Be warned that
|
||||
if you unbind the quit key and don't bind a new key for quitting, you
|
||||
may be unable to exit gnuboy cleanly!
|
||||
|
||||
The "unbind" command is similar, but it only unbinds one key at a
|
||||
time. For example, to unbind the "space" key, use this command:
|
||||
|
||||
unbind space
|
||||
|
||||
See below for a list of key names to use with unbind.
|
||||
|
||||
Now we get to the main useful keybinding command: "bind". For example,
|
||||
if you want the "tab" key to perform the Gameboy "select" button
|
||||
function, use the following bind command:
|
||||
|
||||
bind tab +select
|
||||
|
||||
The significance of the + sign will be explained below. As with the
|
||||
"set" command, quotation marks can be used with bind if the command
|
||||
needs to contain spaces.
|
||||
|
||||
|
||||
KEY NAMES FOR BINDINGS
|
||||
|
||||
When using the bind and unbind commands, you need to tell gnuboy which
|
||||
key you wish to affect. Most of the keys that correspond to a
|
||||
character you can type can just be referenced by that character. For
|
||||
example, the alphabetical keys are bound by the lowercase letter they
|
||||
represent, and the numeral keys (on the main keyboard, not the numeric
|
||||
keypad) can be bound by their numeral. Other keys require a name. Some
|
||||
are really obvious:
|
||||
|
||||
shift, ctrl, alt, up, down, right, left
|
||||
enter, tab, space, home, end, esc, pause
|
||||
f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12
|
||||
|
||||
Others are a bit less obvious but still should make sense. Some of
|
||||
these can also be referenced by other names; read the source file
|
||||
keytable.c for a full list:
|
||||
|
||||
bs Backspace
|
||||
ins Insert
|
||||
del Delete
|
||||
prior Page Up
|
||||
next Page Down
|
||||
caps Caps Lock
|
||||
numlock Num Lock
|
||||
scroll Scroll Lock
|
||||
minus - or _
|
||||
equals = or +
|
||||
tilde ` or ~
|
||||
slash / or ?
|
||||
bslash \ or |
|
||||
semi ; or :
|
||||
quote ' or "
|
||||
|
||||
The numeric keypad is referenced as follows
|
||||
|
||||
num0-num9 Numeral keys 0-9 (on keypad)
|
||||
numplus Numeric keypad +
|
||||
numminus Numeric keypad -
|
||||
nummul Numeric keypad *
|
||||
numdiv Numeric keypad /
|
||||
numdot Numeric keypad .
|
||||
numenter Numeric keypad Enter key
|
||||
|
||||
Joystick buttons and directions also have names for binding, and they
|
||||
are bound just like ordinary keys. Their names are as follows:
|
||||
|
||||
joyup Joystick up
|
||||
joydown Joystick down
|
||||
joyleft Joystick left
|
||||
joyright Joystick right
|
||||
joy0-joy15 Joystick buttons
|
||||
|
||||
The way joystick buttons are numbered varies from one joystick to
|
||||
another. Experiment to find the names that are right for the buttons
|
||||
you want to use.
|
||||
|
||||
|
||||
RC FILES -- THE SOURCE COMMAND
|
||||
|
||||
The "source" command simply causes gnuboy to process another rc file
|
||||
before resuming processing of the current one. It is useful for
|
||||
splitting up your config into multiple parts, perhaps one file
|
||||
auto-generated by a front-end and another hand-customized. Use of this
|
||||
command is very simple:
|
||||
|
||||
source myfile.rc
|
||||
|
||||
will perform all the commands in myfile.rc. Note that the source
|
||||
command also provides a method for binding multiple commands to a
|
||||
single key. For example, simply
|
||||
|
||||
bind f1 "source f1stuff.rc"
|
||||
|
||||
and then f1stuff.rc will be run whenever you press F1.
|
||||
|
||||
|
||||
RC FILES -- ACTION COMMANDS
|
||||
|
||||
Finally, we have rc commands that perform actions. These commands are
|
||||
probably only useful when bound to a key, and might cause unexpected
|
||||
behavior or even crashes if used by themselves in an rc file loaded at
|
||||
startup.
|
||||
|
||||
First of all, the "quit" command should be obvious. It simply exits
|
||||
the emulator. If the rom that's loaded uses battery backed save ram or
|
||||
realtime clock, these files will automatically be saved at exit.
|
||||
|
||||
The "reset" command should also be fairly obvious. It acts as a reset
|
||||
button, restarting execution of the loaded rom at the beginning, as if
|
||||
you turned the Gameboy power off and back on.
|
||||
|
||||
Slightly more interesting are the "savestate" and "loadstate"
|
||||
commands. These are used for saving and resuming "saved state" files,
|
||||
which allow you to save the exact status of the emulation environment
|
||||
and restore it later, effectively letting you "save game" at any point
|
||||
in any game. If a number is specified after either of those commands,
|
||||
the indicated save slot number is used. Otherwise, the slot set in the
|
||||
"saveslot" variable will be used. See the information on variables
|
||||
below for more info.
|
||||
|
||||
Most importantly, we have the action commands that control the
|
||||
emulated Gameboy input pad. They are described below:
|
||||
|
||||
|
||||
COMMANDS THAT BEGIN WITH A PLUS SIGN
|
||||
|
||||
Normally, gnuboy only performs the command bound to a key when the key
|
||||
is pressed; nothing happens when it is released. But for some things,
|
||||
particularly the Gameboy pad buttons, it's important for something to
|
||||
happen when the bound key is released. This is the purpose of commands
|
||||
that begin with a + sign. When a key is released, gnuboy checks to see
|
||||
if the bound command begins with +, and if so, it changes the + to -
|
||||
and performs the resulting command. This causes the Gameboy pad
|
||||
buttons to go back to their normal state when the keys bound to them
|
||||
are released.
|
||||
|
||||
The Gameboy pad commands, which should be self-explanatory, are as
|
||||
follows:
|
||||
|
||||
+a, +b, +start, +select, +up, +down, +left, +right
|
||||
|
||||
If you're at all familiar with Quake's config system, this should all
|
||||
be clear.
|
||||
|
||||
|
||||
THE GNUBOY COMMAND LINE
|
||||
|
||||
Additional rc files to process, variable settings, and keybindings can
|
||||
be specified on the command line when gnuboy is run.
|
||||
|
||||
Processing an extra config file is simple:
|
||||
|
||||
gnuboy --source myfile.rc game.gb
|
||||
|
||||
Specifying an extra rc file on the command line like this is
|
||||
especially useful for frontends, which may want to put all the options
|
||||
they set in one rc file so they don't have to pass a super-long
|
||||
command line to gnuboy.
|
||||
|
||||
Binding keys is also pretty simple. Just use something like:
|
||||
|
||||
gnuboy --bind tab +select game.gb
|
||||
|
||||
Setting variables is where things get a bit more complicated. For
|
||||
on/off (boolean) settings, you can just do something like
|
||||
|
||||
gnuboy --no-sound game.gb
|
||||
|
||||
to turn a variable (sound) off, i.e. set it to 0. Likewise, boolean
|
||||
variables can be turned on via something like
|
||||
|
||||
gnuboy --rgb332 game.gb
|
||||
|
||||
which turns the "rgb332" variable on (see below for information on
|
||||
what it does).
|
||||
|
||||
For other variables where you actually want to set a number or a
|
||||
string, use this form:
|
||||
|
||||
gnuboy --savename=mygame2 game.gb
|
||||
|
||||
Finally, for variables with multiple numbers to be set, you can
|
||||
separate them by commas as follows:
|
||||
|
||||
gnuboy --vmode=512,384,32
|
||||
|
||||
to avoid having to quote the spaces.
|
||||
|
||||
|
||||
[ P A R T I I ]
|
||||
GUIDE TO CONFIGURABLE VARIABLES
|
||||
|
||||
What follows is a detailed explanation of most of the configuration
|
||||
variables available for your tweaking. They are organized by what part
|
||||
of gnuboy's behavior they affect -- graphics, sound, emulation, and so
|
||||
on.
|
||||
|
||||
Some variables may or may not be available depending on how gnuboy was
|
||||
built. For example, if you built gnuboy on a system without sound
|
||||
support, some variables related to sound may not exist for you, and
|
||||
attempts to set them will be silently ignored. In most cases, it's
|
||||
noted in the documentation when variables might not be available.
|
||||
|
||||
Also, there are a few highly system-specific variables, such as names
|
||||
of devices to use for video and sound on *nix systems. These are
|
||||
listed separately at the end, and it should go without saying that
|
||||
they will not be available on all builds of gnuboy.
|
||||
|
||||
|
||||
VIDEO AND GRAPHICS SETTINGS
|
||||
|
||||
Since this is everyone's favorite thing to customize, video seems a
|
||||
good place to start.
|
||||
|
||||
|
||||
SCREEN SCALING
|
||||
|
||||
There are a number of variables that control how gnuboy scales the
|
||||
display. The most basic is the "scale" option, which is just the
|
||||
factor to scale by. For example
|
||||
|
||||
set scale 2
|
||||
|
||||
will double the size of the display. Set the scale factor to 1 for no
|
||||
scaling.
|
||||
|
||||
There are two ways gnuboy can go about doing scaling. The preferable
|
||||
way is to use your computer's graphics hardware to do all the work.
|
||||
This cuts down on the amount of CPU time consumed and provides
|
||||
filtering to smooth out the blocky pixels, but it's not available on
|
||||
all systems. The other way is for gnuboy to scale the screen itself.
|
||||
|
||||
Normally gnuboy will choose hardware scaling automatically if it's
|
||||
available, but if you want to force it on or off, you can set the
|
||||
option "yuv" (for hardware YUV-colorspace scaling) to 1 or 0. Yes,
|
||||
this option is poorly named, and is likely to change in future
|
||||
versions of gnuboy.
|
||||
|
||||
On one display platform, Linux fbcon, it's possible to disable the
|
||||
interpolation filter in the hardware scaling. To do this, set the
|
||||
variable "yuvinterp" to 0. Some users who like a crisper display may
|
||||
prefer this setting, especially on video cards that make the picture
|
||||
look "muddy" when they scale it. Unfortunately SDL does not seem to
|
||||
provide such an option, so interpolation is always enabled on the SDL
|
||||
based ports.
|
||||
|
||||
When hardware scaling is disabled or not available, gnuboy will do its
|
||||
own scaling. However, the scale factor is limited to 1, 2, 3, or 4.
|
||||
Also, when performing its own scaling, gnuboy defaults to leaving some
|
||||
scanlines blank. This saves a lot of CPU time and allows gnuboy to run
|
||||
full speed on slower systems. You can configure what portion gets
|
||||
filled in with the "density" variable. For example.
|
||||
|
||||
set scale 4
|
||||
set density 4
|
||||
|
||||
will give you 4x scaling with no blank scanlines. Keep in mind that a
|
||||
fairly fast computer (at least 400 MHz or so on x86, or something
|
||||
comparable on other types of CPUs) is required to run fullspeed with
|
||||
this setting. In general, "density" is the number of lines that get
|
||||
filled in, so set it the same as "scale" if you want everything filled
|
||||
in, or lower if you need more speed.
|
||||
|
||||
|
||||
VIDEO MODE
|
||||
|
||||
The variable for setting the desired video mode is called "vmode", and
|
||||
it's made up of three parts: width, height, and bits-per-pixel. For
|
||||
example, to set 640x480x16bpp mode, use
|
||||
|
||||
set vmode 640 480 16
|
||||
|
||||
By default gnuboy will enable hardware scaling and try to scale to the
|
||||
entire screen size if a video mode at least 320x288 is specified. If
|
||||
you don't want this behavior, set the "yuv" option (see above) to 0.
|
||||
Also, if you're setting the "scale" variable to do scaling, you
|
||||
probably don't need to use the "vmode" option, since gnuboy will
|
||||
try to automatically pick a mode that fits the scale. It's there in
|
||||
case you need it, though.
|
||||
|
||||
Note that the DOS port is not yet capable of auto-choosing a video
|
||||
mode, so if you want anything but the default 320x200x8bpp you'll have
|
||||
to set "vmode" yourself. Also, not all ports are capable of all modes.
|
||||
Experiment to find what works for you. Video mode selection is a
|
||||
little bit messy and confusing at this time, and we hope to improve it
|
||||
a good deal in the future.
|
||||
|
||||
|
||||
FULLSCREEN VIDEO
|
||||
|
||||
Some versions of gnuboy provide both fullscreen and windowed
|
||||
operation. The variable "fullscreen" can be set to 1 or 0 to enable or
|
||||
disable fullscreen mode. Also, the variable "altenter" can be set to
|
||||
enable or disable switching between fullscreen and windowed mode at
|
||||
runtime with the Alt+Enter key combination. Unfortunately, this does
|
||||
not yet work on Windows; we hope to fix this limitation in the
|
||||
future.
|
||||
|
||||
|
||||
DMG PALETTE SELECTION
|
||||
|
||||
gnuboy allows you to set the palette used for grayscale when running
|
||||
DMG (original mono Gameboy) roms. There are four variables for this
|
||||
purpose, allowing the background, window, and both sprite palettes to
|
||||
be colored differently. Each one is made up of four numbers, the color
|
||||
to use for each shade of gray, from lightest to darkest. Colors are
|
||||
represented as 24bit numbers, with red in the low (rightmost) places
|
||||
and blue in the upper (leftmost) places. Although you could specify
|
||||
colors in decimal (base 10) if you really wanted, they'd be very
|
||||
difficult to read, so it's preferable to use hex (base 16).
|
||||
|
||||
For example, to set the background to shades of white, the window to
|
||||
shades of red, and the sprite palettes to shades of green and blue,
|
||||
you could use:
|
||||
|
||||
set dmg_bgp 0xffffff 0xaaaaaa 0x555555 0x000000
|
||||
set dmg_wndp 0x0000ff 0x0000aa 0x000055 0x000000
|
||||
set dmg_obp0 0x00ff00 0x00aa00 0x005500 0x000000
|
||||
set dmg_obp1 0xff0000 0xaa0000 0x550000 0x000000
|
||||
|
||||
This will of course look rather ugly, but it does the job illustrating
|
||||
how you set various colors.
|
||||
|
||||
For more extensive examples, see the sample file palette.rc included
|
||||
with gnuboy, which provides a number of sample palettes to try.
|
||||
|
||||
|
||||
RGB MODE WITH ONLY 256 COLORS
|
||||
|
||||
Normally when run in 256-color (8bpp) modes, gnuboy will dynamically
|
||||
allocate colors in the palette as they're needed. However, on the
|
||||
Gameboy Color, it's possible to have well over 1000 colors on the
|
||||
screen at a time, and in games that make use of these "hicolor"
|
||||
tricks, gnuboy will run out of colors and things will look bad.
|
||||
|
||||
If you prefer, you can set the "rgb332" variable:
|
||||
|
||||
set rgb332 1
|
||||
|
||||
This tells gnuboy that instead of using 256-color mode as a
|
||||
palette-based mode, you want it to setup a static palette and pretend
|
||||
8bpp is just a really low quality "truecolor" mode, with only 3 bits
|
||||
of precision in red and green, and only 2 bits of precision in blue.
|
||||
In general this will make most games look worse, since colors have to
|
||||
be approximated fairly poorly and since smooth color gradients are not
|
||||
possible, but it will make "hicolor" Gameboy Color games look a good
|
||||
deal better. Also, rgb332 mode should run slightly faster since it
|
||||
avoids the overhead in dynamic palette allocation.
|
||||
|
||||
If you have to run at 8bpp mode, try it with and without this option
|
||||
and see which way you like better. Of course, the better solution, if
|
||||
at all possible, is to use 16bpp or higher mode, but that may run too
|
||||
slowly on older computers.
|
||||
|
||||
|
||||
COLOR FILTERING
|
||||
|
||||
Optionally, gnuboy can filter screen colors to make them look more
|
||||
washed out or faded like on a real GBC. To enable this feature,
|
||||
|
||||
set colorfilter 1
|
||||
|
||||
By default, gnuboy will not apply the filter when running DMG (mono)
|
||||
games, since many of the sample palettes are already designed to
|
||||
immitate a Gameboy LCD. If you would like to have the filter also take
|
||||
effect when running in DMG mode,
|
||||
|
||||
set filterdmg 1
|
||||
|
||||
You can also customize the filter parameters to get different color
|
||||
effects from the default ones. See the sample file filters.rc for
|
||||
examples.
|
||||
|
||||
|
||||
SPRITE SORTING
|
||||
|
||||
Normally sprites are sorted and prioritized according to their x
|
||||
coordinate when in DMG mode. However, this takes a little bit of extra
|
||||
cpu time, and it's not needed by most DMG games, so it can be disabled
|
||||
as follows:
|
||||
|
||||
set sprsort 0
|
||||
|
||||
Note that although sprite sorting was disabled in previous releases
|
||||
because it was not working properly, it now works great, so unless you
|
||||
really need to maximize performance, you should probably leave it
|
||||
enabled.
|
||||
|
||||
|
||||
SOUND OPTIONS
|
||||
|
||||
Fortunately sound is a lot simpler than video. At this time, there are
|
||||
no fancy interpolation or filtering options, only your basic audio
|
||||
parameters.
|
||||
|
||||
To enable or disable sound, set the "sound" variable to 1 or 0. By
|
||||
default, it's enabled.
|
||||
|
||||
To enable or disable stereo sound, set the "stereo" variable to 1 or
|
||||
0. It defaults to 1 on most ports, but since stereo sometimes fails
|
||||
to work properly on DOS, it's disabled by default on the DOS port.
|
||||
Disabling stereo in no way improves performance, so it should only be
|
||||
done if stereo mode causes a problem on your computer.
|
||||
|
||||
To set the audio sampling rate, use the "samplerate" variable. The
|
||||
default is 44100 Hz. Setting this lower can improve performance. For
|
||||
example, if you have a really slow computer, you might use:
|
||||
|
||||
set samplerate 8000
|
||||
|
||||
Keep in mind that this will sound really really bad.
|
||||
|
||||
|
||||
FILESYSTEM OPTIONS
|
||||
|
||||
There are a good deal of options that affect where and how files are
|
||||
saved and loaded by gnuboy. First, there's "rcpath", which specifies
|
||||
where gnuboy searches for rc files. The default depends on your
|
||||
operating system; see the beginning of this file for details.
|
||||
|
||||
The search path for rc files can contain multiple directories.
|
||||
Normally, the list is separated by colons (:), but on DOS and Windows
|
||||
the colon is used for drive letters, so semicolon (;) must be used
|
||||
instead. Here are some examples, first for *nix:
|
||||
|
||||
set rcpath "/home/laguna/.gnuboy:/usr/local/etc/gnuboy"
|
||||
set rcpath "."
|
||||
|
||||
and for DOS/Windows:
|
||||
|
||||
set rcpath "c:/gnuboy;."
|
||||
set rcpath "c:/Program Files/Gnuboy"
|
||||
|
||||
If you really insist on using backslashes on DOS or Windows, you'll
|
||||
have to double them up, since the backslash normally means "treat the
|
||||
next character literally." For example,
|
||||
|
||||
set rcpath "c:\\gnuboy"
|
||||
|
||||
This is untested, and your milage may vary. I recommend just using
|
||||
forward slashes and keeping things simple.
|
||||
|
||||
|
||||
SAVE RELATED OPTIONS
|
||||
|
||||
These are all fairly simple, so I'll just list them quickly, then give
|
||||
a couple examples.
|
||||
|
||||
savedir - directory to store saved games (SRAM and savestates) in
|
||||
savename - base filename to use for saves
|
||||
saveslot - which savestate slot to use
|
||||
forcebatt - always save SRAM even on carts that don't have battery
|
||||
nobatt - never save SRAM
|
||||
syncrtc - resync the realtime clock for elapsed time when loading
|
||||
|
||||
The "savename" variable is particularly useful if you wish to have
|
||||
more than one save associated with a particular rom. Just do something
|
||||
like:
|
||||
|
||||
gnuboy --savename=mygame2 mygame.gb
|
||||
|
||||
and the save files will be called mygame2.sav, mygame2.000, etc rather
|
||||
than just mygame.sav, etc.
|
||||
|
||||
The "saveslot" variable is normally just changed by keybindings, so
|
||||
you can pick a savestate slot while you're playing a game. However, if
|
||||
you for example prefer that the default slot at startup be 1 rather
|
||||
than 0, you can use:
|
||||
|
||||
set saveslot 1
|
||||
|
||||
The "forcebatt" and "nobatt" options are fairly self-explanatory and
|
||||
not very useful, except perhaps for debugging or use with corrupted
|
||||
roms.
|
||||
|
||||
The "syncrtc" option needs a bit of explanation. Some roms, notably
|
||||
Pokemon ones and Harvest Moon, use a realtime clock to keep track of
|
||||
the time of day even when they're not running. Since gnuboy is just an
|
||||
emulator, it can't work like a real cartridge and make things like
|
||||
this keep happening while the emulator is not running. However, it can
|
||||
resync the Gameboy realtime clock based on your computer's clock when
|
||||
it starts. This is what the "syncrtc" option does. By default it's
|
||||
enabled. If you disable it, then no time will seem to have elapsed
|
||||
between when you exit the emulator once and when you start it again
|
||||
the next time.
|
||||
|
||||
|
||||
JOYSTICK OPTIONS
|
||||
|
||||
So far there is just one joystick option, "joy", used to enable or
|
||||
disable joystick support.
|
||||
|
||||
|
||||
DEBUGGING OPTIONS
|
||||
|
||||
These probably won't be useful to most people, but if you're trying to
|
||||
debug a homebrew game you're writing or fix a bug in gnuboy they might
|
||||
be of help:
|
||||
|
||||
The "trace" variable, if enabled, dumps a full execution trace to
|
||||
stdout. Be prepared for at least 20 megs of logs to look through at
|
||||
minimum, and more like 150 megs if you want enough to find anything
|
||||
useful. Redirecting stdout to a file is a must!
|
||||
|
||||
The "sprdebug" variable is used to see how many sprites are visible
|
||||
per line. Try it and see!
|
||||
|
||||
|
||||
PLATFORM-SPECIFIC OPTIONS
|
||||
|
||||
On certain *nix systems, you may need to specify device nodes to use
|
||||
if the defaults don't work:
|
||||
|
||||
oss_device - Open Sound System "DSP" device
|
||||
fb_device - Video framebuffer device
|
||||
joy_device - Joystick device
|
||||
|
||||
The Linux fbcon version of gnuboy does not support the "vmode" option
|
||||
yet, but it can set the mode for you by running the "fbset" program,
|
||||
if you have it. Just set the "fb_mode" variable to the exact name of
|
||||
the mode you want in /etc/fb.modes. For example,
|
||||
|
||||
set fb_mode 640x480-90
|
||||
|
||||
You can also override the default color depth with the "fb_depth"
|
||||
variable.
|
||||
|
||||
The DOS port of gnuboy has support for real console system gamepads
|
||||
via the "Directpad Pro" (DPP) connector. To enable this feature, set
|
||||
"dpp" to 1, set "dpp_port" to the IO port number the pad is connected
|
||||
to (e.g. 0x378 -- be sure to prefix it with 0x for hex!!), and set
|
||||
"dpp_pad" to the number of the pad you want to use. This code has not
|
||||
been heavily tested, so it may or may not work for you. Be sure to get
|
||||
the port number right or bad things may happen!
|
||||
|
||||
|
||||
CONCLUSION
|
||||
|
||||
Well, that's about it for configuration. Hopefully this document
|
||||
clears up a lot of the confusion about what you can and can't
|
||||
configure in gnuboy yet, and how you go about doing it. Again, check
|
||||
the sample.rc, palette.rc, and classic.rc files for lots of examples
|
||||
of how rc files work.
|
||||
|
||||
As always, more info will come as time passes on. Keep on the lookout
|
||||
for new releases and more features. Thank you for flying gnuboy and
|
||||
have a nice day.
|
||||
|
||||
|
||||
|
||||
- Laguna
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
|
||||
Gilgamesh --
|
||||
concept
|
||||
research
|
||||
testing
|
||||
debug and tools coding
|
||||
website and build maintainence
|
||||
publicity
|
||||
dos and windows builds
|
||||
|
||||
Laguna --
|
||||
design
|
||||
main program
|
||||
asm optimizations
|
||||
documentation
|
||||
publicity
|
||||
|
||||
Damian M Gryski --
|
||||
SDL port
|
||||
various bugfix patches
|
||||
|
||||
Ralf Hoffmann --
|
||||
Linux joystick code
|
||||
SDL joystick bugfix
|
||||
|
||||
David Lau --
|
||||
SDL joystick code
|
||||
|
||||
Mattias Wadman --
|
||||
help with OpenBSD portability issues
|
||||
LCDC behavior information
|
||||
|
||||
Matthew Conte --
|
||||
DOS sound code
|
||||
thinlib
|
||||
|
||||
Markus F.X.J. Oberhumer --
|
||||
SDL fullscreen code
|
||||
|
||||
Dave Kiddell --
|
||||
Windows port (SDL+mingw32)
|
||||
SDL bugfixes
|
||||
|
||||
Magnus Damm --
|
||||
YUV colorspace code
|
||||
SDL YUV hardware scaling support
|
||||
|
||||
Gerd Knorr --
|
||||
fbtv, from which mga accel code was taken
|
||||
|
||||
Jonathan Gevaryahu AKA Lord Nightmare --
|
||||
tons of help improving sound emulation!
|
||||
color filter code and default filter values
|
||||
misc debugging support
|
||||
|
||||
Neil Stevens --
|
||||
collecting samples for sound channel 4 (noise)
|
||||
|
||||
David Madore --
|
||||
public domain "inflate" decompressor
|
||||
|
||||
Hii (author of TGB) --
|
||||
lots of info on various memory mappers
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
GNUBOY FREQUENTLY ASKED QUESTIONS
|
||||
|
||||
|
||||
Q: How do I configure gnuboy?
|
||||
|
||||
A: You can specify various options to gnuboy by means of "rcvars",
|
||||
either on the command line or in your gnuboy.rc file. To set rcvars
|
||||
from the command line, just use --varname=value, or --no-varname to
|
||||
turn off yes/no options. If you wish to use a gnuboy.rc file, create
|
||||
it with any text editor and save it in ~/.gnuboy (for *nix systems) or
|
||||
the same directory as gnuboy.exe (for DOS/Windows systems). In this
|
||||
file you can set rcvars with lines of the form "set varname value".
|
||||
See the sample.rc file included for examples.
|
||||
|
||||
|
||||
Q: Are you planning to add serial cable (gamelink) emulation?
|
||||
|
||||
A: Yes, read the wishlist in the README. At this time we don't have
|
||||
all the technical information to emulate it 100% correctly, so if you
|
||||
think you can help us find the info, get in touch.
|
||||
|
||||
|
||||
Q: gnuboy is too slow. How can I make it run faster?
|
||||
|
||||
A: You can try turning the sampling rate for sound down (for example,
|
||||
--samplerate=22050) or disabling sound entirely (--no-sound). Also,
|
||||
running at 8bpp with --rgb565 enabled will result in the highest video
|
||||
performance at the expense of some color quality. Of course, gnuboy is
|
||||
very fast, and shouldn't need any performance tweaks as long as your
|
||||
system is at least as fast as a Pentium/120.
|
||||
|
||||
|
||||
Q: Why did the keybindings change in 1.0?
|
||||
|
||||
A: Even though lots of emulators do it, we figured it wasn't a very
|
||||
good idea to use modifier keys for the controls, since some systems
|
||||
may be configured to trap these for other uses. This especially became
|
||||
a problem after adding support for Alt+Enter to toggle fullscreen. If
|
||||
you want to go back to the old bindings and don't want to configure
|
||||
them yourself, you can find all the old settings (including the old
|
||||
default palette) in classic.rc. Just copy and paste to your gnuboy.rc.
|
||||
|
||||
|
||||
Q: Will gnuboy ever support recording and playback?
|
||||
|
||||
A: We get this question fairly often, and I'm never sure how to answer
|
||||
it. We are planning to support recording audio output before too
|
||||
terribly long, but whether full demo recording and playback will ever
|
||||
be supported is uncertain. We'll keep it in mind for the future,
|
||||
though.
|
||||
|
||||
|
||||
Q: Why doesn't gnuboy do anything when I run it?
|
||||
|
||||
A: You need to specify the name of the ROM to load on the command
|
||||
line. One way to do this on Windows is to drag the ROM file onto
|
||||
gnuboy.exe (or a shortcut to it). Associating *.gb and *.gbc with
|
||||
gnuboy also works. Of course, you can also just use the run command on
|
||||
the start menu, or open a dos prompt. Unix users of course are
|
||||
expected to know how to run programs.
|
||||
|
||||
|
||||
Q: gnuboy doesn't run on WinNT/2k!!
|
||||
|
||||
A: Set the following environment variables before running:
|
||||
SDL_VIDEODRIVER=windib
|
||||
SDL_AUDIODRIVER=waveout
|
||||
Doing so should fix problems with other SDL programs too. If it still
|
||||
doesn't work, let us know. Your milage may vary; some people have
|
||||
reported that this doesn't help.
|
||||
|
||||
|
||||
Q: Why is sound pitch off by about 1% in gnuboy?
|
||||
|
||||
A: You have a very good ear. It's a rounding issue that won't be
|
||||
outright fixed for a while. If you want a workaround, set the sample
|
||||
rate to a power of two (for example 32768 works well) on the command
|
||||
line or in your gnuboy.rc.
|
||||
|
||||
|
||||
Q: Why does sound have ugly static noise on Windows?
|
||||
|
||||
A: This is a bug in SDL's DirectSound support. Try setting the
|
||||
environment variable:
|
||||
SDL_AUDIODRIVER=waveout
|
||||
before running gnuboy. Hopefully this won't cause any problems.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,472 @@
|
|||
|
||||
HACKING ON THE GNUBOY SOURCE TREE
|
||||
|
||||
|
||||
BASIC INFO
|
||||
|
||||
In preparation for the first release, I'm putting together a simple
|
||||
document to aid anyone interested in playing around with or improving
|
||||
the gnuboy source. First of all, before working on anything, you
|
||||
should know my policies as maintainer. I'm happy to accept contributed
|
||||
code, but there are a few guidelines:
|
||||
|
||||
* Obviously, all code must be able to be distributed under the GNU
|
||||
GPL. This means that your terms of use for the code must be equivalent
|
||||
to or weaker than those of the GPL. Public domain and MIT-style
|
||||
licenses are perfectly fine for new code that doesn't incorporate
|
||||
existing parts of gnuboy, e.g. libraries, but anything derived from or
|
||||
built upon the GPL'd code can only be distributed under GPL. When in
|
||||
doubt, read COPYING.
|
||||
|
||||
* Please stick to a coding and naming convention similar to the
|
||||
existing code. I can reformat contributions if I need to when
|
||||
integrating them, but it makes it much easier if that's already done
|
||||
by the coder. In particular, indentions are a single tab (char 9), and
|
||||
all symbols are all lowercase, except for macros which are all
|
||||
uppercase.
|
||||
|
||||
* All code must be completely deterministic and consistent across all
|
||||
platforms. this results in the two following rules...
|
||||
|
||||
* No floating point code whatsoever. Use fixed point or better yet
|
||||
exact analytical integer methods as opposed to any approximation.
|
||||
|
||||
* No threads. Emulation with threads is a poor approximation if done
|
||||
sloppily, and it's slow anyway even if done right since things must be
|
||||
kept synchronous. Also, threads are not portable. Just say no to
|
||||
threads.
|
||||
|
||||
* All non-portable code belongs in the sys/ or asm/ trees. #ifdef
|
||||
should be avoided except for general conditionally-compiled code, as
|
||||
opposed to little special cases for one particular cpu or operating
|
||||
system. (i.e. #ifdef USE_ASM is ok, #ifdef __i386__ is NOT!)
|
||||
|
||||
* That goes for *nix code too. gnuboy is written in ANSI C, and I'm
|
||||
not going to go adding K&R function declarations or #ifdef's to make
|
||||
sure the standard library is functional. If your system is THAT
|
||||
broken, fix the system, don't "fix" the emulator.
|
||||
|
||||
* Please no feature-creep. If something can be done through an
|
||||
external utility or front-end, or through clever use of the rc
|
||||
subsystem, don't add extra code to the main program.
|
||||
|
||||
* On that note, the modules in the sys/ tree serve the singular
|
||||
purpose of implementing calls necessary to get input and display
|
||||
graphics (and eventually sound). Unlike in poorly-designed emulators,
|
||||
they are not there to give every different target platform its own gui
|
||||
and different set of key bindings.
|
||||
|
||||
* Furthermore, the main loop is not in the platform-specific code, and
|
||||
it will never be. Windows people, put your code that would normally go
|
||||
in a message loop in ev_refresh and/or sys_sleep!
|
||||
|
||||
* Commented code is welcome but not required.
|
||||
|
||||
* I prefer asm in AT&T syntax (the style used by *nix assemblers and
|
||||
likewise DJGPP) as opposed to Intel/NASM/etc style. If you really must
|
||||
use a different style, I can convert it, but I don't want to add extra
|
||||
dependencies on nonstandard assemblers to the build process. Also,
|
||||
portable C versions of all code should be available.
|
||||
|
||||
* Have fun with it. If my demands stifle your creativity, feel free to
|
||||
fork your own projects. I can always adapt and merge code later if
|
||||
your rogue ideas are good enough. :)
|
||||
|
||||
OK, enough of that. Now for the fun part...
|
||||
|
||||
|
||||
THE SOURCE TREE STRUCTURE
|
||||
|
||||
[documentation]
|
||||
README - general information related to using gnuboy
|
||||
INSTALL - compiling and installation instructions
|
||||
HACKING - this file, obviously
|
||||
COPYING - the gnu gpl, grants freedom under condition of preseving it
|
||||
|
||||
[build files]
|
||||
Version - doubles as a C and makefile include, identifies version number
|
||||
Rules - generic build rules to be included by makefiles
|
||||
Makefile.* - system-specific makefiles
|
||||
configure* - script for generating *nix makefiles
|
||||
|
||||
[non-portable code]
|
||||
sys/*/* - hardware and software platform-specific code
|
||||
asm/*/* - optimized asm versions of some code, not used yet
|
||||
asm/*/asm.h - header specifying which functions are replaced by asm
|
||||
asm/i386/asmnames.h - #defines to fix _ prefix brain damage on DOS/Windows
|
||||
|
||||
[main emulator stuff]
|
||||
main.c - entry point, event handler...basically a mess
|
||||
loader.c - handles file io for rom and ram
|
||||
emu.c - another mess, basically the frame loop that calls state.c
|
||||
debug.c - currently just cpu trace, eventually interactive debugging
|
||||
hw.c - interrupt generation, gamepad state, dma, etc.
|
||||
mem.c - memory mapper, read and write operations
|
||||
fastmem.h - short static functions that will inline for fast memory io
|
||||
regs.h - macros for accessing hardware registers
|
||||
save.c - savestate handling
|
||||
|
||||
[cpu subsystem]
|
||||
cpu.c - main cpu emulation
|
||||
cpuregs.h - macros for cpu registers and flags
|
||||
cpucore.h - data tables for cpu emulation
|
||||
asm/i386/cpu.s - entire cpu core, rewritten in asm
|
||||
|
||||
[graphics subsystem]
|
||||
fb.h - abstract framebuffer definition, extern from platform-specifics
|
||||
lcd.c - main control of refresh procedure
|
||||
lcd.h - vram, palette, and internal structures for refresh
|
||||
asm/i386/lcd.s - asm versions of a few critical functions
|
||||
lcdc.c - lcdc phase transitioning
|
||||
|
||||
[input subsystem]
|
||||
input.h - internal keycode definitions, etc.
|
||||
keytables.c - translations between key names and internal keycodes
|
||||
events.c - event queue
|
||||
|
||||
[resource/config subsystem]
|
||||
rc.h - structure defs
|
||||
rccmds.c - command parser/processor
|
||||
rcvars.c - variable exports and command to set rcvars
|
||||
rckeys.c - keybindingds
|
||||
|
||||
[misc code]
|
||||
path.c - path searching
|
||||
split.c - general purpose code to split strings into argv-style arrays
|
||||
|
||||
|
||||
OVERVIEW OF PROGRAM FLOW
|
||||
|
||||
The initial entry point main() main.c, which will process the command
|
||||
line, call the system/video initialization routines, load the
|
||||
rom/sram, and pass control to the main loop in emu.c. Note that the
|
||||
system-specific main() hook has been removed since it is not needed.
|
||||
|
||||
There have been significant changes to gnuboy's main loop since the
|
||||
original 0.8.0 release. The former state.c is no more, and the new
|
||||
code that takes its place, in lcdc.c, is now called from the cpu loop,
|
||||
which although slightly unfortunate for performance reasons, is
|
||||
necessary to handle some strange special cases.
|
||||
|
||||
Still, unlike some emulators, gnuboy's main loop is not the cpu
|
||||
emulation loop. Instead, a main loop in emu.c which handles video
|
||||
refresh, polling events, sleeping between frames, etc. calls
|
||||
cpu_emulate passing it an idea number of cycles to run. The actual
|
||||
number of cycles for which the cpu runs will vary slightly depending
|
||||
on the length of the final instruction processed, but it should never
|
||||
be more than 8 or 9 beyond the ideal cycle count passed, and the
|
||||
actual number will be returned to the calling function in case it
|
||||
needs this information. The cpu code now takes care of all timer and
|
||||
lcdc events in its main loop, so the caller no longer needs to be
|
||||
aware of such things.
|
||||
|
||||
Note that all cycle counts are measured in CGB double speed MACHINE
|
||||
cycles (2**21 Hz), NOT hardware clock cycles (2**23 Hz). This is
|
||||
necessary because the cpu speed can be switched between single and
|
||||
double speed during a single call to cpu_emulate. When running in
|
||||
single speed or DMG mode, all instruction lengths are doubled.
|
||||
|
||||
As for the LCDC state, things are much simpler now. No more huge
|
||||
glorious state table, no more P/Q/R, just a couple simple functions.
|
||||
Aside from the number of cycles left before the next state change, all
|
||||
the state information fits nicely in the locations the Game Boy itself
|
||||
provides for it -- the LCDC, STAT, and LY registers.
|
||||
|
||||
If the special cases for the last line of VBLANK look strange to you,
|
||||
good. There's some weird stuff going on here. According to documents
|
||||
I've found, LY changes from 153 to 0 early in the last line, then
|
||||
remains at 0 until the end of the first visible scanline. I don't
|
||||
recall finding any roms that rely on this behavior, but I implemented
|
||||
it anyway.
|
||||
|
||||
That covers the basics. As for flow of execution, here's a simplified
|
||||
call tree that covers most of the significant function calls taking
|
||||
place in normal operation:
|
||||
|
||||
main sys/
|
||||
\_ real_main main.c
|
||||
|_ sys_init sys/
|
||||
|_ vid_init sys/
|
||||
|_ loader_init loader.c
|
||||
|_ emu_reset emu.c
|
||||
\_ emu_run emu.c
|
||||
|_ cpu_emulate cpu.c
|
||||
| |_ div_advance cpu.c *
|
||||
| |_ timer_advance cpu.c *
|
||||
| |_ lcdc_advance cpu.c *
|
||||
| | \_ lcdc_trans lcdc.c
|
||||
| | |_ lcd_refreshline lcd.c
|
||||
| | |_ stat_change lcdc.c
|
||||
| | | \_ lcd_begin lcd.c
|
||||
| | \_ stat_trigger lcdc.c
|
||||
| \_ sound_advance cpu.c *
|
||||
|_ vid_end sys/
|
||||
|_ sys_elapsed sys/
|
||||
|_ sys_sleep sys/
|
||||
|_ vid_begin sys/
|
||||
\_ doevents main.c
|
||||
|
||||
(* included in cpu.c so they can inline; also in cpu.s)
|
||||
|
||||
|
||||
MEMORY READ/WRITE MAP
|
||||
|
||||
Whenever possible, gnuboy avoids emulating memory reads and writes
|
||||
with a function call. To this end, two pointer tables are kept -- one
|
||||
for reading, the other for writing. They are indexed by bits 12-15 of
|
||||
the address in Game Boy memory space, and yield a base pointer from
|
||||
which the whole address can be used as an offset to access Game Boy
|
||||
memory with no function calls whatsoever. For regions that cannot be
|
||||
accessed without function calls, the pointer in the table is NULL.
|
||||
|
||||
For example, reading from address addr can be accomplished by testing
|
||||
to make sure mbc.rmap[addr>>12] is not NULL, then simply reading
|
||||
mbc.rmap[addr>>12][addr].
|
||||
|
||||
And for the disbelievers in this optimization, here are some numbers
|
||||
to compare. First, FFL2 with memory tables disabled:
|
||||
|
||||
% cumulative self self total
|
||||
time seconds seconds calls us/call us/call name
|
||||
28.69 0.57 0.57 refresh_2
|
||||
13.17 0.84 0.26 4307863 0.06 0.06 mem_read
|
||||
11.63 1.07 0.23 cpu_emulate
|
||||
|
||||
Now, with memory tables enabled:
|
||||
|
||||
38.86 0.66 0.66 refresh_2
|
||||
8.42 0.80 0.14 156380 0.91 0.91 spr_enum
|
||||
6.76 0.91 0.11 483134 0.24 1.31 lcdc_trans
|
||||
6.16 1.02 0.10 cpu_emulate
|
||||
.
|
||||
.
|
||||
.
|
||||
0.59 1.61 0.01 216497 0.05 0.05 mem_read
|
||||
|
||||
As you can see, not only does mem_read take up (proportionally) 1/20
|
||||
as much time, since it is rarely called, but the main cpu loop in
|
||||
cpu_emulate also runs considerably faster with all the function call
|
||||
overhead and cache misses avoided.
|
||||
|
||||
These tests were performed on K6-2/450 with the assembly cores
|
||||
enabled; your milage may vary. Regardless, however, I think it's clear
|
||||
that using the address mapping tables is quite a worthwhile
|
||||
optimization.
|
||||
|
||||
|
||||
LCD RENDERING CORE DESIGN
|
||||
|
||||
The LCD core presently used in gnuboy is very much a high-level one,
|
||||
performing the task of rasterizing scanlines as many independent steps
|
||||
rather than one big loop, as is often seen in other emulators and the
|
||||
original gnuboy LCD core. In some ways, this is a bit of a tradeoff --
|
||||
there's a good deal of overhead in rebuilding the tile pattern cache
|
||||
for roms that change their tile patterns frequently, such as full
|
||||
motion video demos. Even still, I consider the method we're presently
|
||||
using far superior to generating the output display directly from the
|
||||
gameboy tiledata -- in the vast majority of roms, tiles are changed so
|
||||
infrequently that the overhead is irrelevant. Even if the tiles are
|
||||
changed rapidly, the only chance for overhead beyond what would be
|
||||
present in a monolithic rendering loop lies in (host cpu) cache misses
|
||||
and the possibility that we might (tile pattern) cache a tile that has
|
||||
changed but that will never actually be used, or that will only be
|
||||
used in one orientation (horizontally and vertically flipped versions
|
||||
of all tiles are cached as well). Such tile caching issues could be
|
||||
addressed in the long term if they cause a problem, but I don't see it
|
||||
hurting performance too significantly at the present. As for host cpu
|
||||
cache miss issues, I find that putting multiple data decoding and
|
||||
rendering steps together in a single loop harms performance much more
|
||||
significantly than building a 256k (pattern) cache table, on account
|
||||
of interfering with branch prediction, register allocation, and so on.
|
||||
|
||||
Well, with those justifications given, let's proceed to the steps
|
||||
involved in rendering a scanline:
|
||||
|
||||
updatepatpix() - updates tile pattern cache.
|
||||
|
||||
tilebuf() - reads gb tile memory according to its complicated tile
|
||||
addressing system which can be changed via the LCDC register, and
|
||||
outputs nice linear arrays of the actual tile indices used in the
|
||||
background and window on the present line.
|
||||
|
||||
Before continuing, let me explain the output format used by the
|
||||
following functions. There is a byte array scan.buf, accessible by
|
||||
macro as BUF, which is the output buffer for the line. The structure
|
||||
of this array is simple: it is composed of 6 bpp gameboy color
|
||||
numbers, where the bits 0-1 are the color number from the tile, bits
|
||||
2-4 are the (cgb or dmg) palette index, and bit 5 is 0 for background
|
||||
or window, 1 for sprite.
|
||||
|
||||
What is the justification for using a strange format like this, rather
|
||||
than raw host color numbers for output? Well, believe it or not, it
|
||||
improves performance. It's already necessary to have the gameboy color
|
||||
numbers available for use in sprite priority. And, when running in
|
||||
mono gb mode, building this output data is VERY fast -- it's just a
|
||||
matter of doing 64 bit copies from the tile pattern cache to the
|
||||
output buffer.
|
||||
|
||||
Furthermore, using a unified output format like this eliminates the
|
||||
need to have separate rendering functions for each host color depth or
|
||||
mode. We just call a one-line function to apply a palette to the
|
||||
output buffer as we copy it to the video display, and we're done. And,
|
||||
if you're not convinced about performance, just do some profiling.
|
||||
You'll see that the vast majority of the graphics time is spent in the
|
||||
one-line copy function (render_[124] depending on bytes per pixel),
|
||||
even when using the fast asm versions of those routines. That is to
|
||||
say, any overhead in the following functions is for all intents and
|
||||
purposes irrelevant to performance. With that said, here they are:
|
||||
|
||||
bg_scan() - expands the background layer to the output buffer.
|
||||
|
||||
wnd_scan() - expands the window layer.
|
||||
|
||||
spr_scan() - expands the sprites. Note that this requires spr_enum()
|
||||
to have been called already to build a list of which sprites are
|
||||
visible on the current scanline and sort them by priority.
|
||||
|
||||
It should be noted that the background and window functions also have
|
||||
color counterparts, which are considerably slower due to merging of
|
||||
palette data. At this point, they're staying down around 8% time
|
||||
according to the profiler, so I don't see a major need to rewrite them
|
||||
anytime soon. It should be considered, however, that a different
|
||||
intermediate format could be used for gbc, or that asm versions of
|
||||
these two routines could be written, in the long term.
|
||||
|
||||
Finally, some notes on palettes. You may be wondering why the 6 bpp
|
||||
intermediate output can't be used directly on 256-color display
|
||||
targets. After all, that would give a huge performance boost. The
|
||||
problem, however, is that the gameboy palette can change midscreen,
|
||||
whereas none of the presently targetted host systems can handle such a
|
||||
thing, much less do it portably. For color roms, using our own
|
||||
internal color mappings in addition to the host system palette is
|
||||
essential. For details on how this is accomplished, read palette.c.
|
||||
|
||||
Now, in the long term, it MAY be possible to use the 6 bpp color
|
||||
"almost" directly for mono roms. Note that I say almost. The idea is
|
||||
this. Using the color number as an index into a table is slow. It
|
||||
takes an extra read and causes various pipeline stalls depending on
|
||||
the host cpu architecture. But, since there are relatively few
|
||||
possible mono palettes, it may actually be possible to set up the host
|
||||
palette in a clever way so as to cover all the possibilities, then use
|
||||
some fancy arithmetic or bit-twiddling to convert without a lookup
|
||||
table -- and this could presumably be done 4 pixels at a time with
|
||||
32bit operations. This area remains to be explored, but if it works,
|
||||
it might end up being the last hurdle to getting realtime emulation
|
||||
working on very low-end systems like i486.
|
||||
|
||||
|
||||
SOUND
|
||||
|
||||
Rather than processing sound after every few instructions (and thus
|
||||
killing the cache coherency), we update sound in big chunks. Yet this
|
||||
in no way affects precise sound timing, because sound_mix is always
|
||||
called before reading or writing a sound register, and at the end of
|
||||
each frame.
|
||||
|
||||
The main sound module interfaces with the system-specific code through
|
||||
one structure, pcm, and a few functions: pcm_init, pcm_close, and
|
||||
pcm_submit. While the first two should be obvious, pcm_submit needs
|
||||
some explaining. Whenever realtime sound output is operational,
|
||||
pcm_submit is responsible for timing, and should not return until it
|
||||
has successfully processed all the data in its input buffer (pcm.buf).
|
||||
On *nix sound devices, this typically means just waiting for the write
|
||||
syscall to return, but on systems such as DOS where low level IO must
|
||||
be handled in the program, pcm_submit needs to delay until the current
|
||||
position in the DMA buffer has advanced sufficiently to make space for
|
||||
the new samples, then copy them.
|
||||
|
||||
For special sound output implementations like write-to-file or the
|
||||
dummy sound device, pcm_submit should write the data immediately and
|
||||
return 0, indicating to the caller that other methods must be used for
|
||||
timing. On real sound devices that are presently functional,
|
||||
pcm_submit should return 1, regardless of whether it buffered or
|
||||
actually wrote the sound data.
|
||||
|
||||
And yes, for unices without OSS, we hope to add piped audio output
|
||||
soon. Perhaps Sun audio device and a few others as well.
|
||||
|
||||
|
||||
OPTIMIZED ASSEMBLY CODE
|
||||
|
||||
A lot can be said on this matter. Nothing has been said yet.
|
||||
|
||||
|
||||
INTERACTIVE DEBUGGER
|
||||
|
||||
Apologies, there is no interactive debugger in gnuboy at present. I'm
|
||||
still working out the design for it. In the long run, it should be
|
||||
integrated with the rc subsystem, kinda like a cross between gdb and
|
||||
Quake's ever-famous console. Whether it will require a terminal device
|
||||
or support the graphical display remains to be determined.
|
||||
|
||||
In the mean time, you can use the debug trace code already
|
||||
implemented. Just "set trace 1" from your gnuboy.rc or the command
|
||||
line. Read debug.c for info on how to interpret the output, which is
|
||||
condensed as much as possible and not quite self-explanatory.
|
||||
|
||||
|
||||
PORTING
|
||||
|
||||
On all systems on which it is available, the gnu compiler should
|
||||
probably be used. Writing code specific to non-free compilers makes it
|
||||
impossible for free software users to actively contribute. On the
|
||||
other hand, compiler-specific code should always be kept to a minimum,
|
||||
to make porting to or from non-gnu compilers easier.
|
||||
|
||||
Porting to new cpu architectures should not be necessary. Just make
|
||||
sure you unset IS_LITTLE_ENDIAN in the makefiles to enable the big
|
||||
endian default if the target system is big endian. If you do have
|
||||
problems building on certain cpus, however, let us know. Eventually,
|
||||
we will also want asm cpu and graphics code for popular host cpus, but
|
||||
this can wait, since the c code should be sufficiently fast on most
|
||||
platforms.
|
||||
|
||||
The bulk of porting efforts will probably be spent on adding support
|
||||
for new operating systems, and on systems with multiple video (or
|
||||
sound, once that's implemented) architectures, new interfaces for
|
||||
those. In general, the operating system interface code goes in a
|
||||
directory under sys/ named for the os (e.g. sys/nix/ for *nix
|
||||
systems), and display interfaces likewise go in their respective
|
||||
directories under sys/ (e.g. sys/x11/ for the x window system
|
||||
interface).
|
||||
|
||||
For guidelines in writing new system and display interface modules, i
|
||||
recommend reading the files in the sys/dos/, sys/svga/, and sys/nix/
|
||||
directories. These are some of the simpler versions (aside from the
|
||||
tricky dos keyboard handling), as opposed to all the mess needed for
|
||||
x11 support.
|
||||
|
||||
Also, please be aware that the existing system and display interface
|
||||
modules are somewhat primitive; they are designed to be as quick and
|
||||
sloppy as possible while still functioning properly. Eventually they
|
||||
will be greatly improved.
|
||||
|
||||
Finally, remember your obligations under the GNU GPL. If you produce
|
||||
any binaries that are compiled strictly from the source you received,
|
||||
and you intend to release those, you *must* also release the exact
|
||||
sources you used to produce those binaries. This is not pseudo-free
|
||||
software like Snes9x where binaries usually appear before the latest
|
||||
source, and where the source only compiles on one or two platforms;
|
||||
this is true free software, and the source to all binaries always
|
||||
needs to be available at the same time or sooner than the
|
||||
corresponding binaries, if binaries are to be released at all. This of
|
||||
course applies to all releases, not just new ports, but from
|
||||
experience i find that ports people usually need the most reminding.
|
||||
|
||||
|
||||
EPILOGUE
|
||||
|
||||
That's it for now. More info will eventually follow. Happy hacking!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
LIBERTY
|
||||
|
||||
For the true meaning of liberty, please visit the the Foundation's
|
||||
philosopy page at http://www.gnu.org/philosophy/philosophy.html.
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
|
||||
GNUBOY README
|
||||
|
||||
|
||||
INTRO
|
||||
|
||||
Welcome to gnuboy, one of the few pieces of Free Software to emulate
|
||||
the Game Boy handheld game console. Written in ANSI C with a few
|
||||
optional assembler optimizations for particular cpus, gnuboy supports
|
||||
a wide range of host systems, and has been tested successfully on:
|
||||
|
||||
GNU/Linux
|
||||
FreeBSD
|
||||
OpenBSD
|
||||
BeOS
|
||||
Linux/390 (IBM S/390 Mainframe)
|
||||
SunOS/Sun Ultra60
|
||||
IRIX/SGI O2
|
||||
IRIX/SGI Indy
|
||||
AIX/Unknown
|
||||
DR-DOS
|
||||
MS-DOS
|
||||
Windows DOS box
|
||||
Windows 9x/NT/2k
|
||||
|
||||
Additionally, gnuboy should run on any other *nix variants that have
|
||||
ANSI C compilers and that are remotely POSIX compliant. As gnuboy is
|
||||
Free Software, you're welcome to fix any problems you encounter
|
||||
building it for a particular system, or to port it to entirely new
|
||||
systems.
|
||||
|
||||
For build instructions, see the file INSTALL. For information on the
|
||||
structure of the source tree, program flow, design decisions and
|
||||
guidelines, porting, and so on, read HACKING.
|
||||
|
||||
|
||||
GENERAL USAGE
|
||||
|
||||
Just pass the name of the rom to load on the command line. Default
|
||||
keybindings are as follows:
|
||||
|
||||
esc - exit
|
||||
arrow keys - d-pad
|
||||
alt - a
|
||||
ctrl - b
|
||||
space - select
|
||||
enter - start
|
||||
0-9 - select savestate slot
|
||||
ins - save current state
|
||||
del - return to saved state
|
||||
|
||||
joypad - d-pad
|
||||
joy0 - b
|
||||
joy1 - a
|
||||
joy2 - select
|
||||
joy3 - start
|
||||
|
||||
(Note: joystick is not available on all platforms at this time.)
|
||||
|
||||
If you want to change these or other options, you should create a
|
||||
gnuboy.rc file. See the system-specific info below for where to put
|
||||
it.
|
||||
|
||||
The rc subsystem is very similar to Quake's console in many
|
||||
respects. You have commands and variables. First, the commands:
|
||||
|
||||
quit - exit gnuboy (saving sram)
|
||||
reset - reset to powerup state
|
||||
source - process another rc file
|
||||
set - set a variable's value
|
||||
bind - bind keys
|
||||
unbind - remove a keybinding
|
||||
unbindall - remove all keybindings
|
||||
savestate - save current state
|
||||
loadstate - return to saved state
|
||||
|
||||
Additionally, each gameboy pad button has two commands, one to press
|
||||
it, and another to release it -- for example, +start and -start. When
|
||||
a key is bound to one of these commands that starts with a +, it will
|
||||
perform the corresponding - command when it's released, as expected.
|
||||
|
||||
Here's a list of the + commands, though they should be obvious:
|
||||
|
||||
+start +select +a +b +up +down +left +right
|
||||
|
||||
Now for the variables. To set any of the rc variables, just put the
|
||||
command of the form "set variable value" in your gnuboy.rc or other rc
|
||||
file. Some of the more interesting variables are:
|
||||
|
||||
rcpath - search path for loading extra rc files
|
||||
savedir - the directory where save files will be stored
|
||||
savename - base of filename to use for sram and savestates
|
||||
forcedmg - set to 1/true/yes to force color roms to play mono
|
||||
framelen - delay in microseconds between frames
|
||||
framecount - run only the given number of frames, then exit
|
||||
|
||||
dmg_bgp - specify 4 custom colors to be used for mono background
|
||||
dmg_wndp - same thing, but for the window layer
|
||||
dmg_obp0 - and for sprite palette 0
|
||||
dmg_obp1 - and sprite palette 1
|
||||
|
||||
scale - factor for screen scaling; currently only 1 and 2 work
|
||||
density - density level for screen scaling; see description below
|
||||
|
||||
sprsort - x-sort sprites for correctness on dmg roms
|
||||
|
||||
syncrtc - fake elapsed time on rtc since last session at startup
|
||||
|
||||
trace - output a complete cpu trace to stdout
|
||||
sprdebug - display bars indicating sprite count per line
|
||||
|
||||
There are a few others which may or not be useful. Also, certain
|
||||
system and display targets have their own variables, which will be
|
||||
described in the relevant sections below. For more info on how the
|
||||
variables work, read the source.
|
||||
|
||||
For sample rc files, look in the etc/ directory.
|
||||
|
||||
Finally, to display help, version, or copying information, use the
|
||||
--help, --version, or --copying options respectively on the gnuboy
|
||||
command line.
|
||||
|
||||
|
||||
USAGE - *NIX SYSTEMS
|
||||
|
||||
The file gnuboy.rc should be placed in ~/.gnuboy/. If it is not found
|
||||
in this location, the current working directory will be
|
||||
searched. The following defaults will be used:
|
||||
|
||||
rcpath - ~/.gnuboy:.
|
||||
savedir - ~/.gnuboy/saves
|
||||
|
||||
If you don't like these, override them with gnuboy.rc.
|
||||
|
||||
There are presently four *nix targets supported: X11, SDL, and Linux
|
||||
fbcon and svgalib. In the future other fb devices (such as the Sun
|
||||
console) should be supported as well.
|
||||
|
||||
If you have problems with gnuboy running too slowly on svgalib, turn
|
||||
off the vsync option, i.e. set vsync 0. Putting --no-vsync on the
|
||||
command line works as well. At this point svgalib is the only one that
|
||||
supports vsync, so it's a non-issue on the others.
|
||||
|
||||
|
||||
USAGE - DOS and Windows
|
||||
|
||||
Place your gnuboy.rc in the same directory as gnuboy.exe. You need to
|
||||
specify a save directory in it; otherwise the working directory will
|
||||
be used, which is probably not what you want. For example, if you've
|
||||
installed gnuboy.exe in c:/gnuboy, and you want your saves to be
|
||||
stored in c:/gnuboy/saves, place the following in a plain text file
|
||||
called gnuboy.rc in c:/gnuboy.
|
||||
|
||||
set savedir c:/gnuboy/saves
|
||||
|
||||
By default stereo sound is disabled on DOS since it doesn't work right
|
||||
on some of the systems we've tested; to enable it, add the following
|
||||
line to your gnuboy.rc:
|
||||
|
||||
set stereo 1
|
||||
|
||||
|
||||
VIDEO MODES
|
||||
|
||||
Now all the display targets except Linux fbcon support the uniform
|
||||
"vmode" rcvar to set the video mode. From the rc file, you can specify
|
||||
a video mode like this (for 640x480, 16bpp):
|
||||
|
||||
set vmode 640 480 16
|
||||
|
||||
Or you can specify the mode on the command line, as
|
||||
|
||||
--vmode=640,480,16
|
||||
|
||||
If the requested video mode is not available, gnuboy may either give
|
||||
an error message or use a similar available mode.
|
||||
|
||||
|
||||
SCREEN SCALING
|
||||
|
||||
Scaling by integral factors 1-4 is now supported. Just set the rcvar
|
||||
"scale" to the desired scaling factor. Most of the display targets
|
||||
will automatically choose a video mode appropriate to the chosen
|
||||
scale, but DOS and Linux fbcon users should be aware they they need to
|
||||
set the mode manually, as described above. Of course, if you prefer,
|
||||
you can always set it manually.
|
||||
|
||||
By default, for performance reasons, vertical scaling will not be
|
||||
fully dense but will leave some blank scanlines. This behavior can be
|
||||
adjusted by means of the "density" rcvar. Density 0, the default,
|
||||
skips every other line. Nonzero values N fill in the first N copies of
|
||||
the scanline, and leave the remaining scale-N scanlines blank. So, if
|
||||
you want a fully filled in display (and the worst performance), you
|
||||
should set density to the same value as scale.
|
||||
|
||||
Please be aware that this code is still slightly experimental, and the
|
||||
ways of configuring scaling may change considerably in the next few
|
||||
releases.
|
||||
|
||||
|
||||
HARDWARE ACCELERATED YUV-SPACE SCREEN SCALING
|
||||
|
||||
If you're using the SDL display target and your video card/driver
|
||||
supports it, hardware screen scaling is available. This feature
|
||||
provides scaling to any size with almost no cpu usage! It's enabled by
|
||||
default if the screen resolution is set to 320x288 or higher; manually
|
||||
set the "yuv" rcvar to 0 or 1 to force it off or on, respectively.
|
||||
|
||||
Scaling will be performed to fill the entire requested video mode.
|
||||
For example, to scale to 640x480, either add the following line to
|
||||
your gnuboy.rc:
|
||||
|
||||
set vmode 640 480
|
||||
|
||||
or put --vmode=640,480 on the command line. A better alternative is to
|
||||
just request a particular scale, for example with:
|
||||
|
||||
set scale 4
|
||||
|
||||
or --scale=4 on the command line; this way the gameboy's near 1:1
|
||||
aspect ratio won't become distorted.
|
||||
|
||||
|
||||
SOUND SUPPORT
|
||||
|
||||
At this point all features are implemented and everything should be
|
||||
right, so any incorrect sound output should be treated as a bug, which
|
||||
we'll try to fix as soon as possible.
|
||||
|
||||
|
||||
JOYSTICK AND GAMEPAD SUPPORT
|
||||
|
||||
At this time, the Linux and SDL joystick devices are the only ones
|
||||
supported. We hope to have DOS joystick support soon.
|
||||
|
||||
Binding joystick controls works the same way as for the keyboard. Just
|
||||
use the key names joyup, joydown, joyright, joyleft, joy0, joy1, joy2,
|
||||
etc. Default bindings should probably be ok for most users, except
|
||||
that A/B might be backwards on some gamepads.
|
||||
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
Here are some performance estimates i've gathered (given in percent
|
||||
cpu utilization, running at full 60 fps)...
|
||||
|
||||
Optimized C Assembly
|
||||
AMD K6-2/450 12% 8%
|
||||
Pentium/75 (too slow) 70%
|
||||
SGI O2 25% (no asm)
|
||||
SGI Indy 70% (no asm)
|
||||
Sun Ultra60 3-20% (no asm)
|
||||
IBM S/390 about 0.3% (no asm)
|
||||
|
||||
Note that these figures were computed before sound was implemented.
|
||||
Until the sound code is further optimized, gnuboy may run somewhat
|
||||
slower than these numbers suggest.
|
||||
|
||||
|
||||
SUPPORTED MEMORY BANK CONTROLLERS (MBCS)
|
||||
|
||||
At this time, gnuboy supports MBC1, MBC2, MBC3 (including realtime
|
||||
clock), and MBC5 (including the version with rumble support, although
|
||||
that functionality is omitted).
|
||||
|
||||
|
||||
GRAPHICS SUPPORT
|
||||
|
||||
Color Gameboy roms are supported completely, including so-called
|
||||
"highcolor" tricks. Yes, even in 256-color mode, although in games
|
||||
that use too many colors on one screen, the later ones will only be
|
||||
approximated. Use a 16 bpp (or higher) display mode if this is a
|
||||
problem.
|
||||
|
||||
Alternatively, for games that look bad in 256 color mode, you can
|
||||
run in simulated 3/3/2 bits per channel truecolor. Just set the
|
||||
variable rgb332 to something nonzero (or just putting --rgb332 on the
|
||||
command line will work). Color precision is lost somewhat, especially
|
||||
in smooth gradients, but for the most part it looks very good.
|
||||
|
||||
Much care has been put into ensuring that the lcd timings and
|
||||
interrupts behave as closely to the real hardware as possible. A few
|
||||
features remain unimplemented, such as reduced length HBLANK depending
|
||||
on the number of sprites visible on the scanline, but the vast
|
||||
majority of display tricks used in current roms work fine.
|
||||
|
||||
We do, however, lack information on proper GDMA timings, which could
|
||||
theoretically cause problems for some roms. If you can provide us with
|
||||
accurate information, please do!
|
||||
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Eventually I'll put detailed information here. For now, just see known
|
||||
bugs for the few cases where roms fails.
|
||||
|
||||
|
||||
KNOWN BUGS
|
||||
|
||||
The portal between the temple and the Talon in FFL3 is glitched and
|
||||
the game freezes for a second or two building the incorrect animation
|
||||
when entering those screens.
|
||||
|
||||
GDMA finishes instantly, whereas it should take time. Making it take
|
||||
time breaks Wacky Races, last I checked, so apparently the documents I
|
||||
have on GDMA timing are incorrect. Same goes for HDMA. Good
|
||||
information would be much appreciated.
|
||||
|
||||
The main loop in emu_run is very sloppy and not quite right, but it
|
||||
works.
|
||||
|
||||
Sound mixing is taking way too much cpu time. I have some ideas for
|
||||
fixing this, and I plan to write optimized assembly code for sound
|
||||
eventually. If it's a problem try turning down the sample rate.
|
||||
|
||||
YUV-space hardware scaling only supports the common "YUY2" mode so
|
||||
far. More modes will be added in the future.
|
||||
|
||||
|
||||
REPORTING OR FIXING BUGS
|
||||
|
||||
Found a bug not mentioned above, or better yet, fixed one? Send bug
|
||||
reports or patches to gnuboy@starfox.org. Please be aware that
|
||||
distribution of any code based on gnuboy must follow the provisions of
|
||||
the GPL, so if you don't agree to this, don't send code to us or
|
||||
anyone else. Let us know if you wish to be included in the credits.
|
||||
|
||||
For guidelines regarding code contributions, see the file HACKING.
|
||||
|
||||
Please be aware that evaluating contributed code and figuring out if
|
||||
or how to work it in can take time. If we haven't done anything with
|
||||
your code yet, please be patient.
|
||||
|
||||
|
||||
THANKS
|
||||
|
||||
Thanks goes out to everyone who's expressed interest in gnuboy by
|
||||
writing -- users, porters, authors of other emulators, and so forth.
|
||||
Apologies if we don't get a personal response out to everyone, but
|
||||
either way, consider your feedback well appreciated.
|
||||
|
||||
|
||||
EPILOGUE
|
||||
|
||||
OK, that looks like about it. More to come, stick around...
|
||||
|
||||
|
||||
|
||||
-Laguna
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
|
||||
* WHAT'S NEW *
|
||||
|
||||
Here you will find a summary of the changes made in each released
|
||||
version of gnuboy, organized from an end-user perspective.
|
||||
Webmasters, please use this file as a basis for announcing new
|
||||
versions; the CHANGES file is too technical and unorganized.
|
||||
|
||||
|
||||
|
||||
RELEASE 1.0.3
|
||||
|
||||
All ANSI C incompatibilities should be fixed. Please report any that
|
||||
remain.
|
||||
|
||||
Various bugs encountered when building gnuboy on strange compilers
|
||||
have been fixed.
|
||||
|
||||
Internal support for decompressing gzipped roms now exists in a
|
||||
minimal form. The inflate code used is taken from a quine
|
||||
(self-reproducing program) written by David Madore and placed in the
|
||||
public domain. This code is very portable but is rather slow and may
|
||||
crash when given invalid data; however, there should be no impact on
|
||||
security. Currently only gzip files (not pkzip files) are supported.
|
||||
|
||||
HuC3 emultaion has been fixed to some extent. Robopon Sun and Star are
|
||||
both playable now, but many features of the HuC3 are still not
|
||||
implemented.
|
||||
|
||||
Color filtering to make gnuboy look much more like a real CGB is now
|
||||
included, thanks to the work of Jonathan Gevaryahu.
|
||||
|
||||
A new rcvar "gbamode" has been added to unlock the GBA-only features
|
||||
present in some newer CGB games. (This has nothing to do with GBA
|
||||
emulation, which gnuboy does not do and will not do in the future.)
|
||||
|
||||
Sprite sorting in DMG mode has been fixed. This should improve things
|
||||
in various DMG games where sprites previously overlapped in the wrong
|
||||
order.
|
||||
|
||||
|
||||
|
||||
RELEASE 1.0.2
|
||||
|
||||
A minor problem in the frequency sweep function on sound channel 1 was
|
||||
fixed, correcting the sound of the ice beam and metroid encounter
|
||||
sound in Metroid 2.
|
||||
|
||||
Sound channel 3 waveform data is now trashed when the sound is
|
||||
played. This makes it more difficult for games and demos to detect
|
||||
that they are running on an emulator.
|
||||
|
||||
The channel 3 waveform is now properly initialized in both DMG and CGB
|
||||
modes. Before it was incorrectly initialized to have frequency 16
|
||||
times too high, and the initial "random noise" pattern exhibited by
|
||||
DMG wasn't emulated. R-Type now sounds much better.
|
||||
|
||||
The sound length register for channel 3 now works properly, fixing the
|
||||
title screen music in MegaMan 2. No thanks to gbspec.txt for having
|
||||
blatently wrong info about this matter.
|
||||
|
||||
Major problems with sound quality on channel 4 (noise) have been
|
||||
fixed, and the pseudorandom sequence has been replaced to very closely
|
||||
resemble that of a real Gameboy, thanks to the hard work of Lord
|
||||
Nightmare. All these changes make a significant improvement in many
|
||||
games, notably Metroid 2, Final Fantasy Legend II and III, Camp
|
||||
Deadly, and Wario Land.
|
||||
|
||||
Stereo channels are no longer backwards.
|
||||
|
||||
The DMG STAT register write bug, which causes an interrupt if the STAT
|
||||
register is written while in HBLANK or VBLANK, is now emulated. This
|
||||
fixes Legend of Zerd and probably any other DMG game that will not run
|
||||
on a real Gameboy Color.
|
||||
|
||||
A hack/potential fix for a problem that kept Konami Collection Vol 1
|
||||
from working has been put in place.
|
||||
|
||||
A major interrupt bug that prevented Amazing Penguin from running has
|
||||
been fixed.
|
||||
|
||||
Several bugs that could have resulted in crashes under strange
|
||||
circumstances have been fixed.
|
||||
|
||||
Other minor sound issues have been tweaked or fixed.
|
||||
|
||||
|
||||
|
||||
RELEASE 1.0.1
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Keys that didn't work in the SDL-based ports have now been fixed.
|
||||
The --bindir= option to the configure script now works properly.
|
||||
Running "make install" no longer fails when the destination directory
|
||||
doesn't already exist.
|
||||
Various minor cleanups.
|
||||
|
||||
|
||||
|
||||
RELEASE 1.0.0
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Auto-loading rc files on a per-rom basis.
|
||||
Less intense yellow in the default mono palette.
|
||||
Default keybindings no longer use modifier keys.
|
||||
Lots of new documentation.
|
||||
Hardware scaling on matroxfb now looks better.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Disabled some useless optimizations to work around a bug in gcc 2.96, which
|
||||
despite being a broken compiler has become rather popular since Redhat
|
||||
decided to package it without sufficient testing. This will fix the problems
|
||||
lots of people have reported when compiling.
|
||||
Added --disable-arch option to configure to prevent the binaries built from
|
||||
being dependent on the exact host cpu they're built on. This will allow
|
||||
distro maintainers to build packages that work even on older cpus.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.13
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Hardware scaling support on fbcon with matroxfb.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
Now all software scaling code has assembly implementations.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Invalid opcode crash in Montezuma's Return has been fixed.
|
||||
Visual glitches in Pokemon Yellow are now fixed.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Line refresh was taking place too late, causing visual glitch in Alleyway.
|
||||
Flags behavior on the RL, RR, RLC, and RRC opcodes was completely bogus in the
|
||||
asm cpu core. Miracle it didn't break more things. Should be correct now.
|
||||
The SWAP (HL) instruction in the asm cpu core was nonfunctional.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.12
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Hardware YUV scaling with full interpolation on systems that support it,
|
||||
using SDL -- thanks goes to Magnus Damm.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Binary Chaos no longer has graphical glitches, and is fully playable.
|
||||
Wacky Races now displays correctly again (broken since 0.9.7).
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Some test code was left in cpu.s, breaking DOS/Windows builds and
|
||||
slowing things down across the board.
|
||||
SDL joystick code was generating bogus release events.
|
||||
Unused bits of VBK register were 0's; they should be 1's.
|
||||
DMG palette was not being restored correctly after loading savestates.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.11
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Most ports can auto-choose screen size appropriate to scale given.
|
||||
Scaling to 2x, 3x, and 4x is now possible at all color depths.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
SDL port should run considerably faster than before at hires modes.
|
||||
New X11 rcvar "x_shmsync" can be turned off for performance boost,
|
||||
but it can result in heavy shearing and skipped frames.
|
||||
The new scaling code is slightly faster than before.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Konami Collection (GBC) series now works in color mode.
|
||||
Worms Armageddon is now playable, might still have some glitches though.
|
||||
Turok 3 no longer hangs at startup and seems fully playable.
|
||||
Sound samples that played too slow in many games now sound correct.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Video mode setting was not working with svgalib.
|
||||
Undocumented behavior - STOP instruction causes PC to skip forward.
|
||||
SDL hardware surface mode is now always on and should always work fine.
|
||||
More undocumented behavior - HDMA can occur while LCDC is off...?
|
||||
HDMA5 register was not being initialized correctly on reset.
|
||||
Timer was running at half the speed it should when in high-speed mode.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.10
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Primitive but fast and fully functional scale-by-two support.
|
||||
New rcvar "vmode" sets video mode in all the targets that support it.
|
||||
Now up to 16 joystick buttons can be used, as opposed to 8 before.
|
||||
Static palette mode (rcvar "rgb332"), which can make highcolor games
|
||||
look better when run at 8bpp by faking a 3/3/2 color channel mode.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Added a quick hack to fake serial I/O so that Super RC Pro-Am works.
|
||||
Spiderman's web is now visible in Spiderman GBC.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
New refresh code blits lines slightly faster.
|
||||
Added sdl_hwsurface rcvar to turn hardware surface on for speed boost,
|
||||
disabled by default because it crashes on Windows.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Hopefully fixed issue with X header locations affecting some users.
|
||||
DMG sprite sorting isn't working right. It's now disabled by default.
|
||||
VBLANK timings have been changed slightly to fix Daedalian Opus.
|
||||
Fixed various minor bugs found by enabling compiler warnings.
|
||||
Spacebar was not working with SDL. Fixed.
|
||||
Fixed bug that made OAM unreadable.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.9
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
DOS port is now entirely thinlib-based. Should be more robust, featureful.
|
||||
For example, custom video modes such as 256x224 are available.
|
||||
|
||||
PERFORMANCE
|
||||
|
||||
New asm routines for displaying the background layer on color games.
|
||||
This results in a significant performance boost low-end machines (~P75).
|
||||
SDL code no longer fakes 16bpp but uses the native color depth.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
SDL gnuboy no longer produces random pops in sound at startup.
|
||||
Mono/stereo should now be handled correctly in the SDL code.
|
||||
Eliminated compiletime error about SDL_DISABLE on SDL ver < 1.1.8.
|
||||
Serious bug -- loading savestates was not updating the memory bank map --
|
||||
resulted in bogus behavior after loading in certain situations.
|
||||
Scrapped SDL_HWSURFACE to make fullscreen work on Windows.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.8
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Native SDL sound support. This means sound will work on BeOS and Windows.
|
||||
Sprites are priority sorted on DMG games by default now.
|
||||
ROMs can be loaded from stdin using "-" as the filename.
|
||||
SDL port now runs fullscreen by default. Set sdl_fullscreen to 0 to disable.
|
||||
SDL port now supports alt+enter fullscreen toggle.
|
||||
Integrated Windows port by mewse (using SDL and mingw32).
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Added support for undocumented ram size 05 (presumably 256 kbit).
|
||||
This fixes the crash with Pokemon Crystal.
|
||||
Removed hacks for Altered Space and W&W because they break other games.
|
||||
Added new VBLANK code that should fix them again without breaking other stuff.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
SDL keyboard handler was not accepting the numeral keys.
|
||||
SDL video was messed up bad when it couldn't get a true 160x144 display.
|
||||
Loading a ROM with bogus ROM/RAM size headers used to crash the program.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.7
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
DOS sound support!
|
||||
VESA video modes on DOS!
|
||||
Mono sound for cards that don't support stereo.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Altered Space and Wizards & Warriors now run.
|
||||
Change was made to VBLANK behavior; hopefully it doesn't break other games.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Envelope length was being computed wrong.
|
||||
HDMA was incorrectly taking place all at once.
|
||||
Command line parsing incorrectly changed - to _ in places it shouldn't.
|
||||
SDL joystick support was not building correctly on non-Linux systems.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.5
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Showing the name from the ROM header in X11 and SDL titlebars.
|
||||
The various targets can be disabled at compiletime with --without-* options.
|
||||
OSS sound support might work on FreeBSD and OpenBSD but is untested.
|
||||
SDL joystick support.
|
||||
GNU make no longer required to compile.
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
Flags handling in the C and asm cpu cores should be faster.
|
||||
Word-at-a-time memory I/O is now done more efficiently.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Highcolor screens no longer flicker.
|
||||
Misplaced high-pitched beeps in sound have been removed, again.
|
||||
C graphics code was misaligning the screen by one pixel. Fixed.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.4
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Linux fbcon display support.
|
||||
Linux joystick device support.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
HDMA now works in DKC and Lemmings Color.
|
||||
Default wave pattern is now supported.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.2
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
SDL port!
|
||||
Sound channel 4.
|
||||
MBC3 RTC support.
|
||||
|
||||
COMPATIBILITY
|
||||
|
||||
Sound is now properly handled in savestates.
|
||||
Pokemon Silver and Gold should now be playable.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
Another bug in sweep.
|
||||
Nasty aliasing from extremely high sound frequencies.
|
||||
|
||||
|
||||
|
||||
RELEASE 0.9.1
|
||||
|
||||
NEW FEATURES
|
||||
|
||||
Experimental sound support!
|
||||
Better command line parsing.
|
||||
Added --showvars command line option.
|
||||
Various optimizations.
|
||||
|
||||
BUGS FIXED
|
||||
|
||||
HDMA bug.
|
||||
LCDC STAT interrupt bug.
|
||||
|
||||
|
||||
|
||||
NOTE: Earlier releases have not yet been documented in this file.
|
||||
Hopefully they'll be added eventually, at least for the sake of
|
||||
completing the records.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "regs.h"
|
||||
#include "hw.h"
|
||||
#include "cpu.h"
|
||||
#include "mem.h"
|
||||
#include "lcd.h"
|
||||
#include "rc.h"
|
||||
|
||||
|
||||
static int framelen = 16743;
|
||||
static int framecount;
|
||||
|
||||
rcvar_t emu_exports[] =
|
||||
{
|
||||
RCV_INT("framelen", &framelen),
|
||||
RCV_INT("framecount", &framecount),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void emu_init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* emu_reset is called to initialize the state of the emulated
|
||||
* system. It should set cpu registers, hardware registers, etc. to
|
||||
* their appropriate values at powerup time.
|
||||
*/
|
||||
|
||||
void emu_reset()
|
||||
{
|
||||
hw_reset();
|
||||
lcd_reset();
|
||||
cpu_reset();
|
||||
mbc_reset();
|
||||
sound_reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void emu_step()
|
||||
{
|
||||
cpu_emulate(cpu.lcdc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This mess needs to be moved to another module; it's just here to
|
||||
* make things work in the mean time. */
|
||||
|
||||
void *sys_timer();
|
||||
|
||||
void emu_run()
|
||||
{
|
||||
void *timer = sys_timer();
|
||||
int delay;
|
||||
|
||||
vid_begin();
|
||||
lcd_begin();
|
||||
for (;;)
|
||||
{
|
||||
cpu_emulate(2280);
|
||||
while (R_LY > 0 && R_LY < 144)
|
||||
emu_step();
|
||||
|
||||
vid_end();
|
||||
rtc_tick();
|
||||
sound_mix();
|
||||
if (!pcm_submit())
|
||||
{
|
||||
delay = framelen - sys_elapsed(timer);
|
||||
sys_sleep(delay);
|
||||
sys_elapsed(timer);
|
||||
}
|
||||
doevents();
|
||||
vid_begin();
|
||||
if (framecount) { if (!--framecount) die("finished\n"); }
|
||||
|
||||
if (!(R_LCDC & 0x80))
|
||||
cpu_emulate(32832);
|
||||
|
||||
while (R_LY > 0) /* wait for next frame */
|
||||
emu_step();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
# classic.rc - change keybindings, palette, etc
|
||||
# to match the old pre-1.0 settings.
|
||||
#
|
||||
|
||||
unbindall
|
||||
|
||||
bind esc quit
|
||||
bind up +up
|
||||
bind down +down
|
||||
bind left +left
|
||||
bind right +right
|
||||
bind alt +a
|
||||
bind ctrl +b
|
||||
bind enter +start
|
||||
bind space +select
|
||||
bind joyup +up
|
||||
bind joydown +down
|
||||
bind joyleft +left
|
||||
bind joyright +right
|
||||
bind joy0 +b
|
||||
bind joy1 +a
|
||||
bind joy2 +select
|
||||
bind joy3 +start
|
||||
bind 1 "set saveslot 1"
|
||||
bind 2 "set saveslot 2"
|
||||
bind 3 "set saveslot 3"
|
||||
bind 4 "set saveslot 4"
|
||||
bind 5 "set saveslot 5"
|
||||
bind 6 "set saveslot 6"
|
||||
bind 7 "set saveslot 7"
|
||||
bind 8 "set saveslot 8"
|
||||
bind 9 "set saveslot 9"
|
||||
bind 0 "set saveslot 0"
|
||||
bind ins savestate
|
||||
bind del loadstate
|
||||
|
||||
set dmg_bgp 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_wndp 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_obp0 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_obp1 0x78f0f0 0x58b8b8 0x487878 0x184848
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#
|
||||
# Explanation of the filters:
|
||||
#
|
||||
# If, for example, red is set to "a b c d",
|
||||
# where a, b, c, and d are four numbers,
|
||||
# then the output red value for a given input
|
||||
# color will be computed as follows:
|
||||
#
|
||||
# output_red = ( a * input_red +
|
||||
# b * input_green +
|
||||
# c * input_blue ) / 256 + d
|
||||
#
|
||||
# So, a, b, and c are scale factors
|
||||
# (out of 256) for how much weight the input
|
||||
# red, green, and blue components have in the
|
||||
# output color, and d is a constant base
|
||||
# value for the output.
|
||||
#
|
||||
# Below are some sample filters, which should
|
||||
# make everything more clear.
|
||||
#
|
||||
|
||||
# Default filter as of 1.0.3
|
||||
set red 195 25 0 35
|
||||
set green 25 170 25 35
|
||||
set blue 25 60 125 40
|
||||
|
||||
# Do-nothing filer
|
||||
set red 256 0 0 0
|
||||
set green 0 256 0 0
|
||||
set blue 0 0 256 0
|
||||
|
||||
# Lighten the display uniformly
|
||||
set red 128 0 0 128
|
||||
set green 0 128 0 128
|
||||
set blue 0 0 128 128
|
||||
|
||||
# Grayscale
|
||||
set red 85 85 85 0
|
||||
set green 85 85 85 0
|
||||
set blue 85 85 85 0
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.0.1 (GNU/Linux)
|
||||
Comment: For info see http://www.gnupg.org
|
||||
|
||||
mQGiBDp47IARBACeZ/JuuNwArXaMl+9DGG0BSMPv1qJUYNdDqFREg60GDZRrChAV
|
||||
WhSgpZ/NmSNAS8p4AYTtKIIrb0rMbNnEiaPqjftBFFe2JJ52fXsEosw3xk/v556E
|
||||
spAdimPPnng7z6hb4QZitrtco5SxfKUAkZzBVJbZRYCuLu4XHZcbooLshwCg5Jb9
|
||||
Wr6ha8LPNh/nL39J0dDki2UD/RQKzlJWctiSc7jGgCy49GABOb5BiI07cUdOkfwL
|
||||
eDUS+x/O6Dx8pxmwZJMw9LVOlIHhCwwSlT03Rh7bG6l7sWTuij+HFfSYe4UAgj/E
|
||||
Vi6n5j8efNcc61x8NMvrZxuyBwomxKX9y9m1OOxKSpcxFTW2to7YGn9JUXsvSoOV
|
||||
O2dtBACVazyx6Up+8FVKBzM+W4XW1n5em9dqzDbuxAUwvQ7PpC3lP4OJfiyk1ZcX
|
||||
US0bs4Hu8CyitLTm+UIY7+Yfjov5Iye5gjZ4/KnTQndT9uPPmpBNE1xNfrRsaM2j
|
||||
ZYt4rRAUvExKmVUE/x2Z5FxGHmCgw6u/2DEzS/yR8B5sk7SjFrQbTGFndW5hIDxn
|
||||
bnVib3lAc3RhcmZveC5vcmc+iFYEExECABYFAjp47IEECwoEAwMVAwIDFgIBAheA
|
||||
AAoJEBc0OAlJqLdjGNMAn0JBGXpsfdwPpDJlnU8C0hVxLGZyAKCderbZzS1YXkdB
|
||||
WXwkqXuvZ6mjZLkCDQQ6eOyhEAgAwtcGa52r71LZJryOkpE/spACxlCfQyAIrQFC
|
||||
bT9h5aJ5uzmUe8F8446Ex+yGqk+uvxLKFuIpO8iqkbKoVEPC0lneH/1msV8begii
|
||||
sz9VjFD+HEtbmSWU9SG5/Dzf6GV6anSWanzP+kZ9rDX6GgUyxy1LSJSUjyTOaxy2
|
||||
+jSrbaf/HDmG7NVuRy40Yql2fgpvC8zrb5C3kjUY5c4CZTUnTSdE7xlDD2d4+xL/
|
||||
3KA2JFTU98kKVp23nn7NVfaQbUCg7mqa3iEjTS5WbRH+yaLga4s0WfNXjadbCjfl
|
||||
jR5ZtnfPfm4dNNtSpbNf8AYL0H6R/dW9d3NtL8785XoqAwREgwADBQgAiWBsrxYC
|
||||
gImk6tycqUyeHKf2y+jwoXYGkNc1gM2uMcAeculE/q8eA9chF+aL3fkGr4/JsVUL
|
||||
FGD6cc5Uz+QSFZQNU522SVAa8kqM+GiuFm7vszn3j3Y4KaLAYTb6tr/Zi4BymGqg
|
||||
oPEcAhvCGX/CcktFaU21pFDihrmete3j6SrGYSISWtVP9v1SDg+ooXw6FnrT46kd
|
||||
8skCCTEEEA9tfwSOxyNKuAIA0BWQuskmRwaovJSswusZ7VfDojTQm7dthLobj6A1
|
||||
l9I9mssTElKKslx0dGDyJ1mCrLtBzNHV1br0rck9rGVcJD6K5s5D8wgyhoYPe3NZ
|
||||
8K4jAiogvnaiRIhGBBgRAgAGBQI6eOyhAAoJEBc0OAlJqLdjMWYAoLYCWUmd21fl
|
||||
YHa2CuCBshplXI9sAKCXSy1eGBA1a9LQUhH6JoYJ1e6WpQ==
|
||||
=cjF6
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,97 @@
|
|||
#
|
||||
# palettes.rc - lots of sample dmg palettes
|
||||
# copy the one you want to use into your gnuboy.rc
|
||||
#
|
||||
|
||||
|
||||
# New default palette for version 1.0.
|
||||
set dmg_bgp 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C
|
||||
set dmg_wndp 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C
|
||||
set dmg_obp0 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C
|
||||
set dmg_obp1 0x98d0e0 0x68a0b0 0x60707C 0x2C3C3C
|
||||
|
||||
# Old default palette from 0.8.0 thru 0.9.13.
|
||||
# This was designed for use on a laptop display,
|
||||
# so it's probably way too yellowish.
|
||||
set dmg_bgp 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_wndp 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_obp0 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
set dmg_obp1 0x78f0f0 0x58b8b8 0x487878 0x184848
|
||||
|
||||
# Old dim grayscale.
|
||||
set dmg_bgp 0xc0c0c0 0x808080 0x404040 0x000000
|
||||
set dmg_wndp 0xc0c0c0 0x808080 0x404040 0x000000
|
||||
set dmg_obp0 0xc0c0c0 0x808080 0x404040 0x000000
|
||||
set dmg_obp1 0xc0c0c0 0x808080 0x404040 0x000000
|
||||
|
||||
# Light grayscale.
|
||||
set dmg_bgp 0xffffff 0xc0c0c0 0x808080 0x404040
|
||||
set dmg_wndp 0xffffff 0xc0c0c0 0x808080 0x404040
|
||||
set dmg_obp0 0xffffff 0xc0c0c0 0x808080 0x404040
|
||||
set dmg_obp1 0xffffff 0xc0c0c0 0x808080 0x404040
|
||||
|
||||
# Full contrast grayscale.
|
||||
set dmg_bgp 0xffffff 0xaaaaaa 0x555555 0x000000
|
||||
set dmg_wndp 0xffffff 0xaaaaaa 0x555555 0x000000
|
||||
set dmg_obp0 0xffffff 0xaaaaaa 0x555555 0x000000
|
||||
set dmg_obp1 0xffffff 0xaaaaaa 0x555555 0x000000
|
||||
|
||||
# Debug palette.
|
||||
# Each of the four layers is colored differently,
|
||||
# making it easier to debug visual glitches in roms
|
||||
# that use them all together cleverly.
|
||||
set dmg_bgp 0xf898c8 0xf83098 0xc80060 0x600030
|
||||
set dmg_wndp 0xd0c0c0 0xa88080 0x785050 0x382828
|
||||
set dmg_obp0 0x9898f8 0x3030f8 0x0000c8 0x000060
|
||||
set dmg_obp1 0xc8f898 0x98f830 0x60c800 0x306000
|
||||
|
||||
# Sprites standout.
|
||||
# Similar to above, but the colors are more subdued and
|
||||
# the window and background are the same. This palette
|
||||
# may actually be suitable for playing some games...
|
||||
set dmg_bgp 0xd0c0c0 0xa88080 0x785050 0x382828
|
||||
set dmg_wndp 0xd0c0c0 0xa88080 0x785050 0x382828
|
||||
set dmg_obp0 0xc8e0f8 0x90a8e8 0x4878a8 0x183850
|
||||
set dmg_obp1 0x98b8f8 0x3050f8 0x2040a8 0x002060
|
||||
|
||||
# LCD yellows and grays.
|
||||
# An earlier version of the new default palette.
|
||||
set dmg_bgp 0x88e0f0 0x68a8b8 0x586878 0x283838
|
||||
set dmg_wndp 0x88e0f0 0x68a8b8 0x586878 0x283838
|
||||
set dmg_obp0 0x88e0f0 0x68a8b8 0x586878 0x283838
|
||||
set dmg_obp1 0x88e0f0 0x68a8b8 0x586878 0x283838
|
||||
|
||||
# LCD yellowscale.
|
||||
# And another similar one.
|
||||
set dmg_bgp 0x88e0f0 0x68a8b8 0x486878 0x203838
|
||||
set dmg_wndp 0x88e0f0 0x68a8b8 0x486878 0x203838
|
||||
set dmg_obp0 0x88e0f0 0x68a8b8 0x486878 0x203838
|
||||
set dmg_obp1 0x88e0f0 0x68a8b8 0x486878 0x203838
|
||||
|
||||
# Slightly colorful.
|
||||
# Not just a plain lightness gradient, but some change
|
||||
# in hue as well. Looks ok with some games; designed in
|
||||
# particular for the FFL series.
|
||||
set dmg_bgp 0x98e0f8 0x78a0c0 0x747080 0x604038
|
||||
set dmg_wndp 0x98e0f8 0x78a0c0 0x747080 0x604038
|
||||
set dmg_obp0 0x98e0f8 0x78a0c0 0x747080 0x604038
|
||||
set dmg_obp1 0x98e0f8 0x78a0c0 0x747080 0x604038
|
||||
|
||||
# Optionally use these with the above palette to make
|
||||
# sprites stand out a bit.
|
||||
set dmg_obp0 0x98e0f8 0x5090c0 0x507898 0x583838
|
||||
set dmg_obp1 0x98e0f8 0x5090c0 0x686078 0x383838
|
||||
|
||||
# R-Type 1 palette from R-Type DX
|
||||
set dmg_bgp 0xc0ffff 0x408080 0x204040 0x000000
|
||||
set dmg_wndp 0xc0ffff 0x408080 0x204040 0x000000
|
||||
set dmg_obp0 0xc0ffff 0x408080 0x204040 0x000000
|
||||
set dmg_obp1 0xc0ffff 0x408080 0x204040 0x000000
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#
|
||||
# Sample rc file for gnuboy
|
||||
#
|
||||
# You may want to rename this to gnuboy.rc to use it.
|
||||
# Lines that begin with # are comments.
|
||||
#
|
||||
|
||||
|
||||
# Some keybindings
|
||||
|
||||
bind q quit
|
||||
bind r reset
|
||||
|
||||
bind d +a
|
||||
bind s +b
|
||||
|
||||
# Normal speed/fast forward
|
||||
# Note that these only work with sound disabled
|
||||
bind - "set framelen 16743"
|
||||
bind + "set framelen 0"
|
||||
|
||||
|
||||
# Set video mode to 400x300x16bpp
|
||||
set vmode 400 300 16
|
||||
|
||||
|
||||
# Enable full 2x screen scaling
|
||||
# This will not work if your video mode is smaller than 320x288!
|
||||
set scale 2
|
||||
set density 2
|
||||
|
||||
|
||||
# Enable stereo sound. Doesn't work on all systems
|
||||
#set stereo true
|
||||
|
||||
|
||||
# Path settings for DOS port - uncomment to use them!
|
||||
|
||||
#set rcpath c:/gnuboy
|
||||
#set savedir c:/gnuboy/saves
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You get the idea by now...
|
||||
# See the README for more information on rc commands and vars.
|
||||
#
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* events.c
|
||||
*
|
||||
* Event queue.
|
||||
*/
|
||||
|
||||
|
||||
#include "input.h"
|
||||
|
||||
|
||||
char keystates[MAX_KEYS];
|
||||
int nkeysdown;
|
||||
|
||||
#define MAX_EVENTS 32
|
||||
|
||||
static event_t eventqueue[MAX_EVENTS];
|
||||
static int eventhead, eventpos;
|
||||
|
||||
|
||||
int ev_postevent(event_t *ev)
|
||||
{
|
||||
int nextevent;
|
||||
nextevent = (eventhead+1)%MAX_EVENTS;
|
||||
if (nextevent == eventpos)
|
||||
return 0;
|
||||
eventqueue[eventhead] = *ev;
|
||||
eventhead = nextevent;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ev_getevent(event_t *ev)
|
||||
{
|
||||
if (eventpos == eventhead)
|
||||
{
|
||||
ev->type = EV_NONE;
|
||||
return 0;
|
||||
}
|
||||
*ev = eventqueue[eventpos];
|
||||
eventpos = (eventpos+1)%MAX_EVENTS;
|
||||
if (ev->type == EV_PRESS)
|
||||
{
|
||||
keystates[ev->code] = 1;
|
||||
nkeysdown++;
|
||||
}
|
||||
if (ev->type == EV_RELEASE)
|
||||
{
|
||||
keystates[ev->code] = 0;
|
||||
nkeysdown--;
|
||||
if (nkeysdown < 0) nkeysdown = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rc.h"
|
||||
|
||||
extern rcvar_t rcfile_exports[], emu_exports[], loader_exports[],
|
||||
lcd_exports[], rtc_exports[], debug_exports[], sound_exports[],
|
||||
vid_exports[], joy_exports[], pcm_exports[];
|
||||
|
||||
|
||||
rcvar_t *sources[] =
|
||||
{
|
||||
rcfile_exports,
|
||||
emu_exports,
|
||||
loader_exports,
|
||||
lcd_exports,
|
||||
rtc_exports,
|
||||
debug_exports,
|
||||
sound_exports,
|
||||
vid_exports,
|
||||
joy_exports,
|
||||
pcm_exports,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
void init_exports()
|
||||
{
|
||||
rcvar_t **s = sources;
|
||||
|
||||
while (*s)
|
||||
rc_exportvars(*(s++));
|
||||
}
|
||||
|
||||
|
||||
void show_exports()
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; sources[i]; i++)
|
||||
for (j = 0; sources[i][j].name; j++)
|
||||
printf("%s\n", sources[i][j].name);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
|
||||
#include "fastmem.h"
|
||||
|
||||
|
||||
#define D 0 /* direct */
|
||||
#define C 1 /* direct cgb-only */
|
||||
#define R 2 /* io register */
|
||||
#define S 3 /* sound register */
|
||||
#define W 4 /* wave pattern */
|
||||
|
||||
#define F 0xFF /* fail */
|
||||
|
||||
const byte himask[256];
|
||||
|
||||
const byte hi_rmap[256] =
|
||||
{
|
||||
0, 0, R, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S,
|
||||
S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, C, 0, C,
|
||||
0, C, C, C, C, C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, C, C, C, C, 0, 0, 0, 0,
|
||||
C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const byte hi_wmap[256] =
|
||||
{
|
||||
R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R,
|
||||
S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S,
|
||||
S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S,
|
||||
S, S, S, S, S, S, S, S, S, S, S, S, S, S, S, S,
|
||||
R, R, R, R, R, R, R, R, R, R, R, R, 0, R, 0, R,
|
||||
0, C, C, C, C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, R, R, R, R, 0, 0, 0, 0,
|
||||
R, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, R
|
||||
};
|
||||
|
||||
|
||||
void sound_write();
|
||||
static void no_write()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
#ifndef __FASTMEM_H__
|
||||
#define __FASTMEM_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
static byte readb(int a)
|
||||
{
|
||||
byte *p = mbc.rmap[a>>12];
|
||||
if (p) return p[a];
|
||||
else return mem_read(a);
|
||||
}
|
||||
|
||||
static void writeb(int a, byte b)
|
||||
{
|
||||
byte *p = mbc.wmap[a>>12];
|
||||
if (p) p[a] = b;
|
||||
else mem_write(a, b);
|
||||
}
|
||||
|
||||
static int readw(int a)
|
||||
{
|
||||
if ((a+1) & 0xfff)
|
||||
{
|
||||
byte *p = mbc.rmap[a>>12];
|
||||
if (p)
|
||||
{
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#ifndef ALLOW_UNALIGNED_IO
|
||||
if (a&1) return p[a] | (p[a+1]<<8);
|
||||
#endif
|
||||
return *(word *)(p+a);
|
||||
#else
|
||||
return p[a] | (p[a+1]<<8);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return mem_read(a) | (mem_read(a+1)<<8);
|
||||
}
|
||||
|
||||
static void writew(int a, int w)
|
||||
{
|
||||
if ((a+1) & 0xfff)
|
||||
{
|
||||
byte *p = mbc.wmap[a>>12];
|
||||
if (p)
|
||||
{
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#ifndef ALLOW_UNALIGNED_IO
|
||||
if (a&1)
|
||||
{
|
||||
p[a] = w;
|
||||
p[a+1] = w >> 8;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
*(word *)(p+a) = w;
|
||||
return;
|
||||
#else
|
||||
p[a] = w;
|
||||
p[a+1] = w >> 8;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mem_write(a, w);
|
||||
mem_write(a+1, w>>8);
|
||||
}
|
||||
|
||||
static byte readhi(int a)
|
||||
{
|
||||
return readb(a | 0xff00);
|
||||
}
|
||||
|
||||
static void writehi(int a, byte b)
|
||||
{
|
||||
writeb(a | 0xff00, b);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static byte readhi(int a)
|
||||
{
|
||||
byte (*rd)() = hi_read[a];
|
||||
return rd ? rd(a) : (ram.hi[a] | himask[a]);
|
||||
}
|
||||
|
||||
static void writehi(int a, byte b)
|
||||
{
|
||||
byte (*wr)() = hi_write[a];
|
||||
if (wr) wr(a, b);
|
||||
else ram.hi[a] = b & ~himask[a];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
|
||||
#ifndef __FB_H__
|
||||
#define __FB_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
struct fb
|
||||
{
|
||||
byte *ptr;
|
||||
int w, h;
|
||||
int pelsize;
|
||||
int pitch;
|
||||
int indexed;
|
||||
struct
|
||||
{
|
||||
int l, r;
|
||||
} cc[4];
|
||||
int yuv;
|
||||
int enabled;
|
||||
int dirty;
|
||||
};
|
||||
|
||||
|
||||
extern struct fb fb;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "cpu.h"
|
||||
#include "hw.h"
|
||||
#include "regs.h"
|
||||
#include "lcd.h"
|
||||
#include "mem.h"
|
||||
#include "fastmem.h"
|
||||
|
||||
|
||||
struct hw hw;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* hw_interrupt changes the virtual interrupt lines included in the
|
||||
* specified mask to the values the corresponding bits in i take, and
|
||||
* in doing so, raises the appropriate bit of R_IF for any interrupt
|
||||
* lines that transition from low to high.
|
||||
*/
|
||||
|
||||
void hw_interrupt(byte i, byte mask)
|
||||
{
|
||||
byte oldif = R_IF;
|
||||
i &= 0x1F & mask;
|
||||
R_IF |= i & (hw.ilines ^ i);
|
||||
|
||||
/* FIXME - is this correct? not sure the docs understand... */
|
||||
if ((R_IF & (R_IF ^ oldif) & R_IE) && cpu.ime) cpu.halt = 0;
|
||||
/* if ((i & (hw.ilines ^ i) & R_IE) && cpu.ime) cpu.halt = 0; */
|
||||
/* if ((i & R_IE) && cpu.ime) cpu.halt = 0; */
|
||||
|
||||
hw.ilines &= ~mask;
|
||||
hw.ilines |= i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hw_dma performs plain old memory-to-oam dma, the original dmg
|
||||
* dma. Although on the hardware it takes a good deal of time, the cpu
|
||||
* continues running during this mode of dma, so no special tricks to
|
||||
* stall the cpu are necessary.
|
||||
*/
|
||||
|
||||
void hw_dma(byte b)
|
||||
{
|
||||
int i;
|
||||
addr a;
|
||||
|
||||
a = ((addr)b) << 8;
|
||||
for (i = 0; i < 160; i++, a++)
|
||||
lcd.oam.mem[i] = readb(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void hw_hdma_cmd(byte c)
|
||||
{
|
||||
int cnt;
|
||||
addr sa;
|
||||
int da;
|
||||
|
||||
/* Begin or cancel HDMA */
|
||||
if ((hw.hdma|c) & 0x80)
|
||||
{
|
||||
hw.hdma = c;
|
||||
R_HDMA5 = c & 0x7f;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perform GDMA */
|
||||
sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0);
|
||||
da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0);
|
||||
cnt = ((int)c)+1;
|
||||
/* FIXME - this should use cpu time! */
|
||||
/*cpu_timers(102 * cnt);*/
|
||||
cnt <<= 4;
|
||||
while (cnt--)
|
||||
writeb(da++, readb(sa++));
|
||||
R_HDMA1 = sa >> 8;
|
||||
R_HDMA2 = sa & 0xF0;
|
||||
R_HDMA3 = 0x1F & (da >> 8);
|
||||
R_HDMA4 = da & 0xF0;
|
||||
R_HDMA5 = 0xFF;
|
||||
}
|
||||
|
||||
|
||||
void hw_hdma()
|
||||
{
|
||||
int cnt;
|
||||
addr sa;
|
||||
int da;
|
||||
|
||||
sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0);
|
||||
da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0);
|
||||
cnt = 16;
|
||||
while (cnt--)
|
||||
writeb(da++, readb(sa++));
|
||||
R_HDMA1 = sa >> 8;
|
||||
R_HDMA2 = sa & 0xF0;
|
||||
R_HDMA3 = 0x1F & (da >> 8);
|
||||
R_HDMA4 = da & 0xF0;
|
||||
R_HDMA5--;
|
||||
hw.hdma--;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* pad_refresh updates the P1 register from the pad states, generating
|
||||
* the appropriate interrupts (by quickly raising and lowering the
|
||||
* interrupt line) if a transition has been made.
|
||||
*/
|
||||
|
||||
void pad_refresh()
|
||||
{
|
||||
byte oldp1;
|
||||
oldp1 = R_P1;
|
||||
R_P1 &= 0x30;
|
||||
R_P1 |= 0xc0;
|
||||
if (!(R_P1 & 0x10))
|
||||
R_P1 |= (hw.pad & 0x0F);
|
||||
if (!(R_P1 & 0x20))
|
||||
R_P1 |= (hw.pad >> 4);
|
||||
R_P1 ^= 0x0F;
|
||||
if (oldp1 & ~R_P1 & 0x0F)
|
||||
{
|
||||
hw_interrupt(IF_PAD, IF_PAD);
|
||||
hw_interrupt(0, IF_PAD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These simple functions just update the state of a button on the
|
||||
* pad.
|
||||
*/
|
||||
|
||||
void pad_press(byte k)
|
||||
{
|
||||
if (hw.pad & k)
|
||||
return;
|
||||
hw.pad |= k;
|
||||
pad_refresh();
|
||||
}
|
||||
|
||||
void pad_release(byte k)
|
||||
{
|
||||
if (!(hw.pad & k))
|
||||
return;
|
||||
hw.pad &= ~k;
|
||||
pad_refresh();
|
||||
}
|
||||
|
||||
void pad_set(byte k, int st)
|
||||
{
|
||||
st ? pad_press(k) : pad_release(k);
|
||||
}
|
||||
|
||||
void hw_reset()
|
||||
{
|
||||
hw.ilines = hw.pad = 0;
|
||||
|
||||
memset(ram.hi, 0, sizeof ram.hi);
|
||||
|
||||
R_P1 = 0xFF;
|
||||
R_LCDC = 0x91;
|
||||
R_BGP = 0xFC;
|
||||
R_OBP0 = 0xFF;
|
||||
R_OBP1 = 0xFF;
|
||||
R_SVBK = 0x01;
|
||||
R_HDMA5 = 0xFF;
|
||||
R_VBK = 0xFE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
|
||||
|
||||
#ifndef __HW_H__
|
||||
#define __HW_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
#define PAD_RIGHT 0x01
|
||||
#define PAD_LEFT 0x02
|
||||
#define PAD_UP 0x04
|
||||
#define PAD_DOWN 0x08
|
||||
#define PAD_A 0x10
|
||||
#define PAD_B 0x20
|
||||
#define PAD_SELECT 0x40
|
||||
#define PAD_START 0x80
|
||||
|
||||
#define IF_VBLANK 0x01
|
||||
#define IF_STAT 0x02
|
||||
#define IF_TIMER 0x04
|
||||
#define IF_SERIAL 0x08
|
||||
#define IF_PAD 0x10
|
||||
|
||||
struct hw
|
||||
{
|
||||
byte ilines;
|
||||
byte pad;
|
||||
int cgb, gba;
|
||||
int hdma;
|
||||
};
|
||||
|
||||
|
||||
extern struct hw hw;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,512 @@
|
|||
|
||||
/* Slightly modified from its original form so as not to exit the
|
||||
* program on errors. The resulting file remains in the public
|
||||
* domain for all to use. */
|
||||
|
||||
/* --- GZIP file format uncompression routines --- */
|
||||
|
||||
/* The following routines (notably the unzip()) function below
|
||||
* uncompress gzipped data. They are terribly slow at the task, but
|
||||
* it is presumed that they work reasonably well. They don't do any
|
||||
* error checking, but they're probably not too vulnerable to buggy
|
||||
* data either. Another important limitation (but it would be pretty
|
||||
* easy to get around) is that the data must reside in memory, it is
|
||||
* not read as a stream. They have been very little tested. Anyway,
|
||||
* whatever these functions are good for, I put them in the public
|
||||
* domain. -- David Madore <david.madore@ens.fr> 1999/11/21 */
|
||||
|
||||
static unsigned int
|
||||
peek_bits (const unsigned char *data, long p, int q)
|
||||
/* Read q bits starting from bit p from the data pointed to by
|
||||
* data. Data is in little-endian format. */
|
||||
{
|
||||
unsigned int answer;
|
||||
int cnt; /* Number of bits already placed in answer */
|
||||
char ob, lb; /* Offset and length of bit field within current byte */
|
||||
|
||||
answer = 0;
|
||||
for ( cnt=0 ; cnt<q ; /* cnt updated in body */ )
|
||||
{
|
||||
ob = (p+cnt)%8;
|
||||
lb = 8-ob;
|
||||
if ( cnt+lb > q )
|
||||
lb = q-cnt;
|
||||
answer |= ((unsigned int)((data[(p+cnt)/8]>>ob)&((1U<<lb)-1)))<<cnt;
|
||||
cnt += lb;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
read_bits (const unsigned char *data, long *p, int q)
|
||||
/* Read q bits as per peek_bits(), but also increase p by q. */
|
||||
{
|
||||
unsigned int answer;
|
||||
|
||||
answer = peek_bits (data, *p, q);
|
||||
*p += q;
|
||||
return answer;
|
||||
}
|
||||
|
||||
static void
|
||||
make_code_table (const char size_table[], int table_length,
|
||||
unsigned int code_table[], int maxbits)
|
||||
/* Make a code table from a length table. See rfc1951, section
|
||||
* 3.2.2, for details on what this means. The size_table
|
||||
* contains the length of the Huffman codes for each letter, and
|
||||
* the code_table receives the computed codes themselves.
|
||||
* table_length is the size of the tables (alphabet length) and
|
||||
* maxbits is the maximal allowed code length. */
|
||||
{
|
||||
int i, j;
|
||||
unsigned int code;
|
||||
|
||||
code = 0;
|
||||
for ( i=1 ; i<=maxbits ; i++ )
|
||||
{
|
||||
for ( j=0 ; j<table_length ; j++ )
|
||||
{
|
||||
if ( size_table[j]==i )
|
||||
code_table[j] = code++;
|
||||
}
|
||||
code <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
decode_one (const unsigned char *data, long *p,
|
||||
const char size_table[], int table_length,
|
||||
const unsigned int code_table[], int maxbits)
|
||||
/* Decode one alphabet letter from the data, starting at bit p
|
||||
* (which will be increased by the appropriate amount) using
|
||||
* size_table and code_table to decipher the Huffman encoding. */
|
||||
{
|
||||
unsigned int code;
|
||||
int i, j;
|
||||
|
||||
code = 0;
|
||||
/* Read as many bits as are likely to be necessary - backward, of
|
||||
* course. */
|
||||
for ( i=0 ; i<maxbits ; i++ )
|
||||
code = (code<<1) + peek_bits (data, (*p)+i, 1);
|
||||
/* Now examine each symbol of the table to find one that matches the
|
||||
* first bits of the code read. */
|
||||
for ( j=0 ; j<table_length ; j++ )
|
||||
{
|
||||
if ( size_table[j]
|
||||
&& ( (code>>(maxbits-size_table[j])) == code_table[j] ) )
|
||||
{
|
||||
*p += size_table[j];
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* I don't know what these should be. The rfc1951 doesn't seem to say
|
||||
* (it only mentions them in the last paragraph of section 3.2.1). 15
|
||||
* is almost certainly safe, and it is the largest I can put given the
|
||||
* constraints on the size of integers in the C standard. */
|
||||
#define CLEN_MAXBITS 15
|
||||
#define HLIT_MAXBITS 15
|
||||
#define HDIST_MAXBITS 15
|
||||
|
||||
/* The magical table sizes... */
|
||||
#define CLEN_TSIZE 19
|
||||
#define HLIT_TSIZE 288
|
||||
#define HDIST_TSIZE 30
|
||||
|
||||
static int
|
||||
get_tables (const unsigned char *data, long *p,
|
||||
char hlit_size_table[HLIT_TSIZE],
|
||||
unsigned int hlit_code_table[HLIT_TSIZE],
|
||||
char hdist_size_table[HDIST_TSIZE],
|
||||
unsigned int hdist_code_table[HDIST_TSIZE])
|
||||
/* Fill the Huffman tables (first the code lengths table, and
|
||||
* then, using it, the literal/length table and the distance
|
||||
* table). See section 3.2.7 of rfc1951 for details. */
|
||||
{
|
||||
char hlit, hdist, hclen;
|
||||
const int clen_weird_tangle[CLEN_TSIZE]
|
||||
= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
||||
char clen_size_table[CLEN_TSIZE];
|
||||
unsigned int clen_code_table[CLEN_TSIZE];
|
||||
int j;
|
||||
unsigned int b;
|
||||
int remainder; /* See note at end of section 3.2.7 of rfc1951. */
|
||||
char rem_val;
|
||||
|
||||
hlit = read_bits (data, p, 5);
|
||||
hdist = read_bits (data, p, 5);
|
||||
hclen = read_bits (data, p, 4);
|
||||
for ( j=0 ; j<4+hclen ; j++ )
|
||||
clen_size_table[clen_weird_tangle[j]]
|
||||
= read_bits (data, p, 3);
|
||||
for ( ; j<CLEN_TSIZE ; j++ )
|
||||
clen_size_table[clen_weird_tangle[j]] = 0;
|
||||
make_code_table (clen_size_table, CLEN_TSIZE,
|
||||
clen_code_table, CLEN_MAXBITS);
|
||||
remainder = 0;
|
||||
rem_val = 0;
|
||||
for ( j=0 ; j<257+hlit ; j++ )
|
||||
{
|
||||
b = decode_one (data, p, clen_size_table, CLEN_TSIZE,
|
||||
clen_code_table, CLEN_MAXBITS);
|
||||
if ( b<0 ) return -1;
|
||||
if ( b<16 )
|
||||
hlit_size_table[j] = b;
|
||||
else if ( b == 16 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 2);
|
||||
for ( l=0 ; l<k+3 && j+l<257+hlit ; l++ )
|
||||
hlit_size_table[j+l] = hlit_size_table[j-1];
|
||||
j += l-1;
|
||||
remainder = k+3-l; /* THIS IS SO UGLY! */
|
||||
rem_val = hlit_size_table[j-1];
|
||||
}
|
||||
else if ( b == 17 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 3);
|
||||
for ( l=0 ; l<k+3 && j+l<257+hlit ; l++ )
|
||||
hlit_size_table[j+l] = 0;
|
||||
j += l-1;
|
||||
remainder = k+3-l;
|
||||
rem_val = 0;
|
||||
}
|
||||
else if ( b == 18 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 7);
|
||||
for ( l=0 ; l<k+11 && j+l<257+hlit ; l++ )
|
||||
hlit_size_table[j+l] = 0;
|
||||
j += l-1;
|
||||
remainder = k+11-l;
|
||||
rem_val = 0;
|
||||
}
|
||||
}
|
||||
for ( ; j<HLIT_TSIZE ; j++ )
|
||||
hlit_size_table[j] = 0;
|
||||
make_code_table (hlit_size_table, HLIT_TSIZE,
|
||||
hlit_code_table, HLIT_MAXBITS);
|
||||
for ( j=0 ; j<remainder ; j++ )
|
||||
hdist_size_table[j] = rem_val;
|
||||
for ( ; j<1+hdist ; j++ )
|
||||
/* Can you spell: ``copy-paste''? */
|
||||
{
|
||||
b = decode_one (data, p, clen_size_table, CLEN_TSIZE,
|
||||
clen_code_table, CLEN_MAXBITS);
|
||||
if ( b<0 ) return -1;
|
||||
if ( b<16 )
|
||||
hdist_size_table[j] = b;
|
||||
else if ( b == 16 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 2);
|
||||
for ( l=0 ; l<k+3 && j+l<1+hdist ; l++ )
|
||||
hdist_size_table[j+l] = hdist_size_table[j-1];
|
||||
j += l-1;
|
||||
}
|
||||
else if ( b == 17 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 3);
|
||||
for ( l=0 ; l<k+3 && j+l<1+hdist ; l++ )
|
||||
hdist_size_table[j+l] = 0;
|
||||
j += l-1;
|
||||
}
|
||||
else if ( b == 18 )
|
||||
{
|
||||
int k, l;
|
||||
|
||||
k = read_bits (data, p, 7);
|
||||
for ( l=0 ; l<k+11 && j+l<1+hdist ; l++ )
|
||||
hdist_size_table[j+l] = 0;
|
||||
j += l-1;
|
||||
}
|
||||
}
|
||||
for ( ; j<HDIST_TSIZE ; j++ )
|
||||
hdist_size_table[j] = 0;
|
||||
make_code_table (hdist_size_table, HDIST_TSIZE,
|
||||
hdist_code_table, HDIST_MAXBITS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The (circular) output buffer. This lets us track
|
||||
* backreferences. */
|
||||
|
||||
/* Minimal buffer size. Also the only useful value. */
|
||||
#define BUFFER_SIZE 32768
|
||||
|
||||
/* Pointer to the character to be added to the buffer */
|
||||
static unsigned int buffer_ptr = 0;
|
||||
|
||||
/* The buffer itself */
|
||||
static unsigned char buffer[BUFFER_SIZE];
|
||||
|
||||
static void
|
||||
pushout (unsigned char ch)
|
||||
/* Store one byte in the output buffer so it may be retrieved if
|
||||
* it is referenced again. */
|
||||
{
|
||||
buffer[buffer_ptr++] = ch;
|
||||
buffer_ptr %= BUFFER_SIZE;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
pushin (unsigned int dist)
|
||||
/* Retrieve one byte, dist bytes away, from the output buffer. */
|
||||
{
|
||||
return buffer[(buffer_ptr+(BUFFER_SIZE-dist))%BUFFER_SIZE];
|
||||
}
|
||||
|
||||
static int
|
||||
get_data (const unsigned char *data, long *p,
|
||||
const char hlit_size_table[HLIT_TSIZE],
|
||||
const unsigned int hlit_code_table[HLIT_TSIZE],
|
||||
const char hdist_size_table[HDIST_TSIZE],
|
||||
const unsigned int hdist_code_table[HDIST_TSIZE],
|
||||
void (* callback) (unsigned char d))
|
||||
/* Do the actual uncompressing. Call callback on each character
|
||||
* uncompressed. */
|
||||
{
|
||||
unsigned int b;
|
||||
|
||||
while ( 1 ) {
|
||||
b = decode_one (data, p, hlit_size_table, HLIT_TSIZE,
|
||||
hlit_code_table, HLIT_MAXBITS);
|
||||
if ( b<0 ) return -1;
|
||||
if ( b < 256 )
|
||||
/* Literal */
|
||||
{
|
||||
pushout ((unsigned char) b);
|
||||
callback ((unsigned char) b);
|
||||
}
|
||||
else if ( b == 256 )
|
||||
/* End of block */
|
||||
return 0;
|
||||
else if ( b >= 257 )
|
||||
/* Back reference */
|
||||
{
|
||||
unsigned int bb;
|
||||
unsigned int length, dist;
|
||||
unsigned int l;
|
||||
|
||||
switch ( b )
|
||||
{
|
||||
case 257: length = 3; break;
|
||||
case 258: length = 4; break;
|
||||
case 259: length = 5; break;
|
||||
case 260: length = 6; break;
|
||||
case 261: length = 7; break;
|
||||
case 262: length = 8; break;
|
||||
case 263: length = 9; break;
|
||||
case 264: length = 10; break;
|
||||
case 265: length = 11 + read_bits (data, p, 1); break;
|
||||
case 266: length = 13 + read_bits (data, p, 1); break;
|
||||
case 267: length = 15 + read_bits (data, p, 1); break;
|
||||
case 268: length = 17 + read_bits (data, p, 1); break;
|
||||
case 269: length = 19 + read_bits (data, p, 2); break;
|
||||
case 270: length = 23 + read_bits (data, p, 2); break;
|
||||
case 271: length = 27 + read_bits (data, p, 2); break;
|
||||
case 272: length = 31 + read_bits (data, p, 2); break;
|
||||
case 273: length = 35 + read_bits (data, p, 3); break;
|
||||
case 274: length = 43 + read_bits (data, p, 3); break;
|
||||
case 275: length = 51 + read_bits (data, p, 3); break;
|
||||
case 276: length = 59 + read_bits (data, p, 3); break;
|
||||
case 277: length = 67 + read_bits (data, p, 4); break;
|
||||
case 278: length = 83 + read_bits (data, p, 4); break;
|
||||
case 279: length = 99 + read_bits (data, p, 4); break;
|
||||
case 280: length = 115 + read_bits (data, p, 4); break;
|
||||
case 281: length = 131 + read_bits (data, p, 5); break;
|
||||
case 282: length = 163 + read_bits (data, p, 5); break;
|
||||
case 283: length = 195 + read_bits (data, p, 5); break;
|
||||
case 284: length = 227 + read_bits (data, p, 5); break;
|
||||
case 285: length = 258; break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
bb = decode_one (data, p, hdist_size_table, HDIST_TSIZE,
|
||||
hdist_code_table, HDIST_MAXBITS);
|
||||
switch ( bb )
|
||||
{
|
||||
case 0: dist = 1; break;
|
||||
case 1: dist = 2; break;
|
||||
case 2: dist = 3; break;
|
||||
case 3: dist = 4; break;
|
||||
case 4: dist = 5 + read_bits (data, p, 1); break;
|
||||
case 5: dist = 7 + read_bits (data, p, 1); break;
|
||||
case 6: dist = 9 + read_bits (data, p, 2); break;
|
||||
case 7: dist = 13 + read_bits (data, p, 2); break;
|
||||
case 8: dist = 17 + read_bits (data, p, 3); break;
|
||||
case 9: dist = 25 + read_bits (data, p, 3); break;
|
||||
case 10: dist = 33 + read_bits (data, p, 4); break;
|
||||
case 11: dist = 49 + read_bits (data, p, 4); break;
|
||||
case 12: dist = 65 + read_bits (data, p, 5); break;
|
||||
case 13: dist = 97 + read_bits (data, p, 5); break;
|
||||
case 14: dist = 129 + read_bits (data, p, 6); break;
|
||||
case 15: dist = 193 + read_bits (data, p, 6); break;
|
||||
case 16: dist = 257 + read_bits (data, p, 7); break;
|
||||
case 17: dist = 385 + read_bits (data, p, 7); break;
|
||||
case 18: dist = 513 + read_bits (data, p, 8); break;
|
||||
case 19: dist = 769 + read_bits (data, p, 8); break;
|
||||
case 20: dist = 1025 + read_bits (data, p, 9); break;
|
||||
case 21: dist = 1537 + read_bits (data, p, 9); break;
|
||||
case 22: dist = 2049 + read_bits (data, p, 10); break;
|
||||
case 23: dist = 3073 + read_bits (data, p, 10); break;
|
||||
case 24: dist = 4097 + read_bits (data, p, 11); break;
|
||||
case 25: dist = 6145 + read_bits (data, p, 11); break;
|
||||
case 26: dist = 8193 + read_bits (data, p, 12); break;
|
||||
case 27: dist = 12289 + read_bits (data, p, 12); break;
|
||||
case 28: dist = 16385 + read_bits (data, p, 13); break;
|
||||
case 29: dist = 24577 + read_bits (data, p, 13); break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
for ( l=0 ; l<length ; l++ )
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
ch = pushin (dist);
|
||||
pushout (ch);
|
||||
callback (ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
inflate (const unsigned char *data, long *p,
|
||||
void (* callback) (unsigned char d))
|
||||
/* Main uncompression function for the deflate method */
|
||||
{
|
||||
char blast, btype;
|
||||
char hlit_size_table[HLIT_TSIZE];
|
||||
unsigned int hlit_code_table[HLIT_TSIZE];
|
||||
char hdist_size_table[HDIST_TSIZE];
|
||||
unsigned int hdist_code_table[HDIST_TSIZE];
|
||||
|
||||
again:
|
||||
blast = read_bits (data, p, 1);
|
||||
btype = read_bits (data, p, 2);
|
||||
if ( btype == 1 || btype == 2 )
|
||||
{
|
||||
if ( btype == 2 )
|
||||
{
|
||||
/* Dynamic Huffman tables */
|
||||
if (get_tables (data, p,
|
||||
hlit_size_table, hlit_code_table,
|
||||
hdist_size_table, hdist_code_table) < 0) return -1;
|
||||
}
|
||||
else
|
||||
/* Fixed Huffman codes */
|
||||
{
|
||||
int j;
|
||||
|
||||
for ( j=0 ; j<144 ; j++ )
|
||||
hlit_size_table[j] = 8;
|
||||
for ( ; j<256 ; j++ )
|
||||
hlit_size_table[j] = 9;
|
||||
for ( ; j<280 ; j++ )
|
||||
hlit_size_table[j] = 7;
|
||||
for ( ; j<HLIT_TSIZE ; j++ )
|
||||
hlit_size_table[j] = 8;
|
||||
make_code_table (hlit_size_table, HLIT_TSIZE,
|
||||
hlit_code_table, HLIT_MAXBITS);
|
||||
for ( j=0 ; j<HDIST_TSIZE ; j++ )
|
||||
hdist_size_table[j] = 5;
|
||||
make_code_table (hdist_size_table, HDIST_TSIZE,
|
||||
hdist_code_table, HDIST_MAXBITS);
|
||||
}
|
||||
if (get_data (data, p,
|
||||
hlit_size_table, hlit_code_table,
|
||||
hdist_size_table, hdist_code_table,
|
||||
callback) < 0) return -1;;
|
||||
}
|
||||
else if ( btype == 0 )
|
||||
/* Non compressed block */
|
||||
{
|
||||
unsigned int len, nlen;
|
||||
unsigned int l;
|
||||
unsigned char b;
|
||||
|
||||
*p = (*p+7)/8; /* Jump to next byte boundary */
|
||||
len = read_bits (data, p, 16);
|
||||
nlen = read_bits (data, p, 16);
|
||||
for ( l=0 ; l<len ; l++ )
|
||||
{
|
||||
b = read_bits (data, p, 8);
|
||||
pushout (b);
|
||||
callback (b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ( ! blast )
|
||||
goto again;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
unzip (const unsigned char *data, long *p,
|
||||
void (* callback) (unsigned char d))
|
||||
/* Uncompress gzipped data. data is a pointer to the data, p is
|
||||
* a pointer to a long that is initialized to 0 (unless for some
|
||||
* reason you want to start uncompressing further down the data),
|
||||
* and callback is a function taking an unsigned char and
|
||||
* returning void that will be called successively for every
|
||||
* uncompressed byte. */
|
||||
{
|
||||
unsigned char cm, flg;
|
||||
|
||||
if ( read_bits (data, p, 8) != 0x1f
|
||||
|| read_bits (data, p, 8) != 0x8b )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
cm = read_bits (data, p, 8);
|
||||
if ( cm != 0x8 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
flg = read_bits (data, p, 8);
|
||||
if ( flg & 0xe0 )
|
||||
/* fprintf (stderr, "Warning: unknown bits are set in flags.\n") */ ;
|
||||
read_bits (data, p, 32); /* Ignore modification time */
|
||||
read_bits (data, p, 8); /* Ignore extra flags */
|
||||
read_bits (data, p, 8); /* Ignore OS type */
|
||||
if ( flg & 0x4 )
|
||||
{
|
||||
/* Skip over extra data */
|
||||
unsigned int xlen;
|
||||
|
||||
xlen = read_bits (data, p, 16);
|
||||
*p += ((long)xlen)*8;
|
||||
}
|
||||
if ( flg & 0x8 )
|
||||
{
|
||||
/* Skip over file name */
|
||||
while ( read_bits (data, p, 8) );
|
||||
}
|
||||
if ( flg & 0x10 )
|
||||
{
|
||||
/* Skip over comment */
|
||||
while ( read_bits (data, p, 8) );
|
||||
}
|
||||
if ( flg & 0x2 )
|
||||
/* Ignore CRC16 */
|
||||
read_bits (data, p, 16);
|
||||
return inflate (data, p, callback);
|
||||
/* CRC32 and ISIZE are at the end. We don't even bother to look at
|
||||
* them. */
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* input.h
|
||||
*
|
||||
* Definitions for input device stuff - buttons, keys, etc.
|
||||
*/
|
||||
|
||||
|
||||
#define M_IGNORE 0
|
||||
#define M_RELATIVE 1
|
||||
#define M_ABSOLUTE 2
|
||||
|
||||
|
||||
#define K_SHIFT 0x101
|
||||
#define K_CTRL 0x102
|
||||
#define K_ALT 0x103
|
||||
|
||||
#define K_UP 0x10a
|
||||
#define K_DOWN 0x10b
|
||||
#define K_RIGHT 0x10c
|
||||
#define K_LEFT 0x10d
|
||||
|
||||
#define K_ENTER '\r'
|
||||
#define K_TAB '\t'
|
||||
#define K_SPACE ' '
|
||||
#define K_BS 010
|
||||
#define K_DEL 127
|
||||
#define K_INS 0x121
|
||||
#define K_HOME 0x122
|
||||
#define K_END 0x123
|
||||
#define K_PRIOR 0x124
|
||||
#define K_NEXT 0x125
|
||||
#define K_ESC 033
|
||||
#define K_SYSRQ 0x1fe
|
||||
#define K_PAUSE 0x1ff
|
||||
#define K_CAPS 0x1f1
|
||||
#define K_NUMLOCK 0x1f2
|
||||
#define K_SCROLL 0x1f3
|
||||
|
||||
#define K_MINUS '-'
|
||||
#define K_EQUALS '='
|
||||
#define K_TILDE '~'
|
||||
#define K_SLASH '/'
|
||||
#define K_BSLASH '\\'
|
||||
#define K_SEMI ';'
|
||||
#define K_QUOTE '\''
|
||||
|
||||
#define K_F1 0x131
|
||||
#define K_F2 0x132
|
||||
#define K_F3 0x133
|
||||
#define K_F4 0x134
|
||||
#define K_F5 0x135
|
||||
#define K_F6 0x136
|
||||
#define K_F7 0x137
|
||||
#define K_F8 0x138
|
||||
#define K_F9 0x139
|
||||
#define K_F10 0x13a
|
||||
#define K_F11 0x13b
|
||||
#define K_F12 0x13c
|
||||
|
||||
#define K_NUM0 0x140
|
||||
#define K_NUM1 0x141
|
||||
#define K_NUM2 0x142
|
||||
#define K_NUM3 0x143
|
||||
#define K_NUM4 0x144
|
||||
#define K_NUM5 0x145
|
||||
#define K_NUM6 0x146
|
||||
#define K_NUM7 0x147
|
||||
#define K_NUM8 0x148
|
||||
#define K_NUM9 0x149
|
||||
#define K_NUMPLUS 0x14a
|
||||
#define K_NUMMINUS 0x14b
|
||||
#define K_NUMMUL 0x14c
|
||||
#define K_NUMDIV 0x14d
|
||||
#define K_NUMDOT 0x14e
|
||||
#define K_NUMENTER 0x14f
|
||||
|
||||
#define K_MOUSE0 0x1a0
|
||||
#define K_MOUSE1 0x1a1
|
||||
#define K_MOUSE2 0x1a2
|
||||
#define K_MOUSE3 0x1a3
|
||||
#define K_MOUSE4 0x1a4
|
||||
|
||||
#define K_JOY0 0x1b0
|
||||
#define K_JOY1 0x1b1
|
||||
#define K_JOY2 0x1b2
|
||||
#define K_JOY3 0x1b3
|
||||
#define K_JOY4 0x1b4
|
||||
#define K_JOY5 0x1b5
|
||||
#define K_JOY6 0x1b6
|
||||
#define K_JOY7 0x1b7
|
||||
#define K_JOY8 0x1b8
|
||||
#define K_JOY9 0x1b9
|
||||
#define K_JOY10 0x1ba
|
||||
#define K_JOY11 0x1bb
|
||||
#define K_JOY12 0x1bc
|
||||
#define K_JOY13 0x1bd
|
||||
#define K_JOY14 0x1be
|
||||
#define K_JOY15 0x1bf
|
||||
|
||||
#define K_JOYUP 0x1ca
|
||||
#define K_JOYDOWN 0x1cb
|
||||
#define K_JOYRIGHT 0x1cc
|
||||
#define K_JOYLEFT 0x1cd
|
||||
|
||||
#define MAX_KEYS 0x200
|
||||
|
||||
typedef struct keytable_s
|
||||
{
|
||||
char *name;
|
||||
int code;
|
||||
} keytable_t;
|
||||
|
||||
extern keytable_t keytable[];
|
||||
extern char keystates[MAX_KEYS];
|
||||
extern int nkeysdown;
|
||||
|
||||
|
||||
int k_keycode(char *name);
|
||||
char *k_keyname(int code);
|
||||
|
||||
|
||||
|
||||
typedef struct event_s
|
||||
{
|
||||
int type;
|
||||
int code;
|
||||
int dx, dy;
|
||||
int x, y;
|
||||
} event_t;
|
||||
|
||||
#define EV_NONE 0
|
||||
#define EV_PRESS 1
|
||||
#define EV_RELEASE 2
|
||||
#define EV_REPEAT 3
|
||||
#define EV_MOUSE 4
|
||||
|
||||
int ev_postevent(event_t *ev);
|
||||
int ev_getevent(event_t *ev);
|
||||
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
tranformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* keytable.c
|
||||
*
|
||||
* Key names to keycodes mapping.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "input.h"
|
||||
|
||||
/* keytable - Mapping of key names to codes, and back. A single code
|
||||
can have more than one name, in which case the first will be used
|
||||
when saving config, but any may be used in setting config. */
|
||||
|
||||
keytable_t keytable[] =
|
||||
{
|
||||
{ "shift", K_SHIFT },
|
||||
{ "ctrl", K_CTRL },
|
||||
{ "alt", K_ALT },
|
||||
{ "up", K_UP },
|
||||
{ "down", K_DOWN },
|
||||
{ "right", K_RIGHT },
|
||||
{ "left", K_LEFT },
|
||||
{ "enter", K_ENTER },
|
||||
{ "tab", K_TAB },
|
||||
{ "space", K_SPACE },
|
||||
{ "bs", K_BS },
|
||||
{ "backspace", K_BS }, /* dup */
|
||||
{ "del", K_DEL },
|
||||
{ "delete", K_DEL }, /* dup */
|
||||
{ "ins", K_INS },
|
||||
{ "insert", K_INS }, /* dup */
|
||||
{ "home", K_HOME },
|
||||
{ "end", K_END },
|
||||
{ "prior", K_PRIOR },
|
||||
{ "next", K_NEXT },
|
||||
{ "pgup", K_PRIOR }, /* duplicate for pgup/pgdn fans */
|
||||
{ "pgdn", K_NEXT }, /* ditto */
|
||||
{ "esc", K_ESC },
|
||||
{ "escape", K_ESC }, /* dup */
|
||||
{ "pause", K_PAUSE },
|
||||
{ "caps", K_CAPS },
|
||||
{ "capslock", K_CAPS }, /* dup */
|
||||
{ "numlock", K_NUMLOCK },
|
||||
{ "scroll", K_SCROLL },
|
||||
|
||||
{ "minus", K_MINUS },
|
||||
{ "_", K_MINUS }, /* dup */
|
||||
{ "equals", K_EQUALS },
|
||||
{ "plus", K_EQUALS }, /* dup */
|
||||
{ "+", K_EQUALS }, /* dup */
|
||||
{ "tilde", K_TILDE },
|
||||
{ "backquote", K_TILDE }, /* dup */
|
||||
{ "`", K_TILDE }, /* dup */
|
||||
{ "slash", K_SLASH },
|
||||
{ "question", K_SLASH }, /* dup */
|
||||
{ "?", K_SLASH }, /* dup */
|
||||
{ "bslash", K_BSLASH },
|
||||
{ "backslash", K_BSLASH }, /* dup */
|
||||
{ "pipe", K_BSLASH }, /* dup */
|
||||
{ "|", K_BSLASH }, /* dup */
|
||||
{ "semi", K_SEMI },
|
||||
{ "semicolon", K_SEMI }, /* dup */
|
||||
{ "quote", K_QUOTE },
|
||||
|
||||
{ "f1", K_F1 },
|
||||
{ "f2", K_F2 },
|
||||
{ "f3", K_F3 },
|
||||
{ "f4", K_F4 },
|
||||
{ "f5", K_F5 },
|
||||
{ "f6", K_F6 },
|
||||
{ "f7", K_F7 },
|
||||
{ "f8", K_F8 },
|
||||
{ "f9", K_F9 },
|
||||
{ "f10", K_F10 },
|
||||
{ "f11", K_F11 },
|
||||
{ "f12", K_F12 },
|
||||
|
||||
{ "num0", K_NUM0 },
|
||||
{ "num1", K_NUM1 },
|
||||
{ "num2", K_NUM2 },
|
||||
{ "num3", K_NUM3 },
|
||||
{ "num4", K_NUM4 },
|
||||
{ "num5", K_NUM5 },
|
||||
{ "num6", K_NUM6 },
|
||||
{ "num7", K_NUM7 },
|
||||
{ "num8", K_NUM8 },
|
||||
{ "num9", K_NUM9 },
|
||||
{ "numplus", K_NUMPLUS },
|
||||
{ "numminus", K_NUMMINUS },
|
||||
{ "nummul", K_NUMMUL },
|
||||
{ "numdiv", K_NUMDIV },
|
||||
{ "numdot", K_NUMDOT },
|
||||
{ "numenter", K_NUMENTER },
|
||||
|
||||
/* Note that these are not presently used... */
|
||||
{ "mouse0", K_MOUSE0 },
|
||||
{ "mouse1", K_MOUSE1 },
|
||||
{ "mouse2", K_MOUSE2 },
|
||||
{ "mouse3", K_MOUSE3 },
|
||||
{ "mouse4", K_MOUSE4 },
|
||||
|
||||
{ "joyleft", K_JOYLEFT },
|
||||
{ "joyright", K_JOYRIGHT },
|
||||
{ "joyup", K_JOYUP },
|
||||
{ "joydown", K_JOYDOWN },
|
||||
|
||||
{ "joy0", K_JOY0 },
|
||||
{ "joy1", K_JOY1 },
|
||||
{ "joy2", K_JOY2 },
|
||||
{ "joy3", K_JOY3 },
|
||||
{ "joy4", K_JOY4 },
|
||||
{ "joy5", K_JOY5 },
|
||||
{ "joy6", K_JOY6 },
|
||||
{ "joy7", K_JOY7 },
|
||||
{ "joy8", K_JOY8 },
|
||||
{ "joy9", K_JOY9 },
|
||||
{ "joy10", K_JOY10 },
|
||||
{ "joy11", K_JOY11 },
|
||||
{ "joy12", K_JOY12 },
|
||||
{ "joy13", K_JOY13 },
|
||||
{ "joy14", K_JOY14 },
|
||||
{ "joy15", K_JOY15 },
|
||||
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
int k_keycode(char *name)
|
||||
{
|
||||
keytable_t *key;
|
||||
|
||||
for (key = keytable; key->name; key++)
|
||||
if (!strcasecmp(key->name, name))
|
||||
return key->code;
|
||||
if (strlen(name) == 1)
|
||||
return tolower(name[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *k_keyname(int code)
|
||||
{
|
||||
keytable_t *key;
|
||||
|
||||
for (key = keytable; key->name; key++)
|
||||
if (key->code == code)
|
||||
return key->name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,868 @@
|
|||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "regs.h"
|
||||
#include "hw.h"
|
||||
#include "mem.h"
|
||||
#include "lcd.h"
|
||||
#include "rc.h"
|
||||
#include "fb.h"
|
||||
#ifdef USE_ASM
|
||||
#include "asm.h"
|
||||
#endif
|
||||
|
||||
struct lcd lcd;
|
||||
|
||||
struct scan scan;
|
||||
|
||||
#define BG (scan.bg)
|
||||
#define WND (scan.wnd)
|
||||
#define BUF (scan.buf)
|
||||
#define PRI (scan.pri)
|
||||
|
||||
#define PAL1 (scan.pal1)
|
||||
#define PAL2 (scan.pal2)
|
||||
#define PAL4 (scan.pal4)
|
||||
|
||||
#define VS (scan.vs) /* vissprites */
|
||||
#define NS (scan.ns)
|
||||
|
||||
#define L (scan.l) /* line */
|
||||
#define X (scan.x) /* screen position */
|
||||
#define Y (scan.y)
|
||||
#define S (scan.s) /* tilemap position */
|
||||
#define T (scan.t)
|
||||
#define U (scan.u) /* position within tile */
|
||||
#define V (scan.v)
|
||||
#define WX (scan.wx)
|
||||
#define WY (scan.wy)
|
||||
#define WT (scan.wt)
|
||||
#define WV (scan.wv)
|
||||
|
||||
byte patpix[4096][8][8];
|
||||
byte patdirty[1024];
|
||||
byte anydirty;
|
||||
|
||||
static int scale = 1;
|
||||
static int density = 0;
|
||||
|
||||
static int rgb332;
|
||||
|
||||
static int sprsort = 1;
|
||||
static int sprdebug;
|
||||
|
||||
#define DEF_PAL { 0x98d0e0, 0x68a0b0, 0x60707C, 0x2C3C3C }
|
||||
|
||||
static int dmg_pal[4][4] = { DEF_PAL, DEF_PAL, DEF_PAL, DEF_PAL };
|
||||
|
||||
static int usefilter, filterdmg;
|
||||
static int filter[3][4] = {
|
||||
{ 195, 25, 0, 35 },
|
||||
{ 25, 170, 25, 35 },
|
||||
{ 25, 60, 125, 40 }
|
||||
};
|
||||
|
||||
rcvar_t lcd_exports[] =
|
||||
{
|
||||
RCV_INT("scale", &scale),
|
||||
RCV_INT("density", &density),
|
||||
RCV_BOOL("rgb332", &rgb332),
|
||||
RCV_VECTOR("dmg_bgp", dmg_pal[0], 4),
|
||||
RCV_VECTOR("dmg_wndp", dmg_pal[1], 4),
|
||||
RCV_VECTOR("dmg_obp0", dmg_pal[2], 4),
|
||||
RCV_VECTOR("dmg_obp1", dmg_pal[3], 4),
|
||||
RCV_BOOL("sprsort", &sprsort),
|
||||
RCV_BOOL("sprdebug", &sprdebug),
|
||||
RCV_BOOL("colorfilter", &usefilter),
|
||||
RCV_BOOL("filterdmg", &filterdmg),
|
||||
RCV_VECTOR("red", filter[0], 4),
|
||||
RCV_VECTOR("green", filter[1], 4),
|
||||
RCV_VECTOR("blue", filter[2], 4),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
static byte *vdest;
|
||||
|
||||
#ifdef ALLOW_UNALIGNED_IO /* long long is ok since this is i386-only anyway? */
|
||||
#define MEMCPY8(d, s) ((*(long long *)(d)) = (*(long long *)(s)))
|
||||
#else
|
||||
#define MEMCPY8(d, s) memcpy((d), (s), 8)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef ASM_UPDATEPATPIX
|
||||
void updatepatpix()
|
||||
{
|
||||
int i, j, k;
|
||||
int a, c;
|
||||
byte *vram = lcd.vbank[0];
|
||||
|
||||
if (!anydirty) return;
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
if (i == 384) i = 512;
|
||||
if (i == 896) break;
|
||||
if (!patdirty[i]) continue;
|
||||
patdirty[i] = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
a = ((i<<4) | (j<<1));
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
c = vram[a] & (1<<k) ? 1 : 0;
|
||||
c |= vram[a+1] & (1<<k) ? 2 : 0;
|
||||
patpix[i+1024][j][k] = c;
|
||||
}
|
||||
for (k = 0; k < 8; k++)
|
||||
patpix[i][j][k] =
|
||||
patpix[i+1024][j][7-k];
|
||||
}
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
patpix[i+2048][j][k] =
|
||||
patpix[i][7-j][k];
|
||||
patpix[i+3072][j][k] =
|
||||
patpix[i+1024][7-j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
anydirty = 0;
|
||||
}
|
||||
#endif /* ASM_UPDATEPATPIX */
|
||||
|
||||
|
||||
|
||||
void tilebuf()
|
||||
{
|
||||
int i, cnt;
|
||||
int base;
|
||||
byte *tilemap, *attrmap;
|
||||
int *tilebuf;
|
||||
int *wrap;
|
||||
static int wraptable[64] =
|
||||
{
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
|
||||
};
|
||||
|
||||
base = ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5) + S;
|
||||
tilemap = lcd.vbank[0] + base;
|
||||
attrmap = lcd.vbank[1] + base;
|
||||
tilebuf = BG;
|
||||
wrap = wraptable + S;
|
||||
cnt = ((WX + 7) >> 3) + 1;
|
||||
|
||||
if (hw.cgb)
|
||||
{
|
||||
if (R_LCDC & 0x10)
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = *tilemap
|
||||
| (((int)*attrmap & 0x08) << 6)
|
||||
| (((int)*attrmap & 0x60) << 5);
|
||||
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
|
||||
attrmap += *wrap + 1;
|
||||
tilemap += *(wrap++) + 1;
|
||||
}
|
||||
else
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = (256 + ((n8)*tilemap))
|
||||
| (((int)*attrmap & 0x08) << 6)
|
||||
| (((int)*attrmap & 0x60) << 5);
|
||||
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
|
||||
attrmap += *wrap + 1;
|
||||
tilemap += *(wrap++) + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (R_LCDC & 0x10)
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = *(tilemap++);
|
||||
tilemap += *(wrap++);
|
||||
}
|
||||
else
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
|
||||
tilemap += *(wrap++);
|
||||
}
|
||||
}
|
||||
|
||||
if (WX >= 160) return;
|
||||
|
||||
base = ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
|
||||
tilemap = lcd.vbank[0] + base;
|
||||
attrmap = lcd.vbank[1] + base;
|
||||
tilebuf = WND;
|
||||
cnt = ((160 - WX) >> 3) + 1;
|
||||
|
||||
if (hw.cgb)
|
||||
{
|
||||
if (R_LCDC & 0x10)
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = *(tilemap++)
|
||||
| (((int)*attrmap & 0x08) << 6)
|
||||
| (((int)*attrmap & 0x60) << 5);
|
||||
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
|
||||
}
|
||||
else
|
||||
for (i = cnt; i > 0; i--)
|
||||
{
|
||||
*(tilebuf++) = (256 + ((n8)*(tilemap++)))
|
||||
| (((int)*attrmap & 0x08) << 6)
|
||||
| (((int)*attrmap & 0x60) << 5);
|
||||
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (R_LCDC & 0x10)
|
||||
for (i = cnt; i > 0; i--)
|
||||
*(tilebuf++) = *(tilemap++);
|
||||
else
|
||||
for (i = cnt; i > 0; i--)
|
||||
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bg_scan()
|
||||
{
|
||||
int cnt;
|
||||
byte *src, *dest;
|
||||
int *tile;
|
||||
|
||||
if (WX <= 0) return;
|
||||
cnt = WX;
|
||||
tile = BG;
|
||||
dest = BUF;
|
||||
|
||||
src = patpix[*(tile++)][V] + U;
|
||||
memcpy(dest, src, 8-U);
|
||||
dest += 8-U;
|
||||
cnt -= 8-U;
|
||||
if (cnt <= 0) return;
|
||||
while (cnt >= 8)
|
||||
{
|
||||
src = patpix[*(tile++)][V];
|
||||
MEMCPY8(dest, src);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
src = patpix[*tile][V];
|
||||
while (cnt--)
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
void wnd_scan()
|
||||
{
|
||||
int cnt;
|
||||
byte *src, *dest;
|
||||
int *tile;
|
||||
|
||||
if (WX >= 160) return;
|
||||
cnt = 160 - WX;
|
||||
tile = WND;
|
||||
dest = BUF + WX;
|
||||
|
||||
while (cnt >= 8)
|
||||
{
|
||||
src = patpix[*(tile++)][WV];
|
||||
MEMCPY8(dest, src);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
src = patpix[*tile][WV];
|
||||
while (cnt--)
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
static void blendcpy(byte *dest, byte *src, byte b, int cnt)
|
||||
{
|
||||
while (cnt--) *(dest++) = *(src++) | b;
|
||||
}
|
||||
|
||||
static int priused(void *attr)
|
||||
{
|
||||
un32 *a = attr;
|
||||
return (int)((a[0]|a[1]|a[2]|a[3]|a[4]|a[5]|a[6]|a[7])&0x80808080);
|
||||
}
|
||||
|
||||
void bg_scan_pri()
|
||||
{
|
||||
int cnt, i;
|
||||
byte *src, *dest;
|
||||
|
||||
if (WX <= 0) return;
|
||||
i = S;
|
||||
cnt = WX;
|
||||
dest = PRI;
|
||||
src = lcd.vbank[1] + ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5);
|
||||
|
||||
if (!priused(src))
|
||||
{
|
||||
memset(dest, 0, cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dest, src[i++&31]&128, 8-U);
|
||||
dest += 8-U;
|
||||
cnt -= 8-U;
|
||||
if (cnt <= 0) return;
|
||||
while (cnt >= 8)
|
||||
{
|
||||
memset(dest, src[i++&31]&128, 8);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
memset(dest, src[i&31]&128, cnt);
|
||||
}
|
||||
|
||||
void wnd_scan_pri()
|
||||
{
|
||||
int cnt, i;
|
||||
byte *src, *dest;
|
||||
|
||||
if (WX >= 160) return;
|
||||
i = 0;
|
||||
cnt = 160 - WX;
|
||||
dest = PRI + WX;
|
||||
src = lcd.vbank[1] + ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
|
||||
|
||||
if (!priused(src))
|
||||
{
|
||||
memset(dest, 0, cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
while (cnt >= 8)
|
||||
{
|
||||
memset(dest, src[i++]&128, 8);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
memset(dest, src[i]&128, cnt);
|
||||
}
|
||||
|
||||
#ifndef ASM_BG_SCAN_COLOR
|
||||
void bg_scan_color()
|
||||
{
|
||||
int cnt;
|
||||
byte *src, *dest;
|
||||
int *tile;
|
||||
|
||||
if (WX <= 0) return;
|
||||
cnt = WX;
|
||||
tile = BG;
|
||||
dest = BUF;
|
||||
|
||||
src = patpix[*(tile++)][V] + U;
|
||||
blendcpy(dest, src, *(tile++), 8-U);
|
||||
dest += 8-U;
|
||||
cnt -= 8-U;
|
||||
if (cnt <= 0) return;
|
||||
while (cnt >= 8)
|
||||
{
|
||||
src = patpix[*(tile++)][V];
|
||||
blendcpy(dest, src, *(tile++), 8);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
src = patpix[*(tile++)][V];
|
||||
blendcpy(dest, src, *(tile++), cnt);
|
||||
}
|
||||
#endif
|
||||
|
||||
void wnd_scan_color()
|
||||
{
|
||||
int cnt;
|
||||
byte *src, *dest;
|
||||
int *tile;
|
||||
|
||||
if (WX >= 160) return;
|
||||
cnt = 160 - WX;
|
||||
tile = WND;
|
||||
dest = BUF + WX;
|
||||
|
||||
while (cnt >= 8)
|
||||
{
|
||||
src = patpix[*(tile++)][WV];
|
||||
blendcpy(dest, src, *(tile++), 8);
|
||||
dest += 8;
|
||||
cnt -= 8;
|
||||
}
|
||||
src = patpix[*(tile++)][WV];
|
||||
blendcpy(dest, src, *(tile++), cnt);
|
||||
}
|
||||
|
||||
static void recolor(byte *buf, byte fill, int cnt)
|
||||
{
|
||||
while (cnt--) *(buf++) |= fill;
|
||||
}
|
||||
|
||||
void spr_count()
|
||||
{
|
||||
int i;
|
||||
struct obj *o;
|
||||
|
||||
NS = 0;
|
||||
if (!(R_LCDC & 0x02)) return;
|
||||
|
||||
o = lcd.oam.obj;
|
||||
|
||||
for (i = 40; i; i--, o++)
|
||||
{
|
||||
if (L >= o->y || L + 16 < o->y)
|
||||
continue;
|
||||
if (L + 8 >= o->y && !(R_LCDC & 0x04))
|
||||
continue;
|
||||
if (++NS == 10) break;
|
||||
}
|
||||
}
|
||||
|
||||
void spr_enum()
|
||||
{
|
||||
int i, j;
|
||||
struct obj *o;
|
||||
struct vissprite ts[10];
|
||||
int v, pat;
|
||||
int l, x;
|
||||
|
||||
NS = 0;
|
||||
if (!(R_LCDC & 0x02)) return;
|
||||
|
||||
o = lcd.oam.obj;
|
||||
|
||||
for (i = 40; i; i--, o++)
|
||||
{
|
||||
if (L >= o->y || L + 16 < o->y)
|
||||
continue;
|
||||
if (L + 8 >= o->y && !(R_LCDC & 0x04))
|
||||
continue;
|
||||
VS[NS].x = (int)o->x - 8;
|
||||
v = L - (int)o->y + 16;
|
||||
if (hw.cgb)
|
||||
{
|
||||
pat = o->pat | (((int)o->flags & 0x60) << 5)
|
||||
| (((int)o->flags & 0x08) << 6);
|
||||
VS[NS].pal = 32 + ((o->flags & 0x07) << 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
pat = o->pat | (((int)o->flags & 0x60) << 5);
|
||||
VS[NS].pal = 32 + ((o->flags & 0x10) >> 2);
|
||||
}
|
||||
VS[NS].pri = (o->flags & 0x80) >> 7;
|
||||
if ((R_LCDC & 0x04))
|
||||
{
|
||||
pat &= ~1;
|
||||
if (v >= 8)
|
||||
{
|
||||
v -= 8;
|
||||
pat++;
|
||||
}
|
||||
if (o->flags & 0x40) pat ^= 1;
|
||||
}
|
||||
VS[NS].buf = patpix[pat][v];
|
||||
if (++NS == 10) break;
|
||||
}
|
||||
if (!sprsort || hw.cgb) return;
|
||||
/* not quite optimal but it finally works! */
|
||||
for (i = 0; i < NS; i++)
|
||||
{
|
||||
l = 0;
|
||||
x = VS[0].x;
|
||||
for (j = 1; j < NS; j++)
|
||||
{
|
||||
if (VS[j].x < x)
|
||||
{
|
||||
l = j;
|
||||
x = VS[j].x;
|
||||
}
|
||||
}
|
||||
ts[i] = VS[l];
|
||||
VS[l].x = 160;
|
||||
}
|
||||
memcpy(VS, ts, sizeof VS);
|
||||
}
|
||||
|
||||
void spr_scan()
|
||||
{
|
||||
int i, x;
|
||||
byte pal, b, ns = NS;
|
||||
byte *src, *dest, *bg, *pri;
|
||||
struct vissprite *vs;
|
||||
static byte bgdup[256];
|
||||
|
||||
if (!ns) return;
|
||||
|
||||
memcpy(bgdup, BUF, 256);
|
||||
vs = &VS[ns-1];
|
||||
|
||||
for (; ns; ns--, vs--)
|
||||
{
|
||||
x = vs->x;
|
||||
if (x >= 160) continue;
|
||||
if (x <= -8) continue;
|
||||
if (x < 0)
|
||||
{
|
||||
src = vs->buf - x;
|
||||
dest = BUF;
|
||||
i = 8 + x;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = vs->buf;
|
||||
dest = BUF + x;
|
||||
if (x > 152) i = 160 - x;
|
||||
else i = 8;
|
||||
}
|
||||
pal = vs->pal;
|
||||
if (vs->pri)
|
||||
{
|
||||
bg = bgdup + (dest - BUF);
|
||||
while (i--)
|
||||
{
|
||||
b = src[i];
|
||||
if (b && !(bg[i]&3)) dest[i] = pal|b;
|
||||
}
|
||||
}
|
||||
else if (hw.cgb)
|
||||
{
|
||||
bg = bgdup + (dest - BUF);
|
||||
pri = PRI + (dest - BUF);
|
||||
while (i--)
|
||||
{
|
||||
b = src[i];
|
||||
if (b && (!pri[i] || !(bg[i]&3)))
|
||||
dest[i] = pal|b;
|
||||
}
|
||||
}
|
||||
else while (i--) if (src[i]) dest[i] = pal|src[i];
|
||||
/* else while (i--) if (src[i]) dest[i] = 31 + ns; */
|
||||
}
|
||||
if (sprdebug) for (i = 0; i < NS; i++) BUF[i<<1] = 36;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void lcd_begin()
|
||||
{
|
||||
if (fb.indexed)
|
||||
{
|
||||
if (rgb332) pal_set332();
|
||||
else pal_expire();
|
||||
}
|
||||
while (scale * 160 > fb.w || scale * 144 > fb.h) scale--;
|
||||
vdest = fb.ptr + ((fb.w*fb.pelsize)>>1)
|
||||
- (80*fb.pelsize) * scale
|
||||
+ ((fb.h>>1) - 72*scale) * fb.pitch;
|
||||
WY = R_WY;
|
||||
}
|
||||
|
||||
void lcd_refreshline()
|
||||
{
|
||||
int i;
|
||||
byte scalebuf[160*4*4], *dest;
|
||||
|
||||
if (!fb.enabled) return;
|
||||
|
||||
if (!(R_LCDC & 0x80))
|
||||
return; /* should not happen... */
|
||||
|
||||
updatepatpix();
|
||||
|
||||
L = R_LY;
|
||||
X = R_SCX;
|
||||
Y = (R_SCY + L) & 0xff;
|
||||
S = X >> 3;
|
||||
T = Y >> 3;
|
||||
U = X & 7;
|
||||
V = Y & 7;
|
||||
|
||||
WX = R_WX - 7;
|
||||
if (WY>L || WY<0 || WY>143 || WX<-7 || WX>159 || !(R_LCDC&0x20))
|
||||
WX = 160;
|
||||
WT = (L - WY) >> 3;
|
||||
WV = (L - WY) & 7;
|
||||
|
||||
spr_enum();
|
||||
|
||||
tilebuf();
|
||||
if (hw.cgb)
|
||||
{
|
||||
bg_scan_color();
|
||||
wnd_scan_color();
|
||||
if (NS)
|
||||
{
|
||||
bg_scan_pri();
|
||||
wnd_scan_pri();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bg_scan();
|
||||
wnd_scan();
|
||||
recolor(BUF+WX, 0x04, 160-WX);
|
||||
}
|
||||
spr_scan();
|
||||
|
||||
if (fb.dirty) memset(fb.ptr, 0, fb.pitch * fb.h);
|
||||
fb.dirty = 0;
|
||||
if (density > scale) density = scale;
|
||||
if (scale == 1) density = 1;
|
||||
|
||||
dest = (density != 1) ? scalebuf : vdest;
|
||||
|
||||
switch (scale)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
switch (fb.pelsize)
|
||||
{
|
||||
case 1:
|
||||
refresh_1(dest, BUF, PAL1, 160);
|
||||
break;
|
||||
case 2:
|
||||
refresh_2(dest, BUF, PAL2, 160);
|
||||
break;
|
||||
case 3:
|
||||
refresh_3(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 4:
|
||||
refresh_4(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (fb.pelsize)
|
||||
{
|
||||
case 1:
|
||||
refresh_2(dest, BUF, PAL2, 160);
|
||||
break;
|
||||
case 2:
|
||||
refresh_4(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 3:
|
||||
refresh_3_2x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 4:
|
||||
refresh_4_2x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (fb.pelsize)
|
||||
{
|
||||
case 1:
|
||||
refresh_3(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 2:
|
||||
refresh_2_3x(dest, BUF, PAL2, 160);
|
||||
break;
|
||||
case 3:
|
||||
refresh_3_3x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 4:
|
||||
refresh_4_3x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (fb.pelsize)
|
||||
{
|
||||
case 1:
|
||||
refresh_4(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 2:
|
||||
refresh_4_2x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 3:
|
||||
refresh_3_4x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
case 4:
|
||||
refresh_4_4x(dest, BUF, PAL4, 160);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (density != 1)
|
||||
{
|
||||
for (i = 0; i < scale; i++)
|
||||
{
|
||||
if ((i < density) || ((density <= 0) && !(i&1)))
|
||||
memcpy(vdest, scalebuf, 160 * fb.pelsize * scale);
|
||||
vdest += fb.pitch;
|
||||
}
|
||||
}
|
||||
else vdest += fb.pitch * scale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void updatepalette(int i)
|
||||
{
|
||||
int c, r, g, b, y, u, v, rr, gg;
|
||||
|
||||
c = (lcd.pal[i<<1] | ((int)lcd.pal[(i<<1)|1] << 8)) & 0x7FFF;
|
||||
r = (c & 0x001F) << 3;
|
||||
g = (c & 0x03E0) >> 2;
|
||||
b = (c & 0x7C00) >> 7;
|
||||
r |= (r >> 5);
|
||||
g |= (g >> 5);
|
||||
b |= (b >> 5);
|
||||
|
||||
if (usefilter && (filterdmg || hw.cgb))
|
||||
{
|
||||
rr = ((r * filter[0][0] + g * filter[0][1] + b * filter[0][2]) >> 8) + filter[0][3];
|
||||
gg = ((r * filter[1][0] + g * filter[1][1] + b * filter[1][2]) >> 8) + filter[1][3];
|
||||
b = ((r * filter[2][0] + g * filter[2][1] + b * filter[2][2]) >> 8) + filter[2][3];
|
||||
r = rr;
|
||||
g = gg;
|
||||
}
|
||||
|
||||
if (fb.yuv)
|
||||
{
|
||||
y = (((r * 263) + (g * 516) + (b * 100)) >> 10) + 16;
|
||||
u = (((r * 450) - (g * 377) - (b * 73)) >> 10) + 128;
|
||||
v = (((r * -152) - (g * 298) + (b * 450)) >> 10) + 128;
|
||||
if (y < 0) y = 0; if (y > 255) y = 255;
|
||||
if (u < 0) u = 0; if (u > 255) u = 255;
|
||||
if (v < 0) v = 0; if (v > 255) v = 255;
|
||||
PAL4[i] = (y<<fb.cc[0].l) | (y<<fb.cc[3].l)
|
||||
| (u<<fb.cc[1].l) | (v<<fb.cc[2].l);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fb.indexed)
|
||||
{
|
||||
pal_release(PAL1[i]);
|
||||
c = pal_getcolor(c, r, g, b);
|
||||
PAL1[i] = c;
|
||||
PAL2[i] = (c<<8) | c;
|
||||
PAL4[i] = (c<<24) | (c<<16) | (c<<8) | c;
|
||||
return;
|
||||
}
|
||||
|
||||
r = (r >> fb.cc[0].r) << fb.cc[0].l;
|
||||
g = (g >> fb.cc[1].r) << fb.cc[1].l;
|
||||
b = (b >> fb.cc[2].r) << fb.cc[2].l;
|
||||
c = r|g|b;
|
||||
|
||||
switch (fb.pelsize)
|
||||
{
|
||||
case 1:
|
||||
PAL1[i] = c;
|
||||
PAL2[i] = (c<<8) | c;
|
||||
PAL4[i] = (c<<24) | (c<<16) | (c<<8) | c;
|
||||
break;
|
||||
case 2:
|
||||
PAL2[i] = c;
|
||||
PAL4[i] = (c<<16) | c;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
PAL4[i] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pal_write(int i, byte b)
|
||||
{
|
||||
if (lcd.pal[i] == b) return;
|
||||
lcd.pal[i] = b;
|
||||
updatepalette(i>>1);
|
||||
}
|
||||
|
||||
void pal_write_dmg(int i, int mapnum, byte d)
|
||||
{
|
||||
int j;
|
||||
int *cmap = dmg_pal[mapnum];
|
||||
int c, r, g, b;
|
||||
|
||||
if (hw.cgb) return;
|
||||
|
||||
/* if (mapnum >= 2) d = 0xe4; */
|
||||
for (j = 0; j < 8; j += 2)
|
||||
{
|
||||
c = cmap[(d >> j) & 3];
|
||||
r = (c & 0xf8) >> 3;
|
||||
g = (c & 0xf800) >> 6;
|
||||
b = (c & 0xf80000) >> 9;
|
||||
c = r|g|b;
|
||||
/* FIXME - handle directly without faking cgb */
|
||||
pal_write(i+j, c & 0xff);
|
||||
pal_write(i+j+1, c >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void vram_write(int a, byte b)
|
||||
{
|
||||
lcd.vbank[R_VBK&1][a] = b;
|
||||
if (a >= 0x1800) return;
|
||||
patdirty[((R_VBK&1)<<9)+(a>>4)] = 1;
|
||||
anydirty = 1;
|
||||
}
|
||||
|
||||
void vram_dirty()
|
||||
{
|
||||
anydirty = 1;
|
||||
memset(patdirty, 1, sizeof patdirty);
|
||||
}
|
||||
|
||||
void pal_dirty()
|
||||
{
|
||||
int i;
|
||||
if (!hw.cgb)
|
||||
{
|
||||
pal_write_dmg(0, 0, R_BGP);
|
||||
pal_write_dmg(8, 1, R_BGP);
|
||||
pal_write_dmg(64, 2, R_OBP0);
|
||||
pal_write_dmg(72, 3, R_OBP1);
|
||||
}
|
||||
for (i = 0; i < 64; i++)
|
||||
updatepalette(i);
|
||||
}
|
||||
|
||||
void lcd_reset()
|
||||
{
|
||||
memset(&lcd, 0, sizeof lcd);
|
||||
lcd_begin();
|
||||
vram_dirty();
|
||||
pal_dirty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
|
||||
#ifndef __LCD_H__
|
||||
#define __LCD_H__
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
struct vissprite
|
||||
{
|
||||
byte *buf;
|
||||
int x;
|
||||
byte pal, pri, pad[6];
|
||||
};
|
||||
|
||||
struct scan
|
||||
{
|
||||
int bg[64];
|
||||
int wnd[64];
|
||||
byte buf[256];
|
||||
byte pal1[128];
|
||||
un16 pal2[64];
|
||||
un32 pal4[64];
|
||||
byte pri[256];
|
||||
struct vissprite vs[16];
|
||||
int ns, l, x, y, s, t, u, v, wx, wy, wt, wv;
|
||||
};
|
||||
|
||||
struct obj
|
||||
{
|
||||
byte y;
|
||||
byte x;
|
||||
byte pat;
|
||||
byte flags;
|
||||
};
|
||||
|
||||
struct lcd
|
||||
{
|
||||
byte vbank[2][8192];
|
||||
union
|
||||
{
|
||||
byte mem[256];
|
||||
struct obj obj[40];
|
||||
} oam;
|
||||
byte pal[128];
|
||||
};
|
||||
|
||||
extern struct lcd lcd;
|
||||
extern struct scan scan;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "hw.h"
|
||||
#include "cpu.h"
|
||||
#include "regs.h"
|
||||
|
||||
|
||||
#define C (cpu.lcdc)
|
||||
|
||||
|
||||
/*
|
||||
* stat_trigger updates the STAT interrupt line to reflect whether any
|
||||
* of the conditions set to be tested (by bits 3-6 of R_STAT) are met.
|
||||
* This function should be called whenever any of the following occur:
|
||||
* 1) LY or LYC changes.
|
||||
* 2) A state transition affects the low 2 bits of R_STAT (see below).
|
||||
* 3) The program writes to the upper bits of R_STAT.
|
||||
* stat_trigger also updates bit 2 of R_STAT to reflect whether LY=LYC.
|
||||
*/
|
||||
|
||||
void stat_trigger()
|
||||
{
|
||||
static const int condbits[4] = { 0x08, 0x30, 0x20, 0x00 };
|
||||
int flag = 0;
|
||||
|
||||
if ((R_LY < 0x91) && (R_LY == R_LYC))
|
||||
{
|
||||
R_STAT |= 0x04;
|
||||
if (R_STAT & 0x40) flag = IF_STAT;
|
||||
}
|
||||
else R_STAT &= ~0x04;
|
||||
|
||||
if (R_STAT & condbits[R_STAT&3]) flag = IF_STAT;
|
||||
|
||||
if (!(R_LCDC & 0x80)) flag = 0;
|
||||
|
||||
hw_interrupt(flag, IF_STAT);
|
||||
}
|
||||
|
||||
void stat_write(byte b)
|
||||
{
|
||||
R_STAT = (R_STAT & 0x07) | (b & 0x78);
|
||||
if (!hw.cgb && !(R_STAT & 2)) /* DMG STAT write bug => interrupt */
|
||||
hw_interrupt(IF_STAT, IF_STAT);
|
||||
stat_trigger();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* stat_change is called when a transition results in a change to the
|
||||
* LCD STAT condition (the low 2 bits of R_STAT). It raises or lowers
|
||||
* the VBLANK interrupt line appropriately and calls stat_trigger to
|
||||
* update the STAT interrupt line.
|
||||
*/
|
||||
|
||||
static void stat_change(int stat)
|
||||
{
|
||||
stat &= 3;
|
||||
R_STAT = (R_STAT & 0x7C) | stat;
|
||||
|
||||
if (stat != 1) hw_interrupt(0, IF_VBLANK);
|
||||
/* hw_interrupt((stat == 1) ? IF_VBLANK : 0, IF_VBLANK); */
|
||||
stat_trigger();
|
||||
}
|
||||
|
||||
|
||||
void lcdc_change(byte b)
|
||||
{
|
||||
byte old = R_LCDC;
|
||||
R_LCDC = b;
|
||||
if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */
|
||||
{
|
||||
R_LY = 0;
|
||||
stat_change(2);
|
||||
C = 40;
|
||||
lcd_begin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lcdc_trans()
|
||||
{
|
||||
if (!(R_LCDC & 0x80))
|
||||
{
|
||||
while (C <= 0)
|
||||
{
|
||||
switch ((byte)(R_STAT & 3))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
stat_change(2);
|
||||
C += 40;
|
||||
break;
|
||||
case 2:
|
||||
stat_change(3);
|
||||
C += 86;
|
||||
break;
|
||||
case 3:
|
||||
stat_change(0);
|
||||
if (hw.hdma & 0x80)
|
||||
hw_hdma();
|
||||
else
|
||||
C += 102;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (C <= 0)
|
||||
{
|
||||
switch ((byte)(R_STAT & 3))
|
||||
{
|
||||
case 1:
|
||||
if (!(hw.ilines & IF_VBLANK))
|
||||
{
|
||||
C += 218;
|
||||
hw_interrupt(IF_VBLANK, IF_VBLANK);
|
||||
break;
|
||||
}
|
||||
if (R_LY == 0)
|
||||
{
|
||||
lcd_begin();
|
||||
stat_change(2);
|
||||
C += 40;
|
||||
break;
|
||||
}
|
||||
else if (R_LY < 152)
|
||||
C += 228;
|
||||
else if (R_LY == 152)
|
||||
C += 28;
|
||||
else
|
||||
{
|
||||
R_LY = -1;
|
||||
C += 200;
|
||||
}
|
||||
R_LY++;
|
||||
stat_trigger();
|
||||
break;
|
||||
case 2:
|
||||
lcd_refreshline();
|
||||
stat_change(3);
|
||||
C += 86;
|
||||
break;
|
||||
case 3:
|
||||
stat_change(0);
|
||||
if (hw.hdma & 0x80)
|
||||
hw_hdma();
|
||||
/* FIXME -- how much of the hblank does hdma use?? */
|
||||
/* else */
|
||||
C += 102;
|
||||
break;
|
||||
case 0:
|
||||
if (++R_LY >= 144)
|
||||
{
|
||||
if (cpu.halt)
|
||||
{
|
||||
hw_interrupt(IF_VBLANK, IF_VBLANK);
|
||||
C += 228;
|
||||
}
|
||||
else C += 10;
|
||||
stat_change(1);
|
||||
break;
|
||||
}
|
||||
stat_change(2);
|
||||
C += 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,395 @@
|
|||
|
||||
|
||||
#include "defs.h"
|
||||
#include "regs.h"
|
||||
#include "mem.h"
|
||||
#include "hw.h"
|
||||
#include "rtc.h"
|
||||
#include "rc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup();
|
||||
|
||||
static int mbc_table[256] =
|
||||
{
|
||||
0, 1, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3,
|
||||
3, 3, 3, 3, 0, 0, 0, 0, 0, 5, 5, 5, MBC_RUMBLE, MBC_RUMBLE, MBC_RUMBLE, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MBC_HUC3, MBC_HUC1
|
||||
};
|
||||
|
||||
static int rtc_table[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0
|
||||
};
|
||||
|
||||
static int batt_table[256] =
|
||||
{
|
||||
0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0
|
||||
};
|
||||
|
||||
static int romsize_table[256] =
|
||||
{
|
||||
2, 4, 8, 16, 32, 64, 128, 256, 512,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 128, 128, 128
|
||||
/* 0, 0, 72, 80, 96 -- actual values but bad to use these! */
|
||||
};
|
||||
|
||||
static int ramsize_table[256] =
|
||||
{
|
||||
1, 1, 1, 4, 16,
|
||||
4 /* FIXME - what value should this be?! */
|
||||
};
|
||||
|
||||
|
||||
static char *romfile;
|
||||
static char *sramfile;
|
||||
static char *rtcfile;
|
||||
static char *saveprefix;
|
||||
|
||||
static char *savename;
|
||||
static char *savedir;
|
||||
|
||||
static int saveslot;
|
||||
|
||||
static int forcebatt, nobatt;
|
||||
static int forcedmg, gbamode;
|
||||
|
||||
static int memfill = -1, memrand = -1;
|
||||
|
||||
|
||||
static void initmem(void *mem, int size)
|
||||
{
|
||||
char *p = mem;
|
||||
if (memrand >= 0)
|
||||
{
|
||||
srand(memrand ? memrand : time(0));
|
||||
while(size--) *(p++) = rand();
|
||||
}
|
||||
else if (memfill >= 0)
|
||||
memset(p, memfill, size);
|
||||
}
|
||||
|
||||
static byte *loadfile(FILE *f, int *len)
|
||||
{
|
||||
int c, l = 0, p = 0;
|
||||
byte *d = 0, buf[512];
|
||||
|
||||
for(;;)
|
||||
{
|
||||
c = fread(buf, 1, sizeof buf, f);
|
||||
if (c <= 0) break;
|
||||
l += c;
|
||||
d = realloc(d, l);
|
||||
if (!d) return 0;
|
||||
memcpy(d+p, buf, c);
|
||||
p += c;
|
||||
}
|
||||
*len = l;
|
||||
return d;
|
||||
}
|
||||
|
||||
static byte *inf_buf;
|
||||
static int inf_pos, inf_len;
|
||||
|
||||
static void inflate_callback(byte b)
|
||||
{
|
||||
if (inf_pos >= inf_len)
|
||||
{
|
||||
inf_len += 512;
|
||||
inf_buf = realloc(inf_buf, inf_len);
|
||||
if (!inf_buf) die("out of memory inflating file @ %d bytes\n", inf_pos);
|
||||
}
|
||||
inf_buf[inf_pos++] = b;
|
||||
}
|
||||
|
||||
static byte *decompress(byte *data, int *len)
|
||||
{
|
||||
unsigned long pos = 0;
|
||||
if (data[0] != 0x1f || data[1] != 0x8b)
|
||||
return data;
|
||||
inf_buf = 0;
|
||||
inf_pos = inf_len = 0;
|
||||
if (unzip(data, &pos, inflate_callback) < 0)
|
||||
return data;
|
||||
*len = inf_pos;
|
||||
return inf_buf;
|
||||
}
|
||||
|
||||
|
||||
int rom_load()
|
||||
{
|
||||
FILE *f;
|
||||
byte c, *data, *header;
|
||||
int len = 0, rlen;
|
||||
|
||||
if (strcmp(romfile, "-")) f = fopen(romfile, "rb");
|
||||
else f = stdin;
|
||||
if (!f) die("cannot open rom file: %s\n", romfile);
|
||||
|
||||
data = loadfile(f, &len);
|
||||
header = data = decompress(data, &len);
|
||||
|
||||
memcpy(rom.name, header+0x0134, 16);
|
||||
if (rom.name[14] & 0x80) rom.name[14] = 0;
|
||||
if (rom.name[15] & 0x80) rom.name[15] = 0;
|
||||
rom.name[16] = 0;
|
||||
|
||||
c = header[0x0147];
|
||||
mbc.type = mbc_table[c];
|
||||
mbc.batt = (batt_table[c] && !nobatt) || forcebatt;
|
||||
rtc.batt = rtc_table[c];
|
||||
mbc.romsize = romsize_table[header[0x0148]];
|
||||
mbc.ramsize = ramsize_table[header[0x0149]];
|
||||
|
||||
if (!mbc.romsize) die("unknown ROM size %02X\n", header[0x0148]);
|
||||
if (!mbc.ramsize) die("unknown SRAM size %02X\n", header[0x0149]);
|
||||
|
||||
rlen = 16384 * mbc.romsize;
|
||||
rom.bank = realloc(data, rlen);
|
||||
if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
|
||||
|
||||
ram.sbank = malloc(8192 * mbc.ramsize);
|
||||
|
||||
initmem(ram.sbank, 8192 * mbc.ramsize);
|
||||
initmem(ram.ibank, 4096 * 8);
|
||||
|
||||
mbc.rombank = 1;
|
||||
mbc.rambank = 0;
|
||||
|
||||
c = header[0x0143];
|
||||
hw.cgb = ((c == 0x80) || (c == 0xc0)) && !forcedmg;
|
||||
hw.gba = (hw.cgb && gbamode);
|
||||
|
||||
if (strcmp(romfile, "-")) fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sram_load()
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (!mbc.batt || !sramfile || !*sramfile) return -1;
|
||||
|
||||
/* Consider sram loaded at this point, even if file doesn't exist */
|
||||
ram.loaded = 1;
|
||||
|
||||
f = fopen(sramfile, "rb");
|
||||
if (!f) return -1;
|
||||
fread(ram.sbank, 8192, mbc.ramsize, f);
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sram_save()
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
/* If we crash before we ever loaded sram, DO NOT SAVE! */
|
||||
if (!mbc.batt || !sramfile || !ram.loaded || !mbc.ramsize)
|
||||
return -1;
|
||||
|
||||
f = fopen(sramfile, "wb");
|
||||
if (!f) return -1;
|
||||
fwrite(ram.sbank, 8192, mbc.ramsize, f);
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void state_save(int n)
|
||||
{
|
||||
FILE *f;
|
||||
char *name;
|
||||
|
||||
if (n < 0) n = saveslot;
|
||||
if (n < 0) n = 0;
|
||||
name = malloc(strlen(saveprefix) + 5);
|
||||
sprintf(name, "%s.%03d", saveprefix, n);
|
||||
|
||||
if ((f = fopen(name, "wb")))
|
||||
{
|
||||
savestate(f);
|
||||
fclose(f);
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
||||
|
||||
void state_load(int n)
|
||||
{
|
||||
FILE *f;
|
||||
char *name;
|
||||
|
||||
if (n < 0) n = saveslot;
|
||||
if (n < 0) n = 0;
|
||||
name = malloc(strlen(saveprefix) + 5);
|
||||
sprintf(name, "%s.%03d", saveprefix, n);
|
||||
|
||||
if ((f = fopen(name, "rb")))
|
||||
{
|
||||
loadstate(f);
|
||||
fclose(f);
|
||||
vram_dirty();
|
||||
pal_dirty();
|
||||
sound_dirty();
|
||||
mem_updatemap();
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
|
||||
void rtc_save()
|
||||
{
|
||||
FILE *f;
|
||||
if (!rtc.batt) return;
|
||||
if (!(f = fopen(rtcfile, "wb"))) return;
|
||||
rtc_save_internal(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void rtc_load()
|
||||
{
|
||||
FILE *f;
|
||||
if (!rtc.batt) return;
|
||||
if (!(f = fopen(rtcfile, "r"))) return;
|
||||
rtc_load_internal(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
void loader_unload()
|
||||
{
|
||||
sram_save();
|
||||
if (romfile) free(romfile);
|
||||
if (sramfile) free(sramfile);
|
||||
if (saveprefix) free(saveprefix);
|
||||
if (rom.bank) free(rom.bank);
|
||||
if (ram.sbank) free(ram.sbank);
|
||||
romfile = sramfile = saveprefix = 0;
|
||||
rom.bank = 0;
|
||||
ram.sbank = 0;
|
||||
mbc.type = mbc.romsize = mbc.ramsize = mbc.batt = 0;
|
||||
}
|
||||
|
||||
static char *base(char *s)
|
||||
{
|
||||
char *p;
|
||||
p = strrchr(s, '/');
|
||||
if (p) return p+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *ldup(char *s)
|
||||
{
|
||||
int i;
|
||||
char *n, *p;
|
||||
p = n = malloc(strlen(s));
|
||||
for (i = 0; s[i]; i++) if (isalnum(s[i])) *(p++) = tolower(s[i]);
|
||||
*p = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void cleanup()
|
||||
{
|
||||
sram_save();
|
||||
rtc_save();
|
||||
/* IDEA - if error, write emergency savestate..? */
|
||||
}
|
||||
|
||||
void loader_init(char *s)
|
||||
{
|
||||
char *name, *p;
|
||||
|
||||
sys_checkdir(savedir, 1); /* needs to be writable */
|
||||
|
||||
romfile = s;
|
||||
rom_load();
|
||||
vid_settitle(rom.name);
|
||||
if (savename && *savename)
|
||||
{
|
||||
if (savename[0] == '-' && savename[1] == 0)
|
||||
name = ldup(rom.name);
|
||||
else name = strdup(savename);
|
||||
}
|
||||
else if (romfile && *base(romfile) && strcmp(romfile, "-"))
|
||||
{
|
||||
name = strdup(base(romfile));
|
||||
p = strchr(name, '.');
|
||||
if (p) *p = 0;
|
||||
}
|
||||
else name = ldup(rom.name);
|
||||
|
||||
saveprefix = malloc(strlen(savedir) + strlen(name) + 2);
|
||||
sprintf(saveprefix, "%s/%s", savedir, name);
|
||||
|
||||
sramfile = malloc(strlen(saveprefix) + 5);
|
||||
strcpy(sramfile, saveprefix);
|
||||
strcat(sramfile, ".sav");
|
||||
|
||||
rtcfile = malloc(strlen(saveprefix) + 5);
|
||||
strcpy(rtcfile, saveprefix);
|
||||
strcat(rtcfile, ".rtc");
|
||||
|
||||
sram_load();
|
||||
rtc_load();
|
||||
|
||||
atexit(cleanup);
|
||||
}
|
||||
|
||||
rcvar_t loader_exports[] =
|
||||
{
|
||||
RCV_STRING("savedir", &savedir),
|
||||
RCV_STRING("savename", &savename),
|
||||
RCV_INT("saveslot", &saveslot),
|
||||
RCV_BOOL("forcebatt", &forcebatt),
|
||||
RCV_BOOL("nobatt", &nobatt),
|
||||
RCV_BOOL("forcedmg", &forcedmg),
|
||||
RCV_BOOL("gbamode", &gbamode),
|
||||
RCV_INT("memfill", &memfill),
|
||||
RCV_INT("memrand", &memrand),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
|
||||
#ifndef __LOADER_H__
|
||||
#define __LOADER_H__
|
||||
|
||||
|
||||
typedef struct loader_s
|
||||
{
|
||||
char *rom;
|
||||
char *base;
|
||||
char *sram;
|
||||
char *state;
|
||||
int ramloaded;
|
||||
} loader_t;
|
||||
|
||||
|
||||
extern loader_t loader;
|
||||
|
||||
|
||||
int rom_load();
|
||||
int sram_load();
|
||||
int sram_save();
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup();
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "rc.h"
|
||||
|
||||
|
||||
#include "Version"
|
||||
|
||||
|
||||
static char *defaultconfig[] =
|
||||
{
|
||||
"bind esc quit",
|
||||
"bind up +up",
|
||||
"bind down +down",
|
||||
"bind left +left",
|
||||
"bind right +right",
|
||||
"bind d +a",
|
||||
"bind s +b",
|
||||
"bind enter +start",
|
||||
"bind space +select",
|
||||
"bind tab +select",
|
||||
"bind joyup +up",
|
||||
"bind joydown +down",
|
||||
"bind joyleft +left",
|
||||
"bind joyright +right",
|
||||
"bind joy0 +b",
|
||||
"bind joy1 +a",
|
||||
"bind joy2 +select",
|
||||
"bind joy3 +start",
|
||||
"bind 1 \"set saveslot 1\"",
|
||||
"bind 2 \"set saveslot 2\"",
|
||||
"bind 3 \"set saveslot 3\"",
|
||||
"bind 4 \"set saveslot 4\"",
|
||||
"bind 5 \"set saveslot 5\"",
|
||||
"bind 6 \"set saveslot 6\"",
|
||||
"bind 7 \"set saveslot 7\"",
|
||||
"bind 8 \"set saveslot 8\"",
|
||||
"bind 9 \"set saveslot 9\"",
|
||||
"bind 0 \"set saveslot 0\"",
|
||||
"bind ins savestate",
|
||||
"bind del loadstate",
|
||||
"source gnuboy.rc",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static void banner()
|
||||
{
|
||||
printf("\ngnuboy " VERSION "\n");
|
||||
}
|
||||
|
||||
static void copyright()
|
||||
{
|
||||
banner();
|
||||
printf(
|
||||
"Copyright (C) 2000-2001 Laguna and Gilgamesh\n"
|
||||
"Portions contributed by other authors; see CREDITS for details.\n"
|
||||
"\n"
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void usage(char *name)
|
||||
{
|
||||
copyright();
|
||||
printf("Type %s --help for detailed help.\n\n", name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void copying()
|
||||
{
|
||||
copyright();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void help(char *name)
|
||||
{
|
||||
banner();
|
||||
printf("Usage: %s [options] romfile\n", name);
|
||||
printf("\n"
|
||||
" --source FILE read rc commands from FILE\n"
|
||||
" --bind KEY COMMAND bind KEY to perform COMMAND\n"
|
||||
" --VAR=VALUE set rc variable VAR to VALUE\n"
|
||||
" --VAR set VAR to 1 (turn on boolean options)\n"
|
||||
" --no-VAR set VAR to 0 (turn off boolean options)\n"
|
||||
" --showvars list all available rc variables\n"
|
||||
" --help display this help and exit\n"
|
||||
" --version output version information and exit\n"
|
||||
" --copying show copying permissions\n"
|
||||
"");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void version(char *name)
|
||||
{
|
||||
printf("%s-" VERSION "\n", name);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void doevents()
|
||||
{
|
||||
event_t ev;
|
||||
int st;
|
||||
|
||||
ev_poll();
|
||||
while (ev_getevent(&ev))
|
||||
{
|
||||
if (ev.type != EV_PRESS && ev.type != EV_RELEASE)
|
||||
continue;
|
||||
st = (ev.type != EV_RELEASE);
|
||||
rc_dokey(ev.code, st);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void shutdown()
|
||||
{
|
||||
vid_close();
|
||||
pcm_close();
|
||||
}
|
||||
|
||||
void die(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int bad_signals[] =
|
||||
{
|
||||
/* These are all standard, so no need to #ifdef them... */
|
||||
SIGINT, SIGSEGV, SIGTERM, SIGFPE, SIGABRT, SIGILL,
|
||||
#ifdef SIGQUIT
|
||||
SIGQUIT,
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
SIGPIPE,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
static void fatalsignal(int s)
|
||||
{
|
||||
die("Signal %d\n", s);
|
||||
}
|
||||
|
||||
static void catch_signals()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; bad_signals[i]; i++)
|
||||
signal(bad_signals[i], fatalsignal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *base(char *s)
|
||||
{
|
||||
char *p;
|
||||
p = strrchr(s, '/');
|
||||
if (p) return p+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *opt, *arg, *cmd, *s, *rom = 0;
|
||||
|
||||
/* Avoid initializing video if we don't have to */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--help"))
|
||||
help(base(argv[0]));
|
||||
else if (!strcmp(argv[i], "--version"))
|
||||
version(base(argv[0]));
|
||||
else if (!strcmp(argv[i], "--copying"))
|
||||
copying();
|
||||
else if (!strcmp(argv[i], "--bind")) i += 2;
|
||||
else if (!strcmp(argv[i], "--source")) i++;
|
||||
else if (!strcmp(argv[i], "--showvars"))
|
||||
{
|
||||
show_exports();
|
||||
exit(0);
|
||||
}
|
||||
else if (argv[i][0] == '-' && argv[i][1] == '-');
|
||||
else if (argv[i][0] == '-' && argv[i][1]);
|
||||
else rom = argv[i];
|
||||
}
|
||||
|
||||
if (!rom) usage(base(argv[0]));
|
||||
|
||||
/* If we have special perms, drop them ASAP! */
|
||||
vid_preinit();
|
||||
|
||||
init_exports();
|
||||
|
||||
s = strdup(argv[0]);
|
||||
sys_sanitize(s);
|
||||
sys_initpath(s);
|
||||
|
||||
for (i = 0; defaultconfig[i]; i++)
|
||||
rc_command(defaultconfig[i]);
|
||||
|
||||
cmd = malloc(strlen(rom) + 11);
|
||||
sprintf(cmd, "source %s", rom);
|
||||
s = strchr(cmd, '.');
|
||||
if (s) *s = 0;
|
||||
strcat(cmd, ".rc");
|
||||
rc_command(cmd);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--bind"))
|
||||
{
|
||||
if (i + 2 >= argc) die("missing arguments to bind\n");
|
||||
cmd = malloc(strlen(argv[i+1]) + strlen(argv[i+2]) + 9);
|
||||
sprintf(cmd, "bind %s \"%s\"", argv[i+1], argv[i+2]);
|
||||
rc_command(cmd);
|
||||
free(cmd);
|
||||
i += 2;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--source"))
|
||||
{
|
||||
if (i + 1 >= argc) die("missing argument to source\n");
|
||||
cmd = malloc(strlen(argv[i+1]) + 6);
|
||||
sprintf(cmd, "source %s", argv[++i]);
|
||||
rc_command(cmd);
|
||||
free(cmd);
|
||||
}
|
||||
else if (!strncmp(argv[i], "--no-", 5))
|
||||
{
|
||||
opt = strdup(argv[i]+5);
|
||||
while ((s = strchr(opt, '-'))) *s = '_';
|
||||
cmd = malloc(strlen(opt) + 7);
|
||||
sprintf(cmd, "set %s 0", opt);
|
||||
rc_command(cmd);
|
||||
free(cmd);
|
||||
free(opt);
|
||||
}
|
||||
else if (argv[i][0] == '-' && argv[i][1] == '-')
|
||||
{
|
||||
opt = strdup(argv[i]+2);
|
||||
if ((s = strchr(opt, '=')))
|
||||
{
|
||||
*s = 0;
|
||||
arg = s+1;
|
||||
}
|
||||
else arg = "1";
|
||||
while ((s = strchr(opt, '-'))) *s = '_';
|
||||
while ((s = strchr(arg, ','))) *s = ' ';
|
||||
|
||||
cmd = malloc(strlen(opt) + strlen(arg) + 6);
|
||||
sprintf(cmd, "set %s %s", opt, arg);
|
||||
|
||||
rc_command(cmd);
|
||||
free(cmd);
|
||||
free(opt);
|
||||
}
|
||||
/* short options not yet implemented */
|
||||
else if (argv[i][0] == '-' && argv[i][1]);
|
||||
}
|
||||
|
||||
/* FIXME - make interface modules responsible for atexit() */
|
||||
atexit(shutdown);
|
||||
catch_signals();
|
||||
vid_init();
|
||||
pcm_init();
|
||||
|
||||
rom = strdup(rom);
|
||||
sys_sanitize(rom);
|
||||
|
||||
loader_init(rom);
|
||||
|
||||
emu_reset();
|
||||
emu_run();
|
||||
|
||||
/* never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,576 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "hw.h"
|
||||
#include "regs.h"
|
||||
#include "mem.h"
|
||||
#include "rtc.h"
|
||||
#include "lcd.h"
|
||||
|
||||
struct mbc mbc;
|
||||
struct rom rom;
|
||||
struct ram ram;
|
||||
|
||||
|
||||
/*
|
||||
* In order to make reads and writes efficient, we keep tables
|
||||
* (indexed by the high nibble of the address) specifying which
|
||||
* regions can be read/written without a function call. For such
|
||||
* ranges, the pointer in the map table points to the base of the
|
||||
* region in host system memory. For ranges that require special
|
||||
* processing, the pointer is NULL.
|
||||
*
|
||||
* mem_updatemap is called whenever bank changes or other operations
|
||||
* make the old maps potentially invalid.
|
||||
*/
|
||||
|
||||
void mem_updatemap()
|
||||
{
|
||||
int n;
|
||||
byte **map;
|
||||
|
||||
map = mbc.rmap;
|
||||
map[0x0] = rom.bank[0];
|
||||
map[0x1] = rom.bank[0];
|
||||
map[0x2] = rom.bank[0];
|
||||
map[0x3] = rom.bank[0];
|
||||
if (mbc.rombank < mbc.romsize)
|
||||
{
|
||||
map[0x4] = rom.bank[mbc.rombank] - 0x4000;
|
||||
map[0x5] = rom.bank[mbc.rombank] - 0x4000;
|
||||
map[0x6] = rom.bank[mbc.rombank] - 0x4000;
|
||||
map[0x7] = rom.bank[mbc.rombank] - 0x4000;
|
||||
}
|
||||
else map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
|
||||
if (0 && (R_STAT & 0x03) == 0x03)
|
||||
{
|
||||
map[0x8] = NULL;
|
||||
map[0x9] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
map[0x8] = lcd.vbank[R_VBK & 1] - 0x8000;
|
||||
map[0x9] = lcd.vbank[R_VBK & 1] - 0x8000;
|
||||
}
|
||||
if (mbc.enableram && !(rtc.sel&8))
|
||||
{
|
||||
map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
|
||||
map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
|
||||
}
|
||||
else map[0xA] = map[0xB] = NULL;
|
||||
map[0xC] = ram.ibank[0] - 0xC000;
|
||||
n = R_SVBK & 0x07;
|
||||
map[0xD] = ram.ibank[n?n:1] - 0xD000;
|
||||
map[0xE] = ram.ibank[0] - 0xE000;
|
||||
map[0xF] = NULL;
|
||||
|
||||
map = mbc.wmap;
|
||||
map[0x0] = map[0x1] = map[0x2] = map[0x3] = NULL;
|
||||
map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
|
||||
map[0x8] = map[0x9] = NULL;
|
||||
if (mbc.enableram && !(rtc.sel&8))
|
||||
{
|
||||
map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
|
||||
map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
|
||||
}
|
||||
else map[0xA] = map[0xB] = NULL;
|
||||
map[0xC] = ram.ibank[0] - 0xC000;
|
||||
n = R_SVBK & 0x07;
|
||||
map[0xD] = ram.ibank[n?n:1] - 0xD000;
|
||||
map[0xE] = ram.ibank[0] - 0xE000;
|
||||
map[0xF] = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ioreg_write handles output to io registers in the FF00-FF7F,FFFF
|
||||
* range. It takes the register number (low byte of the address) and a
|
||||
* byte value to be written.
|
||||
*/
|
||||
|
||||
void ioreg_write(byte r, byte b)
|
||||
{
|
||||
if (!hw.cgb)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case RI_VBK:
|
||||
case RI_BCPS:
|
||||
case RI_OCPS:
|
||||
case RI_BCPD:
|
||||
case RI_OCPD:
|
||||
case RI_SVBK:
|
||||
case RI_KEY1:
|
||||
case RI_HDMA1:
|
||||
case RI_HDMA2:
|
||||
case RI_HDMA3:
|
||||
case RI_HDMA4:
|
||||
case RI_HDMA5:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(r)
|
||||
{
|
||||
case RI_TIMA:
|
||||
case RI_TMA:
|
||||
case RI_TAC:
|
||||
case RI_SCY:
|
||||
case RI_SCX:
|
||||
case RI_WY:
|
||||
case RI_WX:
|
||||
REG(r) = b;
|
||||
break;
|
||||
case RI_BGP:
|
||||
if (R_BGP == b) break;
|
||||
pal_write_dmg(0, 0, b);
|
||||
pal_write_dmg(8, 1, b);
|
||||
R_BGP = b;
|
||||
break;
|
||||
case RI_OBP0:
|
||||
if (R_OBP0 == b) break;
|
||||
pal_write_dmg(64, 2, b);
|
||||
R_OBP0 = b;
|
||||
break;
|
||||
case RI_OBP1:
|
||||
if (R_OBP1 == b) break;
|
||||
pal_write_dmg(72, 3, b);
|
||||
R_OBP1 = b;
|
||||
break;
|
||||
case RI_IF:
|
||||
case RI_IE:
|
||||
REG(r) = b & 0x1F;
|
||||
break;
|
||||
case RI_P1:
|
||||
REG(r) = b;
|
||||
pad_refresh();
|
||||
break;
|
||||
case RI_SC:
|
||||
/* FIXME - this is a hack for stupid roms that probe serial */
|
||||
if ((b & 0x81) == 0x81)
|
||||
{
|
||||
R_SB = 0xff;
|
||||
hw_interrupt(IF_SERIAL, IF_SERIAL);
|
||||
hw_interrupt(0, IF_SERIAL);
|
||||
}
|
||||
R_SC = b; /* & 0x7f; */
|
||||
break;
|
||||
case RI_DIV:
|
||||
REG(r) = 0;
|
||||
break;
|
||||
case RI_LCDC:
|
||||
lcdc_change(b);
|
||||
break;
|
||||
case RI_STAT:
|
||||
stat_write(b);
|
||||
break;
|
||||
case RI_LYC:
|
||||
REG(r) = b;
|
||||
stat_trigger();
|
||||
break;
|
||||
case RI_VBK:
|
||||
REG(r) = b | 0xFE;
|
||||
mem_updatemap();
|
||||
break;
|
||||
case RI_BCPS:
|
||||
R_BCPS = b & 0xBF;
|
||||
R_BCPD = lcd.pal[b & 0x3F];
|
||||
break;
|
||||
case RI_OCPS:
|
||||
R_OCPS = b & 0xBF;
|
||||
R_OCPD = lcd.pal[64 + (b & 0x3F)];
|
||||
break;
|
||||
case RI_BCPD:
|
||||
R_BCPD = b;
|
||||
pal_write(R_BCPS & 0x3F, b);
|
||||
if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF;
|
||||
break;
|
||||
case RI_OCPD:
|
||||
R_OCPD = b;
|
||||
pal_write(64 + (R_OCPS & 0x3F), b);
|
||||
if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF;
|
||||
break;
|
||||
case RI_SVBK:
|
||||
REG(r) = b & 0x07;
|
||||
mem_updatemap();
|
||||
break;
|
||||
case RI_DMA:
|
||||
hw_dma(b);
|
||||
break;
|
||||
case RI_KEY1:
|
||||
REG(r) = (REG(r) & 0x80) | (b & 0x01);
|
||||
break;
|
||||
case RI_HDMA1:
|
||||
REG(r) = b;
|
||||
break;
|
||||
case RI_HDMA2:
|
||||
REG(r) = b & 0xF0;
|
||||
break;
|
||||
case RI_HDMA3:
|
||||
REG(r) = b & 0x1F;
|
||||
break;
|
||||
case RI_HDMA4:
|
||||
REG(r) = b & 0xF0;
|
||||
break;
|
||||
case RI_HDMA5:
|
||||
hw_hdma_cmd(b);
|
||||
break;
|
||||
}
|
||||
switch (r)
|
||||
{
|
||||
case RI_BGP:
|
||||
case RI_OBP0:
|
||||
case RI_OBP1:
|
||||
/* printf("palette reg %02X write %02X at LY=%02X\n", r, b, R_LY); */
|
||||
case RI_HDMA1:
|
||||
case RI_HDMA2:
|
||||
case RI_HDMA3:
|
||||
case RI_HDMA4:
|
||||
case RI_HDMA5:
|
||||
/* printf("HDMA %d: %02X\n", r - RI_HDMA1 + 1, b); */
|
||||
break;
|
||||
}
|
||||
/* printf("reg %02X => %02X (%02X)\n", r, REG(r), b); */
|
||||
}
|
||||
|
||||
|
||||
byte ioreg_read(byte r)
|
||||
{
|
||||
switch(r)
|
||||
{
|
||||
case RI_SC:
|
||||
r = R_SC;
|
||||
R_SC &= 0x7f;
|
||||
return r;
|
||||
case RI_P1:
|
||||
case RI_SB:
|
||||
case RI_DIV:
|
||||
case RI_TIMA:
|
||||
case RI_TMA:
|
||||
case RI_TAC:
|
||||
case RI_LCDC:
|
||||
case RI_STAT:
|
||||
case RI_SCY:
|
||||
case RI_SCX:
|
||||
case RI_LY:
|
||||
case RI_LYC:
|
||||
case RI_BGP:
|
||||
case RI_OBP0:
|
||||
case RI_OBP1:
|
||||
case RI_WY:
|
||||
case RI_WX:
|
||||
case RI_IE:
|
||||
case RI_IF:
|
||||
return REG(r);
|
||||
case RI_VBK:
|
||||
case RI_BCPS:
|
||||
case RI_OCPS:
|
||||
case RI_BCPD:
|
||||
case RI_OCPD:
|
||||
case RI_SVBK:
|
||||
case RI_KEY1:
|
||||
case RI_HDMA1:
|
||||
case RI_HDMA2:
|
||||
case RI_HDMA3:
|
||||
case RI_HDMA4:
|
||||
case RI_HDMA5:
|
||||
if (hw.cgb) return REG(r);
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Memory bank controllers typically intercept write attempts to
|
||||
* 0000-7FFF, using the address and byte written as instructions to
|
||||
* change rom or sram banks, control special hardware, etc.
|
||||
*
|
||||
* mbc_write takes an address (which should be in the proper range)
|
||||
* and a byte value written to the address.
|
||||
*/
|
||||
|
||||
void mbc_write(int a, byte b)
|
||||
{
|
||||
byte ha = (a>>12);
|
||||
|
||||
/* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */
|
||||
switch (mbc.type)
|
||||
{
|
||||
case MBC_MBC1:
|
||||
switch (ha & 0xE)
|
||||
{
|
||||
case 0x0:
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
case 0x2:
|
||||
if ((b & 0x1F) == 0) b = 0x01;
|
||||
mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
|
||||
break;
|
||||
case 0x4:
|
||||
if (mbc.model)
|
||||
{
|
||||
mbc.rambank = b & 0x03;
|
||||
break;
|
||||
}
|
||||
mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
|
||||
break;
|
||||
case 0x6:
|
||||
mbc.model = b & 0x1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MBC_MBC2: /* is this at all right? */
|
||||
if ((a & 0x0100) == 0x0000)
|
||||
{
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
}
|
||||
if ((a & 0xE100) == 0x2100)
|
||||
{
|
||||
mbc.rombank = b & 0x0F;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MBC_MBC3:
|
||||
switch (ha & 0xE)
|
||||
{
|
||||
case 0x0:
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
case 0x2:
|
||||
if ((b & 0x7F) == 0) b = 0x01;
|
||||
mbc.rombank = b & 0x7F;
|
||||
break;
|
||||
case 0x4:
|
||||
rtc.sel = b & 0x0f;
|
||||
mbc.rambank = b & 0x03;
|
||||
break;
|
||||
case 0x6:
|
||||
rtc_latch(b);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MBC_RUMBLE:
|
||||
switch (ha & 0xF)
|
||||
{
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
/* FIXME - save high bit as rumble state */
|
||||
/* mask off high bit */
|
||||
b &= 0x7;
|
||||
break;
|
||||
}
|
||||
/* fall thru */
|
||||
case MBC_MBC5:
|
||||
switch (ha & 0xF)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
case 0x2:
|
||||
if ((b & 0xFF) == 0) b = 0x01;
|
||||
mbc.rombank = (mbc.rombank & 0x100) | (b & 0xFF);
|
||||
break;
|
||||
case 0x3:
|
||||
mbc.rombank = (mbc.rombank & 0xFF) | ((int)(b&1)<<8);
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
mbc.rambank = b & 0x0f;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */
|
||||
switch (ha & 0xE)
|
||||
{
|
||||
case 0x0:
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
case 0x2:
|
||||
if ((b & 0x1F) == 0) b = 0x01;
|
||||
mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
|
||||
break;
|
||||
case 0x4:
|
||||
if (mbc.model)
|
||||
{
|
||||
mbc.rambank = b & 0x03;
|
||||
break;
|
||||
}
|
||||
mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
|
||||
break;
|
||||
case 0x6:
|
||||
mbc.model = b & 0x1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MBC_HUC3:
|
||||
switch (ha & 0xE)
|
||||
{
|
||||
case 0x0:
|
||||
mbc.enableram = ((b & 0x0F) == 0x0A);
|
||||
break;
|
||||
case 0x2:
|
||||
b &= 0x7F;
|
||||
mbc.rombank = b ? b : 1;
|
||||
break;
|
||||
case 0x4:
|
||||
rtc.sel = b & 0x0f;
|
||||
mbc.rambank = b & 0x03;
|
||||
break;
|
||||
case 0x6:
|
||||
rtc_latch(b);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
mbc.rombank &= (mbc.romsize - 1);
|
||||
mbc.rambank &= (mbc.ramsize - 1);
|
||||
/* printf("%02X\n", mbc.rombank); */
|
||||
mem_updatemap();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mem_write is the basic write function. Although it should only be
|
||||
* called when the write map contains a NULL for the requested address
|
||||
* region, it accepts writes to any address.
|
||||
*/
|
||||
|
||||
void mem_write(int a, byte b)
|
||||
{
|
||||
int n;
|
||||
byte ha = (a>>12) & 0xE;
|
||||
|
||||
/* printf("write to 0x%04X: 0x%02X\n", a, b); */
|
||||
switch (ha)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x2:
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
mbc_write(a, b);
|
||||
break;
|
||||
case 0x8:
|
||||
/* if ((R_STAT & 0x03) == 0x03) break; */
|
||||
vram_write(a & 0x1FFF, b);
|
||||
break;
|
||||
case 0xA:
|
||||
if (!mbc.enableram) break;
|
||||
if (rtc.sel&8)
|
||||
{
|
||||
rtc_write(b);
|
||||
break;
|
||||
}
|
||||
ram.sbank[mbc.rambank][a & 0x1FFF] = b;
|
||||
break;
|
||||
case 0xC:
|
||||
if ((a & 0xF000) == 0xC000)
|
||||
{
|
||||
ram.ibank[0][a & 0x0FFF] = b;
|
||||
break;
|
||||
}
|
||||
n = R_SVBK & 0x07;
|
||||
ram.ibank[n?n:1][a & 0x0FFF] = b;
|
||||
break;
|
||||
case 0xE:
|
||||
if (a < 0xFE00)
|
||||
{
|
||||
mem_write(a & 0xDFFF, b);
|
||||
break;
|
||||
}
|
||||
if ((a & 0xFF00) == 0xFE00)
|
||||
{
|
||||
/* if (R_STAT & 0x02) break; */
|
||||
if (a < 0xFEA0) lcd.oam.mem[a & 0xFF] = b;
|
||||
break;
|
||||
}
|
||||
/* return writehi(a & 0xFF, b); */
|
||||
if (a >= 0xFF10 && a <= 0xFF3F)
|
||||
{
|
||||
sound_write(a & 0xFF, b);
|
||||
break;
|
||||
}
|
||||
if ((a & 0xFF80) == 0xFF80 && a != 0xFFFF)
|
||||
{
|
||||
ram.hi[a & 0xFF] = b;
|
||||
break;
|
||||
}
|
||||
ioreg_write(a & 0xFF, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mem_read is the basic read function...not useful for much anymore
|
||||
* with the read map, but it's still necessary for the final messy
|
||||
* region.
|
||||
*/
|
||||
|
||||
byte mem_read(int a)
|
||||
{
|
||||
int n;
|
||||
byte ha = (a>>12) & 0xE;
|
||||
|
||||
/* printf("read %04x\n", a); */
|
||||
switch (ha)
|
||||
{
|
||||
case 0x0:
|
||||
case 0x2:
|
||||
return rom.bank[0][a];
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
return rom.bank[mbc.rombank][a & 0x3FFF];
|
||||
case 0x8:
|
||||
/* if ((R_STAT & 0x03) == 0x03) return 0xFF; */
|
||||
return lcd.vbank[R_VBK&1][a & 0x1FFF];
|
||||
case 0xA:
|
||||
if (!mbc.enableram && mbc.type == MBC_HUC3)
|
||||
return 0x01;
|
||||
if (!mbc.enableram)
|
||||
return 0xFF;
|
||||
if (rtc.sel&8)
|
||||
return rtc.regs[rtc.sel&7];
|
||||
return ram.sbank[mbc.rambank][a & 0x1FFF];
|
||||
case 0xC:
|
||||
if ((a & 0xF000) == 0xC000)
|
||||
return ram.ibank[0][a & 0x0FFF];
|
||||
n = R_SVBK & 0x07;
|
||||
return ram.ibank[n?n:1][a & 0x0FFF];
|
||||
case 0xE:
|
||||
if (a < 0xFE00) return mem_read(a & 0xDFFF);
|
||||
if ((a & 0xFF00) == 0xFE00)
|
||||
{
|
||||
/* if (R_STAT & 0x02) return 0xFF; */
|
||||
if (a < 0xFEA0) return lcd.oam.mem[a & 0xFF];
|
||||
return 0xFF;
|
||||
}
|
||||
/* return readhi(a & 0xFF); */
|
||||
if (a == 0xFFFF) return REG(0xFF);
|
||||
if (a >= 0xFF10 && a <= 0xFF3F)
|
||||
return sound_read(a & 0xFF);
|
||||
if ((a & 0xFF80) == 0xFF80)
|
||||
return ram.hi[a & 0xFF];
|
||||
return ioreg_read(a & 0xFF);
|
||||
}
|
||||
return 0xff; /* not reached */
|
||||
}
|
||||
|
||||
void mbc_reset()
|
||||
{
|
||||
mbc.rombank = 1;
|
||||
mbc.rambank = 0;
|
||||
mbc.enableram = 0;
|
||||
mem_updatemap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
#ifndef __MEM_H__
|
||||
#define __MEM_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
#define MBC_NONE 0
|
||||
#define MBC_MBC1 1
|
||||
#define MBC_MBC2 2
|
||||
#define MBC_MBC3 3
|
||||
#define MBC_MBC5 5
|
||||
#define MBC_RUMBLE 15
|
||||
#define MBC_HUC1 0xC1
|
||||
#define MBC_HUC3 0xC3
|
||||
|
||||
struct mbc
|
||||
{
|
||||
int type;
|
||||
int model;
|
||||
int rombank;
|
||||
int rambank;
|
||||
int romsize;
|
||||
int ramsize;
|
||||
int enableram;
|
||||
int batt;
|
||||
byte *rmap[0x10], *wmap[0x10];
|
||||
};
|
||||
|
||||
struct rom
|
||||
{
|
||||
byte (*bank)[16384];
|
||||
char name[20];
|
||||
};
|
||||
|
||||
struct ram
|
||||
{
|
||||
byte hi[256];
|
||||
byte ibank[8][4096];
|
||||
byte (*sbank)[8192];
|
||||
int loaded;
|
||||
};
|
||||
|
||||
|
||||
extern struct mbc mbc;
|
||||
extern struct rom rom;
|
||||
extern struct ram ram;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void mem_updatemap();
|
||||
void ioreg_write(byte r, byte b);
|
||||
void mbc_write(int a, byte b);
|
||||
void mem_write(int a, byte b);
|
||||
byte mem_read(int a);
|
||||
|
||||
|
||||
|
||||
#define READB(a) ( mbc.rmap[(a)>>12] \
|
||||
? mbc.rmap[(a)>>12][(a)] \
|
||||
: mem_read((a)) )
|
||||
#define READW(a) ( READB((a)) | ((word)READB((a)+1)<<8) )
|
||||
|
||||
#define WRITEB(a, b) ( mbc.wmap[(a)>>12] \
|
||||
? ( mbc.wmap[(a)>>12][(a)] = (b) ) \
|
||||
: ( mem_write((a), (b)), (b) ) )
|
||||
#define WRITEW(a, w) ( WRITEB((a), (w)&0xFF), WRITEB((a)+1, (w)>>8) )
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* new sound core for 1.1.x
|
||||
*/
|
||||
|
||||
|
||||
|
||||
enum sevcode
|
||||
{
|
||||
SEV_S1E,
|
||||
SEV_S2E,
|
||||
SEV_S3E,
|
||||
SEV_S4E,
|
||||
SEV_S1L,
|
||||
SEV_S2L,
|
||||
SEV_S3L,
|
||||
SEV_S4L,
|
||||
SEV_SW,
|
||||
SEV_WAV
|
||||
};
|
||||
|
||||
|
||||
struct sev
|
||||
{
|
||||
int prev, next;
|
||||
int time;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct sev *sevs;
|
||||
|
||||
|
||||
|
||||
void sound_mix(int cycles)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sound_update(int force)
|
||||
{
|
||||
int now = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (sevs->time > cpu.snd) break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,532 @@
|
|||
|
||||
#ifndef __NOISE_H__
|
||||
#define __NOISE_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
static byte noise7[] =
|
||||
{
|
||||
0xfd,0xf3,0xd7,0x0d,0xd3,0x15,0x82,0xf1,
|
||||
0xdb,0x25,0x21,0x39,0x68,0x8c,0xd5,0x00,
|
||||
};
|
||||
|
||||
static byte noise15[] =
|
||||
{
|
||||
0xff,0xfd,0xff,0xf3,0xff,0xd7,0xff,0x0f,
|
||||
0xfd,0xdf,0xf3,0x3f,0xd5,0x7f,0x00,0xfd,
|
||||
0xfd,0xf3,0xf3,0xd7,0xd7,0x0f,0x0d,0xdd,
|
||||
0xd3,0x33,0x15,0x55,0x80,0x02,0xff,0xf1,
|
||||
0xff,0xdb,0xff,0x27,0xfd,0x2f,0xf1,0x1f,
|
||||
0xd9,0xbf,0x2a,0x7d,0x02,0xf1,0xf1,0xdb,
|
||||
0xdb,0x27,0x25,0x2d,0x21,0x11,0x39,0x99,
|
||||
0x6a,0xa8,0x80,0x0c,0xff,0xd5,0xff,0x03,
|
||||
0xfd,0xf7,0xf3,0xcf,0xd7,0x5f,0x0c,0x3d,
|
||||
0xd7,0x73,0x0c,0xd5,0xd5,0x03,0x01,0xf5,
|
||||
0xfb,0xc3,0xe7,0x77,0xac,0xce,0x15,0x5b,
|
||||
0x80,0x26,0xff,0x29,0xfd,0x0b,0xf1,0xc7,
|
||||
0xdb,0x6f,0x24,0x9d,0x24,0xb1,0x24,0x59,
|
||||
0x26,0x29,0x2b,0x09,0x05,0xc9,0xe3,0x4b,
|
||||
0xb4,0x46,0x46,0x6a,0x6a,0x82,0x80,0xf0,
|
||||
0xfd,0xdd,0xf3,0x33,0xd5,0x57,0x00,0x0d,
|
||||
0xff,0xd3,0xff,0x17,0xfd,0x8f,0xf2,0xdf,
|
||||
0xd1,0x3f,0x19,0x7d,0xa8,0xf2,0x0d,0xd3,
|
||||
0xd3,0x17,0x15,0x8d,0x82,0xd2,0xf1,0x11,
|
||||
0xd9,0x9b,0x2a,0xa5,0x00,0x21,0xff,0x3b,
|
||||
0xfd,0x67,0xf0,0xaf,0xdc,0x1f,0x37,0xbd,
|
||||
0x4e,0x70,0x5a,0xde,0x21,0x3b,0x39,0x65,
|
||||
0x68,0xa0,0x8c,0x3c,0xd7,0x75,0x0c,0xc1,
|
||||
0xd5,0x7b,0x00,0xe5,0xfd,0xa3,0xf2,0x37,
|
||||
0xd3,0x4f,0x14,0x5d,0x86,0x32,0xeb,0x51,
|
||||
0x84,0x1a,0xe7,0xa1,0xae,0x3a,0x1b,0x63,
|
||||
0xa4,0xb6,0x24,0x4b,0x26,0x45,0x2a,0x61,
|
||||
0x02,0xb9,0xf0,0x6b,0xde,0x87,0x38,0xed,
|
||||
0x6d,0x90,0x92,0x9c,0x90,0xb4,0x9c,0x44,
|
||||
0xb6,0x64,0x4a,0xa6,0x40,0x2a,0x7f,0x02,
|
||||
0xfd,0xf1,0xf3,0xdb,0xd7,0x27,0x0d,0x2d,
|
||||
0xd1,0x13,0x19,0x95,0xaa,0x82,0x00,0xf3,
|
||||
0xfd,0xd7,0xf3,0x0f,0xd5,0xdf,0x03,0x3d,
|
||||
0xf5,0x73,0xc0,0xd7,0x7d,0x0c,0xf1,0xd5,
|
||||
0xdb,0x03,0x25,0xf5,0x23,0xc1,0x37,0x79,
|
||||
0x4c,0xe8,0x55,0x8e,0x02,0xdb,0xf1,0x27,
|
||||
0xd9,0x2f,0x29,0x1d,0x09,0xb1,0xca,0x5b,
|
||||
0x42,0x24,0x73,0x26,0xd5,0x29,0x01,0x09,
|
||||
0xf9,0xcb,0xeb,0x47,0x84,0x6e,0xe6,0x99,
|
||||
0xa8,0xaa,0x0c,0x03,0xd7,0xf7,0x0f,0xcd,
|
||||
0xdf,0x53,0x3c,0x15,0x77,0x80,0xce,0xfd,
|
||||
0x59,0xf0,0x2b,0xdf,0x07,0x3d,0xed,0x73,
|
||||
0x90,0xd6,0x9d,0x08,0xb1,0xcc,0x5b,0x56,
|
||||
0x24,0x0b,0x27,0xc5,0x2f,0x61,0x1c,0xb9,
|
||||
0xb4,0x6a,0x46,0x82,0x68,0xf2,0x8d,0xd0,
|
||||
0xd3,0x1d,0x15,0xb1,0x82,0x5a,0xf2,0x21,
|
||||
0xd3,0x3b,0x15,0x65,0x80,0xa2,0xfc,0x31,
|
||||
0xf7,0x5b,0xcc,0x27,0x57,0x2c,0x0d,0x17,
|
||||
0xd1,0x8f,0x1a,0xdd,0xa1,0x32,0x39,0x53,
|
||||
0x68,0x14,0x8f,0x84,0xde,0xe5,0x39,0xa1,
|
||||
0x6a,0x38,0x83,0x6c,0xf4,0x95,0xc4,0x83,
|
||||
0x64,0xf4,0xa5,0xc4,0x23,0x67,0x34,0xad,
|
||||
0x44,0x10,0x67,0x9e,0xae,0xb8,0x18,0x6f,
|
||||
0xae,0x9e,0x18,0xbb,0xac,0x66,0x16,0xab,
|
||||
0x88,0x06,0xcf,0xe9,0x5f,0x88,0x3e,0xcf,
|
||||
0x79,0x5c,0xe8,0x35,0x8f,0x42,0xdc,0x71,
|
||||
0x36,0xd9,0x49,0x28,0x49,0x0e,0x49,0xda,
|
||||
0x4b,0x22,0x45,0x32,0x61,0x52,0xb8,0x10,
|
||||
0x6f,0x9e,0x9e,0xb8,0xb8,0x6c,0x6e,0x96,
|
||||
0x98,0x88,0xac,0xcc,0x15,0x57,0x80,0x0e,
|
||||
0xff,0xd9,0xff,0x2b,0xfd,0x07,0xf1,0xef,
|
||||
0xdb,0x9f,0x26,0xbd,0x28,0x71,0x0e,0xd9,
|
||||
0xd9,0x2b,0x29,0x05,0x09,0xe1,0xcb,0xbb,
|
||||
0x46,0x64,0x6a,0xa6,0x80,0x28,0xff,0x0d,
|
||||
0xfd,0xd3,0xf3,0x17,0xd5,0x8f,0x02,0xdd,
|
||||
0xf1,0x33,0xd9,0x57,0x28,0x0d,0x0f,0xd1,
|
||||
0xdf,0x1b,0x3d,0xa5,0x72,0x20,0xd3,0x3d,
|
||||
0x15,0x71,0x80,0xda,0xfd,0x21,0xf1,0x3b,
|
||||
0xd9,0x67,0x28,0xad,0x0c,0x11,0xd7,0x9b,
|
||||
0x0e,0xa5,0xd8,0x23,0x2f,0x35,0x1d,0x41,
|
||||
0xb0,0x7a,0x5e,0xe2,0x39,0xb3,0x6a,0x54,
|
||||
0x82,0x04,0xf3,0xe5,0xd7,0xa3,0x0e,0x35,
|
||||
0xdb,0x43,0x24,0x75,0x26,0xc1,0x29,0x79,
|
||||
0x08,0xe9,0xcd,0x8b,0x52,0xc4,0x11,0x67,
|
||||
0x98,0xae,0xac,0x18,0x17,0xaf,0x8e,0x1e,
|
||||
0xdb,0xb9,0x26,0x69,0x2a,0x89,0x00,0xc9,
|
||||
0xfd,0x4b,0xf0,0x47,0xde,0x6f,0x3a,0x9d,
|
||||
0x60,0xb0,0xbc,0x5c,0x76,0x36,0xcb,0x49,
|
||||
0x44,0x48,0x66,0x4e,0xaa,0x58,0x02,0x2f,
|
||||
0xf3,0x1f,0xd5,0xbf,0x02,0x7d,0xf2,0xf3,
|
||||
0xd1,0xd7,0x1b,0x0d,0xa5,0xd2,0x23,0x13,
|
||||
0x35,0x95,0x42,0x80,0x70,0xfe,0xdd,0xf9,
|
||||
0x33,0xe9,0x57,0x88,0x0e,0xcf,0xd9,0x5f,
|
||||
0x28,0x3d,0x0f,0x71,0xdc,0xdb,0x35,0x25,
|
||||
0x41,0x20,0x79,0x3e,0xe9,0x79,0x88,0xea,
|
||||
0xcd,0x81,0x52,0xf8,0x11,0xef,0x9b,0x9e,
|
||||
0xa6,0xb8,0x28,0x6f,0x0e,0x9d,0xd8,0xb3,
|
||||
0x2c,0x55,0x16,0x01,0x8b,0xfa,0xc7,0xe1,
|
||||
0x6f,0xb8,0x9e,0x6c,0xba,0x94,0x60,0x86,
|
||||
0xbc,0xe8,0x75,0x8e,0xc2,0xd9,0x71,0x28,
|
||||
0xd9,0x0d,0x29,0xd1,0x0b,0x19,0xc5,0xab,
|
||||
0x62,0x04,0xb3,0xe4,0x57,0xa6,0x0e,0x2b,
|
||||
0xdb,0x07,0x25,0xed,0x23,0x91,0x36,0x99,
|
||||
0x48,0xa8,0x4c,0x0e,0x57,0xda,0x0f,0x23,
|
||||
0xdd,0x37,0x31,0x4d,0x58,0x50,0x2e,0x1f,
|
||||
0x1b,0xbd,0xa6,0x72,0x2a,0xd3,0x01,0x15,
|
||||
0xf9,0x83,0xea,0xf7,0x81,0xce,0xfb,0x59,
|
||||
0xe4,0x2b,0xa7,0x06,0x2d,0xeb,0x13,0x85,
|
||||
0x96,0xe2,0x89,0xb0,0xca,0x5d,0x42,0x30,
|
||||
0x73,0x5e,0xd4,0x39,0x07,0x69,0xec,0x8b,
|
||||
0x94,0xc6,0x85,0x68,0xe0,0x8d,0xbc,0xd2,
|
||||
0x75,0x12,0xc1,0x91,0x7a,0x98,0xe0,0xad,
|
||||
0xbc,0x12,0x77,0x92,0xce,0x91,0x58,0x98,
|
||||
0x2c,0xaf,0x14,0x1d,0x87,0xb2,0xee,0x51,
|
||||
0x9a,0x1a,0xa3,0xa0,0x36,0x3f,0x4b,0x7c,
|
||||
0x44,0xf6,0x65,0xca,0xa3,0x40,0x34,0x7f,
|
||||
0x46,0xfc,0x69,0xf6,0x8b,0xc8,0xc7,0x4d,
|
||||
0x6c,0x50,0x96,0x1c,0x8b,0xb4,0xc6,0x45,
|
||||
0x6a,0x60,0x82,0xbc,0xf0,0x75,0xde,0xc3,
|
||||
0x39,0x75,0x68,0xc0,0x8d,0x7c,0xd0,0xf5,
|
||||
0x1d,0xc1,0xb3,0x7a,0x54,0xe2,0x05,0xb3,
|
||||
0xe2,0x57,0xb2,0x0e,0x53,0xda,0x17,0x23,
|
||||
0x8d,0x36,0xd1,0x49,0x18,0x49,0xae,0x4a,
|
||||
0x1a,0x43,0xa2,0x76,0x32,0xcb,0x51,0x44,
|
||||
0x18,0x67,0xae,0xae,0x18,0x1b,0xaf,0xa6,
|
||||
0x1e,0x2b,0xbb,0x06,0x65,0xea,0xa3,0x80,
|
||||
0x36,0xff,0x49,0xfc,0x4b,0xf6,0x47,0xca,
|
||||
0x6f,0x42,0x9c,0x70,0xb6,0xdc,0x49,0x36,
|
||||
0x49,0x4a,0x48,0x42,0x4e,0x72,0x5a,0xd2,
|
||||
0x21,0x13,0x39,0x95,0x6a,0x80,0x80,0xfc,
|
||||
0xfd,0xf5,0xf3,0xc3,0xd7,0x77,0x0c,0xcd,
|
||||
0xd5,0x53,0x00,0x15,0xff,0x83,0xfe,0xf7,
|
||||
0xf9,0xcf,0xeb,0x5f,0x84,0x3e,0xe7,0x79,
|
||||
0xac,0xea,0x15,0x83,0x82,0xf6,0xf1,0xc9,
|
||||
0xdb,0x4b,0x24,0x45,0x26,0x61,0x2a,0xb9,
|
||||
0x00,0x69,0xfe,0x8b,0xf8,0xc7,0xed,0x6f,
|
||||
0x90,0x9e,0x9c,0xb8,0xb4,0x6c,0x46,0x96,
|
||||
0x68,0x8a,0x8c,0xc0,0xd5,0x7d,0x00,0xf1,
|
||||
0xfd,0xdb,0xf3,0x27,0xd5,0x2f,0x01,0x1d,
|
||||
0xf9,0xb3,0xea,0x57,0x82,0x0e,0xf3,0xd9,
|
||||
0xd7,0x2b,0x0d,0x05,0xd1,0xe3,0x1b,0xb5,
|
||||
0xa6,0x42,0x2a,0x73,0x02,0xd5,0xf1,0x03,
|
||||
0xd9,0xf7,0x2b,0xcd,0x07,0x51,0xec,0x1b,
|
||||
0x97,0xa6,0x8e,0x28,0xdb,0x0d,0x25,0xd1,
|
||||
0x23,0x19,0x35,0xa9,0x42,0x08,0x73,0xce,
|
||||
0xd7,0x59,0x0c,0x29,0xd7,0x0b,0x0d,0xc5,
|
||||
0xd3,0x63,0x14,0xb5,0x84,0x42,0xe6,0x71,
|
||||
0xaa,0xda,0x01,0x23,0xf9,0x37,0xe9,0x4f,
|
||||
0x88,0x5e,0xce,0x39,0x5b,0x68,0x24,0x8f,
|
||||
0x24,0xdd,0x25,0x31,0x21,0x59,0x38,0x29,
|
||||
0x6f,0x08,0x9d,0xcc,0xb3,0x54,0x54,0x06,
|
||||
0x07,0xeb,0xef,0x87,0x9e,0xee,0xb9,0x98,
|
||||
0x6a,0xae,0x80,0x18,0xff,0xad,0xfe,0x13,
|
||||
0xfb,0x97,0xe6,0x8f,0xa8,0xde,0x0d,0x3b,
|
||||
0xd1,0x67,0x18,0xad,0xac,0x12,0x17,0x93,
|
||||
0x8e,0x96,0xd8,0x89,0x2c,0xc9,0x15,0x49,
|
||||
0x80,0x4a,0xfe,0x41,0xfa,0x7b,0xe2,0xe7,
|
||||
0xb1,0xae,0x5a,0x1a,0x23,0xa3,0x36,0x35,
|
||||
0x4b,0x40,0x44,0x7e,0x66,0xfa,0xa9,0xe0,
|
||||
0x0b,0xbf,0xc6,0x7f,0x6a,0xfc,0x81,0xf4,
|
||||
0xfb,0xc5,0xe7,0x63,0xac,0xb6,0x14,0x4b,
|
||||
0x86,0x46,0xea,0x69,0x82,0x8a,0xf0,0xc1,
|
||||
0xdd,0x7b,0x30,0xe5,0x5d,0xa0,0x32,0x3f,
|
||||
0x53,0x7c,0x14,0xf7,0x85,0xce,0xe3,0x59,
|
||||
0xb4,0x2a,0x47,0x02,0x6d,0xf2,0x93,0xd0,
|
||||
0x97,0x1c,0x8d,0xb4,0xd2,0x45,0x12,0x61,
|
||||
0x92,0xba,0x90,0x60,0x9e,0xbc,0xb8,0x74,
|
||||
0x6e,0xc6,0x99,0x68,0xa8,0x8c,0x0c,0xd7,
|
||||
0xd5,0x0f,0x01,0xdd,0xfb,0x33,0xe5,0x57,
|
||||
0xa0,0x0e,0x3f,0xdb,0x7f,0x24,0xfd,0x25,
|
||||
0xf1,0x23,0xd9,0x37,0x29,0x4d,0x08,0x51,
|
||||
0xce,0x1b,0x5b,0xa4,0x26,0x27,0x2b,0x2d,
|
||||
0x05,0x11,0xe1,0x9b,0xba,0xa6,0x60,0x2a,
|
||||
0xbf,0x00,0x7d,0xfe,0xf3,0xf9,0xd7,0xeb,
|
||||
0x0f,0x85,0xde,0xe3,0x39,0xb5,0x6a,0x40,
|
||||
0x82,0x7c,0xf2,0xf5,0xd1,0xc3,0x1b,0x75,
|
||||
0xa4,0xc2,0x25,0x73,0x20,0xd5,0x3d,0x01,
|
||||
0x71,0xf8,0xdb,0xed,0x27,0x91,0x2e,0x99,
|
||||
0x18,0xa9,0xac,0x0a,0x17,0xc3,0x8f,0x76,
|
||||
0xdc,0xc9,0x35,0x49,0x40,0x48,0x7e,0x4e,
|
||||
0xfa,0x59,0xe2,0x2b,0xb3,0x06,0x55,0xe2,
|
||||
0x03,0x83,0xf6,0xf7,0xc9,0xcf,0x4b,0x5c,
|
||||
0x04,0x3e,0x67,0x4e,0xac,0x60,0x17,0x7f,
|
||||
0x80,0xfe,0xc1,0xf9,0x7b,0xe8,0xe7,0x87,
|
||||
0xae,0xc2,0x19,0x93,0xfc,0x96,0x08,0x8f,
|
||||
0xc0,0xe7,0xfc,0x2c,0xf0,0x1d,0xcc,0xc3,
|
||||
0x9e,0x70,0x00,0xc0,0x63,0x7f,0x54,0x78,
|
||||
0x40,0xfe,0x61,0x9b,0xf3,0x40,0x64,0x3f,
|
||||
0x0f,0xf8,0x2c,0xf3,0x3f,0x99,0x83,0x2a,
|
||||
0x79,0x07,0xcb,0xe1,0x9f,0xcc,0xce,0x60,
|
||||
0x6c,0x00,0x84,0x7c,0x0f,0xf5,0xe8,0xcf,
|
||||
0x15,0x66,0x80,0xb0,0xf8,0x5d,0xf4,0x33,
|
||||
0x8a,0x57,0x44,0x0c,0x67,0xd6,0xaf,0x08,
|
||||
0x1f,0xcf,0xb3,0x5e,0x54,0x3a,0x07,0x63,
|
||||
0xec,0xb7,0x94,0x4e,0x86,0x58,0xea,0x2d,
|
||||
0x83,0x12,0xf5,0x91,0xc2,0x9b,0x70,0xa4,
|
||||
0xdc,0x25,0x37,0x21,0x4d,0x38,0x51,0x6e,
|
||||
0x18,0x9b,0xac,0xa6,0x14,0x2b,0x87,0x06,
|
||||
0xed,0xe9,0x93,0x8a,0x96,0xc0,0x89,0x7c,
|
||||
0xc8,0xf5,0x4d,0xc0,0x53,0x7e,0x14,0xfb,
|
||||
0x85,0xe6,0xe3,0xa9,0xb6,0x0a,0x4b,0xc2,
|
||||
0x47,0x72,0x6c,0xd2,0x95,0x10,0x81,0x9c,
|
||||
0xfa,0xb5,0xe0,0x43,0xbe,0x76,0x7a,0xca,
|
||||
0xe1,0x41,0xb8,0x7a,0x6e,0xe2,0x99,0xb0,
|
||||
0xaa,0x5c,0x02,0x37,0xf3,0x4f,0xd4,0x5f,
|
||||
0x06,0x3d,0xeb,0x73,0x84,0xd6,0xe5,0x09,
|
||||
0xa1,0xca,0x3b,0x43,0x64,0x74,0xa6,0xc4,
|
||||
0x29,0x67,0x08,0xad,0xcc,0x13,0x57,0x94,
|
||||
0x0e,0x87,0xd8,0xef,0x2d,0x9d,0x12,0xb1,
|
||||
0x90,0x5a,0x9e,0x20,0xbb,0x3c,0x65,0x76,
|
||||
0xa0,0xc8,0x3d,0x4f,0x70,0x5c,0xde,0x35,
|
||||
0x3b,0x41,0x64,0x78,0xa6,0xec,0x29,0x97,
|
||||
0x0a,0x8d,0xc0,0xd3,0x7d,0x14,0xf1,0x85,
|
||||
0xda,0xe3,0x21,0xb5,0x3a,0x41,0x62,0x78,
|
||||
0xb2,0xec,0x51,0x96,0x1a,0x8b,0xa0,0xc6,
|
||||
0x3d,0x6b,0x70,0x84,0xdc,0xe5,0x35,0xa1,
|
||||
0x42,0x38,0x73,0x6e,0xd4,0x99,0x04,0xa9,
|
||||
0xe4,0x0b,0xa7,0xc6,0x2f,0x6b,0x1c,0x85,
|
||||
0xb4,0xe2,0x45,0xb2,0x62,0x52,0xb2,0x10,
|
||||
0x53,0x9e,0x16,0xbb,0x88,0x66,0xce,0xa9,
|
||||
0x58,0x08,0x2f,0xcf,0x1f,0x5d,0xbc,0x32,
|
||||
0x77,0x52,0xcc,0x11,0x57,0x98,0x0e,0xaf,
|
||||
0xd8,0x1f,0x2f,0xbd,0x1e,0x71,0xba,0xda,
|
||||
0x61,0x22,0xb9,0x30,0x69,0x5e,0x88,0x38,
|
||||
0xcf,0x6d,0x5c,0x90,0x34,0x9f,0x44,0xbc,
|
||||
0x64,0x76,0xa6,0xc8,0x29,0x4f,0x08,0x5d,
|
||||
0xce,0x33,0x5b,0x54,0x24,0x07,0x27,0xed,
|
||||
0x2f,0x91,0x1e,0x99,0xb8,0xaa,0x6c,0x02,
|
||||
0x97,0xf0,0x8f,0xdc,0xdf,0x35,0x3d,0x41,
|
||||
0x70,0x78,0xde,0xed,0x39,0x91,0x6a,0x98,
|
||||
0x80,0xac,0xfc,0x15,0xf7,0x83,0xce,0xf7,
|
||||
0x59,0xcc,0x2b,0x57,0x04,0x0d,0xe7,0xd3,
|
||||
0xaf,0x16,0x1d,0x8b,0xb2,0xc6,0x51,0x6a,
|
||||
0x18,0x83,0xac,0xf6,0x15,0xcb,0x83,0x46,
|
||||
0xf4,0x69,0xc6,0x8b,0x68,0xc4,0x8d,0x64,
|
||||
0xd0,0xa5,0x1c,0x21,0xb7,0x3a,0x4d,0x62,
|
||||
0x50,0xb2,0x1c,0x53,0xb6,0x16,0x4b,0x8a,
|
||||
0x46,0xc2,0x69,0x72,0x88,0xd0,0xcd,0x1d,
|
||||
0x51,0xb0,0x1a,0x5f,0xa2,0x3e,0x33,0x7b,
|
||||
0x54,0xe4,0x05,0xa7,0xe2,0x2f,0xb3,0x1e,
|
||||
0x55,0xba,0x02,0x63,0xf2,0xb7,0xd0,0x4f,
|
||||
0x1e,0x5d,0xba,0x32,0x63,0x52,0xb4,0x10,
|
||||
0x47,0x9e,0x6e,0xba,0x98,0x60,0xae,0xbc,
|
||||
0x18,0x77,0xae,0xce,0x19,0x5b,0xa8,0x26,
|
||||
0x0f,0x2b,0xdd,0x07,0x31,0xed,0x5b,0x90,
|
||||
0x26,0x9f,0x28,0xbd,0x0c,0x71,0xd6,0xdb,
|
||||
0x09,0x25,0xc9,0x23,0x49,0x34,0x49,0x46,
|
||||
0x48,0x6a,0x4e,0x82,0x58,0xf2,0x2d,0xd3,
|
||||
0x13,0x15,0x95,0x82,0x82,0xf0,0xf1,0xdd,
|
||||
0xdb,0x33,0x25,0x55,0x20,0x01,0x3f,0xf9,
|
||||
0x7f,0xe8,0xff,0x8d,0xfe,0xd3,0xf9,0x17,
|
||||
0xe9,0x8f,0x8a,0xde,0xc1,0x39,0x79,0x68,
|
||||
0xe8,0x8d,0x8c,0xd2,0xd5,0x11,0x01,0x99,
|
||||
0xfa,0xab,0xe0,0x07,0xbf,0xee,0x7f,0x9a,
|
||||
0xfe,0xa1,0xf8,0x3b,0xef,0x67,0x9c,0xae,
|
||||
0xb4,0x18,0x47,0xae,0x6e,0x1a,0x9b,0xa0,
|
||||
0xa6,0x3c,0x2b,0x77,0x04,0xcd,0xe5,0x53,
|
||||
0xa0,0x16,0x3f,0x8b,0x7e,0xc4,0xf9,0x65,
|
||||
0xe8,0xa3,0x8c,0x36,0xd7,0x49,0x0c,0x49,
|
||||
0xd6,0x4b,0x0a,0x45,0xc2,0x63,0x72,0xb4,
|
||||
0xd0,0x45,0x1e,0x61,0xba,0xba,0x60,0x62,
|
||||
0xbe,0xb0,0x78,0x5e,0xee,0x39,0x9b,0x6a,
|
||||
0xa4,0x80,0x24,0xff,0x25,0xfd,0x23,0xf1,
|
||||
0x37,0xd9,0x4f,0x28,0x5d,0x0e,0x31,0xdb,
|
||||
0x5b,0x24,0x25,0x27,0x21,0x2d,0x39,0x11,
|
||||
0x69,0x98,0x8a,0xac,0xc0,0x15,0x7f,0x80,
|
||||
0xfe,0xfd,0xf9,0xf3,0xeb,0xd7,0x87,0x0e,
|
||||
0xed,0xd9,0x93,0x2a,0x95,0x00,0x81,0xfc,
|
||||
0xfb,0xf5,0xe7,0xc3,0xaf,0x76,0x1c,0xcb,
|
||||
0xb5,0x46,0x40,0x6a,0x7e,0x82,0xf8,0xf1,
|
||||
0xed,0xdb,0x93,0x26,0x95,0x28,0x81,0x0c,
|
||||
0xf9,0xd5,0xeb,0x03,0x85,0xf6,0xe3,0xc9,
|
||||
0xb7,0x4a,0x4c,0x42,0x56,0x72,0x0a,0xd3,
|
||||
0xc1,0x17,0x79,0x8c,0xea,0xd5,0x81,0x02,
|
||||
0xf9,0xf1,0xeb,0xdb,0x87,0x26,0xed,0x29,
|
||||
0x91,0x0a,0x99,0xc0,0xab,0x7c,0x04,0xf7,
|
||||
0xe5,0xcf,0xa3,0x5e,0x34,0x3b,0x47,0x64,
|
||||
0x6c,0xa6,0x94,0x28,0x87,0x0c,0xed,0xd5,
|
||||
0x93,0x02,0x95,0xf0,0x83,0xdc,0xf7,0x35,
|
||||
0xcd,0x43,0x50,0x74,0x1e,0xc7,0xb9,0x6e,
|
||||
0x68,0x9a,0x8c,0xa0,0xd4,0x3d,0x07,0x71,
|
||||
0xec,0xdb,0x95,0x26,0x81,0x28,0xf9,0x0d,
|
||||
0xe9,0xd3,0x8b,0x16,0xc5,0x89,0x62,0xc8,
|
||||
0xb1,0x4c,0x58,0x56,0x2e,0x0b,0x1b,0xc5,
|
||||
0xa7,0x62,0x2c,0xb3,0x14,0x55,0x86,0x02,
|
||||
0xeb,0xf1,0x87,0xda,0xef,0x21,0x9d,0x3a,
|
||||
0xb1,0x60,0x58,0xbe,0x2c,0x7b,0x16,0xe5,
|
||||
0x89,0xa2,0xca,0x31,0x43,0x58,0x74,0x2e,
|
||||
0xc7,0x19,0x6d,0xa8,0x92,0x0c,0x93,0xd4,
|
||||
0x97,0x04,0x8d,0xe4,0xd3,0xa5,0x16,0x21,
|
||||
0x8b,0x3a,0xc5,0x61,0x60,0xb8,0xbc,0x6c,
|
||||
0x76,0x96,0xc8,0x89,0x4c,0xc8,0x55,0x4e,
|
||||
0x00,0x5b,0xfe,0x27,0xfb,0x2f,0xe5,0x1f,
|
||||
0xa1,0xbe,0x3a,0x7b,0x62,0xe4,0xb1,0xa4,
|
||||
0x5a,0x26,0x23,0x2b,0x35,0x05,0x41,0xe0,
|
||||
0x7b,0xbe,0xe6,0x79,0xaa,0xea,0x01,0x83,
|
||||
0xfa,0xf7,0xe1,0xcf,0xbb,0x5e,0x64,0x3a,
|
||||
0xa7,0x60,0x2c,0xbf,0x14,0x7d,0x86,0xf2,
|
||||
0xe9,0xd1,0x8b,0x1a,0xc5,0xa1,0x62,0x38,
|
||||
0xb3,0x6c,0x54,0x96,0x04,0x8b,0xe4,0xc7,
|
||||
0xa5,0x6e,0x20,0x9b,0x3c,0xa5,0x74,0x20,
|
||||
0xc7,0x3d,0x6d,0x70,0x90,0xdc,0x9d,0x34,
|
||||
0xb1,0x44,0x58,0x66,0x2e,0xab,0x18,0x05,
|
||||
0xaf,0xe2,0x1f,0xb3,0xbe,0x56,0x7a,0x0a,
|
||||
0xe3,0xc1,0xb7,0x7a,0x4c,0xe2,0x55,0xb2,
|
||||
0x02,0x53,0xf2,0x17,0xd3,0x8f,0x16,0xdd,
|
||||
0x89,0x32,0xc9,0x51,0x48,0x18,0x4f,0xae,
|
||||
0x5e,0x1a,0x3b,0xa3,0x66,0x34,0xab,0x44,
|
||||
0x04,0x67,0xe6,0xaf,0xa8,0x1e,0x0f,0xbb,
|
||||
0xde,0x67,0x3a,0xad,0x60,0x10,0xbf,0x9c,
|
||||
0x7e,0xb6,0xf8,0x49,0xee,0x4b,0x9a,0x46,
|
||||
0xa2,0x68,0x32,0x8f,0x50,0xdc,0x1d,0x37,
|
||||
0xb1,0x4e,0x58,0x5a,0x2e,0x23,0x1b,0x35,
|
||||
0xa5,0x42,0x20,0x73,0x3e,0xd5,0x79,0x00,
|
||||
0xe9,0xfd,0x8b,0xf2,0xc7,0xd1,0x6f,0x18,
|
||||
0x9d,0xac,0xb2,0x14,0x53,0x86,0x16,0xeb,
|
||||
0x89,0x86,0xca,0xe9,0x41,0x88,0x7a,0xce,
|
||||
0xe1,0x59,0xb8,0x2a,0x6f,0x02,0x9d,0xf0,
|
||||
0xb3,0xdc,0x57,0x36,0x0d,0x4b,0xd0,0x47,
|
||||
0x1e,0x6d,0xba,0x92,0x60,0x92,0xbc,0x90,
|
||||
0x74,0x9e,0xc4,0xb9,0x64,0x68,0xa6,0x8c,
|
||||
0x28,0xd7,0x0d,0x0d,0xd1,0xd3,0x1b,0x15,
|
||||
0xa5,0x82,0x22,0xf3,0x31,0xd5,0x5b,0x00,
|
||||
0x25,0xff,0x23,0xfd,0x37,0xf1,0x4f,0xd8,
|
||||
0x5f,0x2e,0x3d,0x1b,0x71,0xa4,0xda,0x25,
|
||||
0x23,0x21,0x35,0x39,0x41,0x68,0x78,0x8e,
|
||||
0xec,0xd9,0x95,0x2a,0x81,0x00,0xf9,0xfd,
|
||||
0xeb,0xf3,0x87,0xd6,0xef,0x09,0x9d,0xca,
|
||||
0xb3,0x40,0x54,0x7e,0x06,0xfb,0xe9,0xe7,
|
||||
0x8b,0xae,0xc6,0x19,0x6b,0xa8,0x86,0x0c,
|
||||
0xeb,0xd5,0x87,0x02,0xed,0xf1,0x93,0xda,
|
||||
0x97,0x20,0x8d,0x3c,0xd1,0x75,0x18,0xc1,
|
||||
0xad,0x7a,0x10,0xe3,0x9d,0xb6,0xb2,0x48,
|
||||
0x52,0x4e,0x12,0x5b,0x92,0x26,0x93,0x28,
|
||||
0x95,0x0c,0x81,0xd4,0xfb,0x05,0xe5,0xe3,
|
||||
0xa3,0xb6,0x36,0x4b,0x4a,0x44,0x42,0x66,
|
||||
0x72,0xaa,0xd0,0x01,0x1f,0xf9,0xbf,0xea,
|
||||
0x7f,0x82,0xfe,0xf1,0xf9,0xdb,0xeb,0x27,
|
||||
0x85,0x2e,0xe1,0x19,0xb9,0xaa,0x6a,0x02,
|
||||
0x83,0xf0,0xf7,0xdd,0xcf,0x33,0x5d,0x54,
|
||||
0x30,0x07,0x5f,0xec,0x3f,0x97,0x7e,0x8c,
|
||||
0xf8,0xd5,0xed,0x03,0x91,0xf6,0x9b,0xc8,
|
||||
0xa7,0x4c,0x2c,0x57,0x16,0x0d,0x8b,0xd2,
|
||||
0xc7,0x11,0x6d,0x98,0x92,0xac,0x90,0x14,
|
||||
0x9f,0x84,0xbe,0xe4,0x79,0xa6,0xea,0x29,
|
||||
0x83,0x0a,0xf5,0xc1,0xc3,0x7b,0x74,0xe4,
|
||||
0xc5,0xa5,0x62,0x20,0xb3,0x3c,0x55,0x76,
|
||||
0x00,0xcb,0xfd,0x47,0xf0,0x6f,0xde,0x9f,
|
||||
0x38,0xbd,0x6c,0x70,0x96,0xdc,0x89,0x34,
|
||||
0xc9,0x45,0x48,0x60,0x4e,0xbe,0x58,0x7a,
|
||||
0x2e,0xe3,0x19,0xb5,0xaa,0x42,0x02,0x73,
|
||||
0xf2,0xd7,0xd1,0x0f,0x19,0xdd,0xab,0x32,
|
||||
0x05,0x53,0xe0,0x17,0xbf,0x8e,0x7e,0xda,
|
||||
0xf9,0x21,0xe9,0x3b,0x89,0x66,0xc8,0xa9,
|
||||
0x4c,0x08,0x57,0xce,0x0f,0x5b,0xdc,0x27,
|
||||
0x37,0x2d,0x4d,0x10,0x51,0x9e,0x1a,0xbb,
|
||||
0xa0,0x66,0x3e,0xab,0x78,0x04,0xef,0xe5,
|
||||
0x9f,0xa2,0xbe,0x30,0x7b,0x5e,0xe4,0x39,
|
||||
0xa7,0x6a,0x2c,0x83,0x14,0xf5,0x85,0xc2,
|
||||
0xe3,0x71,0xb4,0xda,0x45,0x22,0x61,0x32,
|
||||
0xb9,0x50,0x68,0x1e,0x8f,0xb8,0xde,0x6d,
|
||||
0x3a,0x91,0x60,0x98,0xbc,0xac,0x74,0x16,
|
||||
0xc7,0x89,0x6e,0xc8,0x99,0x4c,0xa8,0x54,
|
||||
0x0e,0x07,0xdb,0xef,0x27,0x9d,0x2e,0xb1,
|
||||
0x18,0x59,0xae,0x2a,0x1b,0x03,0xa5,0xf6,
|
||||
0x23,0xcb,0x37,0x45,0x4c,0x60,0x56,0xbe,
|
||||
0x08,0x7b,0xce,0xe7,0x59,0xac,0x2a,0x17,
|
||||
0x03,0x8d,0xf6,0xd3,0xc9,0x17,0x49,0x8c,
|
||||
0x4a,0xd6,0x41,0x0a,0x79,0xc2,0xeb,0x71,
|
||||
0x84,0xda,0xe5,0x21,0xa1,0x3a,0x39,0x63,
|
||||
0x68,0xb4,0x8c,0x44,0xd6,0x65,0x0a,0xa1,
|
||||
0xc0,0x3b,0x7f,0x64,0xfc,0xa5,0xf4,0x23,
|
||||
0xc7,0x37,0x6d,0x4c,0x90,0x54,0x9e,0x04,
|
||||
0xbb,0xe4,0x67,0xa6,0xae,0x28,0x1b,0x0f,
|
||||
0xa5,0xde,0x23,0x3b,0x35,0x65,0x40,0xa0,
|
||||
0x7c,0x3e,0xf7,0x79,0xcc,0xeb,0x55,0x84,
|
||||
0x02,0xe7,0xf1,0xaf,0xda,0x1f,0x23,0xbd,
|
||||
0x36,0x71,0x4a,0xd8,0x41,0x2e,0x79,0x1a,
|
||||
0xe9,0xa1,0x8a,0x3a,0xc3,0x61,0x74,0xb8,
|
||||
0xc4,0x6d,0x66,0x90,0xa8,0x9c,0x0c,0xb7,
|
||||
0xd4,0x4f,0x06,0x5d,0xea,0x33,0x83,0x56,
|
||||
0xf4,0x09,0xc7,0xcb,0x6f,0x44,0x9c,0x64,
|
||||
0xb6,0xa4,0x48,0x26,0x4f,0x2a,0x5d,0x02,
|
||||
0x31,0xf3,0x5b,0xd4,0x27,0x07,0x2d,0xed,
|
||||
0x13,0x91,0x96,0x9a,0x88,0xa0,0xcc,0x3d,
|
||||
0x57,0x70,0x0c,0xdf,0xd5,0x3f,0x01,0x7d,
|
||||
0xf8,0xf3,0xed,0xd7,0x93,0x0e,0x95,0xd8,
|
||||
0x83,0x2c,0xf5,0x15,0xc1,0x83,0x7a,0xf4,
|
||||
0xe1,0xc5,0xbb,0x62,0x64,0xb2,0xa4,0x50,
|
||||
0x26,0x1f,0x2b,0xbd,0x06,0x71,0xea,0xdb,
|
||||
0x81,0x26,0xf9,0x29,0xe9,0x0b,0x89,0xc6,
|
||||
0xcb,0x69,0x44,0x88,0x64,0xce,0xa5,0x58,
|
||||
0x20,0x2f,0x3f,0x1d,0x7d,0xb0,0xf2,0x5d,
|
||||
0xd2,0x33,0x13,0x55,0x94,0x02,0x87,0xf0,
|
||||
0xef,0xdd,0x9f,0x32,0xbd,0x50,0x70,0x1e,
|
||||
0xdf,0xb9,0x3e,0x69,0x7a,0x88,0xe0,0xcd,
|
||||
0xbd,0x52,0x70,0x12,0xdf,0x91,0x3e,0x99,
|
||||
0x78,0xa8,0xec,0x0d,0x97,0xd2,0x8f,0x10,
|
||||
0xdd,0x9d,0x32,0xb1,0x50,0x58,0x1e,0x2f,
|
||||
0xbb,0x1e,0x65,0xba,0xa2,0x60,0x32,0xbf,
|
||||
0x50,0x7c,0x1e,0xf7,0xb9,0xce,0x6b,0x5a,
|
||||
0x84,0x20,0xe7,0x3d,0xad,0x72,0x10,0xd3,
|
||||
0x9d,0x16,0xb1,0x88,0x5a,0xce,0x21,0x5b,
|
||||
0x38,0x25,0x6f,0x20,0x9d,0x3c,0xb1,0x74,
|
||||
0x58,0xc6,0x2d,0x6b,0x10,0x85,0x9c,0xe2,
|
||||
0xb5,0xb0,0x42,0x5e,0x72,0x3a,0xd3,0x61,
|
||||
0x14,0xb9,0x84,0x6a,0xe6,0x81,0xa8,0xfa,
|
||||
0x0d,0xe3,0xd3,0xb7,0x16,0x4d,0x8a,0x52,
|
||||
0xc2,0x11,0x73,0x98,0xd6,0xad,0x08,0x11,
|
||||
0xcf,0x9b,0x5e,0xa4,0x38,0x27,0x6f,0x2c,
|
||||
0x9d,0x14,0xb1,0x84,0x5a,0xe6,0x21,0xab,
|
||||
0x3a,0x05,0x63,0xe0,0xb7,0xbc,0x4e,0x76,
|
||||
0x5a,0xca,0x21,0x43,0x38,0x75,0x6e,0xc0,
|
||||
0x99,0x7c,0xa8,0xf4,0x0d,0xc7,0xd3,0x6f,
|
||||
0x14,0x9d,0x84,0xb2,0xe4,0x51,0xa6,0x1a,
|
||||
0x2b,0xa3,0x06,0x35,0xeb,0x43,0x84,0x76,
|
||||
0xe6,0xc9,0xa9,0x4a,0x08,0x43,0xce,0x77,
|
||||
0x5a,0xcc,0x21,0x57,0x38,0x0d,0x6f,0xd0,
|
||||
0x9f,0x1c,0xbd,0xb4,0x72,0x46,0xd2,0x69,
|
||||
0x12,0x89,0x90,0xca,0x9d,0x40,0xb0,0x7c,
|
||||
0x5e,0xf6,0x39,0xcb,0x6b,0x44,0x84,0x64,
|
||||
0xe6,0xa5,0xa8,0x22,0x0f,0x33,0xdd,0x57,
|
||||
0x30,0x0d,0x5f,0xd0,0x3f,0x1f,0x7d,0xbc,
|
||||
0xf2,0x75,0xd2,0xc3,0x11,0x75,0x98,0xc2,
|
||||
0xad,0x70,0x10,0xdf,0x9d,0x3e,0xb1,0x78,
|
||||
0x58,0xee,0x2d,0x9b,0x12,0xa5,0x90,0x22,
|
||||
0x9f,0x30,0xbd,0x5c,0x70,0x36,0xdf,0x49,
|
||||
0x3c,0x49,0x76,0x48,0xca,0x4d,0x42,0x50,
|
||||
0x72,0x1e,0xd3,0xb9,0x16,0x69,0x8a,0x8a,
|
||||
0xc0,0xc1,0x7d,0x78,0xf0,0xed,0xdd,0x93,
|
||||
0x32,0x95,0x50,0x80,0x1c,0xff,0xb5,0xfe,
|
||||
0x43,0xfa,0x77,0xe2,0xcf,0xb1,0x5e,0x58,
|
||||
0x3a,0x2f,0x63,0x1c,0xb5,0xb4,0x42,0x46,
|
||||
0x72,0x6a,0xd2,0x81,0x10,0xf9,0x9d,0xea,
|
||||
0xb3,0x80,0x56,0xfe,0x09,0xfb,0xcb,0xe7,
|
||||
0x47,0xac,0x6e,0x16,0x9b,0x88,0xa6,0xcc,
|
||||
0x29,0x57,0x08,0x0d,0xcf,0xd3,0x5f,0x14,
|
||||
0x3d,0x87,0x72,0xec,0xd1,0x95,0x1a,0x81,
|
||||
0xa0,0xfa,0x3d,0xe3,0x73,0xb4,0xd6,0x45,
|
||||
0x0a,0x61,0xc2,0xbb,0x70,0x64,0xde,0xa5,
|
||||
0x38,0x21,0x6f,0x38,0x9d,0x6c,0xb0,0x94,
|
||||
0x5c,0x86,0x3e,0xeb,0x45,0x84,0x62,0xe6,
|
||||
0xb1,0xa8,0x5a,0x0e,0x23,0xfb,0x33,0x25,
|
||||
0x47,0x20,0x51,0x3e,0x19,0x7f,0xa8,0x66,
|
||||
0x0c,0xfb,0xd0,0x07,0x13,0xe5,0x9f,0x83,
|
||||
0xce,0x98,0x58,0xcd,0x2e,0x19,0x14,0x39,
|
||||
0x86,0x3f,0xff,0x01,0x85,0xff,0xe1,0xe1,
|
||||
0xb3,0xfc,0x46,0x63,0x0f,0xf8,0x00,0x53,
|
||||
0xbe,0x1f,0xfb,0xc0,0xe6,0x7e,0xbc,0xf0,
|
||||
0x01,0xe3,0xc3,0x9f,0xa6,0xcc,0x48,0x7e,
|
||||
0x40,0x82,0x9d,0xf2,0xff,0xd6,0x07,0x13,
|
||||
0xf5,0x87,0x80,0x0f,0x71,0x9c,0xfd,0x35,
|
||||
0x61,0x43,0xf8,0x78,0x7e,0xcf,0x19,0x99,
|
||||
0xa8,0x32,0x00,0x53,0xfc,0x17,0xfb,0x8f,
|
||||
0xc6,0xdf,0xa9,0x3e,0x09,0x7b,0xc8,0xe7,
|
||||
0x4d,0xac,0x52,0x16,0x13,0x8b,0x96,0xc6,
|
||||
0x89,0x68,0xc8,0x8d,0x4c,0xd0,0x55,0x1e,
|
||||
0x01,0xbb,0xfa,0x67,0xe2,0xaf,0xb0,0x1e,
|
||||
0x5f,0xba,0x3e,0x63,0x7a,0xb4,0xe0,0x45,
|
||||
0xbe,0x62,0x7a,0xb2,0xe0,0x51,0xbe,0x1a,
|
||||
0x7b,0xa2,0xe6,0x31,0xab,0x5a,0x04,0x23,
|
||||
0xe7,0x37,0xad,0x4e,0x10,0x5b,0x9e,0x26,
|
||||
0xbb,0x28,0x65,0x0e,0xa1,0xd8,0x3b,0x2f,
|
||||
0x65,0x1c,0xa1,0xb4,0x3a,0x47,0x62,0x6c,
|
||||
0xb2,0x94,0x50,0x86,0x1c,0xeb,0xb5,0x86,
|
||||
0x42,0xea,0x71,0x82,0xda,0xf1,0x21,0xd9,
|
||||
0x3b,0x29,0x65,0x08,0xa1,0xcc,0x3b,0x57,
|
||||
0x64,0x0c,0xa7,0xd4,0x2f,0x07,0x1d,0xed,
|
||||
0xb3,0x92,0x56,0x92,0x08,0x93,0xcc,0x97,
|
||||
0x54,0x8c,0x04,0xd7,0xe5,0x0f,0xa1,0xde,
|
||||
0x3b,0x3b,0x65,0x64,0xa0,0xa4,0x3c,0x27,
|
||||
0x77,0x2c,0xcd,0x15,0x51,0x80,0x1a,0xff,
|
||||
0xa1,0xfe,0x3b,0xfb,0x67,0xe4,0xaf,0xa4,
|
||||
0x1e,0x27,0xbb,0x2e,0x65,0x1a,0xa1,0xa0,
|
||||
0x3a,0x3f,0x63,0x7c,0xb4,0xf4,0x45,0xc6,
|
||||
0x63,0x6a,0xb4,0x80,0x44,0xfe,0x65,0xfa,
|
||||
0xa3,0xe0,0x37,0xbf,0x4e,0x7c,0x5a,0xf6,
|
||||
0x21,0xcb,0x3b,0x45,0x64,0x60,0xa6,0xbc,
|
||||
0x28,0x77,0x0e,0xcd,0xd9,0x53,0x28,0x15,
|
||||
0x0f,0x81,0xde,0xfb,0x39,0xe5,0x6b,0xa0,
|
||||
0x86,0x3c,0xeb,0x75,0x84,0xc2,0xe5,0x71,
|
||||
0xa0,0xda,0x3d,0x23,0x71,0x34,0xd9,0x45,
|
||||
0x28,0x61,0x0e,0xb9,0xd8,0x6b,0x2e,0x85,
|
||||
0x18,0xe1,0xad,0xba,0x12,0x63,0x92,0xb6,
|
||||
0x90,0x48,0x9e,0x4c,0xba,0x54,0x62,0x06,
|
||||
0xb3,0xe8,0x57,0x8e,0x0e,0xdb,0xd9,0x27,
|
||||
0x29,0x2d,0x09,0x11,0xc9,0x9b,0x4a,0xa4,
|
||||
0x40,0x26,0x7f,0x2a,0xfd,0x01,0xf1,0xfb,
|
||||
0xdb,0xe7,0x27,0xad,0x2e,0x11,0x1b,0x99,
|
||||
0xa6,0xaa,0x28,0x03,0x0f,0xf5,0xdf,0xc3,
|
||||
0x3f,0x75,0x7c,0xc0,0xf5,0x7d,0xc0,0xf3,
|
||||
0x7d,0xd4,0xf3,0x05,0xd5,0xe3,0x03,0xb5,
|
||||
0xf6,0x43,0xca,0x77,0x42,0xcc,0x71,0x56,
|
||||
0xd8,0x09,0x2f,0xc9,0x1f,0x49,0xbc,0x4a,
|
||||
0x76,0x42,0xca,0x71,0x42,0xd8,0x71,0x2e,
|
||||
0xd9,0x19,0x29,0xa9,0x0a,0x09,0xc3,0xcb,
|
||||
0x77,0x44,0xcc,0x65,0x56,0xa0,0x08,0x3f,
|
||||
0xcf,0x7f,0x5c,0xfc,0x35,0xf7,0x43,0xcc,
|
||||
0x77,0x56,0xcc,0x09,0x57,0xc8,0x0f,0x4f,
|
||||
0xdc,0x5f,0x36,0x3d,0x4b,0x70,0x44,0xde,
|
||||
0x65,0x3a,0xa1,0x60,0x38,0xbf,0x6c,0x7c,
|
||||
0x96,0xf4,0x89,0xc4,0xcb,0x65,0x44,0xa0,
|
||||
0x64,0x3e,0xa7,0x78,0x2c,0xef,0x15,0x9d,
|
||||
0x82,0xb2,0xf0,0x51,0xde,0x1b,0x3b,0xa5,
|
||||
0x66,0x20,0xab,0x3c,0x05,0x77,0xe0,0xcf,
|
||||
0xbd,0x5e,0x70,0x3a,0xdf,0x61,0x3c,0xb9,
|
||||
0x74,0x68,0xc6,0x8d,0x68,0xd0,0x8d,0x1c,
|
||||
0xd1,0xb5,0x1a,0x41,0xa2,0x7a,0x32,0xe3,
|
||||
0x51,0xb4,0x1a,0x47,0xa2,0x6e,0x32,0x9b,
|
||||
0x50,0xa4,0x1c,0x27,0xb7,0x2e,0x4d,0x1a,
|
||||
0x51,0xa2,0x1a,0x33,0xa3,0x56,0x34,0x0b,
|
||||
0x47,0xc4,0x6f,0x66,0x9c,0xa8,0xb4,0x0c,
|
||||
0x47,0xd6,0x6f,0x0a,0x9d,0xc0,0xb3,0x7c,
|
||||
0x54,0xf6,0x05,0xcb,0xe3,0x47,0xb4,0x6e,
|
||||
0x46,0x9a,0x68,0xa2,0x8c,0x30,0xd7,0x5d,
|
||||
0x0c,0x31,0xd7,0x5b,0x0c,0x25,0xd7,0x23,
|
||||
0x0d,0x35,0xd1,0x43,0x18,0x75,0xae,0xc2,
|
||||
0x19,0x73,0xa8,0xd6,0x0d,0x0b,0xd1,0xc7,
|
||||
0x1b,0x6d,0xa4,0x92,0x24,0x93,0x24,0x95,
|
||||
0x24,0x81,0x24,0xf9,0x25,0xe9,0x23,0x89,
|
||||
0x36,0xc9,0x49,0x48,0x48,0x4e,0x4e,0x5a,
|
||||
0x5a,0x22,0x23,0x33,0x35,0x55,0x40,0x00,
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
|
||||
#include "defs.h"
|
||||
#include "fb.h"
|
||||
|
||||
|
||||
static byte palmap[32768];
|
||||
static byte pallock[256];
|
||||
static int palrev[256];
|
||||
|
||||
/* Course color mapping, for when palette is exhausted. */
|
||||
static byte crsmap[4][32768];
|
||||
static int crsrev[4][256];
|
||||
static const int crsmask[4] = { 0x7BDE, 0x739C, 0x6318, 0x4210 };
|
||||
|
||||
enum plstatus
|
||||
{
|
||||
pl_unused = 0,
|
||||
pl_linger,
|
||||
pl_active,
|
||||
pl_locked
|
||||
};
|
||||
|
||||
|
||||
static byte bestmatch(int c)
|
||||
{
|
||||
byte n, best;
|
||||
int r, g, b;
|
||||
int r2, g2, b2, c2;
|
||||
int err, besterr;
|
||||
|
||||
r = (c & 0x001F) << 3;
|
||||
g = (c & 0x03E0) >> 2;
|
||||
b = (c & 0x7C00) >> 7;
|
||||
|
||||
best = 0;
|
||||
besterr = 1024;
|
||||
for (n = 1; n; n++)
|
||||
{
|
||||
c2 = palrev[n];
|
||||
r2 = (c2 & 0x001F) << 3;
|
||||
g2 = (c2 & 0x03E0) >> 2;
|
||||
b2 = (c2 & 0x7C00) >> 7;
|
||||
err = abs(r-r2) + abs(b-b2) + abs(g-g2);
|
||||
if (err < besterr)
|
||||
{
|
||||
besterr = err;
|
||||
best = n;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static void makecourse(int c, byte n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
c &= crsmask[i];
|
||||
crsmap[i][c] = n;
|
||||
crsrev[i][n] = c;
|
||||
}
|
||||
}
|
||||
|
||||
static byte findcourse(int c)
|
||||
{
|
||||
int i;
|
||||
byte n;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
c &= crsmask[i];
|
||||
n = crsmap[i][c];
|
||||
if (crsrev[i][n] == c)
|
||||
return n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pal_lock(byte n)
|
||||
{
|
||||
if (!n) return;
|
||||
if (pallock[n] >= pl_locked)
|
||||
pallock[n]++;
|
||||
else pallock[n] = pl_locked;
|
||||
}
|
||||
|
||||
byte pal_getcolor(int c, int r, int g, int b)
|
||||
{
|
||||
byte n;
|
||||
static byte l;
|
||||
n = palmap[c];
|
||||
if (n && pallock[n] && palrev[n] == c)
|
||||
{
|
||||
pal_lock(n);
|
||||
return n;
|
||||
}
|
||||
for (n = l+1; n != l; n++)
|
||||
{
|
||||
if (!n || pallock[n] /* || n < 16 */) continue;
|
||||
pal_lock(n);
|
||||
palmap[c] = n;
|
||||
palrev[n] = c;
|
||||
makecourse(c, n);
|
||||
vid_setpal(n, r, g, b);
|
||||
return (l = n);
|
||||
}
|
||||
n = findcourse(c);
|
||||
pal_lock(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void pal_release(byte n)
|
||||
{
|
||||
if (pallock[n] >= pl_locked)
|
||||
pallock[n]--;
|
||||
}
|
||||
|
||||
|
||||
void pal_expire()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (pallock[i] && pallock[i] < pl_locked)
|
||||
pallock[i]--;
|
||||
}
|
||||
|
||||
|
||||
void pal_set332()
|
||||
{
|
||||
int i, r, g, b;
|
||||
|
||||
fb.indexed = 0;
|
||||
fb.cc[0].r = 5;
|
||||
fb.cc[1].r = 5;
|
||||
fb.cc[2].r = 6;
|
||||
fb.cc[0].l = 0;
|
||||
fb.cc[1].l = 3;
|
||||
fb.cc[2].l = 6;
|
||||
|
||||
i = 0;
|
||||
for (b = 0; b < 4; b++) for (g = 0; g < 8; g++) for (r = 0; r < 8; r++)
|
||||
vid_setpal(i++, (r<<5)|(r<<2)|(r>>1),
|
||||
(g<<5)|(g<<2)|(g>>1), (b<<6)|(b<<4)|(b<<2)|b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup();
|
||||
|
||||
#ifdef ALT_PATH_SEP
|
||||
#define SEP ';'
|
||||
#else
|
||||
#define SEP ':'
|
||||
#endif
|
||||
|
||||
char *path_search(char *name, char *mode, char *path)
|
||||
{
|
||||
FILE *f;
|
||||
static char *buf;
|
||||
char *p, *n;
|
||||
int l;
|
||||
|
||||
if (buf) free(buf); buf = 0;
|
||||
if (!path || !*path || *name == '/')
|
||||
return (buf = strdup(name));
|
||||
|
||||
buf = malloc(strlen(path) + strlen(name) + 2);
|
||||
|
||||
for (p = path; *p; p += l)
|
||||
{
|
||||
if (*p == SEP) p++;
|
||||
n = strchr(p, SEP);
|
||||
if (n) l = n - p;
|
||||
else l = strlen(p);
|
||||
strncpy(buf, p, l);
|
||||
buf[l] = '/';
|
||||
strcpy(buf+l+1, name);
|
||||
if ((f = fopen(buf, mode)))
|
||||
{
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
#ifndef __PCM_H__
|
||||
#define __PCM_H__
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
struct pcm
|
||||
{
|
||||
int hz, len;
|
||||
int stereo;
|
||||
byte *buf;
|
||||
int pos;
|
||||
};
|
||||
|
||||
extern struct pcm pcm;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
|
||||
|
||||
#ifndef __RC_H__
|
||||
#define __RC_H__
|
||||
|
||||
|
||||
|
||||
typedef enum rctype
|
||||
{
|
||||
rcv_end,
|
||||
rcv_int,
|
||||
rcv_string,
|
||||
rcv_vector,
|
||||
rcv_bool
|
||||
} rcvtype_t;
|
||||
|
||||
|
||||
typedef struct rcvar_s
|
||||
{
|
||||
char *name;
|
||||
int type;
|
||||
int len;
|
||||
void *mem;
|
||||
} rcvar_t;
|
||||
|
||||
#define RCV_END { 0, rcv_end, 0, 0 }
|
||||
#define RCV_INT(n,v) { (n), rcv_int, 1, (v) }
|
||||
#define RCV_STRING(n,v) { (n), rcv_string, 0, (v) }
|
||||
#define RCV_VECTOR(n,v,l) { (n), rcv_vector, (l), (v) }
|
||||
#define RCV_BOOL(n,v) { (n), rcv_bool, 1, (v) }
|
||||
|
||||
typedef struct rccmd_s
|
||||
{
|
||||
char *name;
|
||||
int (*func)(int, char **);
|
||||
} rccmd_t;
|
||||
|
||||
#define RCC(n,f) { (n), (f) }
|
||||
#define RCC_END { 0, 0 }
|
||||
|
||||
void rc_export(rcvar_t *v);
|
||||
void rc_exportvars(rcvar_t *vars);
|
||||
|
||||
int rc_findvar(char *name);
|
||||
|
||||
int rc_setvar_n(int i, int c, char **v);
|
||||
int rc_setvar(char *name, int c, char **v);
|
||||
|
||||
int rc_getint_n(int i);
|
||||
int *rc_getvec_n(int i);
|
||||
char *rc_getstr_n(int i);
|
||||
|
||||
int rc_getint(char *name);
|
||||
int *rc_getvec(char *name);
|
||||
char *rc_getstr(char *name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "rc.h"
|
||||
#include "hw.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* define the command functions for the controller pad.
|
||||
*/
|
||||
|
||||
#define CMD_PAD(b, B) \
|
||||
static int (cmd_ ## b)(int c, char **v) \
|
||||
{ pad_set((PAD_ ## B), v[0][0] == '+'); return 0; } \
|
||||
static int (cmd_ ## b)(int c, char **v)
|
||||
|
||||
CMD_PAD(up, UP);
|
||||
CMD_PAD(down, DOWN);
|
||||
CMD_PAD(left, LEFT);
|
||||
CMD_PAD(right, RIGHT);
|
||||
CMD_PAD(a, A);
|
||||
CMD_PAD(b, B);
|
||||
CMD_PAD(start, START);
|
||||
CMD_PAD(select, SELECT);
|
||||
|
||||
|
||||
/*
|
||||
* the set command is used to set rc-exported variables.
|
||||
*/
|
||||
|
||||
static int cmd_set(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3)
|
||||
return -1;
|
||||
return rc_setvar(argv[1], argc-2, argv+2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* the following commands allow keys to be bound to perform rc commands.
|
||||
*/
|
||||
|
||||
static int cmd_bind(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3)
|
||||
return -1;
|
||||
return rc_bindkey(argv[1], argv[2]);
|
||||
}
|
||||
|
||||
static int cmd_unbind(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
return rc_unbindkey(argv[1]);
|
||||
}
|
||||
|
||||
static int cmd_unbindall()
|
||||
{
|
||||
rc_unbindall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_source(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
return rc_sourcefile(argv[1]);
|
||||
}
|
||||
|
||||
static int cmd_quit()
|
||||
{
|
||||
exit(0);
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
||||
static int cmd_reset()
|
||||
{
|
||||
emu_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_savestate(int argc, char **argv)
|
||||
{
|
||||
state_save(argc > 1 ? atoi(argv[1]) : -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_loadstate(int argc, char **argv)
|
||||
{
|
||||
state_load(argc > 1 ? atoi(argv[1]) : -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* table of command names and the corresponding functions to be called
|
||||
*/
|
||||
|
||||
rccmd_t rccmds[] =
|
||||
{
|
||||
RCC("set", cmd_set),
|
||||
RCC("bind", cmd_bind),
|
||||
RCC("unbind", cmd_unbind),
|
||||
RCC("unbindall", cmd_unbindall),
|
||||
RCC("source", cmd_source),
|
||||
RCC("reset", cmd_reset),
|
||||
RCC("quit", cmd_quit),
|
||||
RCC("savestate", cmd_savestate),
|
||||
RCC("loadstate", cmd_loadstate),
|
||||
|
||||
RCC("+up", cmd_up),
|
||||
RCC("-up", cmd_up),
|
||||
RCC("+down", cmd_down),
|
||||
RCC("-down", cmd_down),
|
||||
RCC("+left", cmd_left),
|
||||
RCC("-left", cmd_left),
|
||||
RCC("+right", cmd_right),
|
||||
RCC("-right", cmd_right),
|
||||
RCC("+a", cmd_a),
|
||||
RCC("-a", cmd_a),
|
||||
RCC("+b", cmd_b),
|
||||
RCC("-b", cmd_b),
|
||||
RCC("+start", cmd_start),
|
||||
RCC("-start", cmd_start),
|
||||
RCC("+select", cmd_select),
|
||||
RCC("-select", cmd_select),
|
||||
|
||||
RCC_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int rc_command(char *line)
|
||||
{
|
||||
int i, argc, ret;
|
||||
char *argv[128], *linecopy;
|
||||
|
||||
linecopy = malloc(strlen(line)+1);
|
||||
strcpy(linecopy, line);
|
||||
|
||||
argc = splitline(argv, (sizeof argv)/(sizeof argv[0]), linecopy);
|
||||
if (!argc)
|
||||
{
|
||||
free(linecopy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; rccmds[i].name; i++)
|
||||
{
|
||||
if (!strcmp(argv[0], rccmds[i].name))
|
||||
{
|
||||
ret = rccmds[i].func(argc, argv);
|
||||
free(linecopy);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* printf("unknown command: %s\n", argv[0]); */
|
||||
free(linecopy);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "rc.h"
|
||||
#include "hw.h"
|
||||
|
||||
|
||||
char *rcpath;
|
||||
|
||||
char *path_search();
|
||||
|
||||
int rc_sourcefile(char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char *name;
|
||||
char line[256], *p;
|
||||
|
||||
name = path_search(filename, "r", rcpath);
|
||||
f = fopen(name, "r");
|
||||
if (!f) return -1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (feof(f)) break;
|
||||
fgets(line, sizeof line, f);
|
||||
if ((p = strpbrk(line, "#\r\n")))
|
||||
*p = 0;
|
||||
rc_command(line);
|
||||
}
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
rcvar_t rcfile_exports[] =
|
||||
{
|
||||
RCV_STRING("rcpath", &rcpath),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup();
|
||||
|
||||
#include "defs.h"
|
||||
#include "rc.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
|
||||
|
||||
char *keybind[MAX_KEYS];
|
||||
|
||||
|
||||
|
||||
|
||||
int rc_bindkey(char *keyname, char *cmd)
|
||||
{
|
||||
int key;
|
||||
char *a;
|
||||
|
||||
key = k_keycode(keyname);
|
||||
if (!key) return -1;
|
||||
|
||||
a = strdup(cmd);
|
||||
if (!a) die("out of memory binding key\n");
|
||||
|
||||
if (keybind[key]) free(keybind[key]);
|
||||
keybind[key] = a;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rc_unbindkey(char *keyname)
|
||||
{
|
||||
int key;
|
||||
|
||||
key = k_keycode(keyname);
|
||||
if (!key) return -1;
|
||||
|
||||
if (keybind[key]) free(keybind[key]);
|
||||
keybind[key] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void rc_unbindall()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_KEYS; i++)
|
||||
{
|
||||
if (keybind[i])
|
||||
{
|
||||
free(keybind[i]);
|
||||
keybind[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void rc_dokey(int key, int st)
|
||||
{
|
||||
if (!keybind[key]) return;
|
||||
if (keybind[key][0] != '+' && !st) return;
|
||||
|
||||
if (st)
|
||||
rc_command(keybind[key]);
|
||||
else
|
||||
{
|
||||
keybind[key][0] = '-';
|
||||
rc_command(keybind[key]);
|
||||
keybind[key][0] = '+';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup();
|
||||
|
||||
#include "defs.h"
|
||||
#include "rc.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static rcvar_t *rcvars;
|
||||
|
||||
static int nvars;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void rc_export(rcvar_t *v)
|
||||
{
|
||||
const rcvar_t end = RCV_END;
|
||||
|
||||
if (!v) return;
|
||||
nvars++;
|
||||
rcvars = realloc(rcvars, sizeof (rcvar_t) * (nvars+1));
|
||||
if (!rcvars)
|
||||
die("out of memory adding rcvar %s\n", v->name);
|
||||
rcvars[nvars-1] = *v;
|
||||
rcvars[nvars] = end;
|
||||
}
|
||||
|
||||
void rc_exportvars(rcvar_t *vars)
|
||||
{
|
||||
while(vars->type)
|
||||
rc_export(vars++);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rc_findvar(char *name)
|
||||
{
|
||||
int i;
|
||||
if (!rcvars) return -1;
|
||||
for (i = 0; rcvars[i].name; i++)
|
||||
if (!strcmp(rcvars[i].name, name))
|
||||
break;
|
||||
if (!rcvars[i].name)
|
||||
return -1;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int my_atoi(const char *s)
|
||||
{
|
||||
int a = 0;
|
||||
if (*s == '0')
|
||||
{
|
||||
s++;
|
||||
if (*s == 'x' || *s == 'X')
|
||||
{
|
||||
s++;
|
||||
while (*s)
|
||||
{
|
||||
if (isdigit(*s))
|
||||
a = (a<<4) + *s - '0';
|
||||
else if (strchr("ABCDEF", *s))
|
||||
a = (a<<4) + *s - 'A' + 10;
|
||||
else if (strchr("abcdef", *s))
|
||||
a = (a<<4) + *s - 'a' + 10;
|
||||
else return a;
|
||||
s++;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
while (*s)
|
||||
{
|
||||
if (strchr("01234567", *s))
|
||||
a = (a<<3) + *s - '0';
|
||||
else return a;
|
||||
s++;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
if (*s == '-')
|
||||
{
|
||||
s++;
|
||||
for (;;)
|
||||
{
|
||||
if (isdigit(*s))
|
||||
a = (a*10) + *s - '0';
|
||||
else return -a;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
while (*s)
|
||||
{
|
||||
if (isdigit(*s))
|
||||
a = (a*10) + *s - '0';
|
||||
else return a;
|
||||
s++;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
int rc_setvar_n(int i, int c, char **v)
|
||||
{
|
||||
int j;
|
||||
int *n;
|
||||
char **s;
|
||||
|
||||
switch (rcvars[i].type)
|
||||
{
|
||||
case rcv_int:
|
||||
if (c < 1) return -1;
|
||||
n = (int *)rcvars[i].mem;
|
||||
*n = my_atoi(v[0]);
|
||||
return 0;
|
||||
case rcv_string:
|
||||
if (c < 1) return -1;
|
||||
s = (char **)rcvars[i].mem;
|
||||
if (*s) free(*s);
|
||||
*s = strdup(v[0]);
|
||||
if (!*s)
|
||||
die("out of memory setting rcvar %s\n", rcvars[i].name);
|
||||
return 0;
|
||||
case rcv_vector:
|
||||
if (c > rcvars[i].len)
|
||||
c = rcvars[i].len;
|
||||
for (j = 0; j < c ; j++)
|
||||
((int *)rcvars[i].mem)[j] = my_atoi(v[j]);
|
||||
return 0;
|
||||
case rcv_bool:
|
||||
if (c < 1 || atoi(v[0]) || strchr("yYtT", v[0][0]))
|
||||
*(int *)rcvars[i].mem = 1;
|
||||
else if (strchr("0nNfF", v[0][0]))
|
||||
*(int *)rcvars[i].mem = 0;
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int rc_setvar(char *name, int c, char **v)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = rc_findvar(name);
|
||||
if (i < 0) return i;
|
||||
|
||||
return rc_setvar_n(i, c, v);
|
||||
}
|
||||
|
||||
|
||||
void *rc_getmem_n(int i)
|
||||
{
|
||||
return rcvars[i].mem;
|
||||
}
|
||||
|
||||
|
||||
void *rc_getmem(char *name)
|
||||
{
|
||||
int i;
|
||||
i = rc_findvar(name);
|
||||
if (i < 0) return NULL;
|
||||
return rcvars[i].mem;
|
||||
}
|
||||
|
||||
int rc_getint_n(int i)
|
||||
{
|
||||
if (i < 0) return 0;
|
||||
switch (rcvars[i].type)
|
||||
{
|
||||
case rcv_int:
|
||||
case rcv_bool:
|
||||
return *(int *)rcvars[i].mem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int *rc_getvec_n(int i)
|
||||
{
|
||||
if (i < 0) return NULL;
|
||||
switch (rcvars[i].type)
|
||||
{
|
||||
case rcv_int:
|
||||
case rcv_bool:
|
||||
case rcv_vector:
|
||||
return (int *)rcvars[i].mem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *rc_getstr_n(int i)
|
||||
{
|
||||
if (i < 0) return 0;
|
||||
switch (rcvars[i].type)
|
||||
{
|
||||
case rcv_string:
|
||||
return *(char **)rcvars[i].mem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc_getint(char *name)
|
||||
{
|
||||
return rc_getint_n(rc_findvar(name));
|
||||
}
|
||||
|
||||
int *rc_getvec(char *name)
|
||||
{
|
||||
return rc_getvec_n(rc_findvar(name));
|
||||
}
|
||||
|
||||
char *rc_getstr(char *name)
|
||||
{
|
||||
return rc_getstr_n(rc_findvar(name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
|
||||
#include "defs.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#define BUF (scan.buf)
|
||||
|
||||
#ifdef USE_ASM
|
||||
#include "asm.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ASM_REFRESH_1
|
||||
void refresh_1(byte *dest, byte *src, byte *pal, int cnt)
|
||||
{
|
||||
while(cnt--) *(dest++) = pal[*(src++)];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_2
|
||||
void refresh_2(un16 *dest, byte *src, un16 *pal, int cnt)
|
||||
{
|
||||
while (cnt--) *(dest++) = pal[*(src++)];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_3
|
||||
void refresh_3(byte *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c>>8;
|
||||
*(dest++) = c>>16;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_4
|
||||
void refresh_4(un32 *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
while (cnt--) *(dest++) = pal[*(src++)];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef ASM_REFRESH_1_2X
|
||||
void refresh_1_2x(byte *dest, byte *src, byte *pal, int cnt)
|
||||
{
|
||||
byte c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_2_2X
|
||||
void refresh_2_2x(un16 *dest, byte *src, un16 *pal, int cnt)
|
||||
{
|
||||
un16 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_3_2X
|
||||
void refresh_3_2x(byte *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
dest[0] = dest[3] = c;
|
||||
dest[1] = dest[4] = c>>8;
|
||||
dest[2] = dest[5] = c>>16;
|
||||
dest += 6;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_4_2X
|
||||
void refresh_4_2x(un32 *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_2_3X
|
||||
void refresh_2_3x(un16 *dest, byte *src, un16 *pal, int cnt)
|
||||
{
|
||||
un16 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_3_3X
|
||||
void refresh_3_3x(byte *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
dest[0] = dest[3] = dest[6] = c;
|
||||
dest[1] = dest[4] = dest[7] = c>>8;
|
||||
dest[2] = dest[5] = dest[8] = c>>16;
|
||||
dest += 9;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_4_3X
|
||||
void refresh_4_3x(un32 *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_3_4X
|
||||
void refresh_3_4x(byte *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
dest[0] = dest[3] = dest[6] = dest[9] = c;
|
||||
dest[1] = dest[4] = dest[7] = dest[10] = c>>8;
|
||||
dest[2] = dest[5] = dest[8] = dest[11] = c>>16;
|
||||
dest += 12;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASM_REFRESH_4_4X
|
||||
void refresh_4_4x(un32 *dest, byte *src, un32 *pal, int cnt)
|
||||
{
|
||||
un32 c;
|
||||
while (cnt--)
|
||||
{
|
||||
c = pal[*(src++)];
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
*(dest++) = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
|
||||
#ifndef __REGS_H__
|
||||
#define __REGS_H__
|
||||
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
/* General internal/io stuff */
|
||||
|
||||
#define RI_P1 0x00
|
||||
#define RI_SB 0x01
|
||||
#define RI_SC 0x02
|
||||
#define RI_DIV 0x04
|
||||
#define RI_TIMA 0x05
|
||||
#define RI_TMA 0x06
|
||||
#define RI_TAC 0x07
|
||||
|
||||
#define RI_KEY1 0x4D
|
||||
|
||||
#define RI_RP 0x56
|
||||
|
||||
#define RI_SVBK 0x70
|
||||
|
||||
|
||||
|
||||
/* Interrupts flags */
|
||||
|
||||
#define RI_IF 0x0F
|
||||
#define RI_IE 0xFF
|
||||
|
||||
|
||||
|
||||
|
||||
/* LCDC */
|
||||
|
||||
#define RI_LCDC 0x40
|
||||
#define RI_STAT 0x41
|
||||
#define RI_SCY 0x42
|
||||
#define RI_SCX 0x43
|
||||
#define RI_LY 0x44
|
||||
#define RI_LYC 0x45
|
||||
#define RI_DMA 0x46
|
||||
#define RI_BGP 0x47
|
||||
#define RI_OBP0 0x48
|
||||
#define RI_OBP1 0x49
|
||||
#define RI_WY 0x4A
|
||||
#define RI_WX 0x4B
|
||||
|
||||
#define RI_VBK 0x4F
|
||||
|
||||
#define RI_HDMA1 0x51
|
||||
#define RI_HDMA2 0x52
|
||||
#define RI_HDMA3 0x53
|
||||
#define RI_HDMA4 0x54
|
||||
#define RI_HDMA5 0x55
|
||||
|
||||
#define RI_BCPS 0x68
|
||||
#define RI_BCPD 0x69
|
||||
#define RI_OCPS 0x6A
|
||||
#define RI_OCPD 0x6B
|
||||
|
||||
|
||||
|
||||
/* Sound */
|
||||
|
||||
#define RI_NR10 0x10
|
||||
#define RI_NR11 0x11
|
||||
#define RI_NR12 0x12
|
||||
#define RI_NR13 0x13
|
||||
#define RI_NR14 0x14
|
||||
#define RI_NR21 0x16
|
||||
#define RI_NR22 0x17
|
||||
#define RI_NR23 0x18
|
||||
#define RI_NR24 0x19
|
||||
#define RI_NR30 0x1A
|
||||
#define RI_NR31 0x1B
|
||||
#define RI_NR32 0x1C
|
||||
#define RI_NR33 0x1D
|
||||
#define RI_NR34 0x1E
|
||||
#define RI_NR41 0x20
|
||||
#define RI_NR42 0x21
|
||||
#define RI_NR43 0x22
|
||||
#define RI_NR44 0x23
|
||||
#define RI_NR50 0x24
|
||||
#define RI_NR51 0x25
|
||||
#define RI_NR52 0x26
|
||||
|
||||
|
||||
|
||||
#define REG(n) ram.hi[(n)]
|
||||
|
||||
|
||||
|
||||
/* General internal/io stuff */
|
||||
|
||||
#define R_P1 REG(RI_P1)
|
||||
#define R_SB REG(RI_SB)
|
||||
#define R_SC REG(RI_SC)
|
||||
#define R_DIV REG(RI_DIV)
|
||||
#define R_TIMA REG(RI_TIMA)
|
||||
#define R_TMA REG(RI_TMA)
|
||||
#define R_TAC REG(RI_TAC)
|
||||
|
||||
#define R_KEY1 REG(RI_KEY1)
|
||||
|
||||
#define R_RP REG(RI_RP)
|
||||
|
||||
#define R_SVBK REG(RI_SVBK)
|
||||
|
||||
|
||||
|
||||
/* Interrupts flags */
|
||||
|
||||
#define R_IF REG(RI_IF)
|
||||
#define R_IE REG(RI_IE)
|
||||
|
||||
|
||||
|
||||
|
||||
/* LCDC */
|
||||
|
||||
#define R_LCDC REG(RI_LCDC)
|
||||
#define R_STAT REG(RI_STAT)
|
||||
#define R_SCY REG(RI_SCY)
|
||||
#define R_SCX REG(RI_SCX)
|
||||
#define R_LY REG(RI_LY)
|
||||
#define R_LYC REG(RI_LYC)
|
||||
#define R_DMA REG(RI_DMA)
|
||||
#define R_BGP REG(RI_BGP)
|
||||
#define R_OBP0 REG(RI_OBP0)
|
||||
#define R_OBP1 REG(RI_OBP1)
|
||||
#define R_WY REG(RI_WY)
|
||||
#define R_WX REG(RI_WX)
|
||||
|
||||
#define R_VBK REG(RI_VBK)
|
||||
|
||||
#define R_HDMA1 REG(RI_HDMA1)
|
||||
#define R_HDMA2 REG(RI_HDMA2)
|
||||
#define R_HDMA3 REG(RI_HDMA3)
|
||||
#define R_HDMA4 REG(RI_HDMA4)
|
||||
#define R_HDMA5 REG(RI_HDMA5)
|
||||
|
||||
#define R_BCPS REG(RI_BCPS)
|
||||
#define R_BCPD REG(RI_BCPD)
|
||||
#define R_OCPS REG(RI_OCPS)
|
||||
#define R_OCPD REG(RI_OCPD)
|
||||
|
||||
|
||||
|
||||
/* Sound */
|
||||
|
||||
#define R_NR10 REG(RI_NR10)
|
||||
#define R_NR11 REG(RI_NR11)
|
||||
#define R_NR12 REG(RI_NR12)
|
||||
#define R_NR13 REG(RI_NR13)
|
||||
#define R_NR14 REG(RI_NR14)
|
||||
#define R_NR21 REG(RI_NR21)
|
||||
#define R_NR22 REG(RI_NR22)
|
||||
#define R_NR23 REG(RI_NR23)
|
||||
#define R_NR24 REG(RI_NR24)
|
||||
#define R_NR30 REG(RI_NR30)
|
||||
#define R_NR31 REG(RI_NR31)
|
||||
#define R_NR32 REG(RI_NR32)
|
||||
#define R_NR33 REG(RI_NR33)
|
||||
#define R_NR34 REG(RI_NR34)
|
||||
#define R_NR41 REG(RI_NR41)
|
||||
#define R_NR42 REG(RI_NR42)
|
||||
#define R_NR43 REG(RI_NR43)
|
||||
#define R_NR44 REG(RI_NR44)
|
||||
#define R_NR50 REG(RI_NR50)
|
||||
#define R_NR51 REG(RI_NR51)
|
||||
#define R_NR52 REG(RI_NR52)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "mem.h"
|
||||
#include "rtc.h"
|
||||
#include "rc.h"
|
||||
|
||||
struct rtc rtc;
|
||||
|
||||
static int syncrtc = 1;
|
||||
|
||||
rcvar_t rtc_exports[] =
|
||||
{
|
||||
RCV_BOOL("syncrtc", &syncrtc),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
void rtc_latch(byte b)
|
||||
{
|
||||
if ((rtc.latch ^ b) & b & 1)
|
||||
{
|
||||
rtc.regs[0] = rtc.s;
|
||||
rtc.regs[1] = rtc.m;
|
||||
rtc.regs[2] = rtc.h;
|
||||
rtc.regs[3] = rtc.d;
|
||||
rtc.regs[4] = (rtc.d>>9) | (rtc.stop<<6) | (rtc.carry<<7);
|
||||
rtc.regs[5] = 0xff;
|
||||
rtc.regs[6] = 0xff;
|
||||
rtc.regs[7] = 0xff;
|
||||
}
|
||||
rtc.latch = b;
|
||||
}
|
||||
|
||||
void rtc_write(byte b)
|
||||
{
|
||||
/* printf("write %02X: %02X (%d)\n", rtc.sel, b, b); */
|
||||
if (!(rtc.sel & 8)) return;
|
||||
switch (rtc.sel & 7)
|
||||
{
|
||||
case 0:
|
||||
rtc.s = rtc.regs[0] = b;
|
||||
while (rtc.s >= 60) rtc.s -= 60;
|
||||
break;
|
||||
case 1:
|
||||
rtc.m = rtc.regs[1] = b;
|
||||
while (rtc.m >= 60) rtc.m -= 60;
|
||||
break;
|
||||
case 2:
|
||||
rtc.h = rtc.regs[2] = b;
|
||||
while (rtc.h >= 24) rtc.h -= 24;
|
||||
break;
|
||||
case 3:
|
||||
rtc.regs[3] = b;
|
||||
rtc.d = (rtc.d & 0x100) | b;
|
||||
break;
|
||||
case 4:
|
||||
rtc.regs[4] = b;
|
||||
rtc.d = (rtc.d & 0xff) | ((b&1)<<9);
|
||||
rtc.stop = (b>>6)&1;
|
||||
rtc.carry = (b>>7)&1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_tick()
|
||||
{
|
||||
if (rtc.stop) return;
|
||||
if (++rtc.t == 60)
|
||||
{
|
||||
if (++rtc.s == 60)
|
||||
{
|
||||
if (++rtc.m == 60)
|
||||
{
|
||||
if (++rtc.h == 24)
|
||||
{
|
||||
if (++rtc.d == 365)
|
||||
{
|
||||
rtc.d = 0;
|
||||
rtc.carry = 1;
|
||||
}
|
||||
rtc.h = 0;
|
||||
}
|
||||
rtc.m = 0;
|
||||
}
|
||||
rtc.s = 0;
|
||||
}
|
||||
rtc.t = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_save_internal(FILE *f)
|
||||
{
|
||||
fprintf(f, "%d %d %d %02d %02d %02d %02d\n%d\n",
|
||||
rtc.carry, rtc.stop, rtc.d, rtc.h, rtc.m, rtc.s, rtc.t,
|
||||
time(0));
|
||||
}
|
||||
|
||||
void rtc_load_internal(FILE *f)
|
||||
{
|
||||
int rt = 0;
|
||||
fscanf(
|
||||
f, "%d %d %d %02d %02d %02d %02d\n%d\n",
|
||||
&rtc.carry, &rtc.stop, &rtc.d,
|
||||
&rtc.h, &rtc.m, &rtc.s, &rtc.t, &rt);
|
||||
while (rtc.t >= 60) rtc.t -= 60;
|
||||
while (rtc.s >= 60) rtc.s -= 60;
|
||||
while (rtc.m >= 60) rtc.m -= 60;
|
||||
while (rtc.h >= 24) rtc.h -= 24;
|
||||
while (rtc.d >= 365) rtc.d -= 365;
|
||||
rtc.stop &= 1;
|
||||
rtc.carry &= 1;
|
||||
if (rt) rt = (time(0) - rt) * 60;
|
||||
if (syncrtc) while (rt-- > 0) rtc_tick();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
#ifndef __RTC_H__
|
||||
#define __RTC_H__
|
||||
|
||||
|
||||
struct rtc
|
||||
{
|
||||
int batt;
|
||||
int sel;
|
||||
int latch;
|
||||
int d, h, m, s, t;
|
||||
int stop, carry;
|
||||
byte regs[8];
|
||||
};
|
||||
|
||||
extern struct rtc rtc;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "cpu.h"
|
||||
#include "cpuregs.h"
|
||||
#include "hw.h"
|
||||
#include "regs.h"
|
||||
#include "lcd.h"
|
||||
#include "rtc.h"
|
||||
#include "mem.h"
|
||||
#include "sound.h"
|
||||
|
||||
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define LIL(x) (x)
|
||||
#else
|
||||
#define LIL(x) ((x<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|(x>>24))
|
||||
#endif
|
||||
|
||||
#define I1(s, p) { 1, s, p }
|
||||
#define I2(s, p) { 2, s, p }
|
||||
#define I4(s, p) { 4, s, p }
|
||||
#define R(r) I1(#r, &R_##r)
|
||||
#define NOSAVE { -1, "\0\0\0\0", 0 }
|
||||
#define END { 0, "\0\0\0\0", 0 }
|
||||
|
||||
struct svar
|
||||
{
|
||||
int len;
|
||||
char key[4];
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
static int ver;
|
||||
static int sramblock, iramblock, vramblock;
|
||||
static int hramofs, hiofs, palofs, oamofs, wavofs;
|
||||
|
||||
struct svar svars[] =
|
||||
{
|
||||
I4("GbSs", &ver),
|
||||
|
||||
I2("PC ", &PC),
|
||||
I2("SP ", &SP),
|
||||
I2("BC ", &BC),
|
||||
I2("DE ", &DE),
|
||||
I2("HL ", &HL),
|
||||
I2("AF ", &AF),
|
||||
|
||||
I4("IME ", &cpu.ime),
|
||||
I4("ima ", &cpu.ima),
|
||||
I4("spd ", &cpu.speed),
|
||||
I4("halt", &cpu.halt),
|
||||
I4("div ", &cpu.div),
|
||||
I4("tim ", &cpu.tim),
|
||||
I4("lcdc", &cpu.lcdc),
|
||||
I4("snd ", &cpu.snd),
|
||||
|
||||
I1("ints", &hw.ilines),
|
||||
I1("pad ", &hw.pad),
|
||||
I4("cgb ", &hw.cgb),
|
||||
I4("gba ", &hw.gba),
|
||||
|
||||
I4("mbcm", &mbc.model),
|
||||
I4("romb", &mbc.rombank),
|
||||
I4("ramb", &mbc.rambank),
|
||||
I4("enab", &mbc.enableram),
|
||||
I4("batt", &mbc.batt),
|
||||
|
||||
I4("rtcR", &rtc.sel),
|
||||
I4("rtcL", &rtc.latch),
|
||||
I4("rtcC", &rtc.carry),
|
||||
I4("rtcS", &rtc.stop),
|
||||
I4("rtcd", &rtc.d),
|
||||
I4("rtch", &rtc.h),
|
||||
I4("rtcm", &rtc.m),
|
||||
I4("rtcs", &rtc.s),
|
||||
I4("rtct", &rtc.t),
|
||||
I1("rtR8", &rtc.regs[0]),
|
||||
I1("rtR9", &rtc.regs[1]),
|
||||
I1("rtRA", &rtc.regs[2]),
|
||||
I1("rtRB", &rtc.regs[3]),
|
||||
I1("rtRC", &rtc.regs[4]),
|
||||
|
||||
I4("S1on", &snd.ch[0].on),
|
||||
I4("S1p ", &snd.ch[0].pos),
|
||||
I4("S1c ", &snd.ch[0].cnt),
|
||||
I4("S1ec", &snd.ch[0].encnt),
|
||||
I4("S1sc", &snd.ch[0].swcnt),
|
||||
I4("S1sf", &snd.ch[0].swfreq),
|
||||
|
||||
I4("S2on", &snd.ch[1].on),
|
||||
I4("S2p ", &snd.ch[1].pos),
|
||||
I4("S2c ", &snd.ch[1].cnt),
|
||||
I4("S2ec", &snd.ch[1].encnt),
|
||||
|
||||
I4("S3on", &snd.ch[2].on),
|
||||
I4("S3p ", &snd.ch[2].pos),
|
||||
I4("S3c ", &snd.ch[2].cnt),
|
||||
|
||||
I4("S4on", &snd.ch[3].on),
|
||||
I4("S4p ", &snd.ch[3].pos),
|
||||
I4("S4c ", &snd.ch[3].cnt),
|
||||
I4("S4ec", &snd.ch[3].encnt),
|
||||
|
||||
I4("hdma", &hw.hdma),
|
||||
|
||||
I4("sram", &sramblock),
|
||||
I4("iram", &iramblock),
|
||||
I4("vram", &vramblock),
|
||||
I4("hi ", &hiofs),
|
||||
I4("pal ", &palofs),
|
||||
I4("oam ", &oamofs),
|
||||
I4("wav ", &wavofs),
|
||||
|
||||
/* NOSAVE is a special code to prevent the rest of the table
|
||||
* from being saved, used to support old stuff for backwards
|
||||
* compatibility... */
|
||||
NOSAVE,
|
||||
|
||||
/* the following are obsolete as of 0x104 */
|
||||
|
||||
I4("hram", &hramofs),
|
||||
|
||||
R(P1), R(SB), R(SC),
|
||||
R(DIV), R(TIMA), R(TMA), R(TAC),
|
||||
R(IE), R(IF),
|
||||
R(LCDC), R(STAT), R(LY), R(LYC),
|
||||
R(SCX), R(SCY), R(WX), R(WY),
|
||||
R(BGP), R(OBP0), R(OBP1),
|
||||
R(DMA),
|
||||
|
||||
R(VBK), R(SVBK), R(KEY1),
|
||||
R(BCPS), R(BCPD), R(OCPS), R(OCPD),
|
||||
|
||||
R(NR10), R(NR11), R(NR12), R(NR13), R(NR14),
|
||||
R(NR21), R(NR22), R(NR23), R(NR24),
|
||||
R(NR30), R(NR31), R(NR32), R(NR33), R(NR34),
|
||||
R(NR41), R(NR42), R(NR43), R(NR44),
|
||||
R(NR50), R(NR51), R(NR52),
|
||||
|
||||
I1("DMA1", &R_HDMA1),
|
||||
I1("DMA2", &R_HDMA2),
|
||||
I1("DMA3", &R_HDMA3),
|
||||
I1("DMA4", &R_HDMA4),
|
||||
I1("DMA5", &R_HDMA5),
|
||||
|
||||
END
|
||||
};
|
||||
|
||||
|
||||
void loadstate(FILE *f)
|
||||
{
|
||||
int i, j;
|
||||
byte buf[4096];
|
||||
un32 (*header)[2] = (un32 (*)[2])buf;
|
||||
un32 d;
|
||||
int irl = hw.cgb ? 8 : 2;
|
||||
int vrl = hw.cgb ? 4 : 2;
|
||||
int srl = mbc.ramsize << 1;
|
||||
|
||||
ver = hramofs = hiofs = palofs = oamofs = wavofs = 0;
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(buf, 4096, 1, f);
|
||||
|
||||
for (j = 0; header[j][0]; j++)
|
||||
{
|
||||
for (i = 0; svars[i].ptr; i++)
|
||||
{
|
||||
if (header[j][0] != *(un32 *)svars[i].key)
|
||||
continue;
|
||||
d = LIL(header[j][1]);
|
||||
switch (svars[i].len)
|
||||
{
|
||||
case 1:
|
||||
*(byte *)svars[i].ptr = d;
|
||||
break;
|
||||
case 2:
|
||||
*(un16 *)svars[i].ptr = d;
|
||||
break;
|
||||
case 4:
|
||||
*(un32 *)svars[i].ptr = d;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* obsolete as of version 0x104 */
|
||||
if (hramofs) memcpy(ram.hi+128, buf+hramofs, 127);
|
||||
|
||||
if (hiofs) memcpy(ram.hi, buf+hiofs, sizeof ram.hi);
|
||||
if (palofs) memcpy(lcd.pal, buf+palofs, sizeof lcd.pal);
|
||||
if (oamofs) memcpy(lcd.oam.mem, buf+oamofs, sizeof lcd.oam);
|
||||
|
||||
if (wavofs) memcpy(snd.wave, buf+wavofs, sizeof snd.wave);
|
||||
else memcpy(snd.wave, ram.hi+0x30, 16); /* patch data from older files */
|
||||
|
||||
fseek(f, iramblock<<12, SEEK_SET);
|
||||
fread(ram.ibank, 4096, irl, f);
|
||||
|
||||
fseek(f, vramblock<<12, SEEK_SET);
|
||||
fread(lcd.vbank, 4096, vrl, f);
|
||||
|
||||
fseek(f, sramblock<<12, SEEK_SET);
|
||||
fread(ram.sbank, 4096, srl, f);
|
||||
}
|
||||
|
||||
void savestate(FILE *f)
|
||||
{
|
||||
int i;
|
||||
byte buf[4096];
|
||||
un32 (*header)[2] = (un32 (*)[2])buf;
|
||||
un32 d = 0;
|
||||
int irl = hw.cgb ? 8 : 2;
|
||||
int vrl = hw.cgb ? 4 : 2;
|
||||
int srl = mbc.ramsize << 1;
|
||||
|
||||
ver = 0x105;
|
||||
iramblock = 1;
|
||||
vramblock = 1+irl;
|
||||
sramblock = 1+irl+vrl;
|
||||
wavofs = 4096 - 784;
|
||||
hiofs = 4096 - 768;
|
||||
palofs = 4096 - 512;
|
||||
oamofs = 4096 - 256;
|
||||
memset(buf, 0, sizeof buf);
|
||||
|
||||
for (i = 0; svars[i].len > 0; i++)
|
||||
{
|
||||
header[i][0] = *(un32 *)svars[i].key;
|
||||
switch (svars[i].len)
|
||||
{
|
||||
case 1:
|
||||
d = *(byte *)svars[i].ptr;
|
||||
break;
|
||||
case 2:
|
||||
d = *(un16 *)svars[i].ptr;
|
||||
break;
|
||||
case 4:
|
||||
d = *(un32 *)svars[i].ptr;
|
||||
break;
|
||||
}
|
||||
header[i][1] = LIL(d);
|
||||
}
|
||||
header[i][0] = header[i][1] = 0;
|
||||
|
||||
memcpy(buf+hiofs, ram.hi, sizeof ram.hi);
|
||||
memcpy(buf+palofs, lcd.pal, sizeof lcd.pal);
|
||||
memcpy(buf+oamofs, lcd.oam.mem, sizeof lcd.oam);
|
||||
memcpy(buf+wavofs, snd.wave, sizeof snd.wave);
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fwrite(buf, 4096, 1, f);
|
||||
|
||||
fseek(f, iramblock<<12, SEEK_SET);
|
||||
fwrite(ram.ibank, 4096, irl, f);
|
||||
|
||||
fseek(f, vramblock<<12, SEEK_SET);
|
||||
fwrite(lcd.vbank, 4096, vrl, f);
|
||||
|
||||
fseek(f, sramblock<<12, SEEK_SET);
|
||||
fwrite(ram.sbank, 4096, srl, f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,463 @@
|
|||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "pcm.h"
|
||||
#include "sound.h"
|
||||
#include "cpu.h"
|
||||
#include "hw.h"
|
||||
#include "regs.h"
|
||||
#include "rc.h"
|
||||
#include "noise.h"
|
||||
|
||||
|
||||
const static byte dmgwave[16] =
|
||||
{
|
||||
0xac, 0xdd, 0xda, 0x48,
|
||||
0x36, 0x02, 0xcf, 0x16,
|
||||
0x2c, 0x04, 0xe5, 0x2c,
|
||||
0xac, 0xdd, 0xda, 0x48
|
||||
};
|
||||
|
||||
const static byte cgbwave[16] =
|
||||
{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
};
|
||||
|
||||
const static byte sqwave[4][8] =
|
||||
{
|
||||
{ 0, 0,-1, 0, 0, 0, 0, 0 },
|
||||
{ 0,-1,-1, 0, 0, 0, 0, 0 },
|
||||
{ -1,-1,-1,-1, 0, 0, 0, 0 },
|
||||
{ -1, 0, 0,-1,-1,-1,-1,-1 }
|
||||
};
|
||||
|
||||
const static int freqtab[8] =
|
||||
{
|
||||
(1<<14)*2,
|
||||
(1<<14),
|
||||
(1<<14)/2,
|
||||
(1<<14)/3,
|
||||
(1<<14)/4,
|
||||
(1<<14)/5,
|
||||
(1<<14)/6,
|
||||
(1<<14)/7
|
||||
};
|
||||
|
||||
struct snd snd;
|
||||
|
||||
#define RATE (snd.rate)
|
||||
#define WAVE (snd.wave) /* ram.hi+0x30 */
|
||||
#define S1 (snd.ch[0])
|
||||
#define S2 (snd.ch[1])
|
||||
#define S3 (snd.ch[2])
|
||||
#define S4 (snd.ch[3])
|
||||
|
||||
rcvar_t sound_exports[] =
|
||||
{
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
static void s1_freq_d(int d)
|
||||
{
|
||||
if (RATE > (d<<4)) S1.freq = 0;
|
||||
else S1.freq = (RATE << 17)/d;
|
||||
}
|
||||
|
||||
static void s1_freq()
|
||||
{
|
||||
s1_freq_d(2048 - (((R_NR14&7)<<8) + R_NR13));
|
||||
}
|
||||
|
||||
static void s2_freq()
|
||||
{
|
||||
int d = 2048 - (((R_NR24&7)<<8) + R_NR23);
|
||||
if (RATE > (d<<4)) S2.freq = 0;
|
||||
else S2.freq = (RATE << 17)/d;
|
||||
}
|
||||
|
||||
static void s3_freq()
|
||||
{
|
||||
int d = 2048 - (((R_NR34&7)<<8) + R_NR33);
|
||||
if (RATE > (d<<3)) S3.freq = 0;
|
||||
else S3.freq = (RATE << 21)/d;
|
||||
}
|
||||
|
||||
static void s4_freq()
|
||||
{
|
||||
S4.freq = (freqtab[R_NR43&7] >> (R_NR43 >> 4)) * RATE;
|
||||
if (S4.freq >> 18) S4.freq = 1<<18;
|
||||
}
|
||||
|
||||
void sound_dirty()
|
||||
{
|
||||
S1.swlen = ((R_NR10>>4) & 7) << 14;
|
||||
S1.len = (64-(R_NR11&63)) << 13;
|
||||
S1.envol = R_NR12 >> 4;
|
||||
S1.endir = (R_NR12>>3) & 1;
|
||||
S1.endir |= S1.endir - 1;
|
||||
S1.enlen = (R_NR12 & 7) << 15;
|
||||
s1_freq();
|
||||
S2.len = (64-(R_NR21&63)) << 13;
|
||||
S2.envol = R_NR22 >> 4;
|
||||
S2.endir = (R_NR22>>3) & 1;
|
||||
S2.endir |= S2.endir - 1;
|
||||
S2.enlen = (R_NR22 & 7) << 15;
|
||||
s2_freq();
|
||||
S3.len = (256-R_NR31) << 20;
|
||||
s3_freq();
|
||||
S4.len = (64-(R_NR41&63)) << 13;
|
||||
S4.envol = R_NR42 >> 4;
|
||||
S4.endir = (R_NR42>>3) & 1;
|
||||
S4.endir |= S4.endir - 1;
|
||||
S4.enlen = (R_NR42 & 7) << 15;
|
||||
s4_freq();
|
||||
}
|
||||
|
||||
void sound_off()
|
||||
{
|
||||
memset(&S1, 0, sizeof S1);
|
||||
memset(&S2, 0, sizeof S2);
|
||||
memset(&S3, 0, sizeof S3);
|
||||
memset(&S4, 0, sizeof S4);
|
||||
R_NR10 = 0x80;
|
||||
R_NR11 = 0xBF;
|
||||
R_NR12 = 0xF3;
|
||||
R_NR14 = 0xBF;
|
||||
R_NR21 = 0x3F;
|
||||
R_NR22 = 0x00;
|
||||
R_NR24 = 0xBF;
|
||||
R_NR30 = 0x7F;
|
||||
R_NR31 = 0xFF;
|
||||
R_NR32 = 0x9F;
|
||||
R_NR33 = 0xBF;
|
||||
R_NR41 = 0xFF;
|
||||
R_NR42 = 0x00;
|
||||
R_NR43 = 0x00;
|
||||
R_NR44 = 0xBF;
|
||||
R_NR50 = 0x77;
|
||||
R_NR51 = 0xF3;
|
||||
R_NR52 = 0xF1;
|
||||
sound_dirty();
|
||||
}
|
||||
|
||||
void sound_reset()
|
||||
{
|
||||
memset(&snd, 0, sizeof snd);
|
||||
if (pcm.hz) snd.rate = (1<<21) / pcm.hz;
|
||||
else snd.rate = 0;
|
||||
memcpy(WAVE, hw.cgb ? cgbwave : dmgwave, 16);
|
||||
memcpy(ram.hi+0x30, WAVE, 16);
|
||||
sound_off();
|
||||
}
|
||||
|
||||
|
||||
void sound_mix()
|
||||
{
|
||||
int s, l, r, f, n;
|
||||
|
||||
if (!RATE || cpu.snd < RATE) return;
|
||||
|
||||
for (; cpu.snd >= RATE; cpu.snd -= RATE)
|
||||
{
|
||||
l = r = 0;
|
||||
|
||||
if (S1.on)
|
||||
{
|
||||
s = sqwave[R_NR11>>6][(S1.pos>>18)&7] & S1.envol;
|
||||
S1.pos += S1.freq;
|
||||
if ((R_NR14 & 64) && ((S1.cnt += RATE) >= S1.len))
|
||||
S1.on = 0;
|
||||
if (S1.enlen && (S1.encnt += RATE) >= S1.enlen)
|
||||
{
|
||||
S1.encnt -= S1.enlen;
|
||||
S1.envol += S1.endir;
|
||||
if (S1.envol < 0) S1.envol = 0;
|
||||
if (S1.envol > 15) S1.envol = 15;
|
||||
}
|
||||
if (S1.swlen && (S1.swcnt += RATE) >= S1.swlen)
|
||||
{
|
||||
S1.swcnt -= S1.swlen;
|
||||
f = S1.swfreq;
|
||||
n = (R_NR10 & 7);
|
||||
if (R_NR10 & 8) f -= (f >> n);
|
||||
else f += (f >> n);
|
||||
if (f > 2047)
|
||||
S1.on = 0;
|
||||
else
|
||||
{
|
||||
S1.swfreq = f;
|
||||
R_NR13 = f;
|
||||
R_NR14 = (R_NR14 & 0xF8) | (f>>8);
|
||||
s1_freq_d(2048 - f);
|
||||
}
|
||||
}
|
||||
s <<= 2;
|
||||
if (R_NR51 & 1) r += s;
|
||||
if (R_NR51 & 16) l += s;
|
||||
}
|
||||
|
||||
if (S2.on)
|
||||
{
|
||||
s = sqwave[R_NR21>>6][(S2.pos>>18)&7] & S2.envol;
|
||||
S2.pos += S2.freq;
|
||||
if ((R_NR24 & 64) && ((S2.cnt += RATE) >= S2.len))
|
||||
S2.on = 0;
|
||||
if (S2.enlen && (S2.encnt += RATE) >= S2.enlen)
|
||||
{
|
||||
S2.encnt -= S2.enlen;
|
||||
S2.envol += S2.endir;
|
||||
if (S2.envol < 0) S2.envol = 0;
|
||||
if (S2.envol > 15) S2.envol = 15;
|
||||
}
|
||||
s <<= 2;
|
||||
if (R_NR51 & 2) r += s;
|
||||
if (R_NR51 & 32) l += s;
|
||||
}
|
||||
|
||||
if (S3.on)
|
||||
{
|
||||
s = WAVE[(S3.pos>>22) & 15];
|
||||
if (S3.pos & (1<<21)) s &= 15;
|
||||
else s >>= 4;
|
||||
s -= 8;
|
||||
S3.pos += S3.freq;
|
||||
if ((R_NR34 & 64) && ((S3.cnt += RATE) >= S3.len))
|
||||
S3.on = 0;
|
||||
if (R_NR32 & 96) s <<= (3 - ((R_NR32>>5)&3));
|
||||
else s = 0;
|
||||
if (R_NR51 & 4) r += s;
|
||||
if (R_NR51 & 64) l += s;
|
||||
}
|
||||
|
||||
if (S4.on)
|
||||
{
|
||||
if (R_NR43 & 8) s = 1 & (noise7[
|
||||
(S4.pos>>20)&15] >> (7-((S4.pos>>17)&7)));
|
||||
else s = 1 & (noise15[
|
||||
(S4.pos>>20)&4095] >> (7-((S4.pos>>17)&7)));
|
||||
s = (-s) & S4.envol;
|
||||
S4.pos += S4.freq;
|
||||
if ((R_NR44 & 64) && ((S4.cnt += RATE) >= S4.len))
|
||||
S4.on = 0;
|
||||
if (S4.enlen && (S4.encnt += RATE) >= S4.enlen)
|
||||
{
|
||||
S4.encnt -= S4.enlen;
|
||||
S4.envol += S4.endir;
|
||||
if (S4.envol < 0) S4.envol = 0;
|
||||
if (S4.envol > 15) S4.envol = 15;
|
||||
}
|
||||
s += s << 1;
|
||||
if (R_NR51 & 8) r += s;
|
||||
if (R_NR51 & 128) l += s;
|
||||
}
|
||||
|
||||
l *= (R_NR50 & 0x07);
|
||||
r *= ((R_NR50 & 0x70)>>4);
|
||||
l >>= 4;
|
||||
r >>= 4;
|
||||
|
||||
if (l > 127) l = 127;
|
||||
else if (l < -128) l = -128;
|
||||
if (r > 127) r = 127;
|
||||
else if (r < -128) r = -128;
|
||||
|
||||
if (pcm.buf)
|
||||
{
|
||||
if (pcm.pos >= pcm.len)
|
||||
pcm_submit();
|
||||
if (pcm.stereo)
|
||||
{
|
||||
pcm.buf[pcm.pos++] = l+128;
|
||||
pcm.buf[pcm.pos++] = r+128;
|
||||
}
|
||||
else pcm.buf[pcm.pos++] = ((l+r)>>1)+128;
|
||||
}
|
||||
}
|
||||
R_NR52 = (R_NR52&0xf0) | S1.on | (S2.on<<1) | (S3.on<<2) | (S4.on<<3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
byte sound_read(byte r)
|
||||
{
|
||||
sound_mix();
|
||||
/* printf("read %02X: %02X\n", r, REG(r)); */
|
||||
return REG(r);
|
||||
}
|
||||
|
||||
void s1_init()
|
||||
{
|
||||
S1.swcnt = 0;
|
||||
S1.swfreq = ((R_NR14&7)<<8) + R_NR13;
|
||||
S1.envol = R_NR12 >> 4;
|
||||
S1.endir = (R_NR12>>3) & 1;
|
||||
S1.endir |= S1.endir - 1;
|
||||
S1.enlen = (R_NR12 & 7) << 15;
|
||||
if (!S1.on) S1.pos = 0;
|
||||
S1.on = 1;
|
||||
S1.cnt = 0;
|
||||
S1.encnt = 0;
|
||||
}
|
||||
|
||||
void s2_init()
|
||||
{
|
||||
S2.envol = R_NR22 >> 4;
|
||||
S2.endir = (R_NR22>>3) & 1;
|
||||
S2.endir |= S2.endir - 1;
|
||||
S2.enlen = (R_NR22 & 7) << 15;
|
||||
if (!S2.on) S2.pos = 0;
|
||||
S2.on = 1;
|
||||
S2.cnt = 0;
|
||||
S2.encnt = 0;
|
||||
}
|
||||
|
||||
void s3_init()
|
||||
{
|
||||
int i;
|
||||
if (!S3.on) S3.pos = 0;
|
||||
S3.cnt = 0;
|
||||
S3.on = R_NR30 >> 7;
|
||||
if (S3.on) for (i = 0; i < 16; i++)
|
||||
ram.hi[i+0x30] = 0x13 ^ ram.hi[i+0x31];
|
||||
}
|
||||
|
||||
void s4_init()
|
||||
{
|
||||
S4.envol = R_NR42 >> 4;
|
||||
S4.endir = (R_NR42>>3) & 1;
|
||||
S4.endir |= S4.endir - 1;
|
||||
S4.enlen = (R_NR42 & 7) << 15;
|
||||
S4.on = 1;
|
||||
S4.pos = 0;
|
||||
S4.cnt = 0;
|
||||
S4.encnt = 0;
|
||||
}
|
||||
|
||||
|
||||
void sound_write(byte r, byte b)
|
||||
{
|
||||
#if 0
|
||||
static void *timer;
|
||||
if (!timer) timer = sys_timer();
|
||||
printf("write %02X: %02X @ %d\n", r, b, sys_elapsed(timer));
|
||||
#endif
|
||||
|
||||
if (!(R_NR52 & 128) && r != RI_NR52) return;
|
||||
if ((r & 0xF0) == 0x30)
|
||||
{
|
||||
if (S3.on) sound_mix();
|
||||
if (!S3.on)
|
||||
WAVE[r-0x30] = ram.hi[r] = b;
|
||||
return;
|
||||
}
|
||||
sound_mix();
|
||||
switch (r)
|
||||
{
|
||||
case RI_NR10:
|
||||
R_NR10 = b;
|
||||
S1.swlen = ((R_NR10>>4) & 7) << 14;
|
||||
S1.swfreq = ((R_NR14&7)<<8) + R_NR13;
|
||||
break;
|
||||
case RI_NR11:
|
||||
R_NR11 = b;
|
||||
S1.len = (64-(R_NR11&63)) << 13;
|
||||
break;
|
||||
case RI_NR12:
|
||||
R_NR12 = b;
|
||||
S1.envol = R_NR12 >> 4;
|
||||
S1.endir = (R_NR12>>3) & 1;
|
||||
S1.endir |= S1.endir - 1;
|
||||
S1.enlen = (R_NR12 & 7) << 15;
|
||||
break;
|
||||
case RI_NR13:
|
||||
R_NR13 = b;
|
||||
s1_freq();
|
||||
break;
|
||||
case RI_NR14:
|
||||
R_NR14 = b;
|
||||
s1_freq();
|
||||
if (b & 128) s1_init();
|
||||
break;
|
||||
case RI_NR21:
|
||||
R_NR21 = b;
|
||||
S2.len = (64-(R_NR21&63)) << 13;
|
||||
break;
|
||||
case RI_NR22:
|
||||
R_NR22 = b;
|
||||
S2.envol = R_NR22 >> 4;
|
||||
S2.endir = (R_NR22>>3) & 1;
|
||||
S2.endir |= S2.endir - 1;
|
||||
S2.enlen = (R_NR22 & 7) << 15;
|
||||
break;
|
||||
case RI_NR23:
|
||||
R_NR23 = b;
|
||||
s2_freq();
|
||||
break;
|
||||
case RI_NR24:
|
||||
R_NR24 = b;
|
||||
s2_freq();
|
||||
if (b & 128) s2_init();
|
||||
break;
|
||||
case RI_NR30:
|
||||
R_NR30 = b;
|
||||
if (!(b & 128)) S3.on = 0;
|
||||
break;
|
||||
case RI_NR31:
|
||||
R_NR31 = b;
|
||||
S3.len = (256-R_NR31) << 13;
|
||||
break;
|
||||
case RI_NR32:
|
||||
R_NR32 = b;
|
||||
break;
|
||||
case RI_NR33:
|
||||
R_NR33 = b;
|
||||
s3_freq();
|
||||
break;
|
||||
case RI_NR34:
|
||||
R_NR34 = b;
|
||||
s3_freq();
|
||||
if (b & 128) s3_init();
|
||||
break;
|
||||
case RI_NR41:
|
||||
R_NR41 = b;
|
||||
S4.len = (64-(R_NR41&63)) << 13;
|
||||
break;
|
||||
case RI_NR42:
|
||||
R_NR42 = b;
|
||||
S4.envol = R_NR42 >> 4;
|
||||
S4.endir = (R_NR42>>3) & 1;
|
||||
S4.endir |= S4.endir - 1;
|
||||
S4.enlen = (R_NR42 & 7) << 15;
|
||||
break;
|
||||
case RI_NR43:
|
||||
R_NR43 = b;
|
||||
s4_freq();
|
||||
break;
|
||||
case RI_NR44:
|
||||
R_NR44 = b;
|
||||
if (b & 128) s4_init();
|
||||
break;
|
||||
case RI_NR50:
|
||||
R_NR50 = b;
|
||||
break;
|
||||
case RI_NR51:
|
||||
R_NR51 = b;
|
||||
break;
|
||||
case RI_NR52:
|
||||
R_NR52 = b;
|
||||
if (!(R_NR52 & 128))
|
||||
sound_off();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
#ifndef __SOUND_H__
|
||||
#define __SOUND_H__
|
||||
|
||||
|
||||
struct sndchan
|
||||
{
|
||||
int on;
|
||||
unsigned pos;
|
||||
int cnt, encnt, swcnt;
|
||||
int len, enlen, swlen;
|
||||
int swfreq;
|
||||
int freq;
|
||||
int envol, endir;
|
||||
};
|
||||
|
||||
|
||||
struct snd
|
||||
{
|
||||
int rate;
|
||||
struct sndchan ch[4];
|
||||
byte wave[16];
|
||||
};
|
||||
|
||||
|
||||
extern struct snd snd;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
|
||||
/*
|
||||
* splitline is a destructive argument parser, much like a very primitive
|
||||
* form of a shell parser. it supports quotes for embedded spaces and
|
||||
* literal quotes with the backslash escape.
|
||||
*/
|
||||
|
||||
char *splitnext(char **pos)
|
||||
{
|
||||
char *a, *d, *s;
|
||||
|
||||
d = s = *pos;
|
||||
while (*s == ' ' || *s == '\t') s++;
|
||||
a = s;
|
||||
while (*s && *s != ' ' && *s != '\t')
|
||||
{
|
||||
if (*s == '"')
|
||||
{
|
||||
s++;
|
||||
while (*s && *s != '"')
|
||||
{
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
if (*s)
|
||||
*(d++) = *(s++);
|
||||
}
|
||||
if (*s == '"') s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
*(d++) = *(s++);
|
||||
}
|
||||
}
|
||||
while (*s == ' ' || *s == '\t') s++;
|
||||
*d = 0;
|
||||
*pos = s;
|
||||
return a;
|
||||
}
|
||||
|
||||
int splitline(char **argv, int max, char *line)
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
s = line;
|
||||
for (i = 0; *s && i < max + 1; i++)
|
||||
argv[i] = splitnext(&s);
|
||||
argv[i] = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* dos.c
|
||||
*
|
||||
* System interface for DOS.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
char *strdup();
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#define US(n) ( ((long long)(n)) * 1000000 / UCLOCKS_PER_SEC )
|
||||
|
||||
|
||||
void *sys_timer()
|
||||
{
|
||||
uclock_t *cl;
|
||||
|
||||
cl = malloc(sizeof *cl);
|
||||
*cl = uclock();
|
||||
return cl;
|
||||
}
|
||||
|
||||
int sys_elapsed(uclock_t *cl)
|
||||
{
|
||||
uclock_t now;
|
||||
int usecs;
|
||||
|
||||
now = uclock();
|
||||
usecs = US(now - *cl);
|
||||
*cl = now;
|
||||
return usecs;
|
||||
}
|
||||
|
||||
void sys_sleep(int us)
|
||||
{
|
||||
uclock_t start;
|
||||
if (us <= 0) return;
|
||||
start = uclock();
|
||||
while(US(uclock()-start) < us);
|
||||
}
|
||||
|
||||
void sys_checkdir(char *path, int wr)
|
||||
{
|
||||
}
|
||||
|
||||
void sys_initpath(char *exe)
|
||||
{
|
||||
char *buf, *home, *p;
|
||||
|
||||
home = strdup(exe);
|
||||
p = strrchr(home, '/');
|
||||
if (p) *p = 0;
|
||||
else
|
||||
{
|
||||
buf = ".";
|
||||
rc_setvar("rcpath", 1, &buf);
|
||||
rc_setvar("savedir", 1, &buf);
|
||||
return;
|
||||
}
|
||||
buf = malloc(strlen(home) + 8);
|
||||
sprintf(buf, ".;%s/", home);
|
||||
rc_setvar("rcpath", 1, &buf);
|
||||
sprintf(buf, ".");
|
||||
rc_setvar("savedir", 1, &buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void sys_sanitize(char *s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; s[i]; i++)
|
||||
if (s[i] == '\\') s[i] = '/';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
|
||||
#include "rc.h"
|
||||
|
||||
rcvar_t joy_exports[] =
|
||||
{
|
||||
RCV_END
|
||||
};
|
||||
|
||||
void joy_init()
|
||||
{
|
||||
}
|
||||
|
||||
void joy_close()
|
||||
{
|
||||
}
|
||||
|
||||
void joy_poll()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
#include "pcm.h"
|
||||
#include "rc.h"
|
||||
|
||||
|
||||
struct pcm pcm;
|
||||
|
||||
static byte buf[4096];
|
||||
|
||||
|
||||
rcvar_t pcm_exports[] =
|
||||
{
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
void pcm_init()
|
||||
{
|
||||
pcm.hz = 11025;
|
||||
pcm.buf = buf;
|
||||
pcm.len = sizeof buf;
|
||||
pcm.pos = 0;
|
||||
}
|
||||
|
||||
void pcm_close()
|
||||
{
|
||||
memset(&pcm, 0, sizeof pcm);
|
||||
}
|
||||
|
||||
int pcm_submit()
|
||||
{
|
||||
pcm.pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
|
||||
/*
|
||||
* Support for the Linux framebuffer device
|
||||
* Copyright 2001 Laguna
|
||||
* MGA BES code derived from fbtv
|
||||
* Copyright Gerd Knorr
|
||||
* This file may be distributed under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
char *strdup();
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "fb.h"
|
||||
#include "rc.h"
|
||||
#include "matrox.h"
|
||||
|
||||
struct fb fb;
|
||||
|
||||
|
||||
|
||||
#define FBSET_CMD "fbset"
|
||||
static char *fb_mode;
|
||||
static int fb_depth;
|
||||
static int vmode[3];
|
||||
|
||||
#define FB_DEVICE "/dev/fb0"
|
||||
static char *fb_device;
|
||||
|
||||
static int fbfd = -1;
|
||||
static byte *fbmap;
|
||||
static int maplen;
|
||||
static byte *mmio;
|
||||
static int bes;
|
||||
static int base;
|
||||
static int use_yuv = -1;
|
||||
static int use_interp = 1;
|
||||
|
||||
static struct fb_fix_screeninfo fi;
|
||||
static struct fb_var_screeninfo vi, initial_vi;
|
||||
|
||||
rcvar_t vid_exports[] =
|
||||
{
|
||||
RCV_VECTOR("vmode", &vmode, 3),
|
||||
RCV_STRING("fb_device", &fb_device),
|
||||
RCV_STRING("fb_mode", &fb_mode),
|
||||
RCV_INT("fb_depth", &fb_depth),
|
||||
RCV_BOOL("yuv", &use_yuv),
|
||||
RCV_BOOL("yuvinterp", &use_interp),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void wrio4(int a, int v)
|
||||
{
|
||||
#ifndef IS_LITTLE_ENDIAN
|
||||
v = (v<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | (v>>24);
|
||||
#endif
|
||||
*(int*)(mmio+a) = v;
|
||||
}
|
||||
|
||||
static void overlay_switch()
|
||||
{
|
||||
int a, b;
|
||||
|
||||
if (!fb.yuv) return;
|
||||
if (!fb.enabled)
|
||||
{
|
||||
if (bes) wrio4(BESCTL, 0);
|
||||
bes = 0;
|
||||
return;
|
||||
}
|
||||
if (bes) return;
|
||||
bes = 1;
|
||||
memset(fbmap, 0, maplen);
|
||||
|
||||
/* color keying (turn it off) */
|
||||
mmio[PALWTADD] = XKEYOPMODE;
|
||||
mmio[X_DATAREG] = 0;
|
||||
|
||||
/* src */
|
||||
wrio4(BESA1ORG, base);
|
||||
wrio4(BESA2ORG, base);
|
||||
wrio4(BESB1ORG, base);
|
||||
wrio4(BESB2ORG, base);
|
||||
wrio4(BESPITCH, 320);
|
||||
|
||||
/* dest */
|
||||
a = (vi.xres - vmode[0])>>1;
|
||||
b = vi.xres - a - 1;
|
||||
wrio4(BESHCOORD, (a << 16) | (b - 1));
|
||||
|
||||
/* scale horiz */
|
||||
wrio4(BESHISCAL, 320*131072/(b-a) & 0x001ffffc);
|
||||
wrio4(BESHSRCST, 0 << 16);
|
||||
wrio4(BESHSRCEND, 320 << 16);
|
||||
wrio4(BESHSRCLST, 319 << 16);
|
||||
|
||||
/* dest */
|
||||
a = (vi.yres - vmode[1])>>1;
|
||||
b = vi.yres - a - 1;
|
||||
wrio4(BESVCOORD, (a << 16) | (b - 1));
|
||||
|
||||
/* scale vert */
|
||||
wrio4(BESVISCAL, 144*65536/(b-a) & 0x001ffffc);
|
||||
wrio4(BESV1WGHT, 0);
|
||||
wrio4(BESV2WGHT, 0);
|
||||
wrio4(BESV1SRCLST, 143);
|
||||
wrio4(BESV2SRCLST, 143);
|
||||
|
||||
/* turn on (enable, horizontal+vertical interpolation filters */
|
||||
if (use_interp)
|
||||
wrio4(BESCTL, 0x50c01);
|
||||
else
|
||||
wrio4(BESCTL, 1);
|
||||
wrio4(BESGLOBCTL, 0x83);
|
||||
}
|
||||
|
||||
static void overlay_init()
|
||||
{
|
||||
if (!mmio | !use_yuv) return;
|
||||
if (use_yuv < 0) if ((vmode[0] < 320) || (vmode[1] < 288)) return;
|
||||
switch (fi.accel)
|
||||
{
|
||||
#ifdef FB_ACCEL_MATROX_MGAG200
|
||||
case FB_ACCEL_MATROX_MGAG200:
|
||||
#endif
|
||||
#ifdef FB_ACCEL_MATROX_MGAG400
|
||||
case FB_ACCEL_MATROX_MGAG400:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
fb.w = 160;
|
||||
fb.h = 144;
|
||||
fb.pitch = 640;
|
||||
fb.pelsize = 4;
|
||||
fb.yuv = 1;
|
||||
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = fb.cc[3].r = 0;
|
||||
fb.cc[0].l = 0;
|
||||
fb.cc[1].l = 24;
|
||||
fb.cc[2].l = 8;
|
||||
fb.cc[3].l = 16;
|
||||
base = vi.yres * vi.xres_virtual * ((vi.bits_per_pixel+7)>>3);
|
||||
|
||||
maplen = base + fb.pitch * fb.h;
|
||||
}
|
||||
|
||||
static void plain_init()
|
||||
{
|
||||
fb.w = vi.xres;
|
||||
fb.h = vi.yres;
|
||||
fb.pelsize = (vi.bits_per_pixel+7)>>3;
|
||||
fb.pitch = vi.xres_virtual * fb.pelsize;
|
||||
fb.indexed = fi.visual == FB_VISUAL_PSEUDOCOLOR;
|
||||
|
||||
fb.cc[0].r = 8 - vi.red.length;
|
||||
fb.cc[1].r = 8 - vi.green.length;
|
||||
fb.cc[2].r = 8 - vi.blue.length;
|
||||
fb.cc[0].l = vi.red.offset;
|
||||
fb.cc[1].l = vi.green.offset;
|
||||
fb.cc[2].l = vi.blue.offset;
|
||||
|
||||
maplen = fb.pitch * fb.h;
|
||||
}
|
||||
|
||||
void vid_init()
|
||||
{
|
||||
char cmd[256];
|
||||
|
||||
kb_init();
|
||||
joy_init();
|
||||
|
||||
if (!fb_device)
|
||||
if (!(fb_device = getenv("FRAMEBUFFER")))
|
||||
fb_device = strdup(FB_DEVICE);
|
||||
fbfd = open(fb_device, O_RDWR);
|
||||
if (fbfd < 0) die("cannot open %s\n", fb_device);
|
||||
|
||||
ioctl(fbfd, FBIOGET_VSCREENINFO, &initial_vi);
|
||||
initial_vi.xoffset = initial_vi.yoffset = 0;
|
||||
|
||||
if (fb_mode)
|
||||
{
|
||||
sprintf(cmd, FBSET_CMD " %.80s", fb_mode);
|
||||
system(cmd);
|
||||
}
|
||||
|
||||
ioctl(fbfd, FBIOGET_VSCREENINFO, &vi);
|
||||
if (fb_depth) vi.bits_per_pixel = fb_depth;
|
||||
vi.xoffset = vi.yoffset = 0;
|
||||
vi.accel_flags = 0;
|
||||
vi.activate = FB_ACTIVATE_NOW;
|
||||
ioctl(fbfd, FBIOPUT_VSCREENINFO, &vi);
|
||||
ioctl(fbfd, FBIOGET_VSCREENINFO, &vi);
|
||||
ioctl(fbfd, FBIOGET_FSCREENINFO, &fi);
|
||||
|
||||
if (!vmode[0] || !vmode[1])
|
||||
{
|
||||
int scale = rc_getint("scale");
|
||||
if (scale < 1) scale = 1;
|
||||
vmode[0] = 160 * scale;
|
||||
vmode[1] = 144 * scale;
|
||||
}
|
||||
if (vmode[0] > vi.xres) vmode[0] = vi.xres;
|
||||
if (vmode[1] > vi.yres) vmode[1] = vi.yres;
|
||||
|
||||
mmio = mmap(0, fi.mmio_len, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, fi.smem_len);
|
||||
if ((int)mmio == -1) mmio = 0;
|
||||
|
||||
overlay_init();
|
||||
|
||||
if (!fb.yuv) plain_init();
|
||||
|
||||
fbmap = mmap(0, maplen, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0);
|
||||
if (!fbmap) die("cannot mmap %s (%d bytes)\n", fb_device, maplen);
|
||||
|
||||
fb.ptr = fbmap + base;
|
||||
memset(fbmap, 0, maplen);
|
||||
fb.dirty = 0;
|
||||
fb.enabled = 1;
|
||||
|
||||
overlay_switch();
|
||||
}
|
||||
|
||||
void vid_close()
|
||||
{
|
||||
fb.enabled = 0;
|
||||
overlay_switch();
|
||||
joy_close();
|
||||
kb_close();
|
||||
ioctl(fbfd, FBIOPUT_VSCREENINFO, &initial_vi);
|
||||
memset(fbmap, 0, maplen);
|
||||
}
|
||||
|
||||
void vid_preinit()
|
||||
{
|
||||
}
|
||||
|
||||
void vid_settitle(char *title)
|
||||
{
|
||||
}
|
||||
|
||||
void vid_setpal(int i, int r, int g, int b)
|
||||
{
|
||||
unsigned short rr = r<<8, gg = g<<8, bb = b<<8;
|
||||
struct fb_cmap cmap;
|
||||
memset(&cmap, 0, sizeof cmap);
|
||||
cmap.start = i;
|
||||
cmap.len = 1;
|
||||
cmap.red = &rr;
|
||||
cmap.green = ≫
|
||||
cmap.blue = &bb;
|
||||
ioctl(fbfd, FBIOPUTCMAP, &cmap);
|
||||
}
|
||||
|
||||
void vid_begin()
|
||||
{
|
||||
overlay_switch();
|
||||
}
|
||||
|
||||
void vid_end()
|
||||
{
|
||||
overlay_switch();
|
||||
}
|
||||
|
||||
void ev_poll()
|
||||
{
|
||||
kb_poll();
|
||||
joy_poll();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
char *strdup();
|
||||
#include <linux/joystick.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "rc.h"
|
||||
|
||||
static int usejoy = 1;
|
||||
static char *joydev;
|
||||
static int joyfd = -1;
|
||||
static int pos[2], max[2], min[2];
|
||||
static const int axis[2][2] =
|
||||
{
|
||||
{ K_JOYLEFT, K_JOYRIGHT },
|
||||
{ K_JOYUP, K_JOYDOWN }
|
||||
};
|
||||
|
||||
rcvar_t joy_exports[] =
|
||||
{
|
||||
RCV_BOOL("joy", &usejoy),
|
||||
RCV_STRING("joy_device", &joydev),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void joy_init()
|
||||
{
|
||||
if (!usejoy) return;
|
||||
if (!joydev) joydev = strdup("/dev/js0");
|
||||
joyfd = open(joydev, O_RDONLY|O_NONBLOCK);
|
||||
}
|
||||
|
||||
void joy_close()
|
||||
{
|
||||
close(joyfd);
|
||||
}
|
||||
|
||||
void joy_poll()
|
||||
{
|
||||
struct js_event js;
|
||||
event_t ev;
|
||||
int n;
|
||||
|
||||
if (joyfd < 0) return;
|
||||
|
||||
while (read(joyfd,&js,sizeof(struct js_event)) == sizeof(struct js_event))
|
||||
{
|
||||
switch(js.type)
|
||||
{
|
||||
case JS_EVENT_BUTTON:
|
||||
ev.type = js.value ? EV_PRESS : EV_RELEASE;
|
||||
ev.code = K_JOY0 + js.number;
|
||||
ev_postevent(&ev);
|
||||
break;
|
||||
case JS_EVENT_AXIS:
|
||||
n = js.number & 1;
|
||||
if (js.value < min[n]) min[n] = js.value;
|
||||
else if(js.value > max[n]) max[n] = js.value;
|
||||
ev.code = axis[n][0];
|
||||
if(js.value < (min[n]>>2) && js.value < pos[n])
|
||||
{
|
||||
ev.type = EV_PRESS;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
else if (js.value > pos[n])
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
ev.code = axis[n][1];
|
||||
if(js.value > (max[n]>>2) && js.value > pos[n])
|
||||
{
|
||||
ev.type = EV_PRESS;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
else if (js.value < pos[n])
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
pos[n] = js.value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/kd.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/vt.h>
|
||||
#include <termios.h>
|
||||
|
||||
#undef K_NUMLOCK
|
||||
|
||||
#include "defs.h"
|
||||
#include "rc.h"
|
||||
#include "fb.h"
|
||||
#include "input.h"
|
||||
|
||||
|
||||
|
||||
#define TTY_DEVICE "/dev/tty"
|
||||
|
||||
static int kbfd = -1;
|
||||
|
||||
static int initial_kbmode;
|
||||
static struct termios initial_term, term;
|
||||
|
||||
#define SCAN_ALT 56
|
||||
#define SCAN_FBASE 58
|
||||
static int alt;
|
||||
|
||||
static struct vt_mode vtm, initial_vtm;
|
||||
|
||||
extern int keymap[][2];
|
||||
|
||||
rcvar_t kb_exports[] =
|
||||
{
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
static void vcrelease(int s)
|
||||
{
|
||||
signal(s, vcrelease);
|
||||
ioctl(kbfd, VT_RELDISP, VT_ACKACQ);
|
||||
}
|
||||
|
||||
static void vcacquire(int s)
|
||||
{
|
||||
signal(s, vcacquire);
|
||||
ioctl(kbfd, VT_RELDISP, VT_ACKACQ);
|
||||
fb.enabled = 1;
|
||||
}
|
||||
|
||||
void kb_init()
|
||||
{
|
||||
kbfd = open(TTY_DEVICE, O_RDWR);
|
||||
if (!kbfd) die("no controlling terminal\n");
|
||||
fcntl(kbfd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
if (ioctl(kbfd, KDSETMODE, KD_GRAPHICS) < 0)
|
||||
die("controlling terminal is not the graphics console\n");
|
||||
|
||||
ioctl(kbfd, KDGKBMODE, &initial_kbmode);
|
||||
tcgetattr(kbfd, &initial_term);
|
||||
|
||||
term = initial_term;
|
||||
term.c_lflag &= ~(ICANON | ECHO | ISIG);
|
||||
term.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
|
||||
term.c_cc[VMIN] = 0;
|
||||
term.c_cc[VTIME] = 0;
|
||||
tcsetattr(kbfd, TCSAFLUSH, &term);
|
||||
ioctl(kbfd, KDSKBMODE, K_MEDIUMRAW);
|
||||
|
||||
ioctl(kbfd, VT_GETMODE, &initial_vtm);
|
||||
|
||||
signal(SIGUSR1, vcrelease);
|
||||
signal(SIGUSR2, vcacquire);
|
||||
vtm = initial_vtm;
|
||||
vtm.mode = VT_PROCESS;
|
||||
vtm.relsig = SIGUSR1;
|
||||
vtm.acqsig = SIGUSR2;
|
||||
ioctl(kbfd, VT_SETMODE, &vtm);
|
||||
}
|
||||
|
||||
|
||||
void kb_close()
|
||||
{
|
||||
ioctl(kbfd, VT_SETMODE, &initial_vtm);
|
||||
ioctl(kbfd, KDSKBMODE, initial_kbmode);
|
||||
tcsetattr(kbfd, TCSAFLUSH, &initial_term);
|
||||
ioctl(kbfd, KDSETMODE, KD_TEXT);
|
||||
}
|
||||
|
||||
|
||||
static void vcswitch(int c)
|
||||
{
|
||||
struct vt_stat vts;
|
||||
ioctl(kbfd, VT_GETSTATE, &vts);
|
||||
if (c != vts.v_active)
|
||||
{
|
||||
ioctl(kbfd, VT_ACTIVATE, c);
|
||||
fb.enabled = 0;
|
||||
fb.dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void kb_poll()
|
||||
{
|
||||
int i;
|
||||
event_t ev;
|
||||
byte k;
|
||||
int st;
|
||||
|
||||
while (read(kbfd, &k, 1) > 0)
|
||||
{
|
||||
st = !(k & 0x80);
|
||||
k &= 0x7f;
|
||||
|
||||
if (k == SCAN_ALT) alt = st;
|
||||
if (alt && k > SCAN_FBASE && k < SCAN_FBASE + 10)
|
||||
vcswitch(k - SCAN_FBASE);
|
||||
ev.type = st ? EV_PRESS : EV_RELEASE;
|
||||
for (i = 0; keymap[i][0]; i++)
|
||||
if (keymap[i][0] == k)
|
||||
break;
|
||||
if (!keymap[i][0]) continue;
|
||||
ev.code = keymap[i][1];
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
/* taken from fbtv */
|
||||
|
||||
#define BES_BASE 0x3d00
|
||||
#define BESA1ORG (BES_BASE+0x00)
|
||||
#define BESA2ORG (BES_BASE+0x04)
|
||||
#define BESB1ORG (BES_BASE+0x08)
|
||||
#define BESB2ORG (BES_BASE+0x0c)
|
||||
#define BESA1CORG (BES_BASE+0x10)
|
||||
#define BESA2CORG (BES_BASE+0x14)
|
||||
#define BESB1CORG (BES_BASE+0x18)
|
||||
#define BESB2CORG (BES_BASE+0x1c)
|
||||
#define BESCTL (BES_BASE+0x20)
|
||||
#define BESPITCH (BES_BASE+0x24)
|
||||
#define BESHCOORD (BES_BASE+0x28)
|
||||
#define BESVCOORD (BES_BASE+0x2c)
|
||||
#define BESHISCAL (BES_BASE+0x30)
|
||||
#define BESVISCAL (BES_BASE+0x34)
|
||||
#define BESHSRCST (BES_BASE+0x38)
|
||||
#define BESHSRCEND (BES_BASE+0x3c)
|
||||
|
||||
#define BESV1WGHT (BES_BASE+0x48)
|
||||
#define BESV2WGHT (BES_BASE+0x4c)
|
||||
#define BESHSRCLST (BES_BASE+0x50)
|
||||
#define BESV1SRCLST (BES_BASE+0x54)
|
||||
#define BESV2SRCLST (BES_BASE+0x58)
|
||||
#define BESGLOBCTL (BES_BASE+0xc0)
|
||||
#define BESSTATUS (BES_BASE+0xc4)
|
||||
|
||||
#define PALWTADD 0x3c00
|
||||
#define X_DATAREG 0x3c0a
|
||||
#define XKEYOPMODE 0x51
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
|
||||
#undef WORDS_BIGENDIAN
|
||||
#undef SIZEOF_SHORT
|
||||
#undef SIZEOF_INT
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
#undef HAVE_USLEEP
|
||||
#undef HAVE_SELECT
|
||||
|
||||
#undef HAVE_MMAP
|
||||
|
||||
#undef HAVE_LIBXEXT
|
||||
#undef HAVE_X11_EXTENSIONS_XSHM_H
|
||||
#undef HAVE_SYS_IPC_H
|
||||
#undef HAVE_SYS_SHM_H
|
||||
|
||||
#undef HAVE_SYS_SOUNDCARD_H
|
||||
#undef HAVE_SOUNDCARD_H
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
|
||||
/*
|
||||
* this code is not yet used. eventually we want to support using mmap
|
||||
* to map rom and sram into memory, so we don't waste virtual memory.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
#define DOTDIR ".gnuboy"
|
||||
|
||||
static char *home, *saves;
|
||||
static char *romfile, *sramfile, *saveprefix;
|
||||
|
||||
static int mmapped_rom, mmaped_sram;
|
||||
|
||||
|
||||
byte *map_rom()
|
||||
{
|
||||
int fd, len;
|
||||
byte code;
|
||||
byte *mem;
|
||||
|
||||
fd = open(romfile, O_READ);
|
||||
lseek(fd, 0x0148, SEEK_SET);
|
||||
read(fd, &code, 1);
|
||||
len = loader_romsize(code);
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
|
||||
mem = mmap(0, len, PROT_READ,
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int map_checkdirs()
|
||||
{
|
||||
home = malloc(strlen(getenv("HOME")) + strlen(DOTDIR) + 2);
|
||||
sprintf(home, "%s/" DOTDIR, getenv(HOME));
|
||||
saves = malloc(strlen(home) + 6);
|
||||
sprintf(saves, "%s/saves", home);
|
||||
|
||||
if (access(saves, X_OK|W_OK))
|
||||
{
|
||||
if (access(home, X_OK|W_OK))
|
||||
{
|
||||
if (!access(home, F_OK))
|
||||
die("cannot access %s (%s)\n", home, strerror(errno));
|
||||
if (mkdir(home, 0777))
|
||||
die("cannot create %s (%s)\n", home, strerror(errno));
|
||||
}
|
||||
if (!access(saves, F_OK))
|
||||
die("cannot access %s (%s)\n", home, strerror(errno));
|
||||
if (mkdir(saves, 0777))
|
||||
die("cannot create %s (%s)\n", saves, strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* nix.c
|
||||
*
|
||||
* System interface for *nix systems.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define DOTDIR ".gnuboy"
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
static void my_usleep(unsigned int us)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = us;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
#endif
|
||||
|
||||
void *sys_timer()
|
||||
{
|
||||
struct timeval *tv;
|
||||
|
||||
tv = malloc(sizeof(struct timeval));
|
||||
gettimeofday(tv, NULL);
|
||||
return tv;
|
||||
}
|
||||
|
||||
int sys_elapsed(struct timeval *prev)
|
||||
{
|
||||
struct timeval tv;
|
||||
int secs, usecs;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
secs = tv.tv_sec - prev->tv_sec;
|
||||
usecs = tv.tv_usec - prev->tv_usec;
|
||||
*prev = tv;
|
||||
if (!secs) return usecs;
|
||||
return 1000000 + usecs;
|
||||
}
|
||||
|
||||
void sys_sleep(int us)
|
||||
{
|
||||
if (us <= 0) return;
|
||||
#ifdef HAVE_USLEEP
|
||||
usleep(us);
|
||||
#else
|
||||
my_usleep(us);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sys_checkdir(char *path, int wr)
|
||||
{
|
||||
char *p;
|
||||
if (access(path, X_OK | (wr ? W_OK : 0)))
|
||||
{
|
||||
if (!access(path, F_OK))
|
||||
die("cannot access %s: %s\n", path, strerror(errno));
|
||||
p = strrchr(path, '/');
|
||||
if (!p) die("descended to root trying to create dirs\n");
|
||||
*p = 0;
|
||||
sys_checkdir(path, wr);
|
||||
*p = '/';
|
||||
if (mkdir(path, 0777))
|
||||
die("cannot create %s: %s\n", path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void sys_initpath()
|
||||
{
|
||||
char *buf, *home = getenv("HOME");
|
||||
if (!home)
|
||||
{
|
||||
buf = ".";
|
||||
rc_setvar("rcpath", 1, &buf);
|
||||
rc_setvar("savedir", 1, &buf);
|
||||
return;
|
||||
}
|
||||
buf = malloc(strlen(home) + strlen(DOTDIR) + 8);
|
||||
sprintf(buf, "%s/" DOTDIR ":.", home);
|
||||
rc_setvar("rcpath", 1, &buf);
|
||||
sprintf(buf, "%s/" DOTDIR "/saves" , home);
|
||||
rc_setvar("savedir", 1, &buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void sys_sanitize(char *s)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
char *strdup();
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef IS_FBSD
|
||||
#include "machine/soundcard.h"
|
||||
#define DSP_DEVICE "/dev/dsp"
|
||||
#endif
|
||||
|
||||
#ifdef IS_OBSD
|
||||
#include "soundcard.h"
|
||||
#define DSP_DEVICE "/dev/sound"
|
||||
#endif
|
||||
|
||||
#ifdef IS_LINUX
|
||||
#include <sys/soundcard.h>
|
||||
#define DSP_DEVICE "/dev/dsp"
|
||||
#endif
|
||||
|
||||
#include "defs.h"
|
||||
#include "pcm.h"
|
||||
#include "rc.h"
|
||||
|
||||
/* FIXME - all this code is VERY basic, improve it! */
|
||||
|
||||
|
||||
struct pcm pcm;
|
||||
|
||||
static int dsp;
|
||||
static char *dsp_device;
|
||||
static int stereo = 1;
|
||||
static int samplerate = 44100;
|
||||
static int sound = 1;
|
||||
|
||||
rcvar_t pcm_exports[] =
|
||||
{
|
||||
RCV_BOOL("sound", &sound),
|
||||
RCV_INT("stereo", &stereo),
|
||||
RCV_INT("samplerate", &samplerate),
|
||||
RCV_STRING("oss_device", &dsp_device),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
void pcm_init()
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!sound)
|
||||
{
|
||||
pcm.hz = 11025;
|
||||
pcm.len = 4096;
|
||||
pcm.buf = malloc(pcm.len);
|
||||
pcm.pos = 0;
|
||||
dsp = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dsp_device) dsp_device = strdup(DSP_DEVICE);
|
||||
dsp = open(dsp_device, O_WRONLY);
|
||||
|
||||
n = 0x80009;
|
||||
ioctl(dsp, SNDCTL_DSP_SETFRAGMENT, &n);
|
||||
n = AFMT_U8;
|
||||
ioctl(dsp, SNDCTL_DSP_SETFMT, &n);
|
||||
n = stereo;
|
||||
ioctl(dsp, SNDCTL_DSP_STEREO, &n);
|
||||
pcm.stereo = n;
|
||||
n = samplerate;
|
||||
ioctl(dsp, SNDCTL_DSP_SPEED, &n);
|
||||
pcm.hz = n;
|
||||
pcm.len = n / 60;
|
||||
pcm.buf = malloc(pcm.len);
|
||||
}
|
||||
|
||||
void pcm_close()
|
||||
{
|
||||
if (pcm.buf) free(pcm.buf);
|
||||
memset(&pcm, 0, sizeof pcm);
|
||||
close(dsp);
|
||||
}
|
||||
|
||||
int pcm_submit()
|
||||
{
|
||||
if (dsp < 0)
|
||||
{
|
||||
pcm.pos = 0;
|
||||
return 0;
|
||||
}
|
||||
if (pcm.buf) write(dsp, pcm.buf, pcm.pos);
|
||||
pcm.pos = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* pckeymap.c
|
||||
*
|
||||
* Mappings from IBM-PC scancodes to local key codes.
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
|
||||
int keymap[][2] =
|
||||
{
|
||||
{ 1, K_ESC },
|
||||
{ 2, '1' },
|
||||
{ 3, '2' },
|
||||
{ 4, '3' },
|
||||
{ 5, '4' },
|
||||
{ 6, '5' },
|
||||
{ 7, '6' },
|
||||
{ 8, '7' },
|
||||
{ 9, '8' },
|
||||
{ 10, '9' },
|
||||
{ 11, '0' },
|
||||
{ 12, K_MINUS },
|
||||
{ 13, K_EQUALS },
|
||||
{ 14, K_BS },
|
||||
{ 15, K_TAB },
|
||||
|
||||
{ 16, 'q' },
|
||||
{ 17, 'w' },
|
||||
{ 18, 'e' },
|
||||
{ 19, 'r' },
|
||||
{ 20, 't' },
|
||||
{ 21, 'y' },
|
||||
{ 22, 'u' },
|
||||
{ 23, 'i' },
|
||||
{ 24, 'o' },
|
||||
{ 25, 'p' },
|
||||
|
||||
{ 26, '[' },
|
||||
{ 27, ']' },
|
||||
|
||||
{ 28, K_ENTER },
|
||||
{ 29, K_CTRL },
|
||||
|
||||
{ 30, 'a' },
|
||||
{ 31, 's' },
|
||||
{ 32, 'd' },
|
||||
{ 33, 'f' },
|
||||
{ 34, 'g' },
|
||||
{ 35, 'h' },
|
||||
{ 36, 'j' },
|
||||
{ 37, 'k' },
|
||||
{ 38, 'l' },
|
||||
|
||||
{ 39, K_SEMI },
|
||||
{ 40, '\'' },
|
||||
{ 41, K_TILDE },
|
||||
{ 42, K_SHIFT },
|
||||
{ 43, K_BSLASH },
|
||||
|
||||
{ 44, 'z' },
|
||||
{ 45, 'x' },
|
||||
{ 46, 'c' },
|
||||
{ 47, 'v' },
|
||||
{ 48, 'b' },
|
||||
{ 49, 'n' },
|
||||
{ 50, 'm' },
|
||||
|
||||
{ 51, ',' },
|
||||
{ 52, '.' },
|
||||
{ 53, '/' },
|
||||
|
||||
{ 54, K_SHIFT },
|
||||
|
||||
{ 55, K_NUMMUL },
|
||||
|
||||
{ 56, K_ALT },
|
||||
{ 57, ' ' },
|
||||
{ 58, K_CAPS },
|
||||
|
||||
{ 59, K_F1 },
|
||||
{ 60, K_F2 },
|
||||
{ 61, K_F3 },
|
||||
{ 62, K_F4 },
|
||||
{ 63, K_F5 },
|
||||
{ 64, K_F6 },
|
||||
{ 65, K_F7 },
|
||||
{ 66, K_F8 },
|
||||
{ 67, K_F9 },
|
||||
{ 68, K_F10 },
|
||||
|
||||
{ 69, K_NUMLOCK },
|
||||
{ 70, K_SCROLL },
|
||||
|
||||
{ 71, K_NUM7 },
|
||||
{ 72, K_NUM8 },
|
||||
{ 73, K_NUM9 },
|
||||
{ 74, K_NUMMINUS },
|
||||
{ 75, K_NUM4 },
|
||||
{ 76, K_NUM5 },
|
||||
{ 77, K_NUM6 },
|
||||
{ 78, K_NUMPLUS },
|
||||
{ 79, K_NUM1 },
|
||||
{ 80, K_NUM2 },
|
||||
{ 81, K_NUM3 },
|
||||
{ 82, K_NUM0 },
|
||||
{ 83, K_NUMDOT },
|
||||
|
||||
{ 87, K_F11 },
|
||||
{ 88, K_F12 },
|
||||
|
||||
{ 96, K_NUMENTER },
|
||||
{ 97, K_CTRL },
|
||||
{ 98, K_NUMDIV },
|
||||
{ 99, K_SYSRQ },
|
||||
|
||||
{ 100, K_ALT },
|
||||
{ 101, K_PAUSE },
|
||||
{ 119, K_PAUSE },
|
||||
|
||||
{ 102, K_HOME },
|
||||
{ 103, K_UP },
|
||||
{ 104, K_PRIOR },
|
||||
{ 105, K_LEFT },
|
||||
{ 106, K_RIGHT },
|
||||
{ 107, K_END },
|
||||
{ 108, K_DOWN },
|
||||
{ 109, K_NEXT },
|
||||
{ 110, K_INS },
|
||||
{ 111, K_DEL },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* sdl_keymap.c
|
||||
*
|
||||
* Mappings from SDL keycode to local key codes.
|
||||
* Stolen from xkeymap.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SDL/SDL_keysym.h>
|
||||
#include "input.h"
|
||||
|
||||
int keymap[][2] = {
|
||||
{ SDLK_LSHIFT, K_SHIFT },
|
||||
{ SDLK_RSHIFT, K_SHIFT },
|
||||
{ SDLK_LCTRL, K_CTRL },
|
||||
{ SDLK_RCTRL, K_CTRL },
|
||||
{ SDLK_LALT, K_ALT },
|
||||
{ SDLK_RALT, K_ALT },
|
||||
{ SDLK_LMETA, K_ALT },
|
||||
{ SDLK_RMETA, K_ALT },
|
||||
|
||||
{ SDLK_UP, K_UP },
|
||||
{ SDLK_DOWN, K_DOWN },
|
||||
{ SDLK_RIGHT, K_RIGHT },
|
||||
{ SDLK_LEFT, K_LEFT },
|
||||
{ SDLK_RETURN, K_ENTER },
|
||||
{ SDLK_SPACE, K_SPACE },
|
||||
{ SDLK_TAB, K_TAB },
|
||||
{ SDLK_BACKSPACE, K_BS },
|
||||
{ SDLK_DELETE, K_DEL },
|
||||
{ SDLK_INSERT, K_INS },
|
||||
{ SDLK_HOME, K_HOME },
|
||||
{ SDLK_END, K_END },
|
||||
{ SDLK_ESCAPE, K_ESC },
|
||||
{ SDLK_PAUSE, K_PAUSE },
|
||||
{ SDLK_BREAK, K_PAUSE },
|
||||
{ SDLK_CAPSLOCK, K_CAPS },
|
||||
{ SDLK_NUMLOCK, K_NUMLOCK },
|
||||
{ SDLK_SCROLLOCK, K_SCROLL },
|
||||
|
||||
{ SDLK_MINUS, K_MINUS },
|
||||
{ SDLK_EQUALS, K_EQUALS },
|
||||
|
||||
{ SDLK_LEFTBRACKET, '[' },
|
||||
{ SDLK_RIGHTBRACKET, ']' },
|
||||
{ SDLK_BACKSLASH, K_BSLASH },
|
||||
{ SDLK_BACKQUOTE, K_TILDE },
|
||||
{ SDLK_SEMICOLON, K_SEMI },
|
||||
{ SDLK_QUOTE, K_QUOTE },
|
||||
{ SDLK_QUOTEDBL, K_QUOTE },
|
||||
{ SDLK_COMMA, ',' },
|
||||
{ SDLK_PERIOD, '.' },
|
||||
{ SDLK_SLASH, '/' },
|
||||
|
||||
{ SDLK_F1, K_F1 },
|
||||
{ SDLK_F2, K_F2 },
|
||||
{ SDLK_F3, K_F3 },
|
||||
{ SDLK_F4, K_F4 },
|
||||
{ SDLK_F5, K_F5 },
|
||||
{ SDLK_F6, K_F6 },
|
||||
{ SDLK_F7, K_F7 },
|
||||
{ SDLK_F8, K_F8 },
|
||||
{ SDLK_F9, K_F9 },
|
||||
{ SDLK_F10, K_F10 },
|
||||
{ SDLK_F11, K_F11 },
|
||||
{ SDLK_F12, K_F12 },
|
||||
|
||||
{ SDLK_KP0, K_NUM0 },
|
||||
{ SDLK_KP1, K_NUM1 },
|
||||
{ SDLK_KP2, K_NUM2 },
|
||||
{ SDLK_KP3, K_NUM3 },
|
||||
{ SDLK_KP4, K_NUM4 },
|
||||
{ SDLK_KP5, K_NUM5 },
|
||||
{ SDLK_KP6, K_NUM6 },
|
||||
{ SDLK_KP7, K_NUM7 },
|
||||
{ SDLK_KP8, K_NUM8 },
|
||||
{ SDLK_KP9, K_NUM9 },
|
||||
{ SDLK_KP_PLUS, K_NUMPLUS },
|
||||
{ SDLK_KP_MINUS, K_NUMMINUS },
|
||||
{ SDLK_KP_MULTIPLY, K_NUMMUL },
|
||||
{ SDLK_KP_DIVIDE, K_NUMDIV },
|
||||
{ SDLK_KP_PERIOD, K_NUMDOT },
|
||||
{ SDLK_KP_ENTER, K_NUMENTER },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* sdl.c
|
||||
* sdl interfaces -- based on svga.c
|
||||
*
|
||||
* (C) 2001 Damian Gryski <dgryski@uwaterloo.ca>
|
||||
* Joystick code contributed by David Lau
|
||||
* Sound code added by Laguna
|
||||
*
|
||||
* Licensed under the GPLv2, or later.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
|
||||
#include "fb.h"
|
||||
#include "input.h"
|
||||
#include "rc.h"
|
||||
|
||||
struct fb fb;
|
||||
|
||||
static int use_yuv = -1;
|
||||
static int fullscreen = 1;
|
||||
static int use_altenter = 1;
|
||||
static int use_joy = 1, sdl_joy_num;
|
||||
static SDL_Joystick * sdl_joy = NULL;
|
||||
static const int joy_commit_range = 3276;
|
||||
static char Xstatus, Ystatus;
|
||||
|
||||
static SDL_Surface *screen;
|
||||
static SDL_Overlay *overlay;
|
||||
static SDL_Rect overlay_rect;
|
||||
|
||||
static int vmode[3] = { 0, 0, 16 };
|
||||
|
||||
rcvar_t vid_exports[] =
|
||||
{
|
||||
RCV_VECTOR("vmode", &vmode, 3),
|
||||
RCV_BOOL("yuv", &use_yuv),
|
||||
RCV_BOOL("fullscreen", &fullscreen),
|
||||
RCV_BOOL("altenter", &use_altenter),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
rcvar_t joy_exports[] =
|
||||
{
|
||||
RCV_BOOL("joy", &use_joy),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
/* keymap - mappings of the form { scancode, localcode } - from sdl/keymap.c */
|
||||
extern int keymap[][2];
|
||||
|
||||
static int mapscancode(SDLKey sym)
|
||||
{
|
||||
/* this could be faster: */
|
||||
/* build keymap as int keymap[256], then ``return keymap[sym]'' */
|
||||
|
||||
int i;
|
||||
for (i = 0; keymap[i][0]; i++)
|
||||
if (keymap[i][0] == sym)
|
||||
return keymap[i][1];
|
||||
if (sym >= '0' && sym <= '9')
|
||||
return sym;
|
||||
if (sym >= 'a' && sym <= 'z')
|
||||
return sym;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void joy_init()
|
||||
{
|
||||
int i;
|
||||
int joy_count;
|
||||
|
||||
/* Initilize the Joystick, and disable all later joystick code if an error occured */
|
||||
if (!use_joy) return;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
|
||||
return;
|
||||
|
||||
joy_count = SDL_NumJoysticks();
|
||||
|
||||
if (!joy_count)
|
||||
return;
|
||||
|
||||
/* now try and open one. If, for some reason it fails, move on to the next one */
|
||||
for (i = 0; i < joy_count; i++)
|
||||
{
|
||||
sdl_joy = SDL_JoystickOpen(i);
|
||||
if (sdl_joy)
|
||||
{
|
||||
sdl_joy_num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure that Joystick event polling is a go */
|
||||
SDL_JoystickEventState(SDL_ENABLE);
|
||||
}
|
||||
|
||||
static void overlay_init()
|
||||
{
|
||||
if (!use_yuv) return;
|
||||
|
||||
if (use_yuv < 0)
|
||||
if (vmode[0] < 320 || vmode[1] < 288)
|
||||
return;
|
||||
|
||||
overlay = SDL_CreateYUVOverlay(320, 144, SDL_YUY2_OVERLAY, screen);
|
||||
|
||||
if (!overlay) return;
|
||||
|
||||
if (!overlay->hw_overlay || overlay->planes > 1)
|
||||
{
|
||||
SDL_FreeYUVOverlay(overlay);
|
||||
overlay = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockYUVOverlay(overlay);
|
||||
|
||||
fb.w = 160;
|
||||
fb.h = 144;
|
||||
fb.pelsize = 4;
|
||||
fb.pitch = overlay->pitches[0];
|
||||
fb.ptr = overlay->pixels[0];
|
||||
fb.yuv = 1;
|
||||
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = fb.cc[3].r = 0;
|
||||
fb.dirty = 1;
|
||||
fb.enabled = 1;
|
||||
|
||||
overlay_rect.x = 0;
|
||||
overlay_rect.y = 0;
|
||||
overlay_rect.w = vmode[0];
|
||||
overlay_rect.h = vmode[1];
|
||||
|
||||
/* Color channels are 0=Y, 1=U, 2=V, 3=Y1 */
|
||||
switch (overlay->format)
|
||||
{
|
||||
/* FIXME - support more formats */
|
||||
case SDL_YUY2_OVERLAY:
|
||||
default:
|
||||
fb.cc[0].l = 0;
|
||||
fb.cc[1].l = 24;
|
||||
fb.cc[2].l = 8;
|
||||
fb.cc[3].l = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_UnlockYUVOverlay(overlay);
|
||||
}
|
||||
|
||||
void vid_init()
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (!vmode[0] || !vmode[1])
|
||||
{
|
||||
int scale = rc_getint("scale");
|
||||
if (scale < 1) scale = 1;
|
||||
vmode[0] = 160 * scale;
|
||||
vmode[1] = 144 * scale;
|
||||
}
|
||||
|
||||
flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE;
|
||||
|
||||
if (fullscreen)
|
||||
flags |= SDL_FULLSCREEN;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO))
|
||||
die("SDL: Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
|
||||
if (!(screen = SDL_SetVideoMode(vmode[0], vmode[1], vmode[2], flags)))
|
||||
die("SDL: can't set video mode: %s\n", SDL_GetError());
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
|
||||
joy_init();
|
||||
|
||||
overlay_init();
|
||||
|
||||
if (fb.yuv) return;
|
||||
|
||||
SDL_LockSurface(screen);
|
||||
|
||||
fb.w = screen->w;
|
||||
fb.h = screen->h;
|
||||
fb.pelsize = screen->format->BytesPerPixel;
|
||||
fb.pitch = screen->pitch;
|
||||
fb.indexed = fb.pelsize == 1;
|
||||
fb.ptr = screen->pixels;
|
||||
fb.cc[0].r = screen->format->Rloss;
|
||||
fb.cc[0].l = screen->format->Rshift;
|
||||
fb.cc[1].r = screen->format->Gloss;
|
||||
fb.cc[1].l = screen->format->Gshift;
|
||||
fb.cc[2].r = screen->format->Bloss;
|
||||
fb.cc[2].l = screen->format->Bshift;
|
||||
|
||||
SDL_UnlockSurface(screen);
|
||||
|
||||
fb.enabled = 1;
|
||||
fb.dirty = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ev_poll()
|
||||
{
|
||||
event_t ev;
|
||||
SDL_Event event;
|
||||
int axisval;
|
||||
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_ACTIVEEVENT:
|
||||
if (event.active.state == SDL_APPACTIVE)
|
||||
fb.enabled = event.active.gain;
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if ((event.key.keysym.sym == SDLK_RETURN) && (event.key.keysym.mod & KMOD_ALT))
|
||||
SDL_WM_ToggleFullScreen(screen);
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = mapscancode(event.key.keysym.sym);
|
||||
ev_postevent(&ev);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = mapscancode(event.key.keysym.sym);
|
||||
ev_postevent(&ev);
|
||||
break;
|
||||
case SDL_JOYAXISMOTION:
|
||||
switch (event.jaxis.axis)
|
||||
{
|
||||
case 0: /* X axis */
|
||||
axisval = event.jaxis.value;
|
||||
if (axisval > joy_commit_range)
|
||||
{
|
||||
if (Xstatus==2) break;
|
||||
|
||||
if (Xstatus==0)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYLEFT;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = K_JOYRIGHT;
|
||||
ev_postevent(&ev);
|
||||
Xstatus=2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (axisval < -(joy_commit_range))
|
||||
{
|
||||
if (Xstatus==0) break;
|
||||
|
||||
if (Xstatus==2)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYRIGHT;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = K_JOYLEFT;
|
||||
ev_postevent(&ev);
|
||||
Xstatus=0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if control reaches here, the axis is centered,
|
||||
* so just send a release signal if necisary */
|
||||
|
||||
if (Xstatus==2)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYRIGHT;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
if (Xstatus==0)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYLEFT;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
Xstatus=1;
|
||||
break;
|
||||
|
||||
case 1: /* Y axis*/
|
||||
axisval = event.jaxis.value;
|
||||
if (axisval > joy_commit_range)
|
||||
{
|
||||
if (Ystatus==2) break;
|
||||
|
||||
if (Ystatus==0)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYUP;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = K_JOYDOWN;
|
||||
ev_postevent(&ev);
|
||||
Ystatus=2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (axisval < -joy_commit_range)
|
||||
{
|
||||
if (Ystatus==0) break;
|
||||
|
||||
if (Ystatus==2)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYDOWN;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = K_JOYUP;
|
||||
ev_postevent(&ev);
|
||||
Ystatus=0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if control reaches here, the axis is centered,
|
||||
* so just send a release signal if necisary */
|
||||
|
||||
if (Ystatus==2)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYDOWN;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
if (Ystatus==0)
|
||||
{
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOYUP;
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
Ystatus=1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_JOYBUTTONUP:
|
||||
if (event.jbutton.button>15) break;
|
||||
ev.type = EV_RELEASE;
|
||||
ev.code = K_JOY0 + event.jbutton.button;
|
||||
ev_postevent(&ev);
|
||||
break;
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
if (event.jbutton.button>15) break;
|
||||
ev.type = EV_PRESS;
|
||||
ev.code = K_JOY0+event.jbutton.button;
|
||||
ev_postevent(&ev);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vid_setpal(int i, int r, int g, int b)
|
||||
{
|
||||
SDL_Color col;
|
||||
|
||||
col.r = r; col.g = g; col.b = b;
|
||||
|
||||
SDL_SetColors(screen, &col, i, 1);
|
||||
}
|
||||
|
||||
void vid_preinit()
|
||||
{
|
||||
}
|
||||
|
||||
void vid_close()
|
||||
{
|
||||
if (overlay)
|
||||
{
|
||||
SDL_UnlockYUVOverlay(overlay);
|
||||
SDL_FreeYUVOverlay(overlay);
|
||||
}
|
||||
else SDL_UnlockSurface(screen);
|
||||
SDL_Quit();
|
||||
fb.enabled = 0;
|
||||
}
|
||||
|
||||
void vid_settitle(char *title)
|
||||
{
|
||||
SDL_WM_SetCaption(title, title);
|
||||
}
|
||||
|
||||
void vid_begin()
|
||||
{
|
||||
if (overlay)
|
||||
{
|
||||
SDL_LockYUVOverlay(overlay);
|
||||
fb.ptr = overlay->pixels[0];
|
||||
return;
|
||||
}
|
||||
SDL_LockSurface(screen);
|
||||
fb.ptr = screen->pixels;
|
||||
}
|
||||
|
||||
void vid_end()
|
||||
{
|
||||
if (overlay)
|
||||
{
|
||||
SDL_UnlockYUVOverlay(overlay);
|
||||
if (fb.enabled)
|
||||
SDL_DisplayYUVOverlay(overlay, &overlay_rect);
|
||||
return;
|
||||
}
|
||||
SDL_UnlockSurface(screen);
|
||||
if (fb.enabled) SDL_Flip(screen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "pcm.h"
|
||||
|
||||
|
||||
struct pcm pcm;
|
||||
|
||||
|
||||
static int sound = 1;
|
||||
static int samplerate = 44100;
|
||||
static int stereo = 1;
|
||||
static volatile int audio_done;
|
||||
|
||||
rcvar_t pcm_exports[] =
|
||||
{
|
||||
RCV_BOOL("sound", &sound),
|
||||
RCV_INT("stereo", &stereo),
|
||||
RCV_INT("samplerate", &samplerate),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
static void audio_callback(void *blah, byte *stream, int len)
|
||||
{
|
||||
memcpy(stream, pcm.buf, len);
|
||||
audio_done = 1;
|
||||
}
|
||||
|
||||
|
||||
void pcm_init()
|
||||
{
|
||||
int i;
|
||||
SDL_AudioSpec as;
|
||||
|
||||
if (!sound) return;
|
||||
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
as.freq = samplerate;
|
||||
as.format = AUDIO_U8;
|
||||
as.channels = 1 + stereo;
|
||||
as.samples = samplerate / 60;
|
||||
for (i = 1; i < as.samples; i<<=1);
|
||||
as.samples = i;
|
||||
as.callback = audio_callback;
|
||||
as.userdata = 0;
|
||||
if (SDL_OpenAudio(&as, 0) == -1)
|
||||
return;
|
||||
|
||||
pcm.hz = as.freq;
|
||||
pcm.stereo = as.channels - 1;
|
||||
pcm.len = as.size;
|
||||
pcm.buf = malloc(pcm.len);
|
||||
pcm.pos = 0;
|
||||
memset(pcm.buf, 0, pcm.len);
|
||||
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
|
||||
int pcm_submit()
|
||||
{
|
||||
if (!pcm.buf) return 0;
|
||||
if (pcm.pos < pcm.len) return 1;
|
||||
while (!audio_done)
|
||||
SDL_Delay(4);
|
||||
audio_done = 0;
|
||||
pcm.pos = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void pcm_close()
|
||||
{
|
||||
if (sound) SDL_CloseAudio();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* svgalib.c
|
||||
*
|
||||
* svgalib interface.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vga.h>
|
||||
#include <vgakeyboard.h>
|
||||
|
||||
#include "fb.h"
|
||||
#include "input.h"
|
||||
#include "rc.h"
|
||||
|
||||
|
||||
|
||||
struct fb fb;
|
||||
|
||||
|
||||
|
||||
|
||||
static int vmode[3] = { 0, 0, 8 };
|
||||
static int svga_mode;
|
||||
static int svga_vsync = 1;
|
||||
|
||||
rcvar_t vid_exports[] =
|
||||
{
|
||||
RCV_VECTOR("vmode", vmode, 3),
|
||||
RCV_INT("vsync", &svga_vsync),
|
||||
RCV_INT("svga_mode", &svga_mode),
|
||||
RCV_END
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* keymap - mappings of the form { scancode, localcode } - from pc/keymap.c */
|
||||
extern int keymap[][2];
|
||||
|
||||
static int mapscancode(int scan)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; keymap[i][0]; i++)
|
||||
if (keymap[i][0] == scan)
|
||||
return keymap[i][1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbhandler(int scan, int state)
|
||||
{
|
||||
event_t ev;
|
||||
ev.type = state ? EV_PRESS : EV_RELEASE;
|
||||
ev.code = mapscancode(scan);
|
||||
ev_postevent(&ev);
|
||||
}
|
||||
|
||||
int *rc_getvec();
|
||||
|
||||
static int selectmode()
|
||||
{
|
||||
int i;
|
||||
int stop;
|
||||
vga_modeinfo *mi;
|
||||
int best = -1;
|
||||
int besterr = 1<<24;
|
||||
int err;
|
||||
int *vd;
|
||||
|
||||
vd = vmode;
|
||||
|
||||
stop = vga_lastmodenumber();
|
||||
for (i = 0; i <= stop; i++)
|
||||
{
|
||||
if (!vga_hasmode(i)) continue;
|
||||
mi = vga_getmodeinfo(i);
|
||||
|
||||
/* modex is too crappy to deal with */
|
||||
if (!mi->bytesperpixel) continue;
|
||||
|
||||
/* so are banked modes */
|
||||
if (mi->width * mi->height * mi->bytesperpixel > 65536)
|
||||
if (!(mi->flags & (IS_LINEAR))) continue;
|
||||
|
||||
/* we can't use modes that are too small */
|
||||
if (mi->colors < 256) continue;
|
||||
if (mi->width < vd[0]) continue;
|
||||
if (mi->height < vd[1]) continue;
|
||||
|
||||
/* perfect matches always win */
|
||||
if (mi->width == vd[0] && mi->height == vd[1]
|
||||
&& (mi->bytesperpixel<<3) == vd[2])
|
||||
{
|
||||
best = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/* compare error */
|
||||
err = mi->width * mi->height - vd[0] * vd[1]
|
||||
+ abs((mi->bytesperpixel<<3)-vd[2]);
|
||||
if (err < besterr)
|
||||
{
|
||||
best = i;
|
||||
besterr = err;
|
||||
}
|
||||
}
|
||||
if (best < 0)
|
||||
die("no suitable modes available\n");
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vid_preinit()
|
||||
{
|
||||
vga_init();
|
||||
}
|
||||
|
||||
void vid_init()
|
||||
{
|
||||
int m;
|
||||
vga_modeinfo *mi;
|
||||
|
||||
if (!vmode[0] || !vmode[1])
|
||||
{
|
||||
int scale = rc_getint("scale");
|
||||
if (scale < 1) scale = 1;
|
||||
vmode[0] = 160 * scale;
|
||||
vmode[1] = 144 * scale;
|
||||
}
|
||||
|
||||
m = svga_mode;
|
||||
if (!m) m = selectmode();
|
||||
|
||||
if (!vga_hasmode(m))
|
||||
die("no such video mode: %d\n", m);
|
||||
|
||||
vga_setmode(m);
|
||||
mi = vga_getmodeinfo(m);
|
||||
fb.w = mi->width;
|
||||
fb.h = mi->height;
|
||||
fb.pelsize = mi->bytesperpixel;
|
||||
fb.pitch = mi->linewidth;
|
||||
fb.ptr = vga_getgraphmem();
|
||||
fb.enabled = 1;
|
||||
fb.dirty = 0;
|
||||
|
||||
switch (mi->colors)
|
||||
{
|
||||
case 256:
|
||||
fb.indexed = 1;
|
||||
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 8;
|
||||
fb.cc[0].l = fb.cc[1].l = fb.cc[2].l = 0;
|
||||
break;
|
||||
case 32768:
|
||||
fb.indexed = 0;
|
||||
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 3;
|
||||
fb.cc[0].l = 10;
|
||||
fb.cc[1].l = 5;
|
||||
fb.cc[2].l = 0;
|
||||
break;
|
||||
case 65536:
|
||||
fb.indexed = 0;
|
||||
fb.cc[0].r = fb.cc[2].r = 3;
|
||||
fb.cc[1].r = 2;
|
||||
fb.cc[0].l = 11;
|
||||
fb.cc[1].l = 5;
|
||||
fb.cc[2].l = 0;
|
||||
break;
|
||||
case 16384*1024:
|
||||
fb.indexed = 0;
|
||||
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = 0;
|
||||
fb.cc[0].l = 16;
|
||||
fb.cc[1].l = 8;
|
||||
fb.cc[2].l = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
keyboard_init();
|
||||
keyboard_seteventhandler(kbhandler);
|
||||
|
||||
joy_init();
|
||||
}
|
||||
|
||||
|
||||
void vid_close()
|
||||
{
|
||||
if (!fb.ptr) return;
|
||||
memset(&fb, 0, sizeof fb);
|
||||
joy_close();
|
||||
keyboard_close();
|
||||
vga_setmode(TEXT);
|
||||
}
|
||||
|
||||
void vid_settitle(char *title)
|
||||
{
|
||||
}
|
||||
|
||||
void vid_setpal(int i, int r, int g, int b)
|
||||
{
|
||||
vga_setpalette(i, r>>2, g>>2, b>>2);
|
||||
}
|
||||
|
||||
void vid_begin()
|
||||
{
|
||||
if (svga_vsync) vga_waitretrace();
|
||||
}
|
||||
|
||||
void vid_end()
|
||||
{
|
||||
}
|
||||
|
||||
void kb_init()
|
||||
{
|
||||
}
|
||||
|
||||
void kb_close()
|
||||
{
|
||||
}
|
||||
|
||||
void kb_poll()
|
||||
{
|
||||
keyboard_update();
|
||||
}
|
||||
|
||||
void ev_poll()
|
||||
{
|
||||
kb_poll();
|
||||
joy_poll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* pckeymap.c
|
||||
*
|
||||
* Mappings from IBM-PC scancodes to local key codes.
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "thinlib.h"
|
||||
|
||||
int keymap[][2] =
|
||||
{
|
||||
{ THIN_KEY_ESC, K_ESC },
|
||||
{ THIN_KEY_1, '1' },
|
||||
{ THIN_KEY_2, '2' },
|
||||
{ THIN_KEY_3, '3' },
|
||||
{ THIN_KEY_4, '4' },
|
||||
{ THIN_KEY_5, '5' },
|
||||
{ THIN_KEY_6, '6' },
|
||||
{ THIN_KEY_7, '7' },
|
||||
{ THIN_KEY_8, '8' },
|
||||
{ THIN_KEY_9, '9' },
|
||||
{ THIN_KEY_0, '0' },
|
||||
{ THIN_KEY_MINUS, K_MINUS },
|
||||
{ THIN_KEY_EQUALS, K_EQUALS },
|
||||
{ THIN_KEY_BACKSPACE, K_BS },
|
||||
{ THIN_KEY_TAB, K_TAB },
|
||||
|
||||
{ THIN_KEY_Q, 'q' },
|
||||
{ THIN_KEY_W, 'w' },
|
||||
{ THIN_KEY_E, 'e' },
|
||||
{ THIN_KEY_R, 'r' },
|
||||
{ THIN_KEY_T, 't' },
|
||||
{ THIN_KEY_Y, 'y' },
|
||||
{ THIN_KEY_U, 'u' },
|
||||
{ THIN_KEY_I, 'i' },
|
||||
{ THIN_KEY_O, 'o' },
|
||||
{ THIN_KEY_P, 'p' },
|
||||
|
||||
{ THIN_KEY_OPEN_BRACE, '[' },
|
||||
{ THIN_KEY_CLOSE_BRACE, ']' },
|
||||
|
||||
{ THIN_KEY_ENTER, K_ENTER },
|
||||
{ THIN_KEY_LEFT_CTRL, K_CTRL },
|
||||
|
||||
{ THIN_KEY_A, 'a' },
|
||||
{ THIN_KEY_S, 's' },
|
||||
{ THIN_KEY_D, 'd' },
|
||||
{ THIN_KEY_F, 'f' },
|
||||
{ THIN_KEY_G, 'g' },
|
||||
{ THIN_KEY_H, 'h' },
|
||||
{ THIN_KEY_J, 'j' },
|
||||
{ THIN_KEY_K, 'k' },
|
||||
{ THIN_KEY_L, 'l' },
|
||||
|
||||
{ THIN_KEY_SEMICOLON, K_SEMI },
|
||||
{ THIN_KEY_QUOTE, '\'' },
|
||||
{ THIN_KEY_TILDE, K_TILDE },
|
||||
{ THIN_KEY_LEFT_SHIFT, K_SHIFT },
|
||||
{ THIN_KEY_BACKSLASH, K_BSLASH },
|
||||
|
||||
{ THIN_KEY_Z, 'z' },
|
||||
{ THIN_KEY_X, 'x' },
|
||||
{ THIN_KEY_C, 'c' },
|
||||
{ THIN_KEY_V, 'v' },
|
||||
{ THIN_KEY_B, 'b' },
|
||||
{ THIN_KEY_N, 'n' },
|
||||
{ THIN_KEY_M, 'm' },
|
||||
|
||||
{ THIN_KEY_COMMA, ',' },
|
||||
{ THIN_KEY_PERIOD, '.' },
|
||||
{ THIN_KEY_SLASH, '/' },
|
||||
|
||||
{ THIN_KEY_RIGHT_SHIFT, K_SHIFT },
|
||||
|
||||
{ THIN_KEY_NUMPAD_MULT, K_NUMMUL },
|
||||
|
||||
{ THIN_KEY_LEFT_ALT, K_ALT },
|
||||
{ THIN_KEY_SPACE, ' ' },
|
||||
{ THIN_KEY_CAPS_LOCK, K_CAPS },
|
||||
|
||||
{ THIN_KEY_F1, K_F1 },
|
||||
{ THIN_KEY_F2, K_F2 },
|
||||
{ THIN_KEY_F3, K_F3 },
|
||||
{ THIN_KEY_F4, K_F4 },
|
||||
{ THIN_KEY_F5, K_F5 },
|
||||
{ THIN_KEY_F6, K_F6 },
|
||||
{ THIN_KEY_F7, K_F7 },
|
||||
{ THIN_KEY_F8, K_F8 },
|
||||
{ THIN_KEY_F9, K_F9 },
|
||||
{ THIN_KEY_F10, K_F10 },
|
||||
|
||||
{ THIN_KEY_NUM_LOCK, K_NUMLOCK },
|
||||
{ THIN_KEY_SCROLL_LOCK, K_SCROLL },
|
||||
|
||||
{ THIN_KEY_NUMPAD_7, K_NUM7 },
|
||||
{ THIN_KEY_NUMPAD_8, K_NUM8 },
|
||||
{ THIN_KEY_NUMPAD_9, K_NUM9 },
|
||||
{ THIN_KEY_NUMPAD_MINUS, K_NUMMINUS },
|
||||
{ THIN_KEY_NUMPAD_4, K_NUM4 },
|
||||
{ THIN_KEY_NUMPAD_5, K_NUM5 },
|
||||
{ THIN_KEY_NUMPAD_6, K_NUM6 },
|
||||
{ THIN_KEY_NUMPAD_PLUS, K_NUMPLUS },
|
||||
{ THIN_KEY_NUMPAD_1, K_NUM1 },
|
||||
{ THIN_KEY_NUMPAD_2, K_NUM2 },
|
||||
{ THIN_KEY_NUMPAD_3, K_NUM3 },
|
||||
{ THIN_KEY_NUMPAD_0, K_NUM0 },
|
||||
{ THIN_KEY_NUMPAD_DECIMAL, K_NUMDOT },
|
||||
|
||||
{ THIN_KEY_F11, K_F11 },
|
||||
{ THIN_KEY_F12, K_F12 },
|
||||
|
||||
{ THIN_KEY_NUMPAD_ENTER, K_NUMENTER },
|
||||
{ THIN_KEY_RIGHT_CTRL, K_CTRL },
|
||||
{ THIN_KEY_NUMPAD_DIV, K_NUMDIV },
|
||||
{ THIN_KEY_SYSRQ, K_SYSRQ },
|
||||
|
||||
{ THIN_KEY_RIGHT_ALT, K_ALT },
|
||||
//{ THIN_KEY_PAUSE, K_PAUSE },
|
||||
|
||||
{ THIN_KEY_HOME, K_HOME },
|
||||
{ THIN_KEY_UP, K_UP },
|
||||
{ THIN_KEY_PGUP, K_PRIOR },
|
||||
{ THIN_KEY_LEFT, K_LEFT },
|
||||
{ THIN_KEY_RIGHT, K_RIGHT },
|
||||
{ THIN_KEY_END, K_END },
|
||||
{ THIN_KEY_DOWN, K_DOWN },
|
||||
{ THIN_KEY_PGDN, K_NEXT },
|
||||
{ THIN_KEY_INSERT, K_INS },
|
||||
{ THIN_KEY_DELETE, K_DEL },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#
|
||||
# Makefile
|
||||
#
|
||||
# thinlib library makefile
|
||||
#
|
||||
# Copyright (C) 2001 Matthew Conte (matt@conte.com)
|
||||
#
|
||||
# $Id: $
|
||||
|
||||
################################
|
||||
# Configuration
|
||||
|
||||
CFLAGS = -W -Wall -Werror
|
||||
DBGCFLAGS = -ggdb -DTHINLIB_DEBUG
|
||||
OPTCFLAGS = -O3 -fomit-frame-pointer -ffast-math
|
||||
|
||||
# Assembler
|
||||
ASM = nasm
|
||||
ASMFLAGS = -f coff
|
||||
|
||||
DBGASMFLAGS = -g
|
||||
|
||||
################################
|
||||
|
||||
# WANT_DEBUG = TRUE
|
||||
|
||||
################################
|
||||
|
||||
ifeq "$(WANT_DEBUG)" "TRUE"
|
||||
CFLAGS += $(DBGCFLAGS)
|
||||
ASMFLAGS += $(DBGASMFLAGS)
|
||||
else
|
||||
CFLAGS += $(OPTCFLAGS)
|
||||
endif
|
||||
|
||||
################################
|
||||
|
||||
CFILES = tl_main tl_log tl_timer tl_int tl_key tl_mouse tl_joy \
|
||||
tl_dpp tl_bmp tl_vesa tl_vga tl_video tl_sb tl_sound \
|
||||
tl_event tl_prof
|
||||
|
||||
CSRCS = $(addsuffix .c, $(CFILES))
|
||||
OBJS = $(addsuffix .o, $(CFILES))
|
||||
|
||||
################################
|
||||
|
||||
.PHONY = all dep clean
|
||||
|
||||
all: libthin.a thintest.exe
|
||||
|
||||
clean:
|
||||
rm -f libthin.a thintest.exe $(OBJS) _dep
|
||||
|
||||
thintest.exe: thintest.cpp libthin.a
|
||||
$(CXX) -o $@ thintest.cpp -L. -lthin
|
||||
|
||||
libthin.a: $(OBJS)
|
||||
rm -f $@
|
||||
ar scru $@ $(OBJS)
|
||||
|
||||
dep: rmdep _dep
|
||||
|
||||
################################
|
||||
|
||||
rmdep:
|
||||
@rm -f _dep
|
||||
@echo "# dep file" > _dep
|
||||
ifneq "$(CSRCS)" ""
|
||||
@$(foreach .a, $(CSRCS), $(CC) $(CFLAGS) -MM $(.a) >> _dep;)
|
||||
endif
|
||||
ifneq "$(ASMSRCS)" ""
|
||||
@$(foreach .a, $(ASMSRCS), $(ASM) $(ASMFLAGS) -M $(.a) >> _dep;)
|
||||
endif
|
||||
|
||||
_dep:
|
||||
# this is done so that we don't get all the no such file warnings
|
||||
@echo "# dep file" > _dep
|
||||
ifneq "$(CSRCS)" ""
|
||||
@$(foreach .a, $(CSRCS), $(CC) $(CFLAGS) -MM $(.a) >> _dep;)
|
||||
endif
|
||||
ifneq "$(ASMSRCS)" ""
|
||||
@$(foreach .a, $(ASMSRCS), $(ASM) $(ASMFLAGS) -M $(.a) >> _dep;)
|
||||
endif
|
||||
|
||||
include _dep
|
||||
|
||||
################################
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
%.o: %.asm
|
||||
$(ASM) $(ASMFLAGS) -o $@ $<
|
||||
|
||||
################################
|
||||
|
||||
# $Log: $
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** thinlib.h
|
||||
**
|
||||
** main library header
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _THINLIB_H_
|
||||
#define _THINLIB_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* types */
|
||||
#include "tl_types.h"
|
||||
#include "tl_log.h"
|
||||
#include "tl_prof.h"
|
||||
|
||||
/* system */
|
||||
#include "tl_djgpp.h"
|
||||
#include "tl_int.h"
|
||||
#include "tl_timer.h"
|
||||
|
||||
/* input/events */
|
||||
#include "tl_event.h"
|
||||
#include "tl_key.h"
|
||||
#include "tl_mouse.h"
|
||||
#include "tl_joy.h"
|
||||
#include "tl_dpp.h"
|
||||
|
||||
/* video */
|
||||
#include "tl_bmp.h"
|
||||
#include "tl_video.h"
|
||||
|
||||
/* audio */
|
||||
#include "tl_sound.h"
|
||||
|
||||
#define THIN_KEY 0x0001
|
||||
#define THIN_MOUSE 0x0002
|
||||
#define THIN_JOY 0x0004
|
||||
#define THIN_DPP 0x0008
|
||||
#define THIN_TIMER 0x0010
|
||||
#define THIN_VIDEO 0x0020
|
||||
#define THIN_SOUND 0x0040
|
||||
|
||||
|
||||
/* main interface */
|
||||
extern int thin_init(int devices);
|
||||
extern void thin_shutdown(void);
|
||||
|
||||
extern void thin_add_exit(void (*func)(void));
|
||||
extern void thin_remove_exit(void (*func)(void));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* !_THINLIB_H */
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of version 2 of the GNU Library General
|
||||
** Public License 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
|
||||
** Library General Public License for more details. To obtain a
|
||||
** copy of the GNU Library General Public License, write to the Free
|
||||
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**
|
||||
** Any permitted reproduction of these routines, in whole or in part,
|
||||
** must bear this legend.
|
||||
**
|
||||
**
|
||||
** thintest.cpp
|
||||
**
|
||||
** thinlib test
|
||||
** $Id: thintest.cpp,v 1.3 2001/03/12 06:06:55 matt Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "thinlib.h"
|
||||
|
||||
//#define TEST_STEREO
|
||||
#define TEST_DPP
|
||||
|
||||
class test
|
||||
{
|
||||
public:
|
||||
test();
|
||||
~test();
|
||||
void run();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
SAMPLE_RATE = 44100,
|
||||
FRAGSIZE = 256,
|
||||
VID_WIDTH = 320,
|
||||
VID_HEIGHT = 240,
|
||||
VID_BPP = 8
|
||||
};
|
||||
|
||||
int testSound();
|
||||
int testVideo();
|
||||
int testTimer();
|
||||
int testEvents();
|
||||
};
|
||||
|
||||
test::test()
|
||||
{
|
||||
int ret = thin_init(THIN_KEY | THIN_MOUSE | THIN_TIMER
|
||||
| THIN_VIDEO | THIN_SOUND);
|
||||
THIN_ASSERT(-1 != ret);
|
||||
}
|
||||
|
||||
test::~test()
|
||||
{
|
||||
thin_shutdown();
|
||||
}
|
||||
|
||||
static void fillbuf(void *user_data, void *buf, int size)
|
||||
{
|
||||
static int pos = 0;
|
||||
UNUSED(user_data);
|
||||
|
||||
while (size--)
|
||||
{
|
||||
*((uint8 *) buf)++ = 127 + (int8)(127.0 * sin(2 * PI * pos / 128));
|
||||
#ifdef TEST_STEREO
|
||||
*((uint8 *) buf)++ = 127 + (int8)(127.0 * cos(2 * PI * pos / 128));
|
||||
#endif
|
||||
pos = (pos + 1) & 1023;
|
||||
}
|
||||
}
|
||||
|
||||
int test::testSound()
|
||||
{
|
||||
thinsound_t params;
|
||||
|
||||
params.sample_rate = SAMPLE_RATE;
|
||||
params.frag_size = FRAGSIZE;
|
||||
#ifdef TEST_STEREO
|
||||
params.format = THIN_SOUND_STEREO | THIN_SOUND_8BIT;
|
||||
#else
|
||||
params.format = THIN_SOUND_MONO | THIN_SOUND_8BIT;
|
||||
#endif
|
||||
params.callback = fillbuf;
|
||||
params.user_data = NULL;
|
||||
|
||||
if (thin_sound_init(¶ms))
|
||||
return -1;
|
||||
|
||||
thin_sound_start();
|
||||
thin_sound_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test::testVideo()
|
||||
{
|
||||
int i, x, y;
|
||||
bitmap_t *screen;
|
||||
bitmap_t *buffer;
|
||||
|
||||
/* set up video */
|
||||
if (thin_vid_init(VID_WIDTH, VID_HEIGHT, VID_BPP, 0/*THIN_VIDEO_HWSURFACE*/))
|
||||
return -1;
|
||||
|
||||
buffer = thin_bmp_create(VID_WIDTH, VID_HEIGHT, VID_BPP, 0);
|
||||
if (NULL == buffer)
|
||||
return -1;
|
||||
|
||||
/* fill it up with something interesting */
|
||||
for (y = 0; y < buffer->height; y++)
|
||||
for (x = 0; x < buffer->width; x++)
|
||||
buffer->line[y][x] = x ^ y;
|
||||
|
||||
/* blit it out 1000 times */
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
screen = thin_vid_lockwrite();
|
||||
if (NULL == screen)
|
||||
return -1;
|
||||
|
||||
for (y = 0; y < screen->height; y++)
|
||||
memcpy(screen->line[y], buffer->line[y], screen->width);
|
||||
|
||||
thin_vid_freewrite(-1, NULL);
|
||||
}
|
||||
|
||||
thin_vid_shutdown();
|
||||
|
||||
if (1000 != i)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static volatile int timer_ticks = 0;
|
||||
static void timer_handler(void *param)
|
||||
{
|
||||
(void) param;
|
||||
timer_ticks++;
|
||||
}
|
||||
THIN_LOCKED_STATIC_FUNC(timer_handler)
|
||||
|
||||
int test::testTimer()
|
||||
{
|
||||
int last_ticks;
|
||||
|
||||
THIN_LOCK_FUNC(timer_handler);
|
||||
THIN_LOCK_VAR(timer_ticks);
|
||||
|
||||
/* one second intervals... */
|
||||
if (thin_timer_init(60, timer_handler, NULL))
|
||||
return -1;
|
||||
|
||||
timer_ticks = last_ticks = 0;
|
||||
while (timer_ticks <= 60)
|
||||
{
|
||||
if (last_ticks != timer_ticks)
|
||||
{
|
||||
last_ticks = timer_ticks;
|
||||
thin_printf("%d 60 hz tick\n", last_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
thin_timer_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test::testEvents()
|
||||
{
|
||||
thin_event_t event;
|
||||
bool done = false;
|
||||
|
||||
thin_mouse_init(80, 20, 1);
|
||||
thin_joy_init();
|
||||
thin_dpp_init();
|
||||
thin_dpp_add(0x378, 0);
|
||||
|
||||
thin_printf("event test: press ESC...");
|
||||
|
||||
while (!done)
|
||||
{
|
||||
thin_event_gather();
|
||||
|
||||
while (thin_event_get(&event))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case THIN_KEY_PRESS:
|
||||
if (event.data.keysym == THIN_KEY_ESC)
|
||||
done = true;
|
||||
thin_printf("key press\n");
|
||||
break;
|
||||
|
||||
case THIN_KEY_RELEASE:
|
||||
thin_printf("key release\n");
|
||||
break;
|
||||
|
||||
case THIN_MOUSE_MOTION:
|
||||
thin_printf("mouse motion\n");
|
||||
break;
|
||||
|
||||
case THIN_MOUSE_BUTTON_PRESS:
|
||||
thin_printf("mouse button press\n");
|
||||
break;
|
||||
|
||||
case THIN_MOUSE_BUTTON_RELEASE:
|
||||
thin_printf("mouse button release\n");
|
||||
break;
|
||||
|
||||
case THIN_JOY_MOTION:
|
||||
thin_printf("joy motion\n");
|
||||
break;
|
||||
|
||||
case THIN_JOY_BUTTON_PRESS:
|
||||
thin_printf("joy button press\n");
|
||||
break;
|
||||
|
||||
case THIN_JOY_BUTTON_RELEASE:
|
||||
thin_printf("joy button release\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thin_dpp_shutdown();
|
||||
thin_joy_shutdown();
|
||||
thin_mouse_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test::run()
|
||||
{
|
||||
if (testSound())
|
||||
return;
|
||||
|
||||
if (testVideo())
|
||||
return;
|
||||
|
||||
if (testTimer())
|
||||
return;
|
||||
|
||||
if (testEvents())
|
||||
return;
|
||||
|
||||
thin_printf("\ntest complete.\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test *pTest = new test;
|
||||
|
||||
pTest->run();
|
||||
|
||||
delete pTest;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** $Log: thintest.cpp,v $
|
||||
** Revision 1.3 2001/03/12 06:06:55 matt
|
||||
** better keyboard driver, support for bit depths other than 8bpp
|
||||
**
|
||||
** Revision 1.2 2001/02/01 06:28:26 matt
|
||||
** thinlib now works under NT/2000
|
||||
**
|
||||
** Revision 1.1 2001/01/15 05:27:43 matt
|
||||
** initial revision
|
||||
**
|
||||
*/
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_bmp.c
|
||||
**
|
||||
** Bitmap object manipulation routines
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tl_types.h"
|
||||
#include "tl_bmp.h"
|
||||
|
||||
|
||||
#define BPP_PITCH(pitch, bpp) ((pitch) * (((bpp) + 7) / 8))
|
||||
|
||||
|
||||
/* TODO: you can make this faster. */
|
||||
void thin_bmp_clear(const bitmap_t *bitmap, uint8 color)
|
||||
{
|
||||
memset(bitmap->data, color, bitmap->pitch * bitmap->height);
|
||||
}
|
||||
|
||||
static bitmap_t *_make_bitmap(uint8 *data_addr, bool hw, int width,
|
||||
int height, int bpp, int pitch, int overdraw)
|
||||
{
|
||||
bitmap_t *bitmap;
|
||||
int i;
|
||||
|
||||
/* sometimes our data address is zero; for instance, setting
|
||||
** video selectors for VESA mode with far pointers. so we
|
||||
** don't want to bail out if we're passed a zero address.
|
||||
*/
|
||||
|
||||
/* Make sure to add in space for line pointers */
|
||||
bitmap = malloc(sizeof(bitmap_t) + (sizeof(uint8 *) * height));
|
||||
if (NULL == bitmap)
|
||||
return NULL;
|
||||
|
||||
bitmap->hardware = hw;
|
||||
bitmap->height = height;
|
||||
bitmap->width = width;
|
||||
bitmap->bpp = bpp;
|
||||
bitmap->data = data_addr;
|
||||
bitmap->pitch = BPP_PITCH(pitch, bpp);
|
||||
|
||||
/* Set up line pointers */
|
||||
bitmap->line[0] = bitmap->data + overdraw;
|
||||
|
||||
for (i = 1; i < height; i++)
|
||||
bitmap->line[i] = bitmap->line[i - 1] + bitmap->pitch;
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/* Allocate and initialize a bitmap structure */
|
||||
bitmap_t *thin_bmp_create(int width, int height, int bpp, int overdraw)
|
||||
{
|
||||
uint8 *addr;
|
||||
|
||||
/* left and right overdraw */
|
||||
int pitch = width + (overdraw * 2);
|
||||
|
||||
/* dword align */
|
||||
pitch = (pitch + 3) & ~3;
|
||||
|
||||
addr = malloc(height * BPP_PITCH(pitch, bpp));
|
||||
if (NULL == addr)
|
||||
return NULL;
|
||||
|
||||
return _make_bitmap(addr, false, width, height, bpp, pitch, overdraw);
|
||||
}
|
||||
|
||||
/* allocate and initialize a hardware bitmap */
|
||||
bitmap_t *thin_bmp_createhw(uint8 *addr, int width, int height, int bpp, int pitch)
|
||||
{
|
||||
return _make_bitmap(addr, true, width, height, bpp, pitch, 0); /* zero overdraw */
|
||||
}
|
||||
|
||||
/* Deallocate space for a bitmap structure */
|
||||
void thin_bmp_destroy(bitmap_t **bitmap)
|
||||
{
|
||||
if (*bitmap)
|
||||
{
|
||||
if ((*bitmap)->data && false == (*bitmap)->hardware)
|
||||
free((*bitmap)->data);
|
||||
free(*bitmap);
|
||||
*bitmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_bmp.h
|
||||
**
|
||||
** Bitmap object defines / prototypes
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _TL_BMP_H_
|
||||
#define _TL_BMP_H_
|
||||
|
||||
#include "tl_types.h"
|
||||
|
||||
/* a bitmap rectangle */
|
||||
typedef struct rect_s
|
||||
{
|
||||
int16 x, y;
|
||||
uint16 w, h;
|
||||
} rect_t;
|
||||
|
||||
typedef struct rgb_s
|
||||
{
|
||||
int r, g, b;
|
||||
} rgb_t;
|
||||
|
||||
typedef struct bitmap_s
|
||||
{
|
||||
int width, height, pitch;
|
||||
int bpp;
|
||||
bool hardware; /* is data a hardware region? */
|
||||
uint8 *data; /* protected */
|
||||
uint8 *line[0]; /* will hold line pointers */
|
||||
} bitmap_t;
|
||||
|
||||
extern void thin_bmp_clear(const bitmap_t *bitmap, uint8 color);
|
||||
extern bitmap_t *thin_bmp_create(int width, int height, int bpp, int overdraw);
|
||||
extern bitmap_t *thin_bmp_createhw(uint8 *addr, int width, int height, int bpp, int pitch);
|
||||
extern void thin_bmp_destroy(bitmap_t **bitmap);
|
||||
|
||||
#endif /* !_TL_BMP_H_ */
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_djgpp.h
|
||||
**
|
||||
** djgpp frigs
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _TL_DJGPP_H_
|
||||
#define _TL_DJGPP_H_
|
||||
|
||||
#include <dpmi.h>
|
||||
|
||||
/* interface to lock code and data */
|
||||
#define THIN_LOCKED_FUNC(x) void x##_end(void) { }
|
||||
#define THIN_LOCKED_STATIC_FUNC(x) static void x##_end(void) { }
|
||||
#define THIN_LOCK_DATA(d, s) _go32_dpmi_lock_data(d, s)
|
||||
#define THIN_LOCK_CODE(c, s) _go32_dpmi_lock_code(c, s)
|
||||
#define THIN_LOCK_VAR(x) THIN_LOCK_DATA((void *) &x, sizeof(x))
|
||||
#define THIN_LOCK_FUNC(x) THIN_LOCK_CODE((void *) x, (long) x##_end - (long) x)
|
||||
|
||||
#include <sys/nearptr.h>
|
||||
#define THIN_PHYSICAL_ADDR(x) ((x) + __djgpp_conventional_base)
|
||||
|
||||
extern int thinlib_nearptr;
|
||||
|
||||
#endif /* !_TL_DJGPP_H_ */
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_dpp.c
|
||||
**
|
||||
** DOS DirectPad Pro scanning code, based on code from
|
||||
** DirectPad Pro (www.ziplabel.com), written by Earle F. Philhower, III
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#include <pc.h>
|
||||
|
||||
#include "tl_types.h"
|
||||
#include "tl_dpp.h"
|
||||
#include "tl_event.h"
|
||||
|
||||
#define MAX_PADS 5
|
||||
|
||||
#define NES_PWR (0x80 + 0x40 + 0x20 + 0x10 + 0x08)
|
||||
#define NES_CLK 1
|
||||
#define NES_LAT 2
|
||||
#define NES_IN ((inportb(port + 1) & nes_din) ^ xor_val)
|
||||
#define NES_OUT(v) (outportb(port, (v)))
|
||||
|
||||
static const uint8 din_table[MAX_PADS] = { 0x40, 0x20, 0x10, 0x08, 0x80 };
|
||||
static const int xor_table[MAX_PADS] = { 1, 1, 1, 1, 0 };
|
||||
|
||||
static dpp_t dpp[MAX_PADS];
|
||||
static event_id dpp_id; /* event callback id */
|
||||
|
||||
void _dpp_poll(void)
|
||||
{
|
||||
int i;
|
||||
int nes_din, port, xor_val;
|
||||
dpp_t *pad, old;
|
||||
thin_event_t event;
|
||||
|
||||
for (i = 0; i < MAX_PADS; i++)
|
||||
{
|
||||
if (0 == dpp[i].port)
|
||||
continue;
|
||||
|
||||
nes_din = din_table[i];
|
||||
port = dpp[i].port;
|
||||
xor_val = nes_din * xor_table[i];
|
||||
pad = &dpp[i];
|
||||
old = *pad;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_LAT + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->a = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->b = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->select = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->start = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->up = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->down = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->left = NES_IN;
|
||||
|
||||
NES_OUT(NES_PWR);
|
||||
NES_OUT(NES_PWR + NES_CLK);
|
||||
NES_OUT(NES_PWR);
|
||||
pad->right = NES_IN;
|
||||
|
||||
NES_OUT(0); /* power down */
|
||||
|
||||
/* generate some events if necessary */
|
||||
if (pad->left != old.left)
|
||||
{
|
||||
event.type = THIN_JOY_MOTION;
|
||||
event.data.joy_motion.dir = THIN_JOY_LEFT;
|
||||
event.data.joy_motion.state = pad->left;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->right != old.right)
|
||||
{
|
||||
event.type = THIN_JOY_MOTION;
|
||||
event.data.joy_motion.dir = THIN_JOY_RIGHT;
|
||||
event.data.joy_motion.state = pad->right;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->up != old.up)
|
||||
{
|
||||
event.type = THIN_JOY_MOTION;
|
||||
event.data.joy_motion.dir = THIN_JOY_UP;
|
||||
event.data.joy_motion.state = pad->up;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->down != old.down)
|
||||
{
|
||||
event.type = THIN_JOY_MOTION;
|
||||
event.data.joy_motion.dir = THIN_JOY_DOWN;
|
||||
event.data.joy_motion.state = pad->down;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->select != old.select)
|
||||
{
|
||||
event.type = pad->select ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE;
|
||||
event.data.joy_button = 2;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->start != old.start)
|
||||
{
|
||||
event.type = pad->start ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE;
|
||||
event.data.joy_button = 3;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->b != old.b)
|
||||
{
|
||||
event.type = pad->b ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE;
|
||||
event.data.joy_button = 0;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
|
||||
if (pad->a != old.a)
|
||||
{
|
||||
event.type = pad->a ? THIN_JOY_BUTTON_PRESS : THIN_JOY_BUTTON_RELEASE;
|
||||
event.data.joy_button = 1;
|
||||
thin_event_add(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void thin_dpp_read(dpp_t *pad, int pad_num)
|
||||
{
|
||||
*pad = dpp[pad_num];
|
||||
}
|
||||
|
||||
int thin_dpp_add(uint16 port, int pad_num)
|
||||
{
|
||||
dpp[pad_num].port = port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thin_dpp_init(void)
|
||||
{
|
||||
dpp_id = thin_event_add_callback((event_callback_t) _dpp_poll);
|
||||
if (-1 == dpp_id)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void thin_dpp_shutdown(void)
|
||||
{
|
||||
if (-1 != dpp_id)
|
||||
{
|
||||
thin_event_remove_callback(dpp_id);
|
||||
dpp_id = -1;
|
||||
|
||||
memset(dpp, 0, sizeof(dpp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_dpp.h
|
||||
**
|
||||
** DOS DirectPad Pro scanning code prototypes
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _TL_DPP_H_
|
||||
#define _TL_DPP_H_
|
||||
|
||||
#include "tl_types.h"
|
||||
|
||||
typedef struct dpp_s
|
||||
{
|
||||
/* private: */
|
||||
uint16 port; /* LPT port */
|
||||
/* public: */
|
||||
int down, up, left, right;
|
||||
int b, a, select, start;
|
||||
} dpp_t;
|
||||
|
||||
extern int thin_dpp_add(uint16 port, int pad_num);
|
||||
extern int thin_dpp_init(void);
|
||||
extern void thin_dpp_shutdown(void);
|
||||
extern void thin_dpp_read(dpp_t *pad, int pad_num);
|
||||
|
||||
#endif /* !_TL_DPP_H_ */
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_event.c
|
||||
**
|
||||
** event handling routines
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#include "tl_types.h"
|
||||
#include "tl_event.h"
|
||||
#include "tl_djgpp.h"
|
||||
|
||||
|
||||
/* maximum of 8 event handling callbacks */
|
||||
#define MAX_CALLBACKS 8
|
||||
|
||||
|
||||
#define EVENT_QUEUE_MAX 256
|
||||
#define EVENT_QUEUE_MASK (EVENT_QUEUE_MAX - 1)
|
||||
#define EVENT_QUEUE_EMPTY (event_queue.head == event_queue.tail)
|
||||
|
||||
typedef struct event_queue_s
|
||||
{
|
||||
int head;
|
||||
int tail;
|
||||
thin_event_t event[EVENT_QUEUE_MAX];
|
||||
} event_queue_t;
|
||||
|
||||
|
||||
static event_queue_t event_queue;
|
||||
static event_callback_t event_callback[MAX_CALLBACKS];
|
||||
|
||||
|
||||
/* add an event. */
|
||||
void thin_event_add(thin_event_t *event)
|
||||
{
|
||||
event_queue.event[event_queue.head] = *event;
|
||||
event_queue.head = (event_queue.head + 1) & EVENT_QUEUE_MASK;
|
||||
}
|
||||
THIN_LOCKED_FUNC(thin_event_add)
|
||||
|
||||
|
||||
/* get an event from the event queue. returns 0 if no events. */
|
||||
int thin_event_get(thin_event_t *event)
|
||||
{
|
||||
if (EVENT_QUEUE_EMPTY)
|
||||
{
|
||||
event->type = THIN_NOEVENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*event = event_queue.event[event_queue.tail];
|
||||
event_queue.tail = (event_queue.tail + 1) & EVENT_QUEUE_MASK;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* gather up all pollable events */
|
||||
void thin_event_gather(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CALLBACKS; i++)
|
||||
{
|
||||
if (NULL == event_callback[i])
|
||||
return;
|
||||
|
||||
event_callback[i]();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* return an ID of an event callback */
|
||||
event_id thin_event_add_callback(event_callback_t callback)
|
||||
{
|
||||
event_id id;
|
||||
|
||||
for (id = 0; id < MAX_CALLBACKS; id++)
|
||||
{
|
||||
if (NULL == event_callback[id])
|
||||
break;
|
||||
}
|
||||
|
||||
/* no event callbacks available */
|
||||
if (id == MAX_CALLBACKS)
|
||||
return (event_id) -1;
|
||||
|
||||
event_callback[id] = callback;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/* remove an event callback */
|
||||
void thin_event_remove_callback(event_id id)
|
||||
{
|
||||
THIN_ASSERT(id >= 0 && id < MAX_CALLBACKS);
|
||||
|
||||
if (id < 0 || id >= MAX_CALLBACKS)
|
||||
return;
|
||||
|
||||
THIN_ASSERT(NULL != event_callback[id]);
|
||||
|
||||
event_callback[id] = NULL;
|
||||
|
||||
/* move all other callbacks down */
|
||||
for (; id < MAX_CALLBACKS - 1; id++)
|
||||
{
|
||||
event_callback[id] = event_callback[id + 1];
|
||||
event_callback[id + 1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set up the event handling system */
|
||||
void thin_event_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* some modules call thin_event_add from an ISR, so we must
|
||||
** lock everythig that is touched within that function, as
|
||||
** well as the code itself.
|
||||
*/
|
||||
THIN_LOCK_FUNC(thin_event_add);
|
||||
THIN_LOCK_VAR(event_queue);
|
||||
|
||||
for (i = 0; i < MAX_CALLBACKS; i++)
|
||||
event_callback[i] = NULL;
|
||||
|
||||
event_queue.head = event_queue.tail = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_event.h
|
||||
**
|
||||
** event handling routines
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _TL_EVENT_H_
|
||||
#define _TL_EVENT_H_
|
||||
|
||||
typedef void (*event_callback_t)(void);
|
||||
typedef int event_id;
|
||||
|
||||
enum
|
||||
{
|
||||
THIN_NOEVENT = 0,
|
||||
THIN_KEY_PRESS,
|
||||
THIN_KEY_RELEASE,
|
||||
THIN_MOUSE_MOTION,
|
||||
THIN_MOUSE_BUTTON_PRESS,
|
||||
THIN_MOUSE_BUTTON_RELEASE,
|
||||
THIN_JOY_MOTION,
|
||||
THIN_JOY_BUTTON_PRESS,
|
||||
THIN_JOY_BUTTON_RELEASE,
|
||||
THIN_USER_EVENT,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
THIN_JOY_LEFT,
|
||||
THIN_JOY_RIGHT,
|
||||
THIN_JOY_UP,
|
||||
THIN_JOY_DOWN,
|
||||
};
|
||||
|
||||
typedef struct thin_event_s
|
||||
{
|
||||
int type;
|
||||
union
|
||||
{
|
||||
/* keyboard */
|
||||
int keysym;
|
||||
/* mouse motion */
|
||||
struct
|
||||
{
|
||||
int xpos;
|
||||
int ypos;
|
||||
} mouse_motion;
|
||||
/* mouse button */
|
||||
int mouse_button;
|
||||
/* joy motion */
|
||||
struct
|
||||
{
|
||||
int dir;
|
||||
int state;
|
||||
} joy_motion;
|
||||
/* joy button */
|
||||
int joy_button;
|
||||
/* user event */
|
||||
int user_data;
|
||||
} data;
|
||||
} thin_event_t;
|
||||
|
||||
extern void thin_event_add(thin_event_t *event);
|
||||
extern int thin_event_get(thin_event_t *event);
|
||||
extern void thin_event_gather(void);
|
||||
extern event_id thin_event_add_callback(event_callback_t callback);
|
||||
extern void thin_event_remove_callback(event_id id);
|
||||
extern void thin_event_init(void);
|
||||
|
||||
|
||||
#endif /* !_TL_EVENT_H_ */
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
** thinlib (c) 2001 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
**
|
||||
** tl_int.c
|
||||
**
|
||||
** thinlib interrupt handling. Thanks to Shawn Hargreaves
|
||||
** and the Allegro project for providing adequate interrupt
|
||||
** documentation.
|
||||
**
|
||||
** $Id: $
|
||||
*/
|
||||
|
||||
#include <dos.h>
|
||||
#include <go32.h>
|
||||
#include <dpmi.h>
|
||||
#include "thinlib.h"
|
||||
#include "tl_types.h"
|
||||
#include "tl_log.h"
|
||||
#include "tl_djgpp.h"
|
||||
#include "tl_int.h"
|
||||
|
||||
#define PIC1_PORT 0x21
|
||||
#define PIC2_PORT 0xA1
|
||||
|
||||
/* Interrupt stuff */
|
||||
typedef struct intr_s
|
||||
{
|
||||
_go32_dpmi_seginfo old_interrupt;
|
||||
_go32_dpmi_seginfo new_interrupt;
|
||||
uint8 irq_vector;
|
||||
inthandler_t handler;
|
||||
} intr_t;
|
||||
|
||||
#define MAX_INTR 8
|
||||
|
||||
static bool pic_modified = false;
|
||||
static uint8 pic1_mask, pic2_mask;
|
||||
static uint8 pic1_orig, pic2_orig;
|
||||
|
||||
static intr_t intr[MAX_INTR];
|
||||
static bool thin_int_locked = false;
|
||||
|
||||
|
||||
#define MAKE_INT_HANDLER(num) \
|
||||
static void _int_handler_##num##(void) \
|
||||
{ \
|
||||
/* chain if necessary */ \
|
||||
if (intr[(num)].handler()) \
|
||||
{ \
|
||||
void (*func)() = (void *) intr[(num)].old_interrupt.pm_offset; \
|
||||
func(); \
|
||||
} \
|
||||
} \
|
||||
THIN_LOCKED_STATIC_FUNC(_int_handler_##num##);
|
||||
|
||||
MAKE_INT_HANDLER(0)
|
||||
MAKE_INT_HANDLER(1)
|
||||
MAKE_INT_HANDLER(2)
|
||||
MAKE_INT_HANDLER(3)
|
||||
MAKE_INT_HANDLER(4)
|
||||
MAKE_INT_HANDLER(5)
|
||||
MAKE_INT_HANDLER(6)
|
||||
MAKE_INT_HANDLER(7)
|
||||
|
||||
int thin_int_install(int chan, inthandler_t handler)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (chan < 0)// || chan >= MAX_INTR)
|
||||
return -1;
|
||||
|
||||
if (NULL == handler)
|
||||
return -1;
|
||||
|
||||
if (false == thin_int_locked)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_INTR; i++)
|
||||
{
|
||||
intr[i].handler = NULL;
|
||||
intr[i].irq_vector = 0;
|
||||
}
|
||||
|
||||
THIN_LOCK_VAR(intr);
|
||||
THIN_LOCK_FUNC(_int_handler_0);
|
||||
THIN_LOCK_FUNC(_int_handler_1);
|
||||
THIN_LOCK_FUNC(_int_handler_2);
|
||||
THIN_LOCK_FUNC(_int_handler_3);
|
||||
THIN_LOCK_FUNC(_int_handler_4);
|
||||
THIN_LOCK_FUNC(_int_handler_5);
|
||||
THIN_LOCK_FUNC(_int_handler_6);
|
||||
THIN_LOCK_FUNC(_int_handler_7);
|
||||
|
||||
thin_int_locked = true;
|
||||
}
|
||||
|
||||
/* find a free slot */
|
||||
for (i = 0; i < MAX_INTR; i++)
|
||||
{
|
||||
if (NULL == intr[i].handler)
|
||||
{
|
||||
intr_t *pintr = &intr[i];
|
||||
|
||||
pintr->new_interrupt.pm_selector = _go32_my_cs();
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0: pintr->new_interrupt.pm_offset = (int) _int_handler_0; break;
|
||||
case 1: pintr->new_interrupt.pm_offset = (int) _int_handler_1; break;
|
||||
case 2: pintr->new_interrupt.pm_offset = (int) _int_handler_2; break;
|
||||
case 3: pintr->new_interrupt.pm_offset = (int) _int_handler_3; break;
|
||||
case 4: pintr->new_interrupt.pm_offset = (int) _int_handler_4; break;
|
||||
case 5: pintr->new_interrupt.pm_offset = (int) _int_handler_5; break;
|
||||
case 6: pintr->new_interrupt.pm_offset = (int) _int_handler_6; break;
|
||||
case 7: pintr->new_interrupt.pm_offset = (int) _int_handler_7; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
pintr->new_interrupt.pm_offset = (int) handler;
|
||||
|
||||
pintr->handler = handler;
|
||||
pintr->irq_vector = chan;
|
||||
|
||||
_go32_dpmi_get_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->old_interrupt);
|
||||
_go32_dpmi_allocate_iret_wrapper(&pintr->new_interrupt);
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->new_interrupt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; /* none free */
|
||||
}
|
||||
|
||||
void thin_int_remove(int chan)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_INTR; i++)
|
||||
{
|
||||
intr_t *pintr = &intr[i];
|
||||
if (pintr->irq_vector == chan && pintr->handler != NULL)
|
||||
{
|
||||
_go32_dpmi_set_protected_mode_interrupt_vector(pintr->irq_vector, &pintr->old_interrupt);
|
||||
_go32_dpmi_free_iret_wrapper(&pintr->new_interrupt);
|
||||
|
||||
pintr->handler = NULL;
|
||||
pintr->irq_vector = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* helper routines for the irq masking */
|
||||
static void _irq_exit(void)
|
||||
{
|
||||
if (pic_modified)
|
||||
{
|
||||
pic_modified = false;
|
||||
outportb(0x21, pic1_orig);
|
||||
outportb(0xA1, pic2_orig);
|
||||
thin_remove_exit(_irq_exit);
|
||||
}
|
||||
}
|
||||
|
||||
static void _irq_init(void)
|
||||
{
|
||||
if (false == pic_modified)
|
||||
{
|
||||
pic_modified = true;
|
||||
|
||||
/* read initial PIC values */
|
||||
pic1_orig = inportb(0x21);
|
||||
pic2_orig = inportb(0xA1);
|
||||
|
||||
pic1_mask = 0;
|
||||
pic2_mask = 0;
|
||||
|
||||
thin_add_exit(_irq_exit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* restore original mask for interrupt */
|
||||
void thin_irq_restore(int irq)
|
||||
{
|
||||
if (pic_modified)
|
||||
{
|
||||
uint8 pic;
|
||||
|
||||
if (irq > 7)
|
||||
{
|
||||
pic = inportb(0xA1) & ~(1 << (irq - 8));
|
||||
outportb(0xA1, pic | (pic2_orig & (1 << (irq - 8))));
|
||||
pic2_mask &= ~(1 << (irq - 8));
|
||||
|
||||
if (pic2_mask)
|
||||
return;
|
||||
|
||||
irq = 2; /* restore cascade if no high IRQs remain */
|
||||
}
|
||||
|
||||
pic = inportb(0x21) & ~(1 << irq);
|
||||
outportb(0x21, pic | (pic1_orig & (1 << irq)));
|
||||
pic1_mask &= ~(1 << irq);
|
||||
}
|
||||
}
|
||||
|
||||
/* unmask an interrupt */
|
||||
void thin_irq_enable(int irq)
|
||||
{
|
||||
uint8 pic;
|
||||
|
||||
_irq_init();
|
||||
|
||||
pic = inportb(0x21);
|
||||
|
||||
if (irq > 7)
|
||||
{
|
||||
/* unmask cascade (IRQ2) interrupt */
|
||||
//outportb(0x21, pic & 0xFB);
|
||||
outportb(0x21, pic & ~(1 << 2));
|
||||
pic = inportb(0xA1);
|
||||
outportb(0xA1, pic & ~(1 << (irq - 8)));
|
||||
pic2_mask |= 1 << (irq - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
outportb(0x21, pic & ~(1 << irq));
|
||||
pic1_mask |= 1 << irq;
|
||||
}
|
||||
}
|
||||
|
||||
/* mask an interrupt */
|
||||
void thin_irq_disable(int irq)
|
||||
{
|
||||
uint8 pic;
|
||||
|
||||
_irq_init();
|
||||
|
||||
if (irq > 7)
|
||||
{
|
||||
/* PIC 2 */
|
||||
pic = inportb(0xA1);
|
||||
outportb(0xA1, pic & (1 << (irq - 8)));
|
||||
pic2_mask |= 1 << (irq - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* PIC 1 */
|
||||
pic = inportb(0x21);
|
||||
outportb(0x21, pic & (1 << irq));
|
||||
pic1_mask |= 1 << irq;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $Log: $
|
||||
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue