1
0
Fork 0
forked from len0rd/rockbox

Rockboy - gameboy emulation for rockbox, based on gnuboy. Still a bit early, but already playable on iRiver H1xx and the simulators. The archos recorder version is currently rather slow...

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6104 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jens Arnold 2005-03-02 23:49:38 +00:00
parent 48dad47df9
commit 384de10246
56 changed files with 9225 additions and 1 deletions

View file

@ -34,7 +34,13 @@ OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
DEFS := $(SRC:%.c=$(OBJDIR)/%.def)
DIRS = .
all: $(OBJDIR)/libplugin.a $(ROCKS) $(DEPFILE)
#for any recorder and iRiver model
ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET)))))
SUBDIRS += rockboy
endif
.PHONY: $(SUBDIRS)
all: $(OBJDIR)/libplugin.a $(ROCKS) $(SUBDIRS) $(DEPFILE)
ifndef SIMVER
$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKFILE) $(OBJDIR)/libplugin.a
@ -95,10 +101,16 @@ $(LINKFILE): $(LDS)
@echo "build $@"
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
$(SUBDIRS):
@echo "MAKE in $@"
@mkdir -p $(OBJDIR)/$@
@$(MAKE) -C $@ TARGET=$(TARGET) DEBUG=$(DEBUG) OUTDIR=$(OBJDIR) OBJDIR=$(OBJDIR)/$@ VERSION=$(VERSION) EXTRA_DEFINES="$(EXTRA_DEFINES)" MEM=${MEMORYSIZE}
clean:
@echo "cleaning plugins"
@rm -f $(ROCKS) $(LINKFILE) $(OBJDIR)/*.rock $(DEPFILE) $(ELFS) \
$(OBJS) $(DEFS)
@$(MAKE) -C lib clean
@$(MAKE) -C rockboy clean
-include $(DEPFILE)

View file

@ -29,6 +29,10 @@ oscillograph.c
oscilloscope.c
pong.c
rockblox.c
#if (CONFIG_KEYPAD == RECORDER_PAD) && !defined(SIMULATOR)
/* loader, only needed for Archos */
rockboy.c
#endif
sliding_puzzle.c
snake.c
snake2.c

81
apps/plugins/rockboy.c Normal file
View file

@ -0,0 +1,81 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Jens Arnold
*
* Overlay loader for rockboy on Archos
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#if MEM <= 8 && !defined(SIMULATOR)
#define OVL_NAME "/.rockbox/viewers/rockboy.ovl"
#define OVL_DISPLAYNAME "RockBoy"
struct plugin_api* rb;
unsigned char *mp3buf;
int mp3buf_size;
/* this is the plugin entry point */
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int fh, readsize;
struct {
unsigned long magic;
unsigned char *start_addr;
unsigned char *end_addr;
enum plugin_status(*entry_point)(struct plugin_api*, void*);
} header;
/* this macro should be called as the first thing you do in the plugin.
it test that the api version and model the plugin was compiled for
matches the machine it is running on */
TEST_PLUGIN_API(api);
rb = api;
fh = rb->open(OVL_NAME, O_RDONLY);
if (fh < 0)
{
rb->splash(2*HZ, true, "Couldn't open " OVL_DISPLAYNAME " overlay.");
return PLUGIN_ERROR;
}
readsize = rb->read(fh, &header, sizeof(header));
if (readsize != sizeof(header) || header.magic != 0x524f564c)
{
rb->close(fh);
rb->splash(2*HZ, true, OVL_NAME " is not a valid Rockbox overlay.");
return PLUGIN_ERROR;
}
mp3buf = rb->plugin_get_mp3_buffer(&mp3buf_size);
if (header.start_addr < mp3buf || header.end_addr > mp3buf + mp3buf_size)
{
rb->close(fh);
rb->splash(2*HZ, true, OVL_DISPLAYNAME
" overlay doesn't fit into memory.");
return PLUGIN_ERROR;
}
rb->lseek(fh, 0, SEEK_SET);
readsize = rb->read(fh, header.start_addr, header.end_addr - header.start_addr);
rb->close(fh);
if (readsize != header.end_addr - header.start_addr)
{
rb->splash(2*HZ, true, "Error loading " OVL_DISPLAYNAME " overlay.");
return PLUGIN_ERROR;
}
return header.entry_point(api, parameter);
}
#endif

339
apps/plugins/rockboy/COPYING Executable file
View file

@ -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.

View file

@ -0,0 +1,106 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
-I$(FIRMDIR)/common -I$(FIRMDIR)/drivers
CFLAGS = $(GCCOPTS) -O3 $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
-DMEM=${MEMORYSIZE} -DPLUGIN
ifdef APPEXTRA
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
endif
LINKFILE := $(OBJDIR)/link.lds
DEPFILE = $(OBJDIR)/dep-rockboy
SRC = cpu.c emu.c events.c exports.c fastmem.c hw.c lcd.c lcdc.c loader.c \
main.c mem.c nosound.c rccmds.c rcvars.c rtc.c save.c sound.c split.c \
sys_rockbox.c rockboy.c
SOURCES = $(SRC)
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
DIRS = .
ifndef SIMVER
ifneq (,$(findstring RECORDER,$(TARGET))) ## Archos recorder targets
LDS := archos.lds
OUTPUT = $(OUTDIR)/rockboy.ovl
else ## iRiver target
LDS := ../plugin.lds
OUTPUT = $(OUTDIR)/rockboy.rock
endif
else ## simulators
OUTPUT = $(OUTDIR)/rockboy.rock
endif
all: $(OUTPUT)
ifndef SIMVER
$(OBJDIR)/rockboy.elf: $(OBJS) $(LINKFILE) $(OUTDIR)/libplugin.a
@echo "LD $@"
@$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(OUTDIR) -lplugin -lgcc \
-T$(LINKFILE) -Wl,-Map,$(OBJDIR)/rockboy.map
$(OUTPUT): $(OBJDIR)/rockboy.elf
@echo "OBJCOPY $<"
@$(OC) -O binary $< $@
else
ifeq ($(SIMVER), x11)
###################################################
# This is the X11 simulator version
$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
@echo "LD $@"
@$(CC) $(CFLAGS) -shared $(OBJS) -L$(OUTDIR) -lplugin -o $@
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
# 'x' must be kept or you'll have "Win32 error 5"
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
# #define ERROR_ACCESS_DENIED 5L
else
@chmod -x $@
endif
else # end of x11-simulator
###################################################
# This is the win32 simulator version
DLLTOOLFLAGS = --export-all
DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
@echo "DLL $@"
@$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
@$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
$(OUTDIR)/libplugin.a -o $@
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
# 'x' must be kept or you'll have "Win32 error 5"
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
# #define ERROR_ACCESS_DENIED 5L
else
@chmod -x $@
endif
endif # end of win32-simulator
endif # end of simulator section
include $(TOOLSDIR)/make.inc
# MEM should be passed on to this makefile with the chosen memory size given
# in number of MB
$(LINKFILE): $(LDS)
@echo "build $@"
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) \
-E -P - >$@
clean:
@echo "cleaning rockboy"
@rm -rf $(OBJDIR)/rockboy
@rm -f $(OBJDIR)/rockboy.*
-include $(DEPFILE)

199
apps/plugins/rockboy/README Executable file
View file

@ -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>

5
apps/plugins/rockboy/Version Executable file
View file

@ -0,0 +1,5 @@
#define VERSION "1.0.3" /*
VERSION = 1.0.3
# */

46
apps/plugins/rockboy/archos.lds Executable file
View file

@ -0,0 +1,46 @@
#include "config.h"
/* linker script for rockboy as an overlay,
* only used/ necessary for SH-based archos targets */
OUTPUT_FORMAT(elf32-sh)
#define DRAMORIG 0x09000000
#define PLUGIN_LENGTH 0x8000
#define OVERLAY_LENGTH 0x68000
#define OVERLAY_ORIGIN (DRAMORIG + (MEMORYSIZE * 0x100000) - PLUGIN_LENGTH - OVERLAY_LENGTH)
MEMORY
{
OVERLAY_RAM : ORIGIN = OVERLAY_ORIGIN, LENGTH = OVERLAY_LENGTH
}
SECTIONS
{
.header : {
_ovl_start_addr = .;
*(.header)
} > OVERLAY_RAM
.text : {
*(.entry)
*(.text)
} > OVERLAY_RAM
.data : {
*(.data)
} > OVERLAY_RAM
.bss : {
*(.bss)
} > OVERLAY_RAM
.rodata : {
*(.rodata)
*(.rodata.str1.1)
*(.rodata.str1.4)
. = ALIGN(0x4);
_ovl_end_addr = .;
} > OVERLAY_RAM
}

880
apps/plugins/rockboy/cpu.c Normal file
View file

@ -0,0 +1,880 @@
#include "rockmacros.h"
#include "defs.h"
#include "regs.h"
#include "hw.h"
#include "cpu.h"
#include "lcdc.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(void)
{
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 */

View file

@ -0,0 +1,41 @@
#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;
void cpu_reset(void);
void div_advance(int cnt);
void timer_advance(int cnt);
void lcdc_advance(int cnt);
void sound_advance(int cnt);
void cpu_timers(int cnt);
int cpu_emulate(int cycles);
#endif

View file

@ -0,0 +1,290 @@
#include "defs.h"
static const 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,
};
static const 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,
};
static const 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
};
static const 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
};
static const 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
};
static const 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,
};
static const 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,
};
static const 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,
};

View file

@ -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__ */

View file

@ -0,0 +1,699 @@
#include <stdio.h>
#include "rockmacros.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;
char meow[500],buf[300];
// int fd;
if(!debug_trace) return;
// fd=open("/rockboy.trace",O_WRONLY|O_APPEND);
// if(fd<0)
// 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 += snprintf(mnemonic + j,255-j,
"%02Xh", ops[k++]);
break;
case 'W':
case 'w':
ops[k] = readb(a); a++;
ops[k+1] = readb(a); a++;
j += snprintf(mnemonic + j, 255-j,"%04Xh",
((ops[k+1] << 8) | ops[k]));
k += 2;
break;
case 'O':
case 'o':
ops[k] = readb(a); a++;
j += snprintf(mnemonic + j, 255-j,"%+d",
(n8)(ops[k++]));
break;
}
i++;
}
else
{
mnemonic[j++] = pattern[i++];
}
}
mnemonic[j] = 0;
snprintf(buf,299,"%04X ", opaddr);
strcpy(meow,buf);
switch (operand_count[ops[0]]) {
case 1:
snprintf(buf,299,"%02X ", ops[0]);
strcat(meow,buf);
break;
case 2:
snprintf(buf,299,"%02X %02X ", ops[0], ops[1]);
strcat(meow,buf);
break;
case 3:
snprintf(buf,299,"%02X %02X %02X ", ops[0], ops[1], ops[2]);
strcat(meow,buf);
break;
}
snprintf(buf,"%-16.16s", mnemonic);
strcat(meow,buf);
rb->lcd_putsxy(0,0,meow);
rb->lcd_update();
/* fprintf(fd,
" 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' : '-')
);
fprintf(fd,
" IE=%02X IF=%02X LCDC=%02X STAT=%02X LY=%02X LYC=%02X",
R_IE, R_IF, R_LCDC, R_STAT, R_LY, R_LYC
);*/
c--;
}
}

View file

@ -0,0 +1,36 @@
#ifndef __DEFS_H__
#define __DEFS_H__
#include "rockmacros.h"
#ifdef 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

117
apps/plugins/rockboy/emu.c Normal file
View file

@ -0,0 +1,117 @@
#include "rockmacros.h"
#include "defs.h"
#include "regs.h"
#include "hw.h"
#include "cpu.h"
#include "mem.h"
#include "lcd.h"
#include "rc.h"
#include "sound.h"
#include "rtc.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(void)
{
}
/*
* 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(void)
{
hw_reset();
lcd_reset();
cpu_reset();
mbc_reset();
sound_reset();
}
void emu_step(void)
{
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 emu_run(void)
{
void *timer = sys_timer();
char meow[500];
int delay;
int framecount=0;
vid_begin();
lcd_begin();
while(shut==0)
{
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();
framecount++;
snprintf(meow,499,"%d",framecount);
rb->lcd_putsxy(0,0,meow);
rb->lcd_update_rect(0,0,LCD_WIDTH,8);
rb->yield();
}
}

View file

@ -0,0 +1,2 @@
void emu_reset(void);
void emu_run(void);

View file

@ -0,0 +1,61 @@
/*
* events.c
*
* Event queue.
*/
#include "rockmacros.h"
#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;
}

View file

@ -0,0 +1,42 @@
#include "rockmacros.h"
#include "rc.h"
extern rcvar_t emu_exports[], loader_exports[],
lcd_exports[], rtc_exports[], sound_exports[],
vid_exports[], joy_exports[], pcm_exports[];
rcvar_t *sources[] =
{
emu_exports,
loader_exports,
lcd_exports,
rtc_exports,
sound_exports,
vid_exports,
joy_exports,
pcm_exports,
NULL
};
void init_exports(void)
{
rcvar_t **s = sources;
while (*s)
rc_exportvars(*(s++));
}
void show_exports(void)
{
// TODO
/*int i, j;
for (i = 0; sources[i]; i++)
for (j = 0; sources[i][j].name; j++)
printf("%s\n", sources[i][j].name);*/
}

View file

@ -0,0 +1,2 @@
void init_exports(void);
void show_exports(void);

View file

@ -0,0 +1,138 @@
#include "rockmacros.h"
#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
};
byte readb(int a)
{
byte *p = mbc.rmap[a>>12];
if (p) return p[a];
else return mem_read(a);
}
void writeb(int a, byte b)
{
byte *p = mbc.wmap[a>>12];
if (p) p[a] = b;
else mem_write(a, b);
}
int readw(int a)
{
if ((a+1) & 0xfff)
{
byte *p = mbc.rmap[a>>12];
if (p)
{
#ifdef 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);
}
void writew(int a, int w)
{
if ((a+1) & 0xfff)
{
byte *p = mbc.wmap[a>>12];
if (p)
{
#ifdef 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);
}
byte readhi(int a)
{
return readb(a | 0xff00);
}
void writehi(int a, byte b)
{
writeb(a | 0xff00, b);
}
#if 0
byte readhi(int a)
{
byte (*rd)() = hi_read[a];
return rd ? rd(a) : (ram.hi[a] | himask[a]);
}
void writehi(int a, byte b)
{
byte (*wr)() = hi_write[a];
if (wr) wr(a, b);
else ram.hi[a] = b & ~himask[a];
}
#endif

View file

@ -0,0 +1,22 @@
#ifndef __FASTMEM_H__
#define __FASTMEM_H__
#include "defs.h"
#include "mem.h"
byte readb(int a);
void writeb(int a, byte b);
int readw(int a);
void writew(int a, int w);
byte readhi(int a);
void writehi(int a, byte b);
#if 0
byte readhi(int a);
void writehi(int a, byte b);
#endif
#endif

35
apps/plugins/rockboy/fb.h Normal file
View file

@ -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

183
apps/plugins/rockboy/hw.c Normal file
View file

@ -0,0 +1,183 @@
#include "rockmacros.h"
#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(void)
{
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;
}

47
apps/plugins/rockboy/hw.h Normal file
View file

@ -0,0 +1,47 @@
#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 hdma;
int cgb,gba;
};
extern struct hw hw;
void hw_interrupt(byte i, byte mask);
void hw_dma(byte b);
void hw_hdma_cmd(byte c);
void hw_hdma(void);
void pad_refresh(void);
void pad_press(byte k);
void pad_release(byte k);
void pad_set(byte k, int st);
void hw_reset(void);
#endif

View file

@ -0,0 +1,514 @@
/* 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 */
#include "rockmacros.h"
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. */
}

View file

@ -0,0 +1,24 @@
/*
* input.h
*
* Definitions for input device stuff - buttons, keys, etc.
*/
#define MAX_KEYS 10
typedef struct event_s
{
int type;
int code;
} event_t;
#define EV_NONE 0
#define EV_PRESS 1
#define EV_RELEASE 2
#define EV_REPEAT 3
int ev_postevent(event_t *ev);
int ev_getevent(event_t *ev);

956
apps/plugins/rockboy/lcd.c Normal file
View file

@ -0,0 +1,956 @@
#include "config.h"
#include "rockmacros.h"
#include "defs.h"
#include "regs.h"
#include "hw.h"
#include "mem.h"
#include "lcd.h"
#include "rc.h"
#include "fb.h"
#include "palette.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[scanline_ind])
#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 rgb332;
static int sprsort = 1;
static int sprdebug;
static int scanline_ind=0;
#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_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(void)
{
int i, j;
#if CONFIG_CPU != SH7034 || defined(SIMULATOR)
int k, a, c;
#endif
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++)
{
#if CONFIG_CPU == SH7034 && !defined(SIMULATOR)
asm volatile (
"mov.w @%2,r1 \n"
"swap.b r1,r2 \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@%0 \n"
"mov.b r0,@(7,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(1,%0) \n"
"mov.b r0,@(6,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(2,%0) \n"
"mov.b r0,@(5,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(3,%0) \n"
"mov.b r0,@(4,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(4,%0) \n"
"mov.b r0,@(3,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(5,%0) \n"
"mov.b r0,@(2,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(6,%0) \n"
"mov.b r0,@(1,%1) \n"
"mov #0,r0 \n"
"shlr r1 \n"
"rotcl r0 \n"
"shlr r2 \n"
"rotcl r0 \n"
"mov.b r0,@(7,%0) \n"
"mov.b r0,@%1 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(patpix[i+1024][j]),
/* %1 */ "r"(patpix[i][j]),
/* %2 */ "r"(&vram[(i<<4)|(j<<1)])
: /* clobbers */
"r0", "r1", "r2"
);
#else
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];
#endif
}
#if CONFIG_CPU == SH7034 && !defined(SIMULATOR)
asm volatile (
"mov.l @%0,r0 \n"
"mov.l @(4,%0),r1 \n"
"mov.l r0,@(56,%1) \n"
"mov.l r1,@(60,%1) \n"
"mov.l @(8,%0),r0 \n"
"mov.l @(12,%0),r1 \n"
"mov.l r0,@(48,%1) \n"
"mov.l r1,@(52,%1) \n"
"mov.l @(16,%0),r0 \n"
"mov.l @(20,%0),r1 \n"
"mov.l r0,@(40,%1) \n"
"mov.l r1,@(44,%1) \n"
"mov.l @(24,%0),r0 \n"
"mov.l @(28,%0),r1 \n"
"mov.l r0,@(32,%1) \n"
"mov.l r1,@(36,%1) \n"
"mov.l @(32,%0),r0 \n"
"mov.l @(36,%0),r1 \n"
"mov.l r0,@(24,%1) \n"
"mov.l r1,@(28,%1) \n"
"mov.l @(40,%0),r0 \n"
"mov.l @(44,%0),r1 \n"
"mov.l r0,@(16,%1) \n"
"mov.l r1,@(20,%1) \n"
"mov.l @(48,%0),r0 \n"
"mov.l @(52,%0),r1 \n"
"mov.l r0,@(8,%1) \n"
"mov.l r1,@(12,%1) \n"
"mov.l @(56,%0),r0 \n"
"mov.l @(60,%0),r1 \n"
"mov.l r0,@%1 \n"
"mov.l r1,@(4,%1) \n"
"add %2,%0 \n"
"add %2,%1 \n"
"mov.l @%0,r0 \n"
"mov.l @(4,%0),r1 \n"
"mov.l r0,@(56,%1) \n"
"mov.l r1,@(60,%1) \n"
"mov.l @(8,%0),r0 \n"
"mov.l @(12,%0),r1 \n"
"mov.l r0,@(48,%1) \n"
"mov.l r1,@(52,%1) \n"
"mov.l @(16,%0),r0 \n"
"mov.l @(20,%0),r1 \n"
"mov.l r0,@(40,%1) \n"
"mov.l r1,@(44,%1) \n"
"mov.l @(24,%0),r0 \n"
"mov.l @(28,%0),r1 \n"
"mov.l r0,@(32,%1) \n"
"mov.l r1,@(36,%1) \n"
"mov.l @(32,%0),r0 \n"
"mov.l @(36,%0),r1 \n"
"mov.l r0,@(24,%1) \n"
"mov.l r1,@(28,%1) \n"
"mov.l @(40,%0),r0 \n"
"mov.l @(44,%0),r1 \n"
"mov.l r0,@(16,%1) \n"
"mov.l r1,@(20,%1) \n"
"mov.l @(48,%0),r0 \n"
"mov.l @(52,%0),r1 \n"
"mov.l r0,@(8,%1) \n"
"mov.l r1,@(12,%1) \n"
"mov.l @(56,%0),r0 \n"
"mov.l @(60,%0),r1 \n"
"mov.l r0,@%1 \n"
"mov.l r1,@(4,%1) \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(patpix[i][0]),
/* %1 */ "r"(patpix[i+2048][0]),
/* %2 */ "r"(1024*64)
: /* clobbers */
"r0", "r1"
);
#else
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];
}
}
#endif
}
anydirty = 0;
}
#endif /* ASM_UPDATEPATPIX */
void tilebuf(void)
{
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++)));
}
}
// V = vertical line
// WX = WND start (if 0, no need to do anything) -> WY
// U = start...something...thingy... 7 at most
void bg_scan(void)
{
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(void)
{
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(void)
{
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(void)
{
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);
}
void bg_scan_color(void)
{
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);
}
// blend in window source WND target BUF
// WX = starting X in buf where WND starts
// WV = vertical line selected for this scanline
// reverse:
// WY = starting y in buf where WND starts ?
// W?? = horizontal line selected for this scanline
void wnd_scan_color(void)
{
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(void)
{
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(void)
{
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(void)
{
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(void)
{
/* 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)
+ ((fb.h>>1) - 72) * fb.pitch;
WY = R_WY;
}
void lcd_refreshline(void)
{
if (!fb.enabled) return;
if (!(R_LCDC & 0x80))
return; /* should not happen... */
#if LCD_HEIGHT == 64
if (R_LY >= 128 || R_LY & 1) /* calculate only even lines */
#else
if (R_LY >= 128)
#endif
return;
updatepatpix();
L = R_LY;
#if LCD_HEIGHT == 64
scanline_ind = (L/2) % 8;
#else
scanline_ind = L % 8;
#endif
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 = vdest;
*/
if (scanline_ind == 7)
vid_update(L);
// 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(void)
{
anydirty = 1;
memset(patdirty, 1, sizeof patdirty);
}
void pal_dirty(void)
{
// 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(void)
{
memset(&lcd, 0, sizeof lcd);
lcd_begin();
vram_dirty();
pal_dirty();
}

View file

@ -0,0 +1,74 @@
#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[8][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
void updatepatpix(void);
void tilebuf(void);
void bg_scan(void);
void wnd_scan(void);
void bg_scan_pri(void);
void wnd_scan_pri(void);
void spr_count(void);
void spr_enum(void);
void spr_scan(void);
void lcd_begin(void);
void lcd_refreshline(void);
void pal_write(int i, byte b);
void pal_write_dmg(int i, int mapnum, byte d);
void vram_write(int a, byte b);
void vram_dirty(void);
void pal_dirty(void);
void lcd_reset(void);

180
apps/plugins/rockboy/lcdc.c Normal file
View file

@ -0,0 +1,180 @@
#include "rockmacros.h"
#include "defs.h"
#include "hw.h"
#include "cpu.h"
#include "regs.h"
#include "lcd.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(void)
{
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(void)
{
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;
}
}
}

View file

@ -0,0 +1,4 @@
void stat_trigger(void);
void stat_write(byte b);
void lcdc_change(byte b);
void lcdc_trans(void);

View file

@ -0,0 +1,383 @@
#include <stdio.h>
#include <string.h>
#include "rockmacros.h"
#include "defs.h"
#include "regs.h"
#include "mem.h"
#include "hw.h"
#include "rtc.h"
#include "rc.h"
#include "save.h"
#include "sound.h"
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[500];
static char rtcfile[500];
static char saveprefix[500];
static char *savename;
static char *savedir = "/.rockbox/rockboy";
static int saveslot;
static int forcebatt, nobatt;
static int forcedmg;
static int memfill = -1, memrand = -1;
//static byte romMemory[4*1025*1024];
int mp3_buffer_size;
void *bufferpos;
static void initmem(void *mem, int size)
{
char *p = mem;
if (memrand >= 0)
{
srand(memrand ? memrand : -6 ); //time(0));
while(size--) *(p++) = rand();
}
else if (memfill >= 0)
memset(p, memfill, size);
}
static byte *loadfile(int fd, int *len)
{
int c, l = 0, p = 0;
byte *d, buf[512];
d=malloc(32768);
for(;;)
{
c = read(fd, buf, sizeof buf);
if (c <= 0) break;
l += c;
memcpy(d+p, buf, c);
p += c;
}
setmallocpos(d+p+64);
*len = l;
return d;
}
//static byte sram[65536];
int rom_load(void)
{
int fd;
byte c, *data, *header;
int len = 0, rlen;
fd = open(romfile, O_RDONLY);
if (fd<0) {
die("cannot open rom file");
die(romfile);
return 1;
}
data = loadfile(fd, &len);
header = data; // no zip. = 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;
// mbc.batt = 1; // always store savegame mem.
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]);
return 1;
}
if (!mbc.ramsize) {
die("unknown SRAM size %02X\n", header[0x0149]);
return 1;
}
rlen = 16384 * mbc.romsize;
rom.bank = (void *) data; //realloc(data, rlen);
if (rlen > len) memset(rom.bank[0]+len, 0xff, rlen - len);
ram.sbank = malloc(8192 * mbc.ramsize);
//ram.ibank = malloc(4096*8);
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 = 0; //(hw.cgb && gbamode);
close(fd);
return 0;
}
int sram_load(void)
{
int fd;
char meow[500];
if (!mbc.batt || !sramfile || !*sramfile) return -1;
/* Consider sram loaded at this point, even if file doesn't exist */
ram.loaded = 1;
fd = open(sramfile, O_RDONLY);
snprintf(meow,499,"Opening %s %d",sramfile,fd);
rb->splash(HZ*2, true, meow);
if (fd<0) return -1;
snprintf(meow,499,"Loading savedata from %s",sramfile);
rb->splash(HZ*2, true, meow);
read(fd,ram.sbank, 8192*mbc.ramsize);
close(fd);
return 0;
}
int sram_save(void)
{
int fd;
char meow[500];
/* If we crash before we ever loaded sram, DO NOT SAVE! */
if (!mbc.batt || !sramfile || !ram.loaded || !mbc.ramsize)
return -1;
fd = open(sramfile, O_WRONLY|O_CREAT);
// snprintf(meow,499,"Opening %s %d",sramfile,fd);
// rb->splash(HZ*2, true, meow);
if (fd<0) return -1;
snprintf(meow,499,"Saving savedata to %s",sramfile);
rb->splash(HZ*2, true, meow);
write(fd,ram.sbank, 8192*mbc.ramsize);
close(fd);
return 0;
}
void state_save(int n)
{
int fd;
char name[500];
if (n < 0) n = saveslot;
if (n < 0) n = 0;
snprintf(name, 499,"%s.%03d", saveprefix, n);
if ((fd = open(name, O_WRONLY|O_CREAT)>=0))
{
savestate(fd);
close(fd);
}
}
void state_load(int n)
{
int fd;
char name[500];
if (n < 0) n = saveslot;
if (n < 0) n = 0;
snprintf(name, 499, "%s.%03d", saveprefix, n);
if ((fd = open(name, O_RDONLY)>=0))
{
loadstate(fd);
close(fd);
vram_dirty();
pal_dirty();
sound_dirty();
mem_updatemap();
}
}
void rtc_save(void)
{
int fd;
if (!rtc.batt) return;
if ((fd = open(rtcfile, O_WRONLY|O_CREAT))<0) return;
rtc_save_internal(fd);
close(fd);
}
void rtc_load(void)
{
int fd;
if (!rtc.batt) return;
if ((fd = open(rtcfile, O_RDONLY))<0) return;
rtc_load_internal(fd);
close(fd);
}
void loader_unload(void)
{
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 = 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;
}*/
void cleanup(void)
{
sram_save();
rtc_save();
// IDEA - if error, write emergency savestate..?
}
void loader_init(char *s)
{
char *name;
DIR* dir;
// sys_checkdir(savedir, 1); /* needs to be writable */
dir=opendir(savedir);
if(!dir)
mkdir(savedir,0);
else
closedir(dir);
romfile = s;
if(rom_load())
return;
vid_settitle(rom.name);
name = rom.name;
snprintf(saveprefix, 499, "%s/%s", savedir, name);
strcpy(sramfile, saveprefix);
strcat(sramfile, ".sav");
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_INT("memfill", &memfill),
RCV_INT("memrand", &memrand),
RCV_END
};

View file

@ -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(void);
int sram_load(void);
int sram_save(void);
void loader_init(char *s);
void cleanup(void);
#endif

View file

@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include "rockmacros.h"
#include "input.h"
#include "rc.h"
#include "exports.h"
#include "emu.h"
#include "loader.h"
#include "hw.h"
//#include "Version"
static char *defaultconfig[] =
{
"bind up +up",
"bind down +down",
"bind left +left",
"bind right +right",
"bind joy0 +b",
"bind joy1 +a",
"bind joy2 +select",
"bind joy3 +start",
"bind ins savestate",
"bind del loadstate",
NULL
};
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);
pad_set(ev.code, st);
}
}
int gnuboy_main(char *rom)
{
int i;
// Avoid initializing video if we don't have to
// If we have special perms, drop them ASAP!
rb->splash(HZ*1, true, "Init exports");
init_exports();
rb->splash(HZ*1, true, "Loading default config");
for (i = 0; defaultconfig[i]; i++)
rc_command(defaultconfig[i]);
// sprintf(cmd, "source %s", rom);
// s = strchr(cmd, '.');
// if (s) *s = 0;
// strcat(cmd, ".rc");
// rc_command(cmd);
// FIXME - make interface modules responsible for atexit()
rb->splash(HZ*1, true, "Init video");
vid_init();
rb->splash(HZ*1, true, "Init sound (nosound)");
pcm_init();
rb->splash(HZ*1, true, "Loading rom");
loader_init(rom);
if(shut)
return PLUGIN_ERROR;
rb->splash(HZ*1, true, "Emu reset");
emu_reset();
rb->splash(HZ*1, true, "Emu run");
emu_run();
// never reached
return PLUGIN_OK;
}

578
apps/plugins/rockboy/mem.c Normal file
View file

@ -0,0 +1,578 @@
#include "rockmacros.h"
#include "defs.h"
#include "hw.h"
#include "regs.h"
#include "mem.h"
#include "rtc.h"
#include "lcd.h"
#include "lcdc.h"
#include "sound.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(void)
{
mbc.rombank = 1;
mbc.rambank = 0;
mbc.enableram = 0;
mem_updatemap();
}

View file

@ -0,0 +1,80 @@
#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);
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);
void mbc_reset(void);
#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

View file

@ -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

View file

@ -0,0 +1,43 @@
#include "rockmacros.h"
#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(void)
{
pcm.hz = 11025;
pcm.buf = buf;
pcm.len = sizeof buf;
pcm.pos = 0;
}
void pcm_close(void)
{
memset(&pcm, 0, sizeof pcm);
}
int pcm_submit(void)
{
pcm.pos = 0;
return 0;
}

View file

@ -0,0 +1,153 @@
#include "rockmacros.h"
#include "defs.h"
#include "fb.h"
#include "palette.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(void)
{
int i;
for (i = 0; i < 256; i++)
if (pallock[i] && pallock[i] < pl_locked)
pallock[i]--;
}
void pal_set332(void)
{
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);
}

View file

@ -0,0 +1,6 @@
void pal_lock(byte n);
byte pal_getcolor(int c, int r, int g, int b);
void pal_release(byte n);
void pal_expire(void);
void pal_set332(void);
void vid_setpal(int i, int r, int g, int b);

View file

@ -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

71
apps/plugins/rockboy/rc.h Normal file
View file

@ -0,0 +1,71 @@
#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);
int rc_bindkey(char *keyname, char *cmd);
int rc_unbindkey(char *keyname);
void rc_unbindall(void);
int rc_sourcefile(char *filename);
void rc_dokey(int key, int st);
int rc_command(char *line);
#endif

View file

@ -0,0 +1,122 @@
#include "rockmacros.h"
#include "defs.h"
#include "rc.h"
#include "hw.h"
#include "emu.h"
#include "save.h"
#include "split.h"
/*
* 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_reset(int argc, char **argv)
{
(void)argc;
(void)argv;
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("reset", cmd_reset),
RCC("savestate", cmd_savestate),
RCC("loadstate", cmd_loadstate),
RCC_END
};
int rc_command(char *line)
{
int i, argc, ret;
char *argv[128], linecopy[500];
// 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;
}

View file

@ -0,0 +1,233 @@
#include <string.h>
#include "rockmacros.h"
#include "defs.h"
#include "rc.h"
static rcvar_t rcvars[150];
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);
strcpy(*s,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));
}

181
apps/plugins/rockboy/regs.h Normal file
View file

@ -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

View file

@ -0,0 +1,137 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Gameboy emulator based on gnuboy
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "loader.h"
#include "rockmacros.h"
#if MEM <= 8 && !defined(SIMULATOR)
/* On archos this is loaded as an overlay */
/* These are defined in the linker script */
extern unsigned char ovl_start_addr[];
extern unsigned char ovl_end_addr[];
const struct {
unsigned long magic;
unsigned char *start_addr;
unsigned char *end_addr;
enum plugin_status (*entry_point)(struct plugin_api*, void*);
} header __attribute__ ((section (".header"))) = {
0x524f564c, /* ROVL */
ovl_start_addr, ovl_end_addr, plugin_start
};
#endif
/* here is a global api struct pointer. while not strictly necessary,
it's nice not to have to pass the api pointer in all function calls
in the plugin */
struct plugin_api* rb;
int shut,cleanshut;
char *errormsg;
int gnuboy_main(char *rom);
/* libc functions */
int isdigit(int c) {
return c>='0' && c<= '9';
}
int isalpha(int c) {
return (c>='a' && c<='z')||(c>='A' && c<='Z');
}
int isupper(int c) {
return c>='A'&&c<='Z';
}
int isalnum(int c) {
return isdigit(c)||isalpha(c);
}
void die(char *message, ...)
{
shut=1;
errormsg=message;
}
void *mp3_bufferbase;
void *mp3_bufferpointer;
unsigned int mp3_buffer_free;
void *my_malloc(size_t size)
{
void *alloc;
if (!mp3_bufferbase)
{
mp3_bufferbase = mp3_bufferpointer
= rb->plugin_get_mp3_buffer(&mp3_buffer_free);
#if MEM <= 8 && !defined(SIMULATOR)
/* loaded as an overlay, protect from overwriting ourselves */
if ((unsigned)(ovl_start_addr - (unsigned char *)mp3_bufferbase)
< mp3_buffer_free)
mp3_buffer_free = ovl_start_addr - (unsigned char *)mp3_bufferbase;
#endif
}
if (size + 4 > mp3_buffer_free)
return 0;
alloc = mp3_bufferpointer;
mp3_bufferpointer += size + 4;
mp3_buffer_free -= size + 4;
return alloc;
}
void setmallocpos(void *pointer)
{
mp3_bufferpointer = pointer;
mp3_buffer_free = mp3_bufferpointer - mp3_bufferbase;
}
/* this is the plugin entry point */
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
/* this macro should be called as the first thing you do in the plugin.
it test that the api version and model the plugin was compiled for
matches the machine it is running on */
TEST_PLUGIN_API(api);
/* if you are using a global api pointer, don't forget to copy it!
otherwise you will get lovely "I04: IllInstr" errors... :-) */
rb = api;
shut=0;
cleanshut=0;
mp3_bufferbase=mp3_bufferpointer=0;
mp3_buffer_free=0;
/* now go ahead and have fun! */
rb->splash(HZ*2, true, "Rockboy v0.3");
rb->lcd_clear_display();
gnuboy_main(parameter);
if(shut&&!cleanshut) {
rb->splash(HZ*2, true, errormsg);
return PLUGIN_ERROR;
}
rb->splash(HZ*2, true, "Shutting down.. byebye ^^");
cleanup();
return PLUGIN_OK;
}

View file

@ -0,0 +1,88 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Michiel van der Kolk, Jens Arnold
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <plugin.h>
/* workaround for cygwin not defining endian macros */
#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && defined(_X86_)
#define LITTLE_ENDIAN
#endif
#define malloc(a) my_malloc(a)
void *my_malloc(size_t size);
extern struct plugin_api* rb;
extern int shut,cleanshut;
void vid_update(int scanline);
void vid_init(void);
void vid_begin(void);
void vid_end(void);
void die(char *message, ...);
void setmallocpos(void *pointer);
void vid_settitle(char *title);
void *sys_timer(void);
int sys_elapsed(long *oldtick);
void sys_sleep(int us);
int pcm_submit(void);
void pcm_init(void);
void doevents(void);
int isupper(int c);
int isdigit(int c);
void ev_poll(void);
#ifdef SIMULATOR
#undef opendir
#define opendir(a) rb->sim_opendir((a))
#undef closedir
#define closedir(a) rb->sim_closedir((a))
#undef mkdir
#define mkdir(a,b) rb->sim_mkdir((a),(b))
#undef open
#define open(a,b) rb->sim_open((a),(b))
#undef lseek
#define lseek(a,b,c) rb->sim_lseek((a),(b),(c))
#else /* !SIMULATOR */
#define opendir(a) rb->opendir((a))
#define closedir(a) rb->closedir((a))
#define mkdir(a,b) rb->mkdir((a),(b))
#define open(a,b) rb->open((a),(b))
#define lseek(a,b,c) rb->lseek((a),(b),(c))
#endif /* !SIMULATOR */
#define strcat(a,b) rb->strcat((a),(b))
#define close(a) rb->close((a))
#define read(a,b,c) rb->read((a),(b),(c))
#define write(a,b,c) rb->write((a),(b),(c))
#define memset(a,b,c) rb->memset((a),(b),(c))
#define memcpy(a,b,c) rb->memcpy((a),(b),(c))
#define strcpy(a,b) rb->strcpy((a),(b))
#define strncpy(a,b,c) rb->strncpy((a),(b),(c))
#define strlen(a) rb->strlen((a))
#define strcmp(a,b) rb->strcmp((a),(b))
#define strchr(a,b) rb->strchr((a),(b))
#define strrchr(a,b) rb->strrchr((a),(b))
#define strcasecmp(a,b) rb->strcasecmp((a),(b))
#define srand(a) rb->srand((a))
#define rand() rb->rand()
#define atoi(a) rb->atoi((a))
#define strcat(a,b) rb->strcat((a),(b))
#define snprintf(...) rb->snprintf(__VA_ARGS__)
#define fprintf(...) rb->fdprintf(__VA_ARGS__)
#define tolower(_A_) (isupper(_A_) ? (_A_ - 'A' + 'a') : _A_)

135
apps/plugins/rockboy/rtc.c Normal file
View file

@ -0,0 +1,135 @@
#include "rockmacros.h"
#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(int fd)
{
(void)fd; // stop compiler complaining
// TODO
// 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(int fd)
{
//int rt = 0;
(void)fd; // stop compiler complaining
// TODO
/* 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(); */
}

View file

@ -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;
void rtc_latch(byte b);
void rtc_write(byte b);
void rtc_tick(void);
void rtc_save_internal(int fd);
void rtc_load_internal(int fd);
#endif

286
apps/plugins/rockboy/save.c Normal file
View file

@ -0,0 +1,286 @@
#include "rockmacros.h"
#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 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(int fd)
{
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;
read(fd,buf, 4096);
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 */
lseek(fd, iramblock<<12, SEEK_SET);
read(fd,ram.ibank, 4096*irl);
lseek(fd, vramblock<<12, SEEK_SET);
read(fd,lcd.vbank, 4096*vrl);
lseek(fd, sramblock<<12, SEEK_SET);
read(fd,ram.sbank, 4096*srl);
}
void savestate(int fd)
{
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);
lseek(fd, 0, SEEK_SET);
write(fd,buf, 4096);
lseek(fd, iramblock<<12, SEEK_SET);
write(fd,ram.ibank, 4096*irl);
lseek(fd, vramblock<<12, SEEK_SET);
write(fd,lcd.vbank, 4096*vrl);
lseek(fd, sramblock<<12, SEEK_SET);
write(fd,ram.sbank, 4096*srl);
}

View file

@ -0,0 +1,4 @@
void loadstate(int fd);
void savestate(int fd);
void state_save(int n);
void state_load(int n);

View file

@ -0,0 +1,466 @@
#include "rockmacros.h"
#include "defs.h"
#include "pcm.h"
#include "sound.h"
#include "cpu.h"
#include "hw.h"
#include "regs.h"
#include "rc.h"
#include "noise.h"
static const byte dmgwave[16] =
{
0xac, 0xdd, 0xda, 0x48,
0x36, 0x02, 0xcf, 0x16,
0x2c, 0x04, 0xe5, 0x2c,
0xac, 0xdd, 0xda, 0x48
};
static const byte cgbwave[16] =
{
0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff,
0x00, 0xff, 0x00, 0xff,
};
static const 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 }
};
static const 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;
int pcm_submit(void);
#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(void)
{
s1_freq_d(2048 - (((R_NR14&7)<<8) + R_NR13));
}
static void s2_freq(void)
{
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(void)
{
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(void)
{
S4.freq = (freqtab[R_NR43&7] >> (R_NR43 >> 4)) * RATE;
if (S4.freq >> 18) S4.freq = 1<<18;
}
void sound_dirty(void)
{
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(void)
{
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(void)
{
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(void)
{
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(void)
{
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(void)
{
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(void)
{
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(void)
{
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;
}
}

View file

@ -0,0 +1,41 @@
#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;
byte sound_read(byte r);
void sound_write(byte r, byte b);
void sound_dirty(void);
void sound_off(void);
void sound_reset(void);
void sound_mix(void);
void s1_init(void);
void s2_init(void);
void s3_init(void);
void s4_init(void);
#endif

View file

@ -0,0 +1,59 @@
#include "rockmacros.h"
/*
* 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;
}

View file

@ -0,0 +1 @@
int splitline(char **argv, int max, char *line);

View file

@ -0,0 +1,271 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Michiel van der Kolk, Jens Arnold
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "rockmacros.h"
#include "fb.h"
#include "input.h"
#include "rc.h"
#include "lcd.h"
#include "hw.h"
#include "config.h"
rcvar_t joy_exports[] =
{
RCV_END
};
rcvar_t vid_exports[] =
{
RCV_END
};
struct fb fb;
byte *video_base_buf;
extern int debug_trace;
static byte frameb[145][160];
void vid_settitle(char *title)
{
rb->splash(HZ*2, true, title);
}
void joy_init(void)
{
}
void joy_close(void)
{
}
#if CONFIG_KEYPAD == IRIVER_H100_PAD
#define ROCKBOY_PAD_A BUTTON_ON
#define ROCKBOY_PAD_B BUTTON_OFF
#define ROCKBOY_PAD_START BUTTON_REC
#define ROCKBOY_PAD_SELECT BUTTON_MODE
#define ROCKBOY_QUIT BUTTON_SELECT
#elif CONFIG_KEYPAD == RECORDER_PAD
#define ROCKBOY_PAD_A BUTTON_F1
#define ROCKBOY_PAD_B BUTTON_F2
#define ROCKBOY_PAD_START BUTTON_F3
#define ROCKBOY_PAD_SELECT BUTTON_PLAY
#define ROCKBOY_QUIT BUTTON_OFF
#endif
unsigned int oldbuttonstate = 0, newbuttonstate;
void ev_poll(void)
{
event_t ev;
int released, pressed;
newbuttonstate = rb->button_status();
released = ~newbuttonstate & oldbuttonstate;
pressed = newbuttonstate & ~oldbuttonstate;
oldbuttonstate = newbuttonstate;
if(released) {
ev.type = EV_RELEASE;
if(released & BUTTON_LEFT) { ev.code=PAD_LEFT; ev_postevent(&ev); }
if(released & BUTTON_RIGHT) {ev.code=PAD_RIGHT; ev_postevent(&ev);}
if(released & BUTTON_DOWN) { ev.code=PAD_DOWN; ev_postevent(&ev); }
if(released & BUTTON_UP) { ev.code=PAD_UP; ev_postevent(&ev); }
if(released & ROCKBOY_PAD_A) { ev.code=PAD_A; ev_postevent(&ev); }
if(released & ROCKBOY_PAD_B) { ev.code=PAD_B; ev_postevent(&ev); }
if(released & ROCKBOY_PAD_START) {
ev.code=PAD_START;
ev_postevent(&ev);
}
if(released & ROCKBOY_PAD_SELECT) {
ev.code=PAD_SELECT;
ev_postevent(&ev);
}
}
if(pressed) { /* button press */
ev.type = EV_PRESS;
if(pressed & BUTTON_LEFT) { ev.code=PAD_LEFT; ev_postevent(&ev); }
if(pressed & BUTTON_RIGHT) { ev.code=PAD_RIGHT; ev_postevent(&ev);}
if(pressed & BUTTON_DOWN) { ev.code=PAD_DOWN; ev_postevent(&ev); }
if(pressed & BUTTON_UP) { ev.code=PAD_UP; ev_postevent(&ev); }
if(pressed & ROCKBOY_PAD_A) { ev.code=PAD_A; ev_postevent(&ev); }
if(pressed & ROCKBOY_PAD_B) { ev.code=PAD_B; ev_postevent(&ev); }
if(pressed & ROCKBOY_PAD_START) {
ev.code=PAD_START;
ev_postevent(&ev);
}
if(pressed & ROCKBOY_PAD_SELECT) {
ev.code=PAD_SELECT;
ev_postevent(&ev);
}
if(pressed & ROCKBOY_QUIT) {
die("");
cleanshut=1;
}
}
}
void vid_setpal(int i, int r, int g, int b)
{
(void)i;
(void)r;
(void)g;
(void)b;
}
void vid_init(void)
{
}
void vid_begin(void)
{
fb.pelsize=1; // 8 bit framebuffer.. (too much.. but lowest gnuboy will support.. so yea...
fb.h=144;
fb.w=160;
fb.pitch=160;
fb.enabled=1;
fb.dirty=0;
video_base_buf=fb.ptr=(byte *)frameb;
}
void vid_update(int scanline)
{
int cnt=0,scanline_remapped;
byte *frameb;
#if LCD_HEIGHT == 64 /* Archos */
int balance = 0;
if (scanline >= 128)
return;
scanline_remapped = scanline / 16;
frameb = rb->lcd_framebuffer + scanline_remapped * LCD_WIDTH;
while (cnt < 160) {
balance += LCD_WIDTH;
if (balance > 0)
{
#ifdef SIMULATOR /* simulator uses C */
register unsigned scrbyte = 0;
if (scan.buf[0][cnt] & 0x02) scrbyte |= 0x01;
if (scan.buf[1][cnt] & 0x02) scrbyte |= 0x02;
if (scan.buf[2][cnt] & 0x02) scrbyte |= 0x04;
if (scan.buf[3][cnt] & 0x02) scrbyte |= 0x08;
if (scan.buf[4][cnt] & 0x02) scrbyte |= 0x10;
if (scan.buf[5][cnt] & 0x02) scrbyte |= 0x20;
if (scan.buf[6][cnt] & 0x02) scrbyte |= 0x40;
if (scan.buf[7][cnt] & 0x02) scrbyte |= 0x80;
*(frameb++) = scrbyte;
#else
asm volatile (
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"mov.b @%0,r0 \n"
"add %1,%0 \n"
"tst #0x02, r0 \n" /* ~bit 1 */
"rotcr r1 \n"
"shlr16 r1 \n"
"shlr8 r1 \n"
"not r1,r1 \n" /* account for negated bits */
"mov.b r1,@%2 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(scan.buf[0] + cnt),
/* %1 */ "r"(256), /* scan.buf line length */
/* %2 */ "r"(frameb++)
: /* clobbers */
"r0", "r1"
);
#endif
balance -= 160;
}
cnt ++;
}
rb->lcd_update_rect(0, (scanline/2) & ~7, LCD_WIDTH, 8);
#else /* LCD_HEIGHT != 64, iRiver */
if (scanline >= 128)
return;
scanline_remapped = scanline / 8;
frameb = rb->lcd_framebuffer + scanline_remapped * LCD_WIDTH;
while (cnt < 160) {
register unsigned scrbyte = 0;
if (scan.buf[0][cnt] & 0x02) scrbyte |= 0x01;
if (scan.buf[1][cnt] & 0x02) scrbyte |= 0x02;
if (scan.buf[2][cnt] & 0x02) scrbyte |= 0x04;
if (scan.buf[3][cnt] & 0x02) scrbyte |= 0x08;
if (scan.buf[4][cnt] & 0x02) scrbyte |= 0x10;
if (scan.buf[5][cnt] & 0x02) scrbyte |= 0x20;
if (scan.buf[6][cnt] & 0x02) scrbyte |= 0x40;
if (scan.buf[7][cnt] & 0x02) scrbyte |= 0x80;
*(frameb++) = scrbyte;
cnt++;
}
rb->lcd_update_rect(0, scanline & ~7, LCD_WIDTH, 8);
#endif
}
void vid_end(void)
{
}
long timerresult;
void *sys_timer(void)
{
timerresult=*rb->current_tick;
return &timerresult;
}
// returns microseconds passed since sys_timer
int sys_elapsed(long *oldtick)
{
return ((*rb->current_tick-(*oldtick))*1000000)/HZ;
}
void sys_sleep(int us)
{
if (us <= 0) return;
// rb->sleep(HZ*us/1000000);
}

View file

@ -6,6 +6,8 @@ rvf,video.rock,5D 7F 5D 7F 5D 7F
mp3,vbrfix.rock,10 08 58 38 04 02
m3u,search.rock,00 00 00 00 00 00
txt,sort.rock, 00 00 00 00 00 00
gb,rockboy.rock, 0C 2A 59 7A 2E 0C
cgb,rockboy.rock, 0C 2A 59 7A 2E 0C
mp2,mpa2wav.rock, 00 00 00 00 00 00
mp3,mpa2wav.rock, 00 00 00 00 00 00
ac3,a52towav.rock, 00 00 00 00 00 00