From 384de102469fee4e0792df8fe38586d3206774ed Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Wed, 2 Mar 2005 23:49:38 +0000 Subject: 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 --- apps/plugins/Makefile | 14 +- apps/plugins/SOURCES | 4 + apps/plugins/rockboy.c | 81 ++++ apps/plugins/rockboy/COPYING | 339 +++++++++++++ apps/plugins/rockboy/Makefile | 106 ++++ apps/plugins/rockboy/README | 199 ++++++++ apps/plugins/rockboy/Version | 5 + apps/plugins/rockboy/archos.lds | 46 ++ apps/plugins/rockboy/cpu.c | 880 ++++++++++++++++++++++++++++++++++ apps/plugins/rockboy/cpu.h | 41 ++ apps/plugins/rockboy/cpucore.h | 290 +++++++++++ apps/plugins/rockboy/cpuregs.h | 56 +++ apps/plugins/rockboy/debug.c | 699 +++++++++++++++++++++++++++ apps/plugins/rockboy/defs.h | 36 ++ apps/plugins/rockboy/emu.c | 117 +++++ apps/plugins/rockboy/emu.h | 2 + apps/plugins/rockboy/events.c | 61 +++ apps/plugins/rockboy/exports.c | 42 ++ apps/plugins/rockboy/exports.h | 2 + apps/plugins/rockboy/fastmem.c | 138 ++++++ apps/plugins/rockboy/fastmem.h | 22 + apps/plugins/rockboy/fb.h | 35 ++ apps/plugins/rockboy/hw.c | 183 +++++++ apps/plugins/rockboy/hw.h | 47 ++ apps/plugins/rockboy/inflate.c | 514 ++++++++++++++++++++ apps/plugins/rockboy/input.h | 24 + apps/plugins/rockboy/lcd.c | 956 +++++++++++++++++++++++++++++++++++++ apps/plugins/rockboy/lcd.h | 74 +++ apps/plugins/rockboy/lcdc.c | 180 +++++++ apps/plugins/rockboy/lcdc.h | 4 + apps/plugins/rockboy/loader.c | 383 +++++++++++++++ apps/plugins/rockboy/loader.h | 28 ++ apps/plugins/rockboy/main.c | 83 ++++ apps/plugins/rockboy/mem.c | 578 ++++++++++++++++++++++ apps/plugins/rockboy/mem.h | 80 ++++ apps/plugins/rockboy/noise.h | 532 +++++++++++++++++++++ apps/plugins/rockboy/nosound.c | 43 ++ apps/plugins/rockboy/palette.c | 153 ++++++ apps/plugins/rockboy/palette.h | 6 + apps/plugins/rockboy/pcm.h | 21 + apps/plugins/rockboy/rc.h | 71 +++ apps/plugins/rockboy/rccmds.c | 122 +++++ apps/plugins/rockboy/rcvars.c | 233 +++++++++ apps/plugins/rockboy/regs.h | 181 +++++++ apps/plugins/rockboy/rockboy.c | 137 ++++++ apps/plugins/rockboy/rockmacros.h | 88 ++++ apps/plugins/rockboy/rtc.c | 135 ++++++ apps/plugins/rockboy/rtc.h | 25 + apps/plugins/rockboy/save.c | 286 +++++++++++ apps/plugins/rockboy/save.h | 4 + apps/plugins/rockboy/sound.c | 466 ++++++++++++++++++ apps/plugins/rockboy/sound.h | 41 ++ apps/plugins/rockboy/split.c | 59 +++ apps/plugins/rockboy/split.h | 1 + apps/plugins/rockboy/sys_rockbox.c | 271 +++++++++++ apps/plugins/viewers.config | 2 + 56 files changed, 9225 insertions(+), 1 deletion(-) create mode 100644 apps/plugins/rockboy.c create mode 100755 apps/plugins/rockboy/COPYING create mode 100644 apps/plugins/rockboy/Makefile create mode 100755 apps/plugins/rockboy/README create mode 100755 apps/plugins/rockboy/Version create mode 100755 apps/plugins/rockboy/archos.lds create mode 100644 apps/plugins/rockboy/cpu.c create mode 100644 apps/plugins/rockboy/cpu.h create mode 100644 apps/plugins/rockboy/cpucore.h create mode 100644 apps/plugins/rockboy/cpuregs.h create mode 100644 apps/plugins/rockboy/debug.c create mode 100644 apps/plugins/rockboy/defs.h create mode 100644 apps/plugins/rockboy/emu.c create mode 100644 apps/plugins/rockboy/emu.h create mode 100644 apps/plugins/rockboy/events.c create mode 100644 apps/plugins/rockboy/exports.c create mode 100644 apps/plugins/rockboy/exports.h create mode 100644 apps/plugins/rockboy/fastmem.c create mode 100644 apps/plugins/rockboy/fastmem.h create mode 100644 apps/plugins/rockboy/fb.h create mode 100644 apps/plugins/rockboy/hw.c create mode 100644 apps/plugins/rockboy/hw.h create mode 100644 apps/plugins/rockboy/inflate.c create mode 100644 apps/plugins/rockboy/input.h create mode 100644 apps/plugins/rockboy/lcd.c create mode 100644 apps/plugins/rockboy/lcd.h create mode 100644 apps/plugins/rockboy/lcdc.c create mode 100644 apps/plugins/rockboy/lcdc.h create mode 100644 apps/plugins/rockboy/loader.c create mode 100644 apps/plugins/rockboy/loader.h create mode 100644 apps/plugins/rockboy/main.c create mode 100644 apps/plugins/rockboy/mem.c create mode 100644 apps/plugins/rockboy/mem.h create mode 100644 apps/plugins/rockboy/noise.h create mode 100644 apps/plugins/rockboy/nosound.c create mode 100644 apps/plugins/rockboy/palette.c create mode 100644 apps/plugins/rockboy/palette.h create mode 100644 apps/plugins/rockboy/pcm.h create mode 100644 apps/plugins/rockboy/rc.h create mode 100644 apps/plugins/rockboy/rccmds.c create mode 100644 apps/plugins/rockboy/rcvars.c create mode 100644 apps/plugins/rockboy/regs.h create mode 100644 apps/plugins/rockboy/rockboy.c create mode 100644 apps/plugins/rockboy/rockmacros.h create mode 100644 apps/plugins/rockboy/rtc.c create mode 100644 apps/plugins/rockboy/rtc.h create mode 100644 apps/plugins/rockboy/save.c create mode 100644 apps/plugins/rockboy/save.h create mode 100644 apps/plugins/rockboy/sound.c create mode 100644 apps/plugins/rockboy/sound.h create mode 100644 apps/plugins/rockboy/split.c create mode 100644 apps/plugins/rockboy/split.h create mode 100644 apps/plugins/rockboy/sys_rockbox.c diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile index 3e56510f53..6c3917c0cb 100644 --- a/apps/plugins/Makefile +++ b/apps/plugins/Makefile @@ -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) diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 643fc0c5c1..581d164e94 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -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 diff --git a/apps/plugins/rockboy.c b/apps/plugins/rockboy.c new file mode 100644 index 0000000000..4778fa8ee6 --- /dev/null +++ b/apps/plugins/rockboy.c @@ -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 diff --git a/apps/plugins/rockboy/COPYING b/apps/plugins/rockboy/COPYING new file mode 100755 index 0000000000..a43ea2126f --- /dev/null +++ b/apps/plugins/rockboy/COPYING @@ -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. + + + Copyright (C) 19yy + + 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. + + , 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. diff --git a/apps/plugins/rockboy/Makefile b/apps/plugins/rockboy/Makefile new file mode 100644 index 0000000000..f6042a4b1b --- /dev/null +++ b/apps/plugins/rockboy/Makefile @@ -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) + diff --git a/apps/plugins/rockboy/README b/apps/plugins/rockboy/README new file mode 100755 index 0000000000..f10a5f08d3 --- /dev/null +++ b/apps/plugins/rockboy/README @@ -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 + + + + + + + + + + + diff --git a/apps/plugins/rockboy/Version b/apps/plugins/rockboy/Version new file mode 100755 index 0000000000..0b12c4271d --- /dev/null +++ b/apps/plugins/rockboy/Version @@ -0,0 +1,5 @@ +#define VERSION "1.0.3" /* +VERSION = 1.0.3 +# */ + + diff --git a/apps/plugins/rockboy/archos.lds b/apps/plugins/rockboy/archos.lds new file mode 100755 index 0000000000..23d03c6297 --- /dev/null +++ b/apps/plugins/rockboy/archos.lds @@ -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 +} diff --git a/apps/plugins/rockboy/cpu.c b/apps/plugins/rockboy/cpu.c new file mode 100644 index 0000000000..44a870a6eb --- /dev/null +++ b/apps/plugins/rockboy/cpu.c @@ -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<= 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; + 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 */ + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/cpu.h b/apps/plugins/rockboy/cpu.h new file mode 100644 index 0000000000..22d58b0db0 --- /dev/null +++ b/apps/plugins/rockboy/cpu.h @@ -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 diff --git a/apps/plugins/rockboy/cpucore.h b/apps/plugins/rockboy/cpucore.h new file mode 100644 index 0000000000..361c106dab --- /dev/null +++ b/apps/plugins/rockboy/cpucore.h @@ -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, +}; + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/cpuregs.h b/apps/plugins/rockboy/cpuregs.h new file mode 100644 index 0000000000..0d09908cc3 --- /dev/null +++ b/apps/plugins/rockboy/cpuregs.h @@ -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__ */ + + diff --git a/apps/plugins/rockboy/debug.c b/apps/plugins/rockboy/debug.c new file mode 100644 index 0000000000..d0e106ba94 --- /dev/null +++ b/apps/plugins/rockboy/debug.c @@ -0,0 +1,699 @@ + + +#include + +#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--; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/defs.h b/apps/plugins/rockboy/defs.h new file mode 100644 index 0000000000..4c520ef698 --- /dev/null +++ b/apps/plugins/rockboy/defs.h @@ -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 + diff --git a/apps/plugins/rockboy/emu.c b/apps/plugins/rockboy/emu.c new file mode 100644 index 0000000000..b6f2de779a --- /dev/null +++ b/apps/plugins/rockboy/emu.c @@ -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(); + } +} + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/emu.h b/apps/plugins/rockboy/emu.h new file mode 100644 index 0000000000..979b33cc54 --- /dev/null +++ b/apps/plugins/rockboy/emu.h @@ -0,0 +1,2 @@ +void emu_reset(void); +void emu_run(void); diff --git a/apps/plugins/rockboy/events.c b/apps/plugins/rockboy/events.c new file mode 100644 index 0000000000..5558dd86b2 --- /dev/null +++ b/apps/plugins/rockboy/events.c @@ -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; +} + + + + + + + + diff --git a/apps/plugins/rockboy/exports.c b/apps/plugins/rockboy/exports.c new file mode 100644 index 0000000000..43504f4b4f --- /dev/null +++ b/apps/plugins/rockboy/exports.c @@ -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);*/ +} diff --git a/apps/plugins/rockboy/exports.h b/apps/plugins/rockboy/exports.h new file mode 100644 index 0000000000..8d787c0945 --- /dev/null +++ b/apps/plugins/rockboy/exports.h @@ -0,0 +1,2 @@ +void init_exports(void); +void show_exports(void); diff --git a/apps/plugins/rockboy/fastmem.c b/apps/plugins/rockboy/fastmem.c new file mode 100644 index 0000000000..ffb0ed5371 --- /dev/null +++ b/apps/plugins/rockboy/fastmem.c @@ -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 + diff --git a/apps/plugins/rockboy/fastmem.h b/apps/plugins/rockboy/fastmem.h new file mode 100644 index 0000000000..7ab447fd2a --- /dev/null +++ b/apps/plugins/rockboy/fastmem.h @@ -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 diff --git a/apps/plugins/rockboy/fb.h b/apps/plugins/rockboy/fb.h new file mode 100644 index 0000000000..97d16ae1b1 --- /dev/null +++ b/apps/plugins/rockboy/fb.h @@ -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 + + + + diff --git a/apps/plugins/rockboy/hw.c b/apps/plugins/rockboy/hw.c new file mode 100644 index 0000000000..c287e24f8a --- /dev/null +++ b/apps/plugins/rockboy/hw.c @@ -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; +} + + + + + + + diff --git a/apps/plugins/rockboy/hw.h b/apps/plugins/rockboy/hw.h new file mode 100644 index 0000000000..d05fb51194 --- /dev/null +++ b/apps/plugins/rockboy/hw.h @@ -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 diff --git a/apps/plugins/rockboy/inflate.c b/apps/plugins/rockboy/inflate.c new file mode 100644 index 0000000000..6818749187 --- /dev/null +++ b/apps/plugins/rockboy/inflate.c @@ -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 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 ) + lb = q-cnt; + answer |= ((unsigned int)((data[(p+cnt)/8]>>ob)&((1U<>(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= 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> 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].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(); +} + + + + + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/lcd.h b/apps/plugins/rockboy/lcd.h new file mode 100644 index 0000000000..9442b56cf0 --- /dev/null +++ b/apps/plugins/rockboy/lcd.h @@ -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); diff --git a/apps/plugins/rockboy/lcdc.c b/apps/plugins/rockboy/lcdc.c new file mode 100644 index 0000000000..c82b828354 --- /dev/null +++ b/apps/plugins/rockboy/lcdc.c @@ -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; + } + } +} + + + + + + + diff --git a/apps/plugins/rockboy/lcdc.h b/apps/plugins/rockboy/lcdc.h new file mode 100644 index 0000000000..c5edc6c065 --- /dev/null +++ b/apps/plugins/rockboy/lcdc.h @@ -0,0 +1,4 @@ +void stat_trigger(void); +void stat_write(byte b); +void lcdc_change(byte b); +void lcdc_trans(void); diff --git a/apps/plugins/rockboy/loader.c b/apps/plugins/rockboy/loader.c new file mode 100644 index 0000000000..ad7c309bd8 --- /dev/null +++ b/apps/plugins/rockboy/loader.c @@ -0,0 +1,383 @@ + +#include +#include + + +#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 +}; + + + + + + + + + diff --git a/apps/plugins/rockboy/loader.h b/apps/plugins/rockboy/loader.h new file mode 100644 index 0000000000..45ee5e705d --- /dev/null +++ b/apps/plugins/rockboy/loader.h @@ -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 + + diff --git a/apps/plugins/rockboy/main.c b/apps/plugins/rockboy/main.c new file mode 100644 index 0000000000..ea5d628f04 --- /dev/null +++ b/apps/plugins/rockboy/main.c @@ -0,0 +1,83 @@ +#include +#include + +#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; +} diff --git a/apps/plugins/rockboy/mem.c b/apps/plugins/rockboy/mem.c new file mode 100644 index 0000000000..2e1e0e7154 --- /dev/null +++ b/apps/plugins/rockboy/mem.c @@ -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(); +} + + + + + + + diff --git a/apps/plugins/rockboy/mem.h b/apps/plugins/rockboy/mem.h new file mode 100644 index 0000000000..7926e2eda9 --- /dev/null +++ b/apps/plugins/rockboy/mem.h @@ -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 + + + diff --git a/apps/plugins/rockboy/noise.h b/apps/plugins/rockboy/noise.h new file mode 100644 index 0000000000..037499eef3 --- /dev/null +++ b/apps/plugins/rockboy/noise.h @@ -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 + diff --git a/apps/plugins/rockboy/nosound.c b/apps/plugins/rockboy/nosound.c new file mode 100644 index 0000000000..a0c9b17f15 --- /dev/null +++ b/apps/plugins/rockboy/nosound.c @@ -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; +} + + + + + diff --git a/apps/plugins/rockboy/palette.c b/apps/plugins/rockboy/palette.c new file mode 100644 index 0000000000..5c5083d247 --- /dev/null +++ b/apps/plugins/rockboy/palette.c @@ -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); +} + + + + + diff --git a/apps/plugins/rockboy/palette.h b/apps/plugins/rockboy/palette.h new file mode 100644 index 0000000000..05b093be77 --- /dev/null +++ b/apps/plugins/rockboy/palette.h @@ -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); diff --git a/apps/plugins/rockboy/pcm.h b/apps/plugins/rockboy/pcm.h new file mode 100644 index 0000000000..3719933520 --- /dev/null +++ b/apps/plugins/rockboy/pcm.h @@ -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 + + diff --git a/apps/plugins/rockboy/rc.h b/apps/plugins/rockboy/rc.h new file mode 100644 index 0000000000..217b05f5c6 --- /dev/null +++ b/apps/plugins/rockboy/rc.h @@ -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 + + + + diff --git a/apps/plugins/rockboy/rccmds.c b/apps/plugins/rockboy/rccmds.c new file mode 100644 index 0000000000..c9375b69b5 --- /dev/null +++ b/apps/plugins/rockboy/rccmds.c @@ -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; +} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/rcvars.c b/apps/plugins/rockboy/rcvars.c new file mode 100644 index 0000000000..e37657dbad --- /dev/null +++ b/apps/plugins/rockboy/rcvars.c @@ -0,0 +1,233 @@ + + + + +#include +#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)); +} + + + + + + + + diff --git a/apps/plugins/rockboy/regs.h b/apps/plugins/rockboy/regs.h new file mode 100644 index 0000000000..4457fd90ed --- /dev/null +++ b/apps/plugins/rockboy/regs.h @@ -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 + + + + + diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c new file mode 100644 index 0000000000..c9788e2438 --- /dev/null +++ b/apps/plugins/rockboy/rockboy.c @@ -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; +} diff --git a/apps/plugins/rockboy/rockmacros.h b/apps/plugins/rockboy/rockmacros.h new file mode 100644 index 0000000000..63f9b106e9 --- /dev/null +++ b/apps/plugins/rockboy/rockmacros.h @@ -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 + +/* 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_) + diff --git a/apps/plugins/rockboy/rtc.c b/apps/plugins/rockboy/rtc.c new file mode 100644 index 0000000000..99e71dcfae --- /dev/null +++ b/apps/plugins/rockboy/rtc.c @@ -0,0 +1,135 @@ + + + +#include "rockmacros.h" +#include + +#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(); */ +} + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/rtc.h b/apps/plugins/rockboy/rtc.h new file mode 100644 index 0000000000..2665cd81c3 --- /dev/null +++ b/apps/plugins/rockboy/rtc.h @@ -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 diff --git a/apps/plugins/rockboy/save.c b/apps/plugins/rockboy/save.c new file mode 100644 index 0000000000..bb9f905b8f --- /dev/null +++ b/apps/plugins/rockboy/save.c @@ -0,0 +1,286 @@ + + +#include "rockmacros.h" +#include + +#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); +} + + + + + + + + + + + + + + + + + + + diff --git a/apps/plugins/rockboy/save.h b/apps/plugins/rockboy/save.h new file mode 100644 index 0000000000..01b3b14f05 --- /dev/null +++ b/apps/plugins/rockboy/save.h @@ -0,0 +1,4 @@ +void loadstate(int fd); +void savestate(int fd); +void state_save(int n); +void state_load(int n); diff --git a/apps/plugins/rockboy/sound.c b/apps/plugins/rockboy/sound.c new file mode 100644 index 0000000000..edf31d81b7 --- /dev/null +++ b/apps/plugins/rockboy/sound.c @@ -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; + } +} + + + + diff --git a/apps/plugins/rockboy/sound.h b/apps/plugins/rockboy/sound.h new file mode 100644 index 0000000000..1a24ee600f --- /dev/null +++ b/apps/plugins/rockboy/sound.h @@ -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 + diff --git a/apps/plugins/rockboy/split.c b/apps/plugins/rockboy/split.c new file mode 100644 index 0000000000..5d8af08ee1 --- /dev/null +++ b/apps/plugins/rockboy/split.c @@ -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; +} + + + + + diff --git a/apps/plugins/rockboy/split.h b/apps/plugins/rockboy/split.h new file mode 100644 index 0000000000..a371430946 --- /dev/null +++ b/apps/plugins/rockboy/split.h @@ -0,0 +1 @@ +int splitline(char **argv, int max, char *line); diff --git a/apps/plugins/rockboy/sys_rockbox.c b/apps/plugins/rockboy/sys_rockbox.c new file mode 100644 index 0000000000..43cd8ad29e --- /dev/null +++ b/apps/plugins/rockboy/sys_rockbox.c @@ -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); +} diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config index 2290a8e635..08bd7ff939 100644 --- a/apps/plugins/viewers.config +++ b/apps/plugins/viewers.config @@ -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 -- cgit v1.2.3