summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILDING18
-rw-r--r--CHANGES8
-rw-r--r--COPYING341
-rw-r--r--Makefile137
-rw-r--r--README22
-rw-r--r--fat_patch.sh4
-rw-r--r--include/config.h55
-rw-r--r--include/ds81_debug.h43
-rw-r--r--include/framebuffer.h90
-rw-r--r--include/gui.h32
-rw-r--r--include/keyboard.h142
-rw-r--r--include/monitor.h29
-rw-r--r--include/snapshot.h37
-rw-r--r--include/stream.h35
-rw-r--r--include/tapes.h27
-rw-r--r--include/textmode.h37
-rw-r--r--include/touchwrap.h38
-rw-r--r--include/z80.h257
-rw-r--r--include/z80_config.h59
-rw-r--r--include/z80_private.h276
-rw-r--r--include/zx81.h93
-rw-r--r--instructions.txt180
-rw-r--r--mkrelease.sh16
-rw-r--r--source/config.c145
-rw-r--r--source/framebuffer.c386
-rw-r--r--source/gui.c862
-rw-r--r--source/keyboard.c483
-rw-r--r--source/main.c461
-rw-r--r--source/monitor.c362
-rw-r--r--source/snapshot.c195
-rw-r--r--source/stream.c86
-rw-r--r--source/tapes.c282
-rw-r--r--source/textmode.c157
-rw-r--r--source/touchwrap.c55
-rw-r--r--source/z80.c394
-rw-r--r--source/z80_decode.c2533
-rw-r--r--source/z80_dis.c2494
-rw-r--r--source/zx81.c1171
-rw-r--r--version1
39 files changed, 12043 insertions, 0 deletions
diff --git a/BUILDING b/BUILDING
new file mode 100644
index 0000000..e0516fa
--- /dev/null
+++ b/BUILDING
@@ -0,0 +1,18 @@
+Build Instructions
+------------------
+
+As this uses the example makefiles from devkitpro, all that is required is
+a 'make' command in the top level directory:
+
+$ make
+
+
+By default FAT support will be initialised. To prevent this you need to supply
+additional flag settings:
+
+$ make ADDITIONAL_CFLAGS="-DDSVIC_DISABLE_FAT"
+
+
+There is a script mkrelease.sh which simply makes a FAT and non-FAT version of
+DSVIC for release. This script also sets the displayed version number to the
+string contained in the 'version' file (by default a time-stamp is produced).
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..98dc169
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,8 @@
++ Completed
+* In progress
+- Abandoned.
+
+Initial work:
+ * Basic CPU emulation
+ * Basic VIC emulation
+ * Basic user interface
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..abd3cf7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..00d7675
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,137 @@
+# This is a generic DS makefile, as taken from the libnds example programs.
+#
+
+#-------------------------------------------------------------------------------
+.SUFFIXES:
+#-------------------------------------------------------------------------------
+
+ifeq ($(strip $(DEVKITARM)),)
+$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
+endif
+
+include $(DEVKITARM)/ds_rules
+
+#-------------------------------------------------------------------------------
+# TARGET is the name of the output
+# BUILD is the directory where object files & intermediate files will be placed
+# SOURCES is a list of directories containing source code
+# INCLUDES is a list of directories containing extra header files
+#-------------------------------------------------------------------------------
+TARGET := $(shell basename $(CURDIR))
+BUILD := build
+SOURCES := source gbagfx
+DATA := data
+INCLUDES := include gbagfx
+
+#-------------------------------------------------------------------------------
+# options for code generation
+#-------------------------------------------------------------------------------
+ARCH := -mthumb -mthumb-interwork
+
+# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD
+# *insists* it has a FPU or VFP, and it won't take no for an answer!
+CFLAGS := -g -Wall -O2\
+ -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
+ -ffast-math \
+ $(ARCH) \
+ $(ADDITIONAL_CFLAGS)
+
+CFLAGS += $(INCLUDE) -DARM9
+CXXFLAGS := $(CFLAGS)
+
+ASFLAGS := -g $(ARCH)
+LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -mno-fpu -Wl,-Map,$(notdir $*.map)
+
+#-------------------------------------------------------------------------------
+# any extra libraries we wish to link with the project
+#-------------------------------------------------------------------------------
+LIBS := -lfat -lnds9
+
+
+#-------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# include and lib
+#-------------------------------------------------------------------------------
+LIBDIRS := $(LIBNDS)
+
+#-------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add
+# additional rules for different file extensions
+#-------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#-------------------------------------------------------------------------------
+
+export OUTPUT := $(CURDIR)/$(TARGET)
+
+export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+ $(foreach dir,$(DATA),$(CURDIR)/$(dir))
+
+export DEPSDIR := $(CURDIR)/$(BUILD)
+
+CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(CPPFILES)),)
+#---------------------------------------------------------------------------------
+ export LD := $(CC)
+#---------------------------------------------------------------------------------
+else
+#---------------------------------------------------------------------------------
+ export LD := $(CXX)
+#---------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------
+
+export OFILES := $(addsuffix .o,$(BINFILES)) \
+ $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ -I$(CURDIR)/$(BUILD)
+
+export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+
+.PHONY: $(BUILD) clean
+
+#---------------------------------------------------------------------------------
+$(BUILD):
+ @[ -d $@ ] || mkdir -p $@
+ @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+#---------------------------------------------------------------------------------
+clean:
+ @echo clean ...
+ @rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(TARGET).arm9 $(TARGET).ds.gba
+
+
+#---------------------------------------------------------------------------------
+else
+
+DEPENDS := $(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+$(OUTPUT).ds.gba : $(OUTPUT).nds
+$(OUTPUT).nds : $(OUTPUT).arm9
+$(OUTPUT).arm9 : $(OUTPUT).elf
+$(OUTPUT).elf : $(OFILES)
+
+#---------------------------------------------------------------------------------
+%.bin.o : %.bin
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(bin2o)
+
+
+-include $(DEPENDS)
+
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
diff --git a/README b/README
new file mode 100644
index 0000000..f92618c
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+ DS81
+ Copyright 2006 Ian Cowburn
+ ianc@noddybox.co.uk
+
+The code to DS81 is released under the GNU General Public License. See COPYING
+for details.
+
+Other included software is provided in good faith, is not released under the
+GNU General Public License, and is copyright their respective authors. If any
+of these authors disagree with this distribution of their work then it will be
+gladly removed.
+
+ZX81 BASIC ROM (c) 1981 Nine Tiles Networks LTD
+
+3D Monster Maze (c) 1983 Malcolm E. Evans
+
+Mazogs, City Patrol and Sabotage (c) 1981-1982 Don Priestley
+
+
+See the file INSTRUCTIONS.TXT for instructions on use.
+See the file BUILDING for instructions on building the sources.
+See the file CHANGES for recent changes.
diff --git a/fat_patch.sh b/fat_patch.sh
new file mode 100644
index 0000000..ec373f9
--- /dev/null
+++ b/fat_patch.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+make
+dlditool.exe ../DLDI/mmcf.dldi dsvic.nds
+dlditool.exe ../DLDI/mmcf.dldi dsvic.ds.gba
diff --git a/include/config.h b/include/config.h
new file mode 100644
index 0000000..3b99da6
--- /dev/null
+++ b/include/config.h
@@ -0,0 +1,55 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: config.h 65 2008-12-12 00:19:08Z ianc $
+*/
+#ifndef DS81_CONFIG_H
+#define DS81_CONFIG_H
+
+/* Default snapshot dir
+*/
+#define DEFAULT_SNAPDIR "/ZX81SNAP/"
+
+typedef enum
+{
+ DS81_STICKY_SHIFT,
+ DS81_AVERAGE_TOUCHSCREEN,
+ DS81_STATIC_RAM_AT_0x2000,
+ DS81_ALLOW_TAPE_SAVE,
+ DS81_LOAD_DEFAULT_SNAPSHOT,
+ DS81_NUM_CONFIG_ITEMS
+} DS81_ConfigItem;
+
+/* Returns TRUE if config loaded from FAT device
+*/
+int LoadConfig(void);
+
+/* Returns TRUE if config saved to FAT device
+*/
+int SaveConfig(void);
+
+/* Gets a description for a config item.
+*/
+const char *ConfigDesc(DS81_ConfigItem item);
+
+/* Table of configs. Done like this for simple performance reasons.
+*/
+extern int DS81_Config[/*DS81_ConfigItem item*/];
+
+#endif /* DS81_CONFIG_H */
diff --git a/include/ds81_debug.h b/include/ds81_debug.h
new file mode 100644
index 0000000..fa79526
--- /dev/null
+++ b/include/ds81_debug.h
@@ -0,0 +1,43 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: ds81_debug.h 61 2008-11-03 17:07:32Z ianc $
+*/
+#ifndef DS81_DEBUG_H
+#define DS81_DEBUG_H
+
+#include "gui.h"
+#include "framebuffer.h"
+
+#define DS81_DEBUG(fmt, args...) \
+ do \
+ { \
+ char tempdebug[512]; \
+ sprintf(tempdebug, fmt, ## args); \
+ GUI_Alert(FALSE, tempdebug); \
+ } while(0)
+
+#define DS81_DEBUG_STATUS(fmt, args...) \
+ do \
+ { \
+ FB_FillBox(0,184,256,8,COL_DARKGREY); \
+ FB_printf(0,184,COL_WHITE,COL_DARKGREY, fmt , ## args); \
+ } while(0)
+
+#endif /* DS81_DEBUG_H */
diff --git a/include/framebuffer.h b/include/framebuffer.h
new file mode 100644
index 0000000..695bf44
--- /dev/null
+++ b/include/framebuffer.h
@@ -0,0 +1,90 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: framebuffer.h 43 2007-03-12 00:59:51Z ianc $
+*/
+#ifndef DS81_FRAMEBUFFER_H
+#define DS81_FRAMEBUFFER_H
+
+/* Predefined colours.
+*/
+typedef enum
+{
+ COL_TRANSPARENT = -1,
+ COL_BLACK = 0,
+ COL_WHITE = 240,
+ COL_RED = 241,
+ COL_GREEN = 242,
+ COL_BLUE = 243,
+ COL_GUISELECT = 244,
+ COL_GREY = 245,
+ COL_LIGHTGREY = 246,
+ COL_DARKGREY = 247,
+ COL_YELLOW = 248
+} FB_Colour;
+
+
+/* Initialise 'framebuffer' code. vram is where the 8-bit framebuffer is.
+ palette is the palette to use/set.
+*/
+void FB_Init(uint16 *vram, uint16 *palette);
+
+/* Gives access to the parameters of the frame buffer.
+*/
+uint16 *FB_VRAM(void);
+uint16 *FB_PALETTE(void);
+
+/* Load the internal framebuffer font as a set of ASCII tiles (starting with
+ space) at tiles. The tiles will use colour COL_WHITE.
+*/
+void FB_LoadASCIITiles(uint16 *tiles);
+
+/* Print the text into the framebuffer.
+*/
+void FB_Print(const char *text, int x, int y,
+ FB_Colour colour, FB_Colour paper);
+void FB_Centre(const char *text, int y,
+ FB_Colour colour, FB_Colour paper);
+void FB_printf(int x, int y, FB_Colour colour, FB_Colour paper,
+ const char *format, ...);
+
+/* Lines and boxes.
+*/
+void FB_HLine(int x1, int x2, int y, FB_Colour colour);
+void FB_VLine(int x, int y1, int y2, FB_Colour colour);
+void FB_Box(int x, int y, int w, int h, FB_Colour colour);
+void FB_FillBox(int x, int y, int w, int h, FB_Colour colour);
+
+/* Clear to background
+*/
+void FB_Clear(void);
+
+/* Draw the image. The image must be an 8-bit image, but with only the first
+ 16 palette entries used. Just to complicate matters!
+
+ The image is assumed to be an even number of pixels wide. Also the passed
+ X co-ord will be forced even.
+
+ offset is used to give an offset into the palette to place colours from the
+ image. Palette entries 1 - 128 will always be safe to use (these routines
+ will never use them).
+*/
+void FB_Blit(sImage *img, int x, int y, int offset);
+
+#endif /* DS81_FRAMEBUFFER_H */
diff --git a/include/gui.h b/include/gui.h
new file mode 100644
index 0000000..06c68c3
--- /dev/null
+++ b/include/gui.h
@@ -0,0 +1,32 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: gui.h 64 2008-12-05 00:37:26Z ianc $
+*/
+#ifndef DS81_GUI_H
+#define DS81_GUI_H
+
+int GUI_Menu(const char *opts[]);
+void GUI_Alert(int fatal, const char *text);
+void GUI_Config(void);
+int GUI_FileSelect(char pwd[], char selected_file[], const char *filter);
+int GUI_InputName(const char *prompt, const char *ext,
+ char name[], int maxlen);
+
+#endif /* DS81_GUI_H */
diff --git a/include/keyboard.h b/include/keyboard.h
new file mode 100644
index 0000000..7b0e8b3
--- /dev/null
+++ b/include/keyboard.h
@@ -0,0 +1,142 @@
+/*
+ ds81 - Nintendo ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: keyboard.h 61 2008-11-03 17:07:32Z ianc $
+*/
+#ifndef DS81_KEYBOARD_H
+#define DS81_KEYBOARD_H
+
+#include <stdio.h>
+
+/* Note that the first 40 values purposefully are the keyboard matrix keys.
+ Note also that they are in display order, not matrix order.
+*/
+typedef enum
+{
+ SK_1,
+ SK_2,
+ SK_3,
+ SK_4,
+ SK_5,
+
+ SK_6,
+ SK_7,
+ SK_8,
+ SK_9,
+ SK_0,
+
+ SK_Q,
+ SK_W,
+ SK_E,
+ SK_R,
+ SK_T,
+
+ SK_Y,
+ SK_U,
+ SK_I,
+ SK_O,
+ SK_P,
+
+ SK_A,
+ SK_S,
+ SK_D,
+ SK_F,
+ SK_G,
+
+ SK_H,
+ SK_J,
+ SK_K,
+ SK_L,
+ SK_NEWLINE,
+
+ SK_SHIFT,
+ SK_Z,
+ SK_X,
+ SK_C,
+ SK_V,
+
+ SK_B,
+ SK_N,
+ SK_M,
+ SK_PERIOD,
+ SK_SPACE,
+
+ SK_ABOUT,
+ SK_CONFIG,
+ SK_PAD_UP,
+ SK_PAD_DOWN,
+ SK_PAD_LEFT,
+ SK_PAD_RIGHT,
+ SK_PAD_A,
+ SK_PAD_B,
+ SK_PAD_X,
+ SK_PAD_Y,
+ SK_PAD_R,
+ SK_PAD_L,
+ SK_PAD_START,
+ SK_PAD_SELECT,
+
+ NUM_SOFT_KEYS
+} SoftKey;
+
+typedef struct
+{
+ SoftKey key;
+ int pressed;
+} SoftKeyEvent;
+
+
+/* Display the soft keyboard.
+*/
+void SK_DisplayKeyboard(void);
+
+/* If dim is TRUE, then the keyboard is displayed with reduced brightness along
+ with the selection box. This routine simply adjusts the palette, and
+ assumes that the keyboard is already on display.
+*/
+void SK_SetDisplayBrightness(int dim);
+
+/* Returns TRUE while there are still key events for this cycle
+*/
+int SK_GetEvent(SoftKeyEvent *ev);
+
+/* Returns TRUE while there are still key events for this cycle. Unlike
+ SK_GetEvent this does not do joypad mappings.
+*/
+int SK_GetBareEvent(SoftKeyEvent *ev);
+
+/* Sets a key to be 'sticky'.
+*/
+void SK_SetSticky(SoftKey key, int is_sticky);
+
+/* Map the joypad to keys. Note that when mapped that both the key and the
+ joypad code will be generated.
+*/
+void SK_DefinePad(SoftKey pad, SoftKey key);
+
+/* Returns a name for key symbols.
+*/
+const char *SK_KeyName(SoftKey pad);
+
+/* Allows the keyboard to save/restore its state from a stream
+*/
+void SK_SaveSnapshot(FILE *fp);
+void SK_LoadSnapshot(FILE *fp);
+
+#endif /* DS81_KEYBOARD_H */
diff --git a/include/monitor.h b/include/monitor.h
new file mode 100644
index 0000000..34f34e3
--- /dev/null
+++ b/include/monitor.h
@@ -0,0 +1,29 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2007 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: monitor.h 44 2007-03-14 01:00:54Z ianc $
+*/
+#ifndef DS81_MONITOR_H
+#define DS81_MONITOR_H
+
+#include "z80.h"
+
+void MachineCodeMonitor(Z80 *cpu);
+
+#endif /* DS81_MONITOR_H */
diff --git a/include/snapshot.h b/include/snapshot.h
new file mode 100644
index 0000000..38ec989
--- /dev/null
+++ b/include/snapshot.h
@@ -0,0 +1,37 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: snapshot.h 65 2008-12-12 00:19:08Z ianc $
+*/
+#ifndef DS81_SNAPSHOT_H
+#define DS81_SNAPSHOT_H
+
+#include "z80.h"
+
+typedef enum
+{
+ SNAP_TYPE_FULL,
+ SNAP_TYPE_KEYBOARD
+} SnapshotType;
+
+void SNAP_Enable(int enable);
+void SNAP_Save(Z80 *cpu, SnapshotType type);
+void SNAP_Load(Z80 *cpu, const char *optional_name, SnapshotType type);
+
+#endif /* DS81_SNAPSHOT_H */
diff --git a/include/stream.h b/include/stream.h
new file mode 100644
index 0000000..2c3b915
--- /dev/null
+++ b/include/stream.h
@@ -0,0 +1,35 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: stream.h 64 2008-12-05 00:37:26Z ianc $
+*/
+#ifndef DS81_STREAM_H
+#define DS81_STREAM_H
+
+#include <stdio.h>
+
+void PUT_Byte(FILE *fp, unsigned char c);
+void PUT_Long(FILE *fp, long l);
+void PUT_ULong(FILE *fp, unsigned long l);
+
+unsigned char GET_Byte(FILE *fp);
+long GET_Long(FILE *fp);
+unsigned long GET_ULong(FILE *fp);
+
+#endif /* DS81_STREAM_H */
diff --git a/include/tapes.h b/include/tapes.h
new file mode 100644
index 0000000..520e26e
--- /dev/null
+++ b/include/tapes.h
@@ -0,0 +1,27 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: tapes.h 13 2006-10-12 16:38:57Z ianc $
+*/
+#ifndef DS81_TAPES_H
+#define DS81_TAPES_H
+
+void SelectTape(void);
+
+#endif /* DS81_TAPES_H */
diff --git a/include/textmode.h b/include/textmode.h
new file mode 100644
index 0000000..1e069fe
--- /dev/null
+++ b/include/textmode.h
@@ -0,0 +1,37 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2007 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: textmode.h 41 2007-03-01 00:36:54Z ianc $
+*/
+#ifndef DS81_TEXTMODE_H
+#define DS81_TEXTMODE_H
+
+/* Note that the co-ords are into the map -- the user is free to use this and
+ move the map around, scale it, blend it, do want they want with it...
+
+ The routines assume they can write into this map using the ASCII code
+ with 32 subtracted for each char.
+*/
+void TM_Init(uint16 *vram, int map_width, int map_height, int map_is_rotation);
+
+void TM_Cls(void);
+void TM_Put(int x, int y, const char *str);
+void TM_printf(int x, int y, const char *format, ...);
+
+#endif /* DS81_TEXTMODE_H */
diff --git a/include/touchwrap.h b/include/touchwrap.h
new file mode 100644
index 0000000..5a0fe21
--- /dev/null
+++ b/include/touchwrap.h
@@ -0,0 +1,38 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: touchwrap.h 35 2007-02-16 01:10:41Z ianc $
+*/
+#ifndef DS81_TOUCHWRAP_H
+#define DS81_TOUCHWRAP_H
+
+/* Don't know whether I have a problem with my DS or the library, but sometimes
+ the touchscreen value is off (one co-ord generally completely out).
+
+ To alleviate this, and as this is a simple touch screen keyboard, allow
+ touchs to be averaged if the config says so. And averaged touch just means
+ that two touchs have to happen within 5 pixels on X and Y before being
+ allowed.
+
+ If not configured to average, this simply reads the touchscreen position
+ and returns true.
+*/
+int AllowTouch(touchPosition *tp);
+
+#endif /* DS81_TOUCHWRAP_H */
diff --git a/include/z80.h b/include/z80.h
new file mode 100644
index 0000000..a00c8b0
--- /dev/null
+++ b/include/z80.h
@@ -0,0 +1,257 @@
+/*
+
+ z80 - Z80 emulation
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80.h 61 2008-11-03 17:07:32Z ianc $
+
+*/
+
+#ifndef Z80_H
+#define Z80_H "$Id: z80.h 61 2008-11-03 17:07:32Z ianc $"
+
+#include <stdio.h>
+
+/* Configuration
+*/
+#include "z80_config.h"
+
+
+/* ---------------------------------------- TYPES
+*/
+
+/* Large unsigned type
+*/
+typedef unsigned long Z80Val;
+
+
+/* 8-bit type. The emulation will exit with code 2 if this isn't 8 bits.
+*/
+typedef unsigned char Z80Byte;
+
+
+/* 8-bit signed type. The emulation will exit with code 2 if this isn't 8 bits.
+*/
+typedef signed char Z80Relative;
+
+
+/* 16-bit type. The emulation will exit with code 2 if this isn't 16 bits.
+*/
+typedef unsigned short Z80Word;
+
+
+/* A Z80 16-bit register. To access the HI/LO component use the indexes
+ Z80_HI_WORD and Z80_LO_WORD which will be initialised once Z80Init has been
+ called.
+*/
+typedef union
+{
+ Z80Word w;
+ Z80Byte b[2];
+} Z80Reg;
+
+extern int Z80_HI_WORD;
+extern int Z80_LO_WORD;
+
+
+/* The processor
+*/
+struct Z80Private;
+
+typedef struct
+{
+ Z80Word PC;
+
+ Z80Reg AF;
+ Z80Reg BC;
+ Z80Reg DE;
+ Z80Reg HL;
+
+ Z80Word AF_;
+ Z80Word BC_;
+ Z80Word DE_;
+ Z80Word HL_;
+
+ Z80Reg IX;
+ Z80Reg IY;
+
+ Z80Word SP;
+
+ Z80Byte IFF1;
+ Z80Byte IFF2;
+ Z80Byte IM;
+ Z80Byte I;
+ Z80Byte R;
+
+ struct Z80Private *priv;
+} Z80;
+
+
+/* Interfaces used to handle memory
+*/
+typedef Z80Byte (*Z80ReadMemory)(Z80 *cpu, Z80Word address);
+typedef void (*Z80WriteMemory)(Z80 *cpu, Z80Word address, Z80Byte value);
+
+
+/* Interfaces needed to handle ports (IN/OUT commands)
+*/
+typedef Z80Byte (*Z80ReadPort)(Z80 *cpu, Z80Word address);
+typedef void (*Z80WritePort)(Z80 *cpu, Z80Word address, Z80Byte value);
+
+
+/* Callback. Callback should return TRUE for processing to continue.
+*/
+typedef int (*Z80Callback)(Z80 *cpu, Z80Val data);
+
+
+/* Callback reasons
+
+ eZ80_Instruction Called before the initial fetch for an instruction
+ (called just to once no matter how many bytes the
+ instruction is made up of).
+
+ eZ80_EDHook Called when an undefined ED opcode is executed.
+
+ eZ80_Halt Called when the HALT instruction is hit and released.
+
+ eZ80_RETI Called when the RETI instruction is executed
+*/
+typedef enum
+{
+ eZ80_Instruction, /* data = no cycles since reset */
+ eZ80_EDHook, /* data = byte after ED opcode (only for NOP opcodes) */
+ eZ80_Halt, /* data = 1 halt raised, 0 halt cleared by int */
+ eZ80_RETI, /* data = ignored */
+ eZ80_NO_CALLBACK /* leave at end */
+} Z80CallbackReason;
+
+
+/* Flags in the F register
+*/
+typedef enum
+{
+ eZ80_Carry =0x01,
+ eZ80_Neg =0x02,
+ eZ80_PV =0x04,
+ eZ80_Hidden3 =0x08,
+ eZ80_HalfCarry =0x10,
+ eZ80_Hidden5 =0x20,
+ eZ80_Zero =0x40,
+ eZ80_Sign =0x80
+} Z80FlagRegister;
+
+
+/* Disassembly label -- only useful if ENABLE_DISASSEMBLER is set.
+ Labels are stored as an array, where a NULL in the label field marks
+ the end of the list.
+*/
+typedef struct
+{
+ Z80Word address;
+ const char *label;
+} Z80Label;
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+
+/* Initialises the processor.
+*/
+#ifdef ENABLE_ARRAY_MEMORY
+Z80 *Z80Init(Z80ReadPort read_port,
+ Z80WritePort write_port);
+#else
+Z80 *Z80Init(Z80ReadMemory read_memory,
+ Z80WriteMemory write_memory,
+ Z80ReadPort read_port,
+ Z80WritePort write_port,
+ Z80ReadMemory read_for_disassem);
+#endif
+
+
+/* Resets the processor.
+*/
+void Z80Reset(Z80 *cpu);
+
+
+/* Lodge a callback to be invoked after special events. Returns FALSE
+ if the callback couldn't be lodged (there is a max of 10 callbacks per
+ reason).
+*/
+int Z80LodgeCallback(Z80 *cpu,
+ Z80CallbackReason reason,
+ Z80Callback callback);
+
+
+/* Remove a callback. Does nothing if reason was not lodged with
+ Z80LodgeCallback()
+*/
+void Z80RemoveCallback(Z80 *cpu,
+ Z80CallbackReason reason,
+ Z80Callback callback);
+
+
+/* Cause an interrupt before the next opcode.
+ devbyte is the byte generated by the device (if any).
+*/
+void Z80Interrupt(Z80 *cpu, Z80Byte devbyte);
+
+
+/* Cause an NMI
+*/
+void Z80NMI(Z80 *cpu);
+
+
+/* Execute a single instruction. Returns FALSE if any callback returned
+ FALSE.
+*/
+int Z80SingleStep(Z80 *cpu);
+
+
+/* Executes until a callback returns FALSE (never returns otherwise)
+*/
+void Z80Exec(Z80 *cpu);
+
+
+/* Manipulate the cylce count of the Z80
+*/
+Z80Val Z80Cycles(Z80 *cpu);
+void Z80ResetCycles(Z80 *cpu, Z80Val cycles);
+
+
+/* Set address to label mappings for the disassembler
+*/
+void Z80SetLabels(Z80Label labels[]);
+
+
+/* Simple disassembly of memory accessed through read_for_disassem, or
+ Z80_MEMORY as appropriate. addr is updated on exit.
+*/
+const char *Z80Disassemble(Z80 *cpu, Z80Word *addr);
+
+/* Allows the CPU state to be saved/loaded from a stream
+*/
+void Z80SaveSnapshot(Z80 *cpu, FILE *fp);
+void Z80LoadSnapshot(Z80 *cpu, FILE *fp);
+
+#endif
+
+/* END OF FILE */
diff --git a/include/z80_config.h b/include/z80_config.h
new file mode 100644
index 0000000..467a789
--- /dev/null
+++ b/include/z80_config.h
@@ -0,0 +1,59 @@
+/*
+
+ z80 - Z80 emulation
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80_config.h 41 2007-03-01 00:36:54Z ianc $
+
+*/
+
+#ifndef Z80_CONFIG_H
+#define Z80_CONFIG_H "$Id: z80_config.h 41 2007-03-01 00:36:54Z ianc $"
+
+
+/* This file defines various compile-time configuration options
+ for the Z80 emulation
+*/
+
+
+/* Define this to enable the disassembly interface
+*/
+#define ENABLE_DISASSEM
+
+
+/* Define this to enable the array-based memory model. In this mode
+ an externally visible Z80Byte array called Z80_MEMORY must be
+ defined. The macros RAMBOT and RAMTOP define the writable area of
+ memory and must be changed accordingly.
+
+ In this mode the signature of Z80Init changes so that the memory functions
+ are not passed. ALL processor instances share the same memory.
+#define ENABLE_ARRAY_MEMORY
+*/
+
+#ifdef ENABLE_ARRAY_MEMORY
+#define RAMBOT 0x0000
+#define RAMTOP 0xffff
+#endif
+
+
+#endif
+
+/* END OF FILE */
diff --git a/include/z80_private.h b/include/z80_private.h
new file mode 100644
index 0000000..f444632
--- /dev/null
+++ b/include/z80_private.h
@@ -0,0 +1,276 @@
+/*
+
+ z80 - Z80 emulation
+
+ Copyright (C) 2006 Ian Cowburn (ianc@noddybox.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80_private.h 13 2006-10-12 16:38:57Z ianc $
+
+ Private macros for Z80
+
+*/
+
+#ifndef Z80_PRIVATE_H
+#define Z80_PRIVATE_H "$Id: z80_private.h 13 2006-10-12 16:38:57Z ianc $"
+
+#include "z80_config.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAX_PER_CALLBACK 10
+
+
+/* ---------------------------------------- TYPES
+*/
+
+struct Z80Private
+{
+ Z80Val cycle;
+
+ int halt;
+
+ Z80Byte shift;
+
+ int raise;
+ Z80Byte devbyte;
+ int nmi;
+
+#ifndef ENABLE_ARRAY_MEMORY
+ Z80ReadMemory disread;
+
+ Z80ReadMemory mread;
+ Z80WriteMemory mwrite;
+#endif
+
+ Z80ReadPort pread;
+ Z80WritePort pwrite;
+
+ Z80Callback callback[eZ80_NO_CALLBACK][MAX_PER_CALLBACK];
+
+ int last_cb;
+};
+
+#define PRIV cpu->priv
+
+
+/* ---------------------------------------- ARRAY MEMORY
+*/
+
+#ifdef ENABLE_ARRAY_MEMORY
+extern Z80Byte Z80_MEMORY[];
+#endif
+
+
+/* ---------------------------------------- MACROS
+*/
+
+/* NOTE: A lot of these macros assume you have a variable called 'cpu'
+ which is a pointer to Z80
+*/
+
+
+/* Invoke a callback class
+*/
+#define CALLBACK(r,d) do \
+ { \
+ int f; \
+ \
+ for(f=0;f<MAX_PER_CALLBACK;f++) \
+ if (PRIV->callback[r][f]) \
+ PRIV->last_cb &= \
+ PRIV->callback[r][f](cpu,d);\
+ } while(0)
+
+/* Flag register
+*/
+#define C_Z80 0x01
+#define N_Z80 0x02
+#define P_Z80 0x04
+#define V_Z80 P_Z80
+#define H_Z80 0x10
+#define Z_Z80 0x40
+#define S_Z80 0x80
+
+#define B3_Z80 0x08
+#define B5_Z80 0x20
+
+
+#define SET(v,b) (v)|=b
+#define CLR(v,b) (v)&=~(b)
+
+#define SETFLAG(f) SET(cpu->AF.b[LO],f)
+#define CLRFLAG(f) CLR(cpu->AF.b[LO],f)
+
+#ifdef ENABLE_ARRAY_MEMORY
+
+#define PEEK(addr) Z80_MEMORY[addr]
+
+static inline Z80Word PEEKW(Z80Word addr)
+{
+ return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8);
+}
+
+#define POKE(addr,val) do \
+ { \
+ Z80Word ba=addr; \
+ if (ba>=RAMBOT && ba<=RAMTOP) \
+ Z80_MEMORY[ba]=val; \
+ } while(0)
+
+#define POKEW(addr,val) do \
+ { \
+ Z80Word wa=addr; \
+ Z80Word wv=val; \
+ POKE(wa,wv); \
+ POKE(wa+1,wv>>8); \
+ } while(0)
+
+
+#define FETCH_BYTE (Z80_MEMORY[cpu->PC++])
+#define FETCH_WORD (cpu->PC+=2, \
+ Z80_MEMORY[cpu->PC-2]| \
+ ((Z80Word)Z80_MEMORY[cpu->PC-1]<<8))
+
+#else
+
+#define PEEK(addr) (PRIV->mread(cpu,addr))
+#define PEEKW(addr) FPEEKW(cpu,addr)
+
+#define POKE(addr,val) PRIV->mwrite(cpu,addr,val)
+#define POKEW(addr,val) FPOKEW(cpu,addr,val)
+
+#define FETCH_BYTE (PRIV->mread(cpu,cpu->PC++))
+#define FETCH_WORD (cpu->PC+=2,FPEEKW(cpu,cpu->PC-2))
+
+#endif
+
+
+#define IS_C (cpu->AF.b[LO]&C_Z80)
+#define IS_N (cpu->AF.b[LO]&N_Z80)
+#define IS_P (cpu->AF.b[LO]&P_Z80)
+#define IS_H (cpu->AF.b[LO]&H_Z80)
+#define IS_Z (cpu->AF.b[LO]&Z_Z80)
+#define IS_S (cpu->AF.b[LO]&S_Z80)
+
+#define CARRY IS_C
+
+#define IS_IX_IY (PRIV->shift==0xdd || PRIV->shift==0xfd)
+#define OFFSET(off) off=(IS_IX_IY ? (Z80Relative)FETCH_BYTE:0)
+
+#define TSTATE(n) PRIV->cycle+=n
+
+#define ADD_R(v) cpu->R=((cpu->R&0x80)|((cpu->R+(v))&0x7f))
+#define INC_R ADD_R(1)
+
+#ifdef ENABLE_ARRAY_MEMORY
+
+#define PUSH(REG) do \
+ { \
+ Z80Word pv=REG; \
+ cpu->SP-=2; \
+ POKE(cpu->SP,pv); \
+ POKE(cpu->SP+1,pv>>8); \
+ } while(0)
+
+#else
+
+#define PUSH(REG) do \
+ { \
+ Z80Word pushv=REG; \
+ cpu->SP-=2; \
+ PRIV->mwrite(cpu,cpu->SP,pushv); \
+ PRIV->mwrite(cpu,cpu->SP+1,pushv>>8);\
+ } while(0)
+#endif
+
+#define POP(REG) do \
+ { \
+ REG=PEEK(cpu->SP) | \
+ (Z80Word)PEEK(cpu->SP+1)<<8; \
+ cpu->SP+=2; \
+ } while(0)
+
+#define SETHIDDEN(res) cpu->AF.b[LO]=(cpu->AF.b[LO]&~(B3_Z80|B5_Z80))|\
+ ((res)&(B3_Z80|B5_Z80))
+
+#define CALL do \
+ { \
+ PUSH(cpu->PC+2); \
+ cpu->PC=PEEKW(cpu->PC); \
+ } while(0)
+
+#define NOCALL cpu->PC+=2
+#define JP cpu->PC=PEEKW(cpu->PC)
+#define NOJP cpu->PC+=2
+#define JR cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1
+#define NOJR cpu->PC++
+
+#define OUT(P,V) do \
+ { \
+ if (PRIV->pwrite) \
+ PRIV->pwrite(cpu,P,V); \
+ } while(0)
+
+#define IN(P) (PRIV->pread?PRIV->pread(cpu,P):0)
+
+
+
+/* ---------------------------------------- LABELS
+*/
+extern Z80Label *z80_labels;
+
+
+/* ---------------------------------------- GLOBAL GENERAL OPCODES/ROUTINES
+*/
+void Z80_Decode(Z80 *cpu, Z80Byte opcode);
+void Z80_InitialiseInternals(void);
+
+
+/* ---------------------------------------- DISASSEMBLY
+*/
+#ifdef ENABLE_DISASSEM
+typedef void (*DIS_OP_CALLBACK)(Z80 *z80, Z80Byte op, Z80Word *pc);
+
+extern DIS_OP_CALLBACK dis_CB_opcode[];
+extern DIS_OP_CALLBACK dis_DD_opcode[];
+extern DIS_OP_CALLBACK dis_DD_CB_opcode[];
+extern DIS_OP_CALLBACK dis_ED_opcode[];
+extern DIS_OP_CALLBACK dis_FD_opcode[];
+extern DIS_OP_CALLBACK dis_FD_CB_opcode[];
+extern DIS_OP_CALLBACK dis_opcode_z80[];
+
+const char *Z80_Dis_Printf(const char *format, ...);
+
+Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc);
+Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc);
+
+void Z80_Dis_Set(const char *op, const char *arg);
+const char *Z80_Dis_GetOp(void);
+const char *Z80_Dis_GetArg(void);
+#endif /* ENABLE_DISASSEM */
+
+#endif /* Z80_PRIVATE_H */
+
+/* END OF FILE */
diff --git a/include/zx81.h b/include/zx81.h
new file mode 100644
index 0000000..1f77448
--- /dev/null
+++ b/include/zx81.h
@@ -0,0 +1,93 @@
+/*
+
+ ds81 - Nintendo DS ZX81 emulator
+
+ Copyright (C) 2006 Ian Cowburn (ianc@noddybox.co.uk)
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Provides the emulation for the ZX81
+
+*/
+
+#ifndef DS81_ZX81_H
+#define DS81_ZX81_H
+
+#include <stdio.h>
+
+#include "z80.h"
+#include "keyboard.h"
+
+
+/* Initialise the ZX81
+*/
+void ZX81Init(uint16 *text_vram, uint16 *bitmap_vram, Z80 *z80);
+
+/* Handle keypresses
+*/
+void ZX81HandleKey(SoftKey k, int is_pressed);
+
+/* Enable fopen() loading of tape files
+*/
+void ZX81EnableFileSystem(int enable);
+
+/* Set a file to load from tape
+*/
+void ZX81SetTape(const Z80Byte *image, int len);
+
+/* Reset the 81
+*/
+void ZX81Reset(Z80 *z80);
+
+/* Tell the 81 that config may have changed.
+*/
+void ZX81Reconfigure(void);
+
+/* Displays a string on the ZX81's dislpay. The screen is cleared and the
+ string displayed with \n characters breaking the line.
+
+ Not all characters can be respresented by the ZX81, and the screen will be
+ lost on the next emulation update cycle.
+
+ The character '%' toggles inverse video.
+
+ ZX81SuspendDisplay() and ZX81ResumeDisplay() should be called so that the
+ ZX81 can set up its internals.
+*/
+void ZX81DisplayString(const char *p);
+void ZX81SuspendDisplay(void);
+void ZX81ResumeDisplay(void);
+
+/* Interfaces for the Z80
+*/
+Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr);
+void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val);
+Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port);
+void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val);
+
+#define ZX81ReadDisassem ZX81ReadMem
+
+/* Interfaces to allows the ZX81 to save/load itself as a snapshot to/from
+ a stream.
+*/
+void ZX81SaveSnapshot(FILE *fp);
+void ZX81LoadSnapshot(FILE *fp);
+
+#endif
+
+
+/* END OF FILE */
diff --git a/instructions.txt b/instructions.txt
new file mode 100644
index 0000000..f475a4e
--- /dev/null
+++ b/instructions.txt
@@ -0,0 +1,180 @@
+ DSVIC
+ ---------==============================---------
+
+ Copyright 2010 Ian Cowburn
+ ianc@noddybox.co.uk
+
+
+1. LICENSE
+----------
+
+ The code to DSVIC is released under the GNU General Public License. See
+ the text file COPYING for details.
+
+ Other included software is provided in good faith, is not released under
+ the GNU General Public License, and is copyright their respective authors.
+
+ VIC-20 ROM (c) 1981 Commodore Business Machines
+
+
+2. DSVIC
+--------
+
+ DSVIC is an emulation of a VIC-20 and is is supplied in two main forms,
+ as a native Nintendo DS executable and a version with a Gameboy Advance
+ wrapper (in case your Ninentdo DS homebrew device only supports running
+ GBA executables).
+
+ In addition to this two different versions are supplied, one which
+ initialises the FAT library and one which doesn't. They are identical save
+ for this, and separate ones are supplied in case the FAT library
+ initialisation causes problem on your homebrew device:
+
+ dsvic.nds - Nintendo DS version
+ dsvic.ds.gba - As above with a GBA wrapper.
+
+ dsvic-nofat.nds - Nintendo DS version; no FAT library initialisation.
+ dsvic-nofat.ds.gba - As above with a GBA wrapper.
+
+ I'm probably being overly paranoid there, but better safe than sorry.
+
+ In any of the following sections where files are mentioned it obviously
+ doesn't apply to the 'nofat' versions.
+
+
+3. Using DSVIC
+--------------
+
+ When run DSVIC displays a splash screen with copyright information and
+ whether the FAT library has been able to find a supported device for the
+ loading of external tapes.
+
+ Once the A button has been pressed the VIC-20 resets and displays itself
+ on the top screen, and a soft keyboard is displayed on the bottom, touch
+ sensitive, screen.
+
+ Also at this point, if so configured, a default memory snap will be loaded.
+ See the "Memory Snapshots" section for more details.
+
+ When using the soft keyboard by default the shift keys are 'sticky' and
+ once used will stay held down until pressed again.
+
+ At the bottom of the keyboard is an area where you can click to bring up a
+ menu. Either use the stylus, or the joypad and button A to select an
+ option from the following choices:
+
+ RESET VIC-20
+ This resets the emulated VIC-20.
+
+ SELECT CART
+ Selects the built-in cart to use (DSVIC has a number of VIC-20
+ cartridge games built into it). The next section has extra
+ information on the loading of games.
+
+ CONFIGURE
+ Lets you configure settings (see last section for settings).
+
+ If you press SELECT to exit the configuration screen then the
+ configuration is saved into the file /DSVIC.CFG which is read on
+ start-up.
+
+ SAVE MEMORY SNAPSHOT
+ Saves a memory snapshot. This option only works if a FAT-enabled
+ version of DSVIC is being used. See the "Memory Snapshot" section
+ for more details.
+
+ LOAD MEMORY SNAPSHOT
+ Loads a memory snapshot. This option only works if a FAT-enabled
+ version of DSVIC is being used. See the "Memory Snapshot" section
+ for more details.
+
+ CANCEL
+ Cancels the menu.
+
+
+
+4. Using the internal cartridges on DSVIC
+-----------------------------------------
+
+ Games on the VIC-20 were supplied on cassette or cartridge.
+
+ DSVIC includes a few cartridges that are selectable from the menu. Follow
+ the on-screen instructions to select the game. A quick description and
+ the controls to use are displayed on the top screen.
+
+
+5. Using external images on DSVIC
+---------------------------------
+
+ <TODO>
+
+ If you are using the version of DSVIC that allows the use of FAT devices,
+ and you device is supported, they you can load any old tape.
+
+ FAT support is via the new DLDI interface, so you may need to dynamically
+ link in the appropriate FAT driver. Details are available here:
+
+ http://chishm.drunkencoders.com/DLDI/index.html
+
+ Note that the default driver linked in is the Datel Max Media Dock
+ (Compact Flash) -- solely as that's what I have.
+
+ Simply place the .P file (VIC-20 games are usually distributed as .P files
+ that are simply an image of the memory that would have been dumped to tape)
+ and either put it in the root directory of the FAT device or in a directory
+ called VIC-20SNAP.
+
+ Alternatively if you can't remember the names of files, loading "*" will
+ give you with a file selector to select the tape file with.
+
+ It can't be at all guaranteed that all original VIC-20 games will work as
+ expected. After all, DSVIC isn't really a VIC-20.
+
+
+6. Configuration Options
+------------------------
+
+ STICKY SHIFT
+
+ This option allows you to decide whether the shift key on the soft
+ keyboard is sticky (toggles when you press it) or acts like the other
+ keys. You should never need to make it non-sticky unless a game needs
+ it.
+
+ <TODO>
+ ALLOW TAPE SAVE
+
+ If enabled this means that files saved with the SAVE command will
+ try and create a .P file in the VIC-20SNAP directory, or the root
+ directory. You can SAVE "*" to bring up the file selector.
+
+ If not enabled attempts to SAVE files from BASIC will be silently
+ ignored.
+ </TODO>
+
+ LOAD DEFAULT MEMORY SNAP
+
+ If enabled DSVIC will look for a memory snapshot called AUTO.V20 in
+ either the root directory or the VICSNAP directory.
+
+ See the "Memory Snapshot" section for more details on snapshots.
+
+
+8. Memory Snapshots
+-------------------
+
+ DSVIC supports basic memory snapshots. When you select "SAVE MEMORY
+ SNAPSHOT" from the main menu DSVIC will prompt for a filename (only up
+ to 8 alphabetical characters). Once entered the snapshot will be saved
+ in the directory VICSNAP with an automatically added .V20 extension.
+
+ If this save fails, an attempt is made to save the snapshot in the root
+ directory of the device.
+
+ On selecting to load a memory snapshot a file selector is displayed. On
+ selecting one of the snapshots it will be instantly loaded.
+
+-------------------------------------------------------------------------------
+$Id$
+
+ vim:expandtab:spell
diff --git a/mkrelease.sh b/mkrelease.sh
new file mode 100644
index 0000000..942726d
--- /dev/null
+++ b/mkrelease.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+rm -f *.nds *.elf *.gba *.arm9
+
+version=`cat version`
+
+make clean
+make ADDITIONAL_CFLAGS="-DDSVIC_DISABLE_FAT -DDSVIC_VERSION=\"\\\"$version\\\"\""
+
+mv dsvic.nds dsvic-nofat.nds
+mv dsvic.ds.gba dsvic-nofat.ds.gba
+
+make clean
+make ADDITIONAL_CFLAGS="-DDSVIC_VERSION=\"\\\"$version\\\"\""
+
+./fat_patch.sh
diff --git a/source/config.c b/source/config.c
new file mode 100644
index 0000000..1bf2341
--- /dev/null
+++ b/source/config.c
@@ -0,0 +1,145 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: config.c 65 2008-12-12 00:19:08Z ianc $
+*/
+
+#include <nds.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+/* ---------------------------------------- PRIVATE DATA
+*/
+const char *conf_filename = "DS81.CFG";
+
+const char *conf_entry[DS81_NUM_CONFIG_ITEMS]=
+{
+ "sticky_shift",
+ "average_touchscreen",
+ "static_ram_at_0x2000",
+ "allow_tape_save",
+ "load_default_snapshot"
+};
+
+
+/* ---------------------------------------- GLOBAL DATA
+*/
+int DS81_Config[DS81_NUM_CONFIG_ITEMS]=
+{
+ TRUE,
+ FALSE,
+ FALSE,
+ FALSE,
+ FALSE
+};
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+int LoadConfig(void)
+{
+ FILE *fp = NULL;
+
+#ifndef DS81_DISABLE_FAT
+ fp=fopen(conf_filename,"r");
+#endif
+
+ if (fp)
+ {
+ char line[80];
+
+ while(fgets(line, sizeof line, fp))
+ {
+ char *p;
+
+ if ((p = strchr(line, '=')))
+ {
+ int f;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ if (strncmp(line, conf_entry[f],
+ strlen(conf_entry[f])) == 0)
+ {
+ DS81_Config[f] = (*(p+1) == '1');
+ }
+ }
+
+ }
+ }
+
+ fclose(fp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int SaveConfig(void)
+{
+ FILE *fp = NULL;
+
+#ifndef DS81_DISABLE_FAT
+ fp=fopen(conf_filename,"w");
+#endif
+
+ if (fp)
+ {
+ int f;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ fprintf(fp,"%s=%d\n",conf_entry[f],DS81_Config[f]);
+ }
+
+ fclose(fp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const char *ConfigDesc(DS81_ConfigItem item)
+{
+ switch(item)
+ {
+ case DS81_STICKY_SHIFT:
+ return "STICKY SHIFT";
+
+ case DS81_AVERAGE_TOUCHSCREEN:
+ return "AVERAGE TOUCHSCREEN";
+
+ case DS81_STATIC_RAM_AT_0x2000:
+ return "RAM AT 8192";
+
+ case DS81_LOAD_DEFAULT_SNAPSHOT:
+ return "LOAD DEFAULT SNAPSHOT";
+
+ case DS81_ALLOW_TAPE_SAVE:
+ return "ALLOW TAPE SAVING";
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
diff --git a/source/framebuffer.c b/source/framebuffer.c
new file mode 100644
index 0000000..0884f76
--- /dev/null
+++ b/source/framebuffer.c
@@ -0,0 +1,386 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: framebuffer.c 43 2007-03-12 00:59:51Z ianc $
+*/
+
+#include <nds.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "framebuffer.h"
+
+/* ---------------------------------------- STATIC DATA
+*/
+#define WIDTH 256
+#define SCAN 128
+#define HEIGHT 192
+
+static uint16 *buff;
+static uint16 *pal;
+
+static uint8 font[]=
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00,
+ 0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x7e, 0x24, 0x24, 0x7e, 0x24, 0x00,
+ 0x00, 0x10, 0x7c, 0x14, 0x7c, 0x50, 0x7c, 0x10,
+ 0x00, 0x46, 0x26, 0x10, 0x08, 0x64, 0x62, 0x00,
+ 0x00, 0x08, 0x14, 0x08, 0x54, 0x22, 0x5c, 0x00,
+ 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00,
+ 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00,
+ 0x00, 0x00, 0x28, 0x10, 0x7c, 0x10, 0x28, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00,
+ 0x00, 0x3c, 0x62, 0x52, 0x4a, 0x46, 0x3c, 0x00,
+ 0x00, 0x18, 0x14, 0x10, 0x10, 0x10, 0x7c, 0x00,
+ 0x00, 0x3c, 0x42, 0x40, 0x3c, 0x02, 0x7e, 0x00,
+ 0x00, 0x3c, 0x42, 0x30, 0x40, 0x42, 0x3c, 0x00,
+ 0x00, 0x10, 0x18, 0x14, 0x12, 0x7e, 0x10, 0x00,
+ 0x00, 0x7e, 0x02, 0x3e, 0x40, 0x42, 0x3c, 0x00,
+ 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3c, 0x00,
+ 0x00, 0x7e, 0x40, 0x20, 0x10, 0x08, 0x08, 0x00,
+ 0x00, 0x3c, 0x42, 0x3c, 0x42, 0x42, 0x3c, 0x00,
+ 0x00, 0x3c, 0x42, 0x42, 0x7c, 0x40, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x04,
+ 0x00, 0x00, 0x20, 0x10, 0x08, 0x10, 0x20, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x10, 0x08, 0x00,
+ 0x00, 0x3c, 0x42, 0x20, 0x10, 0x00, 0x10, 0x00,
+ 0x00, 0x3c, 0x52, 0x6a, 0x7a, 0x02, 0x3c, 0x00,
+ 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00,
+ 0x00, 0x3e, 0x42, 0x3e, 0x42, 0x42, 0x3e, 0x00,
+ 0x00, 0x3c, 0x42, 0x02, 0x02, 0x42, 0x3c, 0x00,
+ 0x00, 0x1e, 0x22, 0x42, 0x42, 0x22, 0x1e, 0x00,
+ 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x7e, 0x00,
+ 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x02, 0x00,
+ 0x00, 0x3c, 0x42, 0x02, 0x72, 0x42, 0x3c, 0x00,
+ 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00,
+ 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00,
+ 0x00, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00,
+ 0x00, 0x22, 0x12, 0x0e, 0x12, 0x22, 0x42, 0x00,
+ 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00,
+ 0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00,
+ 0x00, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x00,
+ 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00,
+ 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x00,
+ 0x00, 0x3c, 0x42, 0x42, 0x4a, 0x52, 0x3c, 0x00,
+ 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x22, 0x42, 0x00,
+ 0x00, 0x3c, 0x02, 0x3c, 0x40, 0x42, 0x3c, 0x00,
+ 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
+ 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00,
+ 0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00,
+ 0x00, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x24, 0x00,
+ 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00,
+ 0x00, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00,
+ 0x00, 0x7e, 0x20, 0x10, 0x08, 0x04, 0x7e, 0x00,
+ 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00,
+ 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
+ 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00,
+ 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x38, 0x44, 0x1e, 0x04, 0x04, 0x7e, 0x00,
+ 0x00, 0x00, 0x1c, 0x20, 0x3c, 0x22, 0x3c, 0x00,
+ 0x00, 0x04, 0x04, 0x3c, 0x44, 0x44, 0x3c, 0x00,
+ 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x38, 0x00,
+ 0x00, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x3c, 0x00,
+ 0x00, 0x00, 0x1c, 0x22, 0x1e, 0x02, 0x3c, 0x00,
+ 0x00, 0x30, 0x08, 0x18, 0x08, 0x08, 0x08, 0x00,
+ 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x1c,
+ 0x00, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x00,
+ 0x00, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x1c, 0x00,
+ 0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x24, 0x18,
+ 0x00, 0x04, 0x14, 0x0c, 0x0c, 0x14, 0x24, 0x00,
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00,
+ 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x2a, 0x00,
+ 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00,
+ 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00,
+ 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02,
+ 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x60,
+ 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x1c, 0x02, 0x1c, 0x20, 0x1e, 0x00,
+ 0x00, 0x08, 0x1c, 0x08, 0x08, 0x08, 0x30, 0x00,
+ 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00,
+ 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00,
+ 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00,
+ 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00,
+ 0x00, 0x00, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x1c,
+ 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00,
+ 0x00, 0x70, 0x10, 0x0c, 0x10, 0x10, 0x70, 0x00,
+ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00,
+ 0x00, 0x0e, 0x08, 0x30, 0x08, 0x08, 0x0e, 0x00,
+ 0x00, 0x28, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x42, 0x99, 0x85, 0x85, 0x99, 0x42, 0x3c
+};
+
+
+/* ---------------------------------------- PRIVATE INTERFACES
+*/
+static inline void Plot(int x, int y, int col)
+{
+ uint16 *base;
+ uint16 cur;
+ int odd;
+
+ if (col == -1)
+ return;
+
+ odd = x&1;
+ x /= 2;
+
+ base = buff+x+y*SCAN;
+ cur = *base;
+
+ if (odd)
+ {
+ cur = (cur & 0xff) | (col<<8);
+ }
+ else
+ {
+ cur = (cur & 0xff00) | col;
+ }
+
+ *base = cur;
+}
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+void FB_Init(uint16 *vram, uint16 *palette)
+{
+ buff = vram;
+ pal = palette;
+
+ pal[COL_BLACK] = RGB15(0,0,0);
+ pal[COL_WHITE] = RGB15(31,31,31);
+ pal[COL_RED] = RGB15(31,0,0);
+ pal[COL_GREEN] = RGB15(0,31,0);
+ pal[COL_BLUE] = RGB15(0,0,31);
+ pal[COL_GUISELECT] = RGB15(8,8,31);
+ pal[COL_GREY] = RGB15(15,15,15);
+ pal[COL_LIGHTGREY] = RGB15(22,22,22);
+ pal[COL_DARKGREY] = RGB15(8,8,8);
+ pal[COL_YELLOW] = RGB15(31,31,0);
+}
+
+
+uint16 *FB_VRAM(void)
+{
+ return buff;
+}
+
+
+uint16 *FB_PALETTE(void)
+{
+ return pal;
+}
+
+
+void FB_LoadASCIITiles(uint16 *tiles)
+{
+ uint8 *src;
+ int c;
+ int row;
+ int val;
+ int mask;
+
+ src = font;
+
+ for(c = 32; c < 127; c++)
+ {
+ for(row = 0; row < 8; row++)
+ {
+ for(mask = 1; mask < 0xff; mask<<=1)
+ {
+ if (*src & mask)
+ {
+ val = COL_WHITE;
+ }
+ else
+ {
+ val = 0;
+ }
+
+ mask <<= 1;
+
+ if (*src & mask)
+ {
+ val |= COL_WHITE << 8;
+ }
+
+ *tiles++ = val;
+ }
+
+ src++;
+ }
+ }
+}
+
+
+void FB_Print(const char *text, int x, int y, FB_Colour colour, FB_Colour paper)
+{
+ int cx,cy;
+ int ch;
+
+ while(*text)
+ {
+ ch=((*text)-32)*8;
+
+ for(cy=0;cy<8;cy++)
+ {
+ for(cx=0;cx<8;cx++)
+ {
+ if (font[ch]&(1<<cx))
+ {
+ Plot(x+cx, y+cy, colour);
+ }
+ else
+ {
+ Plot(x+cx, y+cy, paper);
+ }
+ }
+
+ ch++;
+ }
+
+ x+=8;
+ text++;
+ }
+}
+
+
+void FB_Centre(const char *text, int y, FB_Colour colour, FB_Colour paper)
+{
+ FB_Print(text,WIDTH/2-strlen(text)*4,y,colour,paper);
+}
+
+
+void FB_printf(int x, int y, FB_Colour colour, FB_Colour paper,
+ const char *format, ...)
+{
+ char buff[80];
+ va_list va;
+
+ va_start(va,format);
+ vsnprintf(buff,sizeof buff,format,va);
+ va_end(va);
+
+ FB_Print(buff,x,y,colour,paper);
+}
+
+
+void FB_HLine(int x1, int x2, int y, FB_Colour colour)
+{
+ uint16 *line;
+
+ line=buff+y*WIDTH+x1;
+
+ while(x1<=x2)
+ {
+ Plot(x1++,y,colour);
+ }
+}
+
+
+void FB_VLine(int x, int y1, int y2, FB_Colour colour)
+{
+ while(y1<=y2)
+ {
+ Plot(x,y1++,colour);
+ }
+}
+
+
+void FB_Box(int x, int y, int w, int h, FB_Colour colour)
+{
+ FB_HLine(x,x+w-1,y,colour);
+ FB_HLine(x,x+w-1,y+h-1,colour);
+ FB_VLine(x,y,y+h-1,colour);
+ FB_VLine(x+w-1,y,y+h-1,colour);
+}
+
+
+void FB_FillBox(int x, int y, int w, int h, FB_Colour colour)
+{
+ while(h--)
+ {
+ FB_HLine(x,x+w-1,y++,colour);
+ }
+}
+
+
+void FB_Clear(void)
+{
+ uint16 *p;
+ int f;
+
+ f=WIDTH*HEIGHT/2;
+ p=buff;
+
+ while(f--)
+ {
+ *p++=0;
+ }
+}
+
+
+void FB_Blit(sImage *img, int x, int y, int offset)
+{
+ uint16 *dest;
+ uint16 *row;
+ uint8 *src;
+ uint16 pix;
+ int hww;
+ int ht;
+ int f;
+
+ x /= 2;
+
+ ht = img->height;
+ hww = img->width / 2;
+ dest = buff+x+y*SCAN;
+ src = img->image.data8;
+
+ for(f=0;f<16;f++)
+ {
+ pal[offset+f] = img->palette[f];
+ }
+
+ while(ht--)
+ {
+ row = dest;
+
+ for(f=0;f<hww;f++)
+ {
+ pix = *src++ + offset;
+ pix |= (*src++ + offset) << 8;
+
+ *row++ = pix;
+ }
+
+ dest += SCAN;
+ }
+}
diff --git a/source/gui.c b/source/gui.c
new file mode 100644
index 0000000..d465aca
--- /dev/null
+++ b/source/gui.c
@@ -0,0 +1,862 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: gui.c 75 2010-11-19 14:52:49Z ianc $
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <nds.h>
+
+#include <sys/dir.h>
+
+#include "framebuffer.h"
+#include "zx81.h"
+#include "keyboard.h"
+#include "config.h"
+
+
+/* ---------------------------------------- PRIVATE INTERFACES - PATH HANDLING
+*/
+#define FSEL_FILENAME_LEN 20
+#define FSEL_LINES 16
+#define FSEL_MAX_FILES 1024
+
+#define FSEL_LIST_Y 10
+#define FSEL_LIST_H FSEL_LINES*8
+
+typedef struct
+{
+ char name[FSEL_FILENAME_LEN+1];
+ int is_dir;
+ int size;
+} FSEL_File;
+
+static FSEL_File fsel[FSEL_MAX_FILES];
+
+
+static void CheckPath(char *path)
+{
+ size_t l;
+
+ l = strlen(path);
+
+ if (l == 1)
+ {
+ path[0] = '/';
+ }
+ else
+ {
+ if (path[l-1] != '/')
+ {
+ path[l] = '/';
+ path[l+1] = 0;
+ }
+ }
+}
+
+
+static void AddPath(char *path, const char *dir)
+{
+ if (strcmp(dir,"..") == 0)
+ {
+ size_t l;
+
+ l = strlen(path);
+
+ if (l > 1)
+ {
+ path[--l] = 0;
+
+ while(l && path[l] != '/')
+ {
+ path[l--] = 0;
+ }
+ }
+ }
+ else
+ {
+ strcat(path,dir);
+ strcat(path,"/");
+ }
+}
+
+
+
+
+static int SortFiles(const void *a, const void *b)
+{
+ const FSEL_File *f1;
+ const FSEL_File *f2;
+
+ f1 = (const FSEL_File *)a;
+ f2 = (const FSEL_File *)b;
+
+ if (f1->is_dir == f2->is_dir)
+ {
+ return strcasecmp(f1->name, f2->name);
+ }
+ else if (f1->is_dir)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+static int ValidFilename(const char *name, int is_dir, const char *filter)
+{
+ size_t l;
+ size_t f;
+
+ l = strlen(name);
+
+ if (l > FSEL_FILENAME_LEN)
+ return 0;
+
+ if (strcmp(name,".") == 0)
+ return 0;
+
+ if (is_dir || !filter)
+ return 1;
+
+ f = strlen(filter);
+
+ if (l > f)
+ {
+ if (strcasecmp(name+l-f,filter) == 0)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int LoadDir(const char *path, const char *filter)
+{
+ DIR_ITER *dir;
+ struct stat st;
+ char name[FILENAME_MAX];
+ int no = 0;
+
+ if ((dir = diropen(path)))
+ {
+ while(no < FSEL_MAX_FILES && dirnext(dir,name,&st) == 0)
+ {
+ if (ValidFilename(name, (st.st_mode & S_IFDIR), filter))
+ {
+ strcpy(fsel[no].name,name);
+ fsel[no].is_dir = (st.st_mode & S_IFDIR);
+ fsel[no].size = (int)st.st_size;
+ no++;
+ }
+ }
+
+ dirclose(dir);
+
+ qsort(fsel,no,sizeof fsel[0],SortFiles);
+ }
+
+ return no;
+}
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+int GUI_Menu(const char *opts[])
+{
+ int x,y;
+ int h;
+ int w;
+ int no;
+ int sel;
+ int f;
+ int done;
+ int defer;
+
+ w=0;
+ h=0;
+ sel=0;
+ done=FALSE;
+ defer=FALSE;
+
+ for(no=0;opts[no];no++)
+ {
+ h+=16;
+
+ if (strlen(opts[no])>w)
+ {
+ w=strlen(opts[no]);
+ }
+ }
+
+ w=w*8+16;
+
+ x=SCREEN_WIDTH/2-w/2;
+ y=2;
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ FB_FillBox(x,y,w,h,COL_BLACK);
+ FB_Box(x,y,w,h,COL_WHITE);
+ FB_FillBox(x+1,y+sel*16+1,w-2,14,COL_GUISELECT);
+
+ for(f=0;f<no;f++)
+ {
+ FB_Centre(opts[f],y+4+f*16,COL_WHITE,COL_TRANSPARENT);
+ }
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!defer && !(key=keysDownRepeat()));
+
+ if (defer)
+ {
+ do
+ {
+ swiWaitForVBlank();
+ } while (keysHeld()&KEY_TOUCH);
+ done=TRUE;
+ }
+ else
+ {
+ if (key & (KEY_A|KEY_B|KEY_X|KEY_Y))
+ {
+ done=TRUE;
+ }
+ else if ((key & KEY_UP) && sel)
+ {
+ sel--;
+ }
+ else if ((key & KEY_DOWN) && sel<no-1)
+ {
+ sel++;
+ }
+ else if (key & KEY_TOUCH)
+ {
+ touchPosition tp;
+
+ touchRead(&tp);
+
+ if (tp.px>=x && tp.px<(w+w) && tp.py>=y && tp.py<(y+h))
+ {
+ defer=TRUE;
+ sel=(tp.py-y)/16;
+ }
+ }
+ }
+ }
+
+ return sel;
+}
+
+
+void GUI_Alert(int fatal, const char *text)
+{
+ char line[80];
+ int h;
+ const char *p;
+ char *d;
+
+ h=40;
+ p=text;
+
+ while(*p)
+ {
+ if (*p++=='\n')
+ {
+ h+=8;
+ }
+ }
+
+ FB_FillBox(0,0,SCREEN_WIDTH,h,COL_BLACK);
+ FB_Box(1,1,SCREEN_WIDTH-2,h-2,COL_WHITE);
+
+ p=text;
+ h=4;
+ d=line;
+
+ while(*p)
+ {
+ if (*p=='\n')
+ {
+ *d++=0;
+ p++;
+ FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT);
+ h+=8;
+ d=line;
+ }
+ else
+ {
+ *d++=*p++;
+ }
+ }
+
+ if (d>line)
+ {
+ *d=0;
+ FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT);
+ h+=8;
+ }
+
+ if (!fatal)
+ {
+ FB_Centre("PRESS ANY BUTTON OR SCREEN",h+16,COL_YELLOW,COL_TRANSPARENT);
+
+ while(!keysDown())
+ {
+ swiWaitForVBlank();
+ }
+
+ while(keysHeld())
+ {
+ swiWaitForVBlank();
+ }
+ }
+ else
+ {
+ FB_Centre("PLEASE RESET YOUR CONSOLE",h+16,COL_YELLOW,COL_TRANSPARENT);
+
+ while(1)
+ {
+ swiWaitForVBlank();
+ }
+ }
+}
+
+
+void GUI_Config(void)
+{
+ int sel;
+ DS81_ConfigItem f;
+ int done;
+ int save;
+
+ sel = 0;
+ done = FALSE;
+ save = FALSE;
+
+ FB_Clear();
+
+ FB_Centre("Up/Down to select",140,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("A to toggle",150,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("Or use touchscreen",160,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("START to finish",170,COL_YELLOW,COL_TRANSPARENT);
+
+#ifndef DS81_DISABLE_FAT
+ FB_Centre("SELECT to finish and save",180,COL_YELLOW,COL_TRANSPARENT);
+#endif
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ FB_Print(ConfigDesc(f),14,20+f*14,COL_WHITE,COL_TRANSPARENT);
+ }
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ FB_FillBox(2,20+f*14-1,10,10,
+ DS81_Config[f] ? COL_WHITE : COL_BLACK);
+
+ FB_Box(2,20+f*14-1,10,10,COL_GREY);
+ }
+
+ FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,COL_GUISELECT);
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!(key=keysDownRepeat()));
+
+ FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,COL_BLACK);
+
+ if (key & KEY_START)
+ {
+ done=TRUE;
+ }
+#ifndef DS81_DISABLE_FAT
+ else if (key & KEY_SELECT)
+ {
+ done=TRUE;
+ save=TRUE;
+ }
+#endif
+ else if (key & KEY_A)
+ {
+ DS81_Config[sel] = !DS81_Config[sel];
+ }
+ else if ((key & KEY_UP) && sel)
+ {
+ sel--;
+ }
+ else if ((key & KEY_DOWN) && sel<DS81_NUM_CONFIG_ITEMS-1)
+ {
+ sel++;
+ }
+ else if (key & KEY_TOUCH)
+ {
+ touchPosition tp;
+ int nsel;
+
+ touchRead(&tp);
+
+ nsel = (tp.py-18)/14;
+
+ if (nsel>=0 && nsel<DS81_NUM_CONFIG_ITEMS)
+ {
+ sel = nsel;
+ DS81_Config[sel] = !DS81_Config[sel];
+ }
+ }
+ }
+
+ if (save)
+ {
+ SaveConfig();
+ }
+}
+
+
+int GUI_FileSelect(char pwd[], char selected_file[], const char *filter)
+{
+ int no;
+ int sel;
+ int top;
+ int bar_size;
+ double bar_step;
+ int done;
+ int ret;
+ FB_Colour paper;
+ int off;
+ int f;
+ int drag;
+ int drag_start;
+
+ CheckPath(pwd);
+
+ FB_Clear();
+
+ FB_printf(0,0,COL_BLACK,COL_LIGHTGREY,"%-32.32s",pwd);
+
+ FB_Centre("Use pad and A to select",140,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("L and R to page up/down",150,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("Or use touchscreen",160,COL_YELLOW,COL_TRANSPARENT);
+ FB_Centre("B to cancel",170,COL_YELLOW,COL_TRANSPARENT);
+
+ no = LoadDir(pwd,filter);
+
+ sel = 0;
+ top = 0;
+ done = FALSE;
+ ret = FALSE;
+ drag = FALSE;
+ drag_start = 0;
+
+ if (no<=FSEL_LINES)
+ {
+ bar_step = 0;
+ bar_size = FSEL_LIST_H;
+ }
+ else
+ {
+ bar_step = FSEL_LIST_H/(double)no;
+ bar_size = bar_step*FSEL_LINES;
+ }
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ for (f=0;f<FSEL_LINES;f++)
+ {
+ off = f + top;
+
+ if (off<no)
+ {
+ if (off == sel)
+ {
+ paper = COL_GUISELECT;
+ }
+ else
+ {
+ paper = COL_BLACK;
+ }
+
+ FB_printf(8,FSEL_LIST_Y+f*8,COL_WHITE,paper,
+ "%-*s %s",
+ FSEL_FILENAME_LEN,
+ fsel[off].name,
+ fsel[off].is_dir ? "DIR" : " ");
+ }
+ else
+ {
+ FB_printf(8,FSEL_LIST_Y+f*8,COL_WHITE,COL_BLACK,
+ "%-*s %s",
+ FSEL_FILENAME_LEN,
+ off==0 ? "No Files!" : "",
+ " ");
+ }
+ }
+
+ FB_FillBox(240,FSEL_LIST_Y,16,FSEL_LIST_H,COL_DARKGREY);
+ FB_FillBox(240,FSEL_LIST_Y+top*bar_step,16,bar_size,COL_WHITE);
+
+ if (drag)
+ {
+ touchPosition tp = {0};
+ int diff = 0;
+
+ while (((key=keysHeld()) & KEY_TOUCH) && diff == 0)
+ {
+ touchRead(&tp);
+ diff = tp.py - drag_start;
+ swiWaitForVBlank();
+ }
+
+ if (key & KEY_TOUCH)
+ {
+ int new_top;
+
+ new_top = top + diff / bar_step;
+
+ if (new_top > (no - FSEL_LINES))
+ {
+ new_top = no - FSEL_LINES;
+ }
+
+ if (new_top < 0)
+ {
+ new_top = 0;
+ }
+
+ if (new_top != top)
+ {
+ top = new_top;
+ sel = top;
+ drag_start = tp.py;
+ }
+ }
+ else
+ {
+ drag = FALSE;
+ }
+ }
+
+ if (!drag)
+ {
+ int activate = FALSE;
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!(key=keysDownRepeat()));
+
+ if (key & KEY_TOUCH)
+ {
+ touchPosition tp;
+
+ touchRead(&tp);
+
+ if (tp.py >= FSEL_LIST_Y && tp.py <= (FSEL_LIST_Y+FSEL_LIST_H))
+ {
+ if (tp.px > 239)
+ {
+ drag = TRUE;
+ drag_start = tp.py;
+ }
+ else
+ {
+ int new_sel;
+
+ new_sel = top + (tp.py - FSEL_LIST_Y)/8;
+
+ if (new_sel < no)
+ {
+ if (new_sel == sel)
+ {
+ activate = TRUE;
+ }
+ else
+ {
+ sel = new_sel;
+ }
+ }
+ }
+ }
+ }
+ else if (key & KEY_UP)
+ {
+ if (sel)
+ {
+ sel--;
+
+ if (sel<top)
+ {
+ top--;
+ }
+ }
+ }
+ else if (key & KEY_DOWN)
+ {
+ if (sel < (no-1))
+ {
+ sel++;
+
+ if (sel >= (top+FSEL_LINES))
+ {
+ top++;
+ }
+ }
+ }
+ else if (key & KEY_L)
+ {
+ if (sel)
+ {
+ sel-=FSEL_LINES;
+
+ if (sel < 0)
+ {
+ sel = 0;
+ }
+
+ top = sel;
+ }
+ }
+ else if (key & KEY_R)
+ {
+ if (sel < (no-1))
+ {
+ sel+=FSEL_LINES;
+
+ if (sel > (no-1))
+ {
+ sel = no-1;
+ }
+
+ top = sel - FSEL_LINES + 1;
+
+ if (top < 0)
+ {
+ top = 0;
+ }
+ }
+ }
+ else if (key & KEY_A)
+ {
+ activate = TRUE;
+ }
+ else if (key & KEY_B)
+ {
+ done = TRUE;
+ }
+
+ if (activate)
+ {
+ if (fsel[sel].is_dir)
+ {
+ AddPath(pwd,fsel[sel].name);
+
+ FB_printf(0,0,COL_BLACK,COL_LIGHTGREY,"%-32.32s",pwd);
+
+ no = LoadDir(pwd,filter);
+
+ sel = 0;
+ top = 0;
+
+ if (no<=FSEL_LINES)
+ {
+ bar_step = 0;
+ bar_size = FSEL_LIST_H;
+ }
+ else
+ {
+ bar_step = FSEL_LIST_H/(double)no;
+ bar_size = bar_step*FSEL_LINES;
+ }
+ }
+ else
+ {
+ done = TRUE;
+ ret = TRUE;
+
+ strcpy(selected_file,pwd);
+ strcat(selected_file,fsel[sel].name);
+ }
+ }
+ }
+ }
+
+ while (keysHeld());
+
+ return ret;
+}
+
+
+int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen)
+{
+ struct
+ {
+ SoftKey key;
+ int ascii;
+ } keymap[] =
+ {
+ {SK_1, '1'},
+ {SK_2, '2'},
+ {SK_3, '3'},
+ {SK_4, '4'},
+ {SK_5, '5'},
+ {SK_6, '6'},
+ {SK_7, '7'},
+ {SK_8, '8'},
+ {SK_9, '9'},
+ {SK_0, '0'},
+ {SK_A, 'A'},
+ {SK_B, 'B'},
+ {SK_C, 'C'},
+ {SK_D, 'D'},
+ {SK_E, 'E'},
+ {SK_F, 'F'},
+ {SK_G, 'G'},
+ {SK_H, 'H'},
+ {SK_I, 'I'},
+ {SK_J, 'J'},
+ {SK_K, 'K'},
+ {SK_L, 'L'},
+ {SK_M, 'M'},
+ {SK_N, 'N'},
+ {SK_O, 'O'},
+ {SK_P, 'P'},
+ {SK_Q, 'Q'},
+ {SK_R, 'R'},
+ {SK_S, 'S'},
+ {SK_T, 'T'},
+ {SK_U, 'U'},
+ {SK_V, 'V'},
+ {SK_W, 'W'},
+ {SK_X, 'X'},
+ {SK_Y, 'Y'},
+ {SK_Z, 'Z'},
+ {0, 0}
+ };
+
+ SoftKeyEvent ev;
+ char text[1024];
+ int done = FALSE;
+ int accept = FALSE;
+ int update = TRUE;
+
+ SK_DisplayKeyboard();
+ ZX81SuspendDisplay();
+
+ name[0] = 0;
+
+ while(!done)
+ {
+ if (update)
+ {
+ sprintf(text, "%s:\n"
+ "\"%s%%l%%%s\""
+ "\n\n\npress enter to accept.\n"
+ "press period to backspace.\n"
+ "press space/break to cancel.\n",
+ prompt, name, ext);
+
+ ZX81DisplayString(text);
+
+ update = FALSE;
+ }
+
+ while(SK_GetBareEvent(&ev))
+ {
+ if (!ev.pressed)
+ {
+ size_t l;
+ int f;
+ int ascii;
+
+ l = strlen(name);
+
+ switch(ev.key)
+ {
+ case SK_PERIOD:
+ if (l)
+ {
+ name[--l] = 0;
+ update = TRUE;
+ }
+ break;
+
+ case SK_SPACE:
+ done = TRUE;
+ accept = FALSE;
+ break;
+
+ case SK_NEWLINE:
+ done = TRUE;
+ accept = TRUE;
+ break;
+
+ default:
+ if (l < maxlen)
+ {
+ f = 0;
+ ascii = 0;
+
+ while(!ascii && keymap[f].ascii)
+ {
+ if (ev.key == keymap[f].key)
+ {
+ ascii = keymap[f].ascii;
+ }
+
+ f++;
+ }
+
+ if (ascii)
+ {
+ name[l++] = ascii;
+ name[l] = 0;
+ update = TRUE;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ swiWaitForVBlank();
+ }
+
+ ZX81ResumeDisplay();
+
+ return accept;
+}
+
diff --git a/source/keyboard.c b/source/keyboard.c
new file mode 100644
index 0000000..001d906
--- /dev/null
+++ b/source/keyboard.c
@@ -0,0 +1,483 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: keyboard.c 64 2008-12-05 00:37:26Z ianc $
+*/
+
+#include <nds.h>
+
+#include "keyboard.h"
+#include "framebuffer.h"
+#include "touchwrap.h"
+#include "keyb_bin.h"
+#include "stream.h"
+
+/* ---------------------------------------- STATIC DATA
+*/
+
+#define PAL_OFFSET 110
+
+static int is_dim = FALSE;
+static int selection_on = COL_WHITE;
+static int selection_off = COL_BLACK;
+
+static struct
+{
+ int state;
+ int new_state;
+ int handled;
+ int is_sticky;
+} key_state[NUM_SOFT_KEYS];
+
+static SoftKey pad_left_key = SK_5;
+static SoftKey pad_right_key = SK_8;
+static SoftKey pad_up_key = SK_7;
+static SoftKey pad_down_key = SK_6;
+static SoftKey pad_A_key = SK_0;
+static SoftKey pad_B_key = SK_NEWLINE;
+static SoftKey pad_X_key = NUM_SOFT_KEYS;
+static SoftKey pad_Y_key = NUM_SOFT_KEYS;
+static SoftKey pad_R_key = NUM_SOFT_KEYS;
+static SoftKey pad_L_key = NUM_SOFT_KEYS;
+static SoftKey pad_start_key = NUM_SOFT_KEYS;
+static SoftKey pad_select_key = NUM_SOFT_KEYS;
+
+#define CLEAR_STATE(SHORTCUT) \
+ do \
+ { \
+ if (SHORTCUT != NUM_SOFT_KEYS && \
+ !key_state[SHORTCUT].handled) \
+ { \
+ key_state[SHORTCUT].new_state = FALSE; \
+ } \
+ } while(0)
+
+#define CHECK_STATE(KEYS,BIT,CODE,SHORTCUT,USE_SHORTCUT) \
+ do \
+ { \
+ key_state[CODE].new_state = (KEYS & BIT); \
+ if (USE_SHORTCUT && SHORTCUT != NUM_SOFT_KEYS && \
+ !key_state[SHORTCUT].handled && (KEYS & BIT)) \
+ { \
+ key_state[SHORTCUT].new_state = TRUE; \
+ } \
+ } while(0)
+
+
+static const char *keynames[]=
+{
+ "1", "2", "3", "4", "5",
+ "6", "7", "8", "9", "0",
+ "Q", "W", "E", "R", "T",
+ "Y", "U", "I", "O", "P",
+ "A", "S", "D", "F", "G",
+ "H", "J", "K", "L", "NEWLINE",
+ "SHIFT", "Z", "X", "C", "V",
+ "B", "N", "M", "PERIOD", "SPACE",
+
+ "ABOUT",
+ "CONFIG",
+ "JOYPAD UP",
+ "JOYPAD DOWN",
+ "JOYPAD LEFT",
+ "JOYPAD RIGHT",
+ "A BUTTON",
+ "B BUTTON",
+ "X BUTTON",
+ "Y BUTTON",
+ "RIGHT SHOULDER BUTTON",
+ "LEFT SHOULDER BUTTON",
+ "START BUTTON",
+ "SELECT BUTTON"
+};
+
+/* ---------------------------------------- PRIVATE INTERFACES
+*/
+static SoftKey LocatePress(const touchPosition *p)
+{
+ int kx=0,ky=0;
+ int py=0;
+ SoftKey key = NUM_SOFT_KEYS;
+
+ if (p->py > 36 && p->px > 2)
+ {
+ kx = (p->px - 3) / 25;
+ ky = p->py - 37;
+
+ py = ky % 30;
+ ky /= 30;
+
+ if (py<17 && kx >= 0 && kx<10 && ky>=0 && ky<=4)
+ {
+ key = kx + ky * 10;
+ }
+ }
+
+ if (key>SK_SPACE)
+ {
+ key = NUM_SOFT_KEYS;
+ }
+
+ return key;
+}
+
+
+static int GetEvent(SoftKeyEvent *ev, int map)
+{
+ static SoftKey last = NUM_SOFT_KEYS;
+ static int poll_index = -1;
+
+ /* Read the keys if this is a new loop
+ */
+ if (poll_index == -1)
+ {
+ int f;
+ uint32 keys;
+
+ keys = keysHeld();
+
+ /* Clear the non-sticky keys
+ */
+ for(f=SK_1; f<=SK_CONFIG; f++)
+ {
+ key_state[f].handled = FALSE;
+
+ if (key_state[f].is_sticky)
+ {
+ key_state[f].new_state = key_state[f].state;
+ }
+ else
+ {
+ key_state[f].new_state = FALSE;
+ }
+ }
+
+ /* Check the soft keyboard
+ */
+ if (keys & KEY_TOUCH)
+ {
+ touchPosition tp;
+
+ if (AllowTouch(&tp))
+ {
+ if (tp.py<21 || tp.py>165)
+ {
+ key_state[SK_CONFIG].new_state = TRUE;
+ }
+ else
+ {
+ SoftKey press;
+
+ press = LocatePress(&tp);
+
+ if (press != NUM_SOFT_KEYS)
+ {
+ key_state[press].handled = TRUE;
+
+ if (key_state[press].is_sticky)
+ {
+ if (last != press)
+ {
+ key_state[press].new_state =
+ !key_state[press].state;
+ }
+ }
+ else
+ {
+ key_state[press].new_state = TRUE;
+ }
+
+ last = press;
+ }
+ }
+ }
+ }
+ else
+ {
+ last = NUM_SOFT_KEYS;
+ }
+
+ /* Check non soft-keyboard controls
+ */
+ CHECK_STATE(keys, KEY_A, SK_PAD_A, pad_A_key, map);
+ CHECK_STATE(keys, KEY_B, SK_PAD_B, pad_B_key, map);
+ CHECK_STATE(keys, KEY_X, SK_PAD_X, pad_X_key, map);
+ CHECK_STATE(keys, KEY_Y, SK_PAD_Y, pad_Y_key, map);
+ CHECK_STATE(keys, KEY_R, SK_PAD_R, pad_R_key, map);
+ CHECK_STATE(keys, KEY_L, SK_PAD_L, pad_L_key, map);
+ CHECK_STATE(keys, KEY_START, SK_PAD_START, pad_start_key, map);
+ CHECK_STATE(keys, KEY_SELECT, SK_PAD_SELECT, pad_select_key, map);
+ CHECK_STATE(keys, KEY_UP, SK_PAD_UP, pad_up_key, map);
+ CHECK_STATE(keys, KEY_DOWN, SK_PAD_DOWN, pad_down_key, map);
+ CHECK_STATE(keys, KEY_LEFT, SK_PAD_LEFT, pad_left_key, map);
+ CHECK_STATE(keys, KEY_RIGHT, SK_PAD_RIGHT, pad_right_key, map);
+
+ /* Reset key event poll index
+ */
+ poll_index = 0;
+
+ /* Update any on-screen indicators
+ */
+ for(f=SK_1; f<SK_CONFIG; f++)
+ {
+ if (key_state[f].state != key_state[f].new_state)
+ {
+ int x,y;
+
+ x = 3 + (f % 10) * 25;
+ y = 37 + (f / 10) * 30;
+
+ FB_Box(x, y, 25, 18, key_state[f].new_state ?
+ selection_on : selection_off);
+ }
+ }
+ }
+
+ while(poll_index < NUM_SOFT_KEYS &&
+ key_state[poll_index].state == key_state[poll_index].new_state)
+ {
+ poll_index++;
+ }
+
+ if (poll_index < NUM_SOFT_KEYS)
+ {
+ key_state[poll_index].state = key_state[poll_index].new_state;
+
+ ev->key = poll_index;
+ ev->pressed = key_state[poll_index].state;
+
+ return TRUE;
+ }
+ else
+ {
+ poll_index = -1;
+ return FALSE;
+ }
+}
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+void SK_DisplayKeyboard(void)
+{
+ static sImage img;
+ static int loaded;
+ int f;
+
+ if (!loaded)
+ {
+ loadPCX(keyb_bin,&img);
+ loaded = true;
+ }
+
+ FB_Blit(&img,0,0,PAL_OFFSET);
+
+ /* Update any on-screen indicators
+ */
+ for(f=SK_1; f<SK_CONFIG; f++)
+ {
+ if (key_state[f].state)
+ {
+ int x,y;
+
+ x = 3 + (f % 10) * 25;
+ y = 37 + (f / 10) * 30;
+
+ FB_Box(x, y, 25, 18, key_state[f].new_state ?
+ selection_on : selection_off);
+ }
+ }
+}
+
+
+void SK_SetDisplayBrightness(int dim)
+{
+ static uint16 saved_pal[16];
+ int f;
+ uint16 *pal;
+
+ pal = FB_PALETTE();
+
+ if (dim != is_dim)
+ {
+ is_dim = dim;
+
+ if (is_dim)
+ {
+ selection_on = COL_DARKGREY;
+
+ for(f=0;f<16;f++)
+ {
+ int r,g,b;
+
+ saved_pal[f] = pal[PAL_OFFSET + f];
+
+ r = saved_pal[f] & 0x1f;
+ g = (saved_pal[f]>>5) & 0x1f;
+ b = (saved_pal[f]>>10) & 0x1f;
+
+ r/=3;
+ g/=3;
+ b/=3;
+
+ pal[PAL_OFFSET + f] = RGB15(r,g,b);
+ }
+ }
+ else
+ {
+ selection_on = COL_WHITE;
+
+ for(f=0;f<16;f++)
+ {
+ pal[PAL_OFFSET + f] = saved_pal[f];
+ }
+ }
+ }
+}
+
+
+int SK_GetEvent(SoftKeyEvent *ev)
+{
+ return GetEvent(ev,TRUE);
+}
+
+
+int SK_GetBareEvent(SoftKeyEvent *ev)
+{
+ return GetEvent(ev,FALSE);
+}
+
+
+void SK_SetSticky(SoftKey key, int is_sticky)
+{
+ key_state[key].is_sticky = is_sticky;
+
+ if (!is_sticky)
+ {
+ key_state[key].new_state = FALSE;
+ }
+}
+
+
+void SK_DefinePad(SoftKey pad, SoftKey key)
+{
+ switch(pad)
+ {
+ case SK_PAD_LEFT:
+ pad_left_key = key;
+ break;
+ case SK_PAD_RIGHT:
+ pad_right_key = key;
+ break;
+ case SK_PAD_UP:
+ pad_up_key = key;
+ break;
+ case SK_PAD_DOWN:
+ pad_down_key = key;
+ break;
+ case SK_PAD_A:
+ pad_A_key = key;
+ break;
+ case SK_PAD_B:
+ pad_B_key = key;
+ break;
+ case SK_PAD_X:
+ pad_X_key = key;
+ break;
+ case SK_PAD_Y:
+ pad_Y_key = key;
+ break;
+ case SK_PAD_R:
+ pad_R_key = key;
+ break;
+ case SK_PAD_L:
+ pad_L_key = key;
+ break;
+ case SK_PAD_START:
+ pad_start_key = key;
+ break;
+ case SK_PAD_SELECT:
+ pad_select_key = key;
+ break;
+ default:
+ break;
+ }
+}
+
+
+const char *SK_KeyName(SoftKey k)
+{
+ return keynames[k];
+}
+
+
+void SK_SaveSnapshot(FILE *fp)
+{
+ int f;
+
+ PUT_Long(fp, pad_left_key);
+ PUT_Long(fp, pad_right_key);
+ PUT_Long(fp, pad_up_key);
+ PUT_Long(fp, pad_down_key);
+ PUT_Long(fp, pad_A_key);
+ PUT_Long(fp, pad_B_key);
+ PUT_Long(fp, pad_X_key);
+ PUT_Long(fp, pad_Y_key);
+ PUT_Long(fp, pad_R_key);
+ PUT_Long(fp, pad_L_key);
+ PUT_Long(fp, pad_start_key);
+ PUT_Long(fp, pad_select_key);
+
+ for(f = 0; f < NUM_SOFT_KEYS; f++)
+ {
+ PUT_Long(fp, key_state[f].state);
+ PUT_Long(fp, key_state[f].new_state);
+ PUT_Long(fp, key_state[f].handled);
+ PUT_Long(fp, key_state[f].is_sticky);
+ }
+}
+
+
+void SK_LoadSnapshot(FILE *fp)
+{
+ int f;
+
+ pad_left_key = GET_Long(fp);
+ pad_right_key = GET_Long(fp);
+ pad_up_key = GET_Long(fp);
+ pad_down_key = GET_Long(fp);
+ pad_A_key = GET_Long(fp);
+ pad_B_key = GET_Long(fp);
+ pad_X_key = GET_Long(fp);
+ pad_Y_key = GET_Long(fp);
+ pad_R_key = GET_Long(fp);
+ pad_L_key = GET_Long(fp);
+ pad_start_key = GET_Long(fp);
+ pad_select_key = GET_Long(fp);
+
+ for(f = 0; f < NUM_SOFT_KEYS; f++)
+ {
+ key_state[f].state = GET_Long(fp);
+ key_state[f].new_state = GET_Long(fp);
+ key_state[f].handled = GET_Long(fp);
+ key_state[f].is_sticky = GET_Long(fp);
+ }
+}
+
+
diff --git a/source/main.c b/source/main.c
new file mode 100644
index 0000000..349e49e
--- /dev/null
+++ b/source/main.c
@@ -0,0 +1,461 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: main.c 77 2010-11-23 08:10:25Z ianc $
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <nds.h>
+#include <fat.h>
+
+#include "framebuffer.h"
+#include "gui.h"
+#include "keyboard.h"
+#include "z80.h"
+#include "zx81.h"
+#include "tapes.h"
+#include "config.h"
+#include "textmode.h"
+#include "monitor.h"
+#include "snapshot.h"
+
+#include "splashimg_bin.h"
+#include "rom_font_bin.h"
+
+#include "ds81_debug.h"
+
+#ifndef DS81_VERSION
+#define DS81_VERSION "DEV " __TIME__ "/" __DATE__
+#endif
+
+
+/* ---------------------------------------- STATIC DATA
+*/
+static const char *main_menu[]=
+ {
+ "Reset ZX81",
+ "Select Tape",
+ "Configure",
+ "Map Joypad to Keys",
+ "Machine Code Monitor",
+#ifndef DS81_DISABLE_FAT
+ "Save Memory Snapshot",
+ "Load Memory Snapshot",
+ "Save Joypad/Key State",
+ "Load Joypad/Key State",
+#endif
+ "Cancel",
+ NULL
+ };
+
+typedef enum
+{
+ MenuReset,
+ MenuSelectTape,
+ MenuConfigure,
+ MenuMapJoypad,
+ MenuMonitor,
+#ifndef DS81_DISABLE_FAT
+ MenuSaveSnapshot,
+ MenuLoadSnapshot,
+ MenuSaveMappings,
+ MenuLoadMappings
+#endif
+} MenuOpt;
+
+
+/* Backgrounds
+*/
+static int main_bitmap_bg;
+static int main_text_overlay_bg;
+static int sub_bitmap_bg;
+static int sub_text_overlay_bg;
+
+/* ---------------------------------------- IRQ FUNCS
+*/
+
+/* ---------------------------------------- DISPLAY FUNCS
+*/
+static void VBlankFunc(void)
+{
+ scanKeys();
+}
+
+static void Splash(void)
+{
+ static char scroller[]=
+ {
+ " "
+ "Welcome to DS81, a ZX81 emulator for the Ninetendo DS. "
+ "You can safely ignore this message. I was just bored for half an "
+ "hour. And no retro game is complete without a side-scroller... "
+ "Thanks to Slay Radio, Ladytron, the Genki Rockets, the High "
+ "Voltage SID Collection and Retro Gamer for coding fuel."
+ };
+
+ static const char *text[]=
+ {
+ "DS81 \177 2006 Ian C",
+ " ",
+ "ZX81 ROM \177 1981",
+ "Nine Tiles Networks LTD",
+ " ",
+ "PRESS A TO CONTINUE",
+ " ",
+ "http://www.noddybox.co.uk/",
+ " ",
+ " ",
+ " ",
+ " ",
+ "Checking for FAT device...",
+ NULL
+ };
+
+ sImage img;
+ int f;
+ int y;
+ int res=FALSE;
+ int scr_x=0;
+
+ ZX81SuspendDisplay();
+ ZX81DisplayString("10 rem " DS81_VERSION "\n"
+ "20 print \"%the zx81 is ace%\"\n"
+ "30 goto 20");
+
+ bgSetScale(sub_text_overlay_bg, 0x80, 0x80);
+
+ TM_printf(0,11,"%-18.18s",scroller);
+
+ FB_Clear();
+
+ loadPCX(splashimg_bin,&img);
+
+ FB_Blit(&img,0,0,1);
+
+ y = 10;
+
+ for(f=0;text[f];f++)
+ {
+ FB_Centre(text[f],y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+ }
+
+ y += 8;
+
+#ifndef DS81_DISABLE_FAT
+ res = fatInitDefault();
+#endif
+
+ if (res)
+ {
+ ZX81EnableFileSystem(TRUE);
+ SNAP_Enable(TRUE);
+
+ FB_Centre("Found a FAT device.",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("If you place .P tape files in",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("the top directory or ZX81SNAP",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("then you should be able to load",y,
+ COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("GAME.P with the command",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("LOAD \"GAME\"",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+ }
+ else
+ {
+ ZX81EnableFileSystem(FALSE);
+ SNAP_Enable(FALSE);
+
+ FB_Centre("Sorry, but you don't have a",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("supported FAT device.",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("Only the internal tape",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+
+ FB_Centre("files can be used.",y,COL_WHITE,COL_TRANSPARENT);
+ y += 8;
+ }
+
+ while(!(keysDown() & KEY_A))
+ {
+ swiWaitForVBlank();
+
+ if (++scr_x == 8)
+ {
+ size_t l = sizeof scroller;
+ char c;
+
+ scr_x = 0;
+
+ c = scroller[0];
+ memmove(scroller,scroller+1,l-2);
+ scroller[l-2] = c;
+
+ TM_printf(0,11,"%-18.18s",scroller);
+ }
+
+ bgSetScroll(sub_text_overlay_bg, scr_x << 8, 0);
+ bgUpdate();
+ }
+
+ bgSetScale(sub_text_overlay_bg, 0x100, 0x100);
+ bgSetScroll(sub_text_overlay_bg, 0, 0);
+ bgUpdate();
+
+ TM_Cls();
+
+ ZX81ResumeDisplay();
+}
+
+
+/* ---------------------------------------- JOYPAD MAPPING
+*/
+static void MapJoypad(void)
+{
+ SoftKeyEvent ev;
+ SoftKey pad = NUM_SOFT_KEYS;
+ int done = FALSE;
+ char text[256];
+
+ SK_DisplayKeyboard();
+
+ ZX81SuspendDisplay();
+
+ ZX81DisplayString("press the joypad button you want\n"
+ "to define and then the ZX81 key\n"
+ "you want to use.\n\n"
+ "press on the config banner to\n"
+ "finish.");
+
+ while(!done)
+ {
+ while(SK_GetBareEvent(&ev))
+ {
+ if (ev.pressed)
+ {
+ if (ev.key==SK_ABOUT || ev.key==SK_CONFIG)
+ {
+ done = true;
+ }
+ }
+ else
+ {
+ if (ev.key>=SK_PAD_UP && ev.key<=SK_PAD_SELECT)
+ {
+ pad = ev.key;
+
+ /* Now, just how dumb was making % the inverse on/off...
+ */
+ sprintf(text,"defining\n %%%s%%",SK_KeyName(pad));
+ ZX81DisplayString(text);
+ }
+
+ if (ev.key<=SK_SPACE && pad!=NUM_SOFT_KEYS)
+ {
+ sprintf(text,"mapped\n %%%s%%\nto\n %%%s%%",
+ SK_KeyName(pad),SK_KeyName(ev.key));
+ ZX81DisplayString(text);
+
+ SK_DefinePad(pad,ev.key);
+
+ pad = NUM_SOFT_KEYS;
+ }
+ }
+ }
+
+ swiWaitForVBlank();
+ }
+
+ ZX81ResumeDisplay();
+}
+
+
+/* ---------------------------------------- MAIN
+*/
+int main(int argc, char *argv[])
+{
+ Z80 *z80;
+
+ powerOn(POWER_ALL_2D);
+
+ /* Set up main screen for ZX81 and load the ROM character data
+ */
+ videoSetMode(MODE_3_2D);
+
+ vramSetBankA(VRAM_A_MAIN_BG_0x06000000);
+ vramSetBankB(VRAM_B_MAIN_BG_0x06020000);
+
+ main_bitmap_bg = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 2, 0);
+ main_text_overlay_bg = bgInit(0, BgType_Text8bpp, BgSize_T_256x256, 0, 1);
+
+ bgSetPriority(main_bitmap_bg, 1);
+ bgSetPriority(main_text_overlay_bg, 0);
+
+ BG_PALETTE[0] = RGB15(31,31,31);
+ BG_PALETTE[1] = RGB15(0,0,0);
+
+ dmaCopy(rom_font_bin,(void *)BG_TILE_RAM(1),rom_font_bin_size);
+
+ /* Set up the sub-screen for rotation (basically for use as a framebuffer).
+ Now overlaid with a text screen for the monitor (I thought a bitmapped
+ printing routine would needlessly slow down the monitor when watching
+ the ZX81 run). Having said the overlay is currently a rotation map
+ for some pointless frippery! Still be quicker though.
+ */
+ videoSetModeSub(MODE_4_2D);
+
+ vramSetBankC(VRAM_C_SUB_BG_0x06200000);
+
+ sub_bitmap_bg = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0);
+ sub_text_overlay_bg = bgInitSub(2, BgType_Rotation, BgSize_R_256x256, 4, 0);
+
+ bgSetPriority(sub_bitmap_bg, 1);
+ bgSetPriority(sub_text_overlay_bg, 0);
+
+ /* Tell 'framebuffer' routines to use this
+ */
+ FB_Init((uint16*)BG_BMP_RAM_SUB(1), BG_PALETTE_SUB);
+
+ /* Set up lower screen text overlay
+ */
+ FB_LoadASCIITiles((uint16*)BG_TILE_RAM_SUB(0));
+ TM_Init((uint16*)BG_MAP_RAM_SUB(4),32,32,TRUE);
+
+ /* Set up interrupts and timers
+ */
+ irqInit();
+ irqSet(IRQ_VBLANK,VBlankFunc);
+ irqEnable(IRQ_VBLANK);
+
+ /* All required stuff initialised
+ */
+ keysSetRepeat(30,15);
+
+ z80 = Z80Init(ZX81ReadMem,
+ ZX81WriteMem,
+ ZX81ReadPort,
+ ZX81WritePort,
+ ZX81ReadDisassem);
+
+ if (!z80)
+ {
+ GUI_Alert(TRUE,"Failed to initialise\nthe Z80 CPU emulation!");
+ }
+
+ ZX81Init((uint16*)BG_MAP_RAM(0), (uint16*)BG_BMP_RAM(2), z80);
+
+ Splash();
+
+ LoadConfig();
+ ZX81Reconfigure();
+
+ SK_DisplayKeyboard();
+
+ SK_SetSticky(SK_SHIFT,DS81_Config[DS81_STICKY_SHIFT]);
+
+ if (DS81_Config[DS81_LOAD_DEFAULT_SNAPSHOT])
+ {
+ SNAP_Load(z80, "AUTO", SNAP_TYPE_FULL);
+ }
+
+ while(1)
+ {
+ SoftKeyEvent ev;
+
+ Z80Exec(z80);
+
+ while(SK_GetEvent(&ev))
+ {
+ switch(ev.key)
+ {
+ case SK_ABOUT:
+ case SK_CONFIG:
+ if (ev.pressed)
+ {
+ switch(GUI_Menu(main_menu))
+ {
+ case MenuReset:
+ ZX81Reset(z80);
+ break;
+
+ case MenuSelectTape:
+ SelectTape();
+ break;
+
+ case MenuConfigure:
+ GUI_Config();
+ SK_SetSticky(SK_SHIFT,
+ DS81_Config[DS81_STICKY_SHIFT]);
+ ZX81Reconfigure();
+ break;
+
+ case MenuMapJoypad:
+ MapJoypad();
+ break;
+
+ case MenuMonitor:
+ MachineCodeMonitor(z80);
+ break;
+
+#ifndef DS81_DISABLE_FAT
+ case MenuSaveSnapshot:
+ SNAP_Save(z80, SNAP_TYPE_FULL);
+ break;
+
+ case MenuLoadSnapshot:
+ SNAP_Load(z80, NULL, SNAP_TYPE_FULL);
+ break;
+
+ case MenuSaveMappings:
+ SNAP_Save(z80, SNAP_TYPE_KEYBOARD);
+ break;
+
+ case MenuLoadMappings:
+ SNAP_Load(z80, NULL, SNAP_TYPE_KEYBOARD);
+ break;
+#endif
+ }
+
+ SK_DisplayKeyboard();
+ }
+ break;
+
+ default:
+ ZX81HandleKey(ev.key,ev.pressed);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/source/monitor.c b/source/monitor.c
new file mode 100644
index 0000000..5ba370d
--- /dev/null
+++ b/source/monitor.c
@@ -0,0 +1,362 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: monitor.c 48 2007-03-25 19:06:31Z ianc $
+*/
+
+#include <nds.h>
+#include <stdlib.h>
+
+#include "monitor.h"
+#include "keyboard.h"
+#include "textmode.h"
+#include "framebuffer.h"
+#include "zx81.h"
+#include "config.h"
+
+/* ---------------------------------------- PRIVATE DATA AND TYPES
+*/
+typedef enum
+{
+ DISPLAY_ADDR,
+ DISPLAY_HL,
+ DISPLAY_IX,
+ DISPLAY_SP,
+ DISPLAY_IY,
+ DISPLAY_BC,
+ DISPLAY_DE,
+ DISPLAY_PC,
+ DISPLAY_TYPE_COUNT
+} MemDisplayType;
+
+typedef enum
+{
+ MODE_CPU_STATE,
+ MODE_HEX,
+ MODE_ASSEM,
+ MODE_TYPE_COUNT
+} DisplayModeType;
+
+
+/* ---------------------------------------- STATIC INTERFACES
+*/
+static void DisplayHelp()
+{
+ static const char *help[]=
+ {
+ /* 12345678901234567890123456789012 */
+ "MONITOR HELP",
+ "",
+ "Click on the config bar to exit.",
+ "",
+ "Press START to toggle between",
+ "single step mode and running.",
+ "",
+ "Press SELECT to toggle between",
+ "CPU info and memory display.",
+ "",
+ "In single step mode press A",
+ "to execute next instruction.",
+ "",
+ "Use L/R (+ Y for larger jumps)",
+ "to alter address in mem display.",
+ "",
+ "Press B to cycle between address",
+ "and register memory display.",
+ "",
+ "Note that all numbers are in hex",
+ "and the all keyboard keys are",
+ "sticky until the monitor exits.",
+ "",
+ "Press X to continue",
+ NULL
+ };
+
+ int f;
+
+ TM_Cls();
+
+ for(f=0; help[f]; f++)
+ {
+ TM_Put(0,f,help[f]);
+ }
+
+ while(!(keysDownRepeat() & KEY_X))
+ {
+ swiWaitForVBlank();
+ }
+}
+
+static void DisplayRunningState(int running)
+{
+ if (running)
+ {
+ TM_Put(0,23,"RUNNING [PRESS X FOR HELP]");
+ }
+ else
+ {
+ TM_Put(0,23,"SINGLE STEP [PRESS X FOR HELP]");
+ }
+}
+
+
+static void DisplayCPU(Z80 *cpu)
+{
+ static const char *flag_char = "SZ5H3PNC";
+ Z80Word tmp;
+ int f;
+ char flags[]="--------";
+
+ tmp = cpu->PC;
+
+ /* Display disassembly
+ */
+ for(f=0;f<17;f++)
+ {
+ /* These may seem a bit convuluted, but there's no point being at home
+ to Mr Undefined Behaviour
+ */
+ TM_printf(0,f,"%c%4.4x:",f==0 ? '>':' ',tmp);
+ TM_Put(7,f,Z80Disassemble(cpu,&tmp));
+ }
+
+ /* Display process state
+ */
+ tmp = cpu->AF.b[Z80_LO_WORD];
+
+ for(f=0;f<8;f++)
+ {
+ if (tmp & 1<<(7-f))
+ {
+ flags[f] = flag_char[f];
+ }
+ }
+
+ TM_printf(0,18,"A:%2.2x F:%s IM:%2.2x",
+ cpu->AF.b[Z80_HI_WORD],flags,cpu->IM);
+
+ TM_printf(0,19,"BC:%4.4x DE:%4.4x HL:%4.4x",
+ cpu->BC.w,cpu->DE.w,cpu->HL.w);
+
+ TM_printf(0,20,"IX:%4.4x IY:%4.4x SP:%4.4x",
+ cpu->IX.w,cpu->IY.w,cpu->SP);
+
+ TM_printf(0,21,"PC:%4.4x IF:%d/%d IR:%2.2x%2.2x",
+ cpu->PC,cpu->IFF1,cpu->IFF2,cpu->I,cpu->R);
+}
+
+
+static void DisplayMem(Z80 *cpu, MemDisplayType disp, Z80Word addr, int as_hex)
+{
+ static const char *label[]=
+ {
+ "Address",
+ "HL",
+ "IX",
+ "SP",
+ "IY",
+ "BC",
+ "DE",
+ "PC"
+ };
+
+ int x,y;
+
+ switch(disp)
+ {
+ case DISPLAY_HL:
+ addr = cpu->HL.w;
+ break;
+
+ case DISPLAY_IX:
+ addr = cpu->IX.w;
+ break;
+
+ case DISPLAY_SP:
+ addr = cpu->SP;
+ break;
+
+ case DISPLAY_IY:
+ addr = cpu->IY.w;
+ break;
+
+ case DISPLAY_BC:
+ addr = cpu->BC.w;
+ break;
+
+ case DISPLAY_DE:
+ addr = cpu->DE.w;
+ break;
+
+ case DISPLAY_PC:
+ addr = cpu->PC;
+ break;
+
+ default:
+ break;
+ }
+
+ TM_printf(0,0,"%s: %4.4x",label[disp],addr);
+
+ if (as_hex)
+ {
+ for(y=0;y<20;y++)
+ {
+ TM_printf(0,y+2,"%4.4x:",addr);
+
+ for(x=0;x<8;x++)
+ {
+ TM_printf(6+x*3,y+2,"%2.2x",ZX81ReadDisassem(cpu,addr++));
+ }
+ }
+ }
+ else
+ {
+ for(y=0;y<20;y++)
+ {
+ TM_printf(0,y+2,"%4.4x:",addr);
+ TM_Put(7,y+2,Z80Disassemble(cpu,&addr));
+ }
+ }
+}
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+void MachineCodeMonitor(Z80 *cpu)
+{
+ static Z80Word display_address = 0x4000;
+ static MemDisplayType mem_display = DISPLAY_ADDR;
+ int done = FALSE;
+ int running = FALSE;
+ DisplayModeType display_mode = MODE_CPU_STATE;
+ int key;
+ SoftKey soft_key;
+
+ SK_DisplayKeyboard();
+ SK_SetDisplayBrightness(TRUE);
+
+ for(soft_key = SK_1; soft_key <= SK_SPACE; soft_key++)
+ {
+ SK_SetSticky(soft_key,TRUE);
+ }
+
+ while(!done)
+ {
+ TM_Cls();
+ DisplayRunningState(running);
+
+ switch(display_mode)
+ {
+ case MODE_CPU_STATE:
+ DisplayCPU(cpu);
+ break;
+ case MODE_HEX:
+ DisplayMem(cpu,mem_display,display_address,TRUE);
+ break;
+ case MODE_ASSEM:
+ DisplayMem(cpu,mem_display,display_address,FALSE);
+ break;
+ default:
+ TM_Put(0,0,"Oops!");
+ break;
+ }
+
+ do
+ {
+ SoftKeyEvent ev;
+
+ swiWaitForVBlank();
+
+ while(SK_GetBareEvent(&ev))
+ {
+ ZX81HandleKey(ev.key,ev.pressed);
+
+ if (ev.key == SK_CONFIG && ev.pressed)
+ {
+ done = TRUE;
+ }
+ }
+
+ key = (keysDownRepeat() & ~KEY_TOUCH);
+
+ } while (!done && !running && !key);
+
+ if (key & KEY_START)
+ {
+ running = !running;
+ }
+
+ if (key & KEY_X)
+ {
+ DisplayHelp();
+ }
+
+ if (key & KEY_SELECT)
+ {
+ display_mode = (display_mode+1) % MODE_TYPE_COUNT;
+ }
+
+ if (key & KEY_L)
+ {
+ if (keysHeld() & KEY_Y)
+ {
+ display_address -= 512;
+ }
+ else
+ {
+ display_address -= 64;
+ }
+ }
+
+ if (key & KEY_R)
+ {
+ if (keysHeld() & KEY_Y)
+ {
+ display_address += 512;
+ }
+ else
+ {
+ display_address += 64;
+ }
+ }
+
+ if (key & KEY_B)
+ {
+ mem_display = (mem_display+1) % DISPLAY_TYPE_COUNT;
+ }
+
+ if (running || (key & KEY_A))
+ {
+ Z80SingleStep(cpu);
+ }
+ }
+
+ SK_SetDisplayBrightness(FALSE);
+ TM_Cls();
+
+ for(soft_key = SK_1; soft_key <= SK_SPACE; soft_key++)
+ {
+ SK_SetSticky(soft_key,FALSE);
+ ZX81HandleKey(soft_key,FALSE);
+ }
+
+ SK_SetSticky(SK_SHIFT,DS81_Config[DS81_STICKY_SHIFT]);
+
+}
diff --git a/source/snapshot.c b/source/snapshot.c
new file mode 100644
index 0000000..1d5aa37
--- /dev/null
+++ b/source/snapshot.c
@@ -0,0 +1,195 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Provides the routines for snapshotting.
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <nds.h>
+
+#include "snapshot.h"
+#include "zx81.h"
+#include "gui.h"
+
+#include "config.h"
+
+#include "ds81_debug.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/* ---------------------------------------- STATICS
+*/
+static int enabled;
+static const char *magic = "V01_DS81";
+static const char *extension[2] = {".D81", ".K81"};
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void WriteMagic(FILE *fp, SnapshotType t)
+{
+ const char *p = magic;
+
+ while(*p)
+ {
+ fputc(*p++, fp);
+ }
+
+ fputc(t, fp);
+}
+
+static int CheckMagic(FILE *fp, SnapshotType t)
+{
+ const char *p = magic;
+
+ while(*p)
+ {
+ if (fgetc(fp) != *p++)
+ {
+ return FALSE;
+ }
+ }
+
+ return (fgetc(fp) == t);
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void SNAP_Enable(int enable)
+{
+ enabled = enable;
+}
+
+void SNAP_Save(Z80 *cpu, SnapshotType type)
+{
+ char base[FILENAME_MAX] = "";
+ char file[FILENAME_MAX];
+ FILE *fp = NULL;
+
+ if (!enabled)
+ {
+ return;
+ }
+
+ if(!GUI_InputName("enter snapshot filename",
+ extension[type], base, 8) || !base[0])
+ {
+ return;
+ }
+
+ strcat(base, extension[type]);
+
+ strcpy(file, DEFAULT_SNAPDIR);
+ strcat(file, base);
+
+ fp = fopen(file, "wb");
+
+ if (!fp)
+ {
+ fp = fopen(base, "wb");
+ }
+
+ if (fp)
+ {
+ WriteMagic(fp, type);
+
+ SK_SaveSnapshot(fp);
+
+ if (type == SNAP_TYPE_FULL)
+ {
+ Z80SaveSnapshot(cpu, fp);
+ ZX81SaveSnapshot(fp);
+ }
+
+ fclose(fp);
+ }
+ else
+ {
+ GUI_Alert(FALSE, "Failed to save snapshot");
+ }
+}
+
+void SNAP_Load(Z80 *cpu, const char *optional_name, SnapshotType type)
+{
+ static char last_dir[FILENAME_MAX] = "/";
+ char file[FILENAME_MAX];
+ FILE *fp = NULL;
+
+ if (!enabled)
+ {
+ return;
+ }
+
+ if (optional_name)
+ {
+ strcpy(file, DEFAULT_SNAPDIR);
+ strcat(file, optional_name);
+ strcat(file, extension[type]);
+
+ fp = fopen(file, "rb");
+
+ if (!fp)
+ {
+ strcpy(file, optional_name);
+ strcat(file, extension[type]);
+
+ fp = fopen(file, "rb");
+ }
+ }
+ else
+ {
+ if (GUI_FileSelect(last_dir, file, extension[type]))
+ {
+ fp = fopen(file, "rb");
+ }
+ }
+
+ if (fp)
+ {
+ if (!CheckMagic(fp, type))
+ {
+ GUI_Alert(FALSE, "Not a valid snapshot");
+ }
+ else
+ {
+ SK_LoadSnapshot(fp);
+
+ if (type == SNAP_TYPE_FULL)
+ {
+ Z80LoadSnapshot(cpu, fp);
+ ZX81LoadSnapshot(fp);
+ }
+ }
+
+ fclose(fp);
+ }
+}
diff --git a/source/stream.c b/source/stream.c
new file mode 100644
index 0000000..f471d93
--- /dev/null
+++ b/source/stream.c
@@ -0,0 +1,86 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Provides the routines for streaming.
+
+*/
+#include "stream.h"
+
+/* The long functions are a tad convuluted, but I'm in a dash.
+*/
+
+void PUT_Byte(FILE *fp, unsigned char c)
+{
+ fputc(c, fp);
+}
+
+void PUT_Long(FILE *fp, long l)
+{
+ union {long l; unsigned char c[4];} u;
+
+ u.l = l;
+
+ fputc(u.c[0], fp);
+ fputc(u.c[1], fp);
+ fputc(u.c[2], fp);
+ fputc(u.c[3], fp);
+}
+
+void PUT_ULong(FILE *fp, unsigned long l)
+{
+ union {unsigned long l; unsigned char c[4];} u;
+
+ u.l = l;
+
+ fputc(u.c[0], fp);
+ fputc(u.c[1], fp);
+ fputc(u.c[2], fp);
+ fputc(u.c[3], fp);
+}
+
+unsigned char GET_Byte(FILE *fp)
+{
+ return (unsigned char)fgetc(fp);
+}
+
+long GET_Long(FILE *fp)
+{
+ union {long l; unsigned char c[4];} u;
+
+ u.c[0] = (unsigned char)fgetc(fp);
+ u.c[1] = (unsigned char)fgetc(fp);
+ u.c[2] = (unsigned char)fgetc(fp);
+ u.c[3] = (unsigned char)fgetc(fp);
+
+ return u.l;
+}
+
+unsigned long GET_ULong(FILE *fp)
+{
+ union {unsigned long l; unsigned char c[4];} u;
+
+ u.c[0] = (unsigned char)fgetc(fp);
+ u.c[1] = (unsigned char)fgetc(fp);
+ u.c[2] = (unsigned char)fgetc(fp);
+ u.c[3] = (unsigned char)fgetc(fp);
+
+ return u.l;
+}
diff --git a/source/tapes.c b/source/tapes.c
new file mode 100644
index 0000000..81db917
--- /dev/null
+++ b/source/tapes.c
@@ -0,0 +1,282 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: tapes.c 61 2008-11-03 17:07:32Z ianc $
+*/
+
+#include <nds.h>
+
+#include "tapes.h"
+#include "framebuffer.h"
+#include "keyboard.h"
+#include "zx81.h"
+
+#include "maze_bin.h"
+#include "maze_inlay_bin.h"
+#include "cpatrol_bin.h"
+#include "cpatrol_inlay_bin.h"
+#include "sabotage_bin.h"
+#include "sabotage_inlay_bin.h"
+#include "mazogs_bin.h"
+#include "mazogs_inlay_bin.h"
+
+#include "ds81_debug.h"
+
+
+/* ---------------------------------------- STATIC DATA
+*/
+typedef struct
+{
+ const u8 *tape;
+ const u8 *tape_end;
+ sImage img;
+ const void *source_pcx;
+ SoftKey *keys;
+ const char *text;
+} Tape;
+
+#define NO_TAPES 4
+
+static SoftKey maze_keys[]=
+ {
+ SK_PAD_UP, SK_7,
+ SK_PAD_LEFT, SK_5,
+ SK_PAD_RIGHT, SK_8,
+ SK_PAD_START, SK_C,
+ SK_PAD_SELECT, SK_A,
+ NUM_SOFT_KEYS
+ };
+
+static SoftKey cpatrol_keys[]=
+ {
+ SK_PAD_UP, SK_F,
+ SK_PAD_RIGHT, SK_J,
+ SK_PAD_LEFT, SK_N,
+ SK_PAD_DOWN, SK_V,
+ SK_PAD_R, SK_N,
+ SK_PAD_L, SK_J,
+ SK_PAD_A, SK_0,
+ SK_PAD_B, SK_NEWLINE,
+ NUM_SOFT_KEYS
+ };
+
+static SoftKey sabotage_keys[]=
+ {
+ SK_PAD_UP, SK_W,
+ SK_PAD_LEFT, SK_H,
+ SK_PAD_RIGHT, SK_J,
+ SK_PAD_DOWN, SK_S,
+ SK_PAD_A, SK_E,
+ SK_PAD_R, SK_1,
+ SK_PAD_L, SK_2,
+ SK_PAD_START, SK_0,
+ NUM_SOFT_KEYS
+ };
+
+static SoftKey mazogs_keys[]=
+ {
+ SK_PAD_UP, SK_W,
+ SK_PAD_LEFT, SK_H,
+ SK_PAD_RIGHT, SK_J,
+ SK_PAD_DOWN, SK_S,
+ SK_PAD_A, SK_NEWLINE,
+ SK_PAD_R, SK_R,
+ SK_PAD_L, SK_L,
+ SK_PAD_START, SK_Y,
+ SK_PAD_SELECT, SK_V,
+ NUM_SOFT_KEYS
+ };
+
+static Tape tapes[NO_TAPES]=
+ {
+ {
+ maze_bin,
+ maze_bin_end,
+ {0},
+ maze_inlay_bin,
+ maze_keys,
+ "%3d monster maze%\n"
+ "(c) 1983 Malcolm E. Evans\n\n"
+ "Escape the maze and its T-Rex\n\n"
+ "use joypad for turning and to\n"
+ "move forward.\n"
+ "%start% to start.\n"
+ "%select% to appeal.\n\n"
+ "%note% when the screen goes grey\n"
+ "for 30-60 seconds this is not a\n"
+ "problem - the game is creating\n"
+ "the maze."
+ },
+ {
+ mazogs_bin,
+ mazogs_bin_end,
+ {0},
+ mazogs_inlay_bin,
+ mazogs_keys,
+ "%Mazogs%\n"
+ "(c) 1981 Don Priestley\n\n"
+ "Find the treasure and\n"
+ "return to the start.\n"
+ "Avoid the %Mazogs% that roam\n"
+ "the maze.\n\n"
+ "Use joypad to move.\n"
+ "%select% to view map.\n"
+ "%start% to quit.\n"
+ "%L% or %R% shoulder to select\n"
+ "direction at start."
+ },
+ {
+ cpatrol_bin,
+ cpatrol_bin_end,
+ {0},
+ cpatrol_inlay_bin,
+ cpatrol_keys,
+ "%city patrol%\n"
+ "(c) 1982 Don Priestley\n\n"
+ "Defend the city from the aliens.\n\n"
+ "yes - that parallax city was\n"
+ "done with a text mode and the\n"
+ "equivalent of a 0.8mhz z80\n\n"
+ "the joypad controls the cursor.\n"
+ "hold %L% or %R% shoulder buttons\n"
+ "to move fast when moving in the\n"
+ "same direction.\n\n"
+ "%A% fires when moving.\n"
+ "%B% fires when still.\n\n"
+ "sorry about that, but the keys\n"
+ "are a bit odd in this game."
+ },
+ {
+ sabotage_bin,
+ sabotage_bin_end,
+ {0},
+ sabotage_inlay_bin,
+ sabotage_keys,
+ "%sabotage%\n"
+ "(c) 1982 Don Priestley\n\n"
+ "Destroy the boxes before the\n"
+ "guard finds you.\n\n"
+ "or find the saboteur as the\n"
+ "guard.\n\n"
+ "while this game may not feature\n"
+ "the dazzling graphics of other\n"
+ "ZX81 games it more than makes\n"
+ "up with a simply joyous\n"
+ "gameplay mechanic.\n\n"
+ "The joypad controls the player.\n"
+ "%A% plants a bomb. %L% shoulder\n"
+ "to play as the guard, %R% as\n"
+ "the saboteur."
+ }
+ };
+
+
+static int current=0;
+
+/* ---------------------------------------- PRIVATE INTERFACES
+*/
+static void InitTapes(void)
+{
+ static int init=FALSE;
+ int f;
+
+ if (init)
+ {
+ return;
+ }
+
+ init=TRUE;
+
+ for(f=0;f<NO_TAPES;f++)
+ {
+ loadPCX(tapes[f].source_pcx,&tapes[f].img);
+ }
+}
+
+static void DisplayTape(Tape *t)
+{
+ FB_Clear();
+ FB_Blit(&t->img,255-t->img.width,0,1);
+
+ FB_Print("LEFT/RIGHT",0,0,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("to choose",0,10,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("A to select",0,30,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("B to cancel",0,40,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("REMEMBER TO",0,60,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("LOAD \"\"",0,70,COL_WHITE,COL_TRANSPARENT);
+ FB_Print("ON THE ZX81!",0,80,COL_WHITE,COL_TRANSPARENT);
+
+ ZX81DisplayString(t->text);
+}
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+void SelectTape(void)
+{
+ int done=FALSE;
+
+ InitTapes();
+
+ ZX81SuspendDisplay();
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ DisplayTape(tapes+current);
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!(key=keysDownRepeat()));
+
+ if (key & KEY_LEFT)
+ {
+ if (--current<0)
+ {
+ current=NO_TAPES-1;
+ }
+ }
+ else if (key & KEY_RIGHT)
+ {
+ current=(current+1)%NO_TAPES;
+ }
+ else if (key & KEY_A)
+ {
+ int f;
+
+ done=TRUE;
+ ZX81SetTape(tapes[current].tape,
+ tapes[current].tape_end - tapes[current].tape);
+
+ for(f=0;tapes[current].keys[f]!=NUM_SOFT_KEYS;f+=2)
+ {
+ SK_DefinePad(tapes[current].keys[f],
+ tapes[current].keys[f+1]);
+ }
+ }
+ else if (key & KEY_B)
+ {
+ done=TRUE;
+ }
+ }
+
+ ZX81ResumeDisplay();
+}
+
diff --git a/source/textmode.c b/source/textmode.c
new file mode 100644
index 0000000..795fc4f
--- /dev/null
+++ b/source/textmode.c
@@ -0,0 +1,157 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2007 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: textmode.c 42 2007-03-02 23:18:38Z ianc $
+*/
+
+#include <nds.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "textmode.h"
+
+/* ---------------------------------------- STATIC DATA
+*/
+static int mapw;
+static int maph;
+static uint16 *text;
+static int is_rot;
+static void (*draw_string)(const char *str, int x, int y);
+
+
+/* ---------------------------------------- PRIVATE INTERFACES
+*/
+static inline void Plot_Text(int x, int y, int c)
+{
+ int xw;
+ int yw;
+
+ xw = x/32;
+ yw = y/32;
+ x %= 32;
+ y %= 32;
+
+ *(text + x + y*32 + (xw+yw) * 1024) = c;
+}
+
+
+static inline void Plot_RS(int x, int y, int c)
+{
+ uint16 ch;
+ int odd;
+ uint16 *off;
+
+ odd = x&1;
+
+ off = text + x/2 + y*mapw/2;
+
+ ch = *off;
+
+ if (odd)
+ {
+ ch = (c<<8) | (ch&0xff);
+ }
+ else
+ {
+ ch = c | (ch&0xff00);
+ }
+
+ *off = ch;
+}
+
+
+static void Text_Put(const char *str, int x, int y)
+{
+ while(*str && x<mapw)
+ {
+ Plot_Text(x,y,*str - 32);
+ x++;
+ str++;
+ }
+}
+
+static void RS_Put(const char *str, int x, int y)
+{
+ while(*str && x<mapw)
+ {
+ Plot_RS(x,y,*str - 32);
+ x++;
+ str++;
+ }
+}
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+void TM_Init(uint16 *vram, int map_width, int map_height, int map_is_rotation)
+{
+ text = vram;
+
+ mapw = map_width;
+ maph = map_height;
+
+ is_rot = map_is_rotation;
+
+ draw_string = map_is_rotation ? RS_Put : Text_Put;
+
+ TM_Cls();
+}
+
+
+void TM_Cls(void)
+{
+ uint16 *scr;
+ int f;
+
+ scr = text;
+
+ if (is_rot)
+ {
+ for(f=0;f<mapw*maph/2;f++)
+ {
+ *scr++=0;
+ }
+ }
+ else
+ {
+ for(f=0;f<mapw*maph;f++)
+ {
+ *scr++=0;
+ }
+ }
+}
+
+
+void TM_Put(int x, int y, const char *str)
+{
+ draw_string(str,x,y);
+}
+
+
+void TM_printf(int x, int y, const char *format, ...)
+{
+ char buff[128];
+ va_list va;
+
+ va_start(va,format);
+ vsnprintf(buff,sizeof buff,format,va);
+ va_end(va);
+
+ draw_string(buff,x,y);
+}
diff --git a/source/touchwrap.c b/source/touchwrap.c
new file mode 100644
index 0000000..dec2b93
--- /dev/null
+++ b/source/touchwrap.c
@@ -0,0 +1,55 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id: touchwrap.c 75 2010-11-19 14:52:49Z ianc $
+*/
+
+#include <nds.h>
+#include <stdlib.h>
+
+#include "touchwrap.h"
+#include "config.h"
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+int AllowTouch(touchPosition *tp)
+{
+ static touchPosition last;
+ int16 dx;
+ int16 dy;
+ int res;
+
+ touchRead(tp);
+
+ if (DS81_Config[DS81_AVERAGE_TOUCHSCREEN])
+ {
+ dx = last.px - tp->px;
+ dy = last.py - tp->py;
+
+ res = (abs(dx) < 5 && abs(dy) < 5);
+ }
+ else
+ {
+ res = TRUE;
+ }
+
+ last = *tp;
+
+ return res;
+}
diff --git a/source/z80.c b/source/z80.c
new file mode 100644
index 0000000..da63450
--- /dev/null
+++ b/source/z80.c
@@ -0,0 +1,394 @@
+/*
+
+ z80 - Z80 Emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80.c 64 2008-12-05 00:37:26Z ianc $
+
+ Z80
+
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "z80.h"
+#include "z80_private.h"
+
+#include "stream.h"
+
+static const char ident[]="$Id: z80.c 64 2008-12-05 00:37:26Z ianc $";
+static const char ident_z80_header[]=Z80_H;
+static const char ident_z80_private_header[]=Z80_PRIVATE_H;
+
+Z80Label *z80_labels=NULL;
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void InitTables()
+{
+ static int init=FALSE;
+
+ if (init)
+ return;
+
+ init=TRUE;
+
+ Z80_InitialiseInternals();
+}
+
+static void Z80_CheckInterrupt(Z80 *cpu)
+{
+ /* Check interrupts
+ */
+ if (PRIV->raise)
+ {
+ if (PRIV->nmi)
+ {
+ if (PRIV->halt)
+ {
+ PRIV->halt=FALSE;
+ CALLBACK(eZ80_Halt,0);
+ cpu->PC++;
+ }
+
+ TSTATE(2);
+ cpu->IFF1=0;
+ PRIV->nmi=FALSE;
+ PUSH(cpu->PC);
+ cpu->PC=0x66;
+ }
+ else if (cpu->IFF1)
+ {
+ if (PRIV->halt)
+ {
+ PRIV->halt=FALSE;
+ CALLBACK(eZ80_Halt,0);
+ cpu->PC++;
+ }
+
+ TSTATE(2);
+
+ cpu->IFF1=0;
+ cpu->IFF2=0;
+
+ switch(cpu->IM)
+ {
+ default:
+ case 0:
+ INC_R;
+ Z80_Decode(cpu,PRIV->devbyte);
+ return;
+ break;
+
+ case 1:
+ PUSH(cpu->PC);
+ cpu->PC=0x38;
+ break;
+
+ case 2:
+ PUSH(cpu->PC);
+ cpu->PC=(Z80Word)cpu->I*256+PRIV->devbyte;
+ break;
+ }
+ }
+
+ PRIV->raise=FALSE;
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+
+#ifdef ENABLE_ARRAY_MEMORY
+Z80 *Z80Init(Z80ReadPort read_port,
+ Z80WritePort write_port)
+#else
+Z80 *Z80Init(Z80ReadMemory read_memory,
+ Z80WriteMemory write_memory,
+ Z80ReadPort read_port,
+ Z80WritePort write_port,
+ Z80ReadMemory read_for_disassem)
+#endif
+{
+ Z80 *cpu;
+ int f;
+ int r;
+
+ InitTables();
+
+#ifndef ENABLE_ARRAY_MEMORY
+ if (!read_memory || !write_memory)
+ return NULL;
+#endif
+
+ cpu=malloc(sizeof *cpu);
+
+ if (cpu)
+ {
+ cpu->priv=malloc(sizeof *cpu->priv);
+
+ if (cpu->priv)
+ {
+#ifndef ENABLE_ARRAY_MEMORY
+ PRIV->mread=read_memory;
+ PRIV->mwrite=write_memory;
+ PRIV->disread=read_for_disassem;
+#endif
+ PRIV->pread=read_port;
+ PRIV->pwrite=write_port;
+
+ for(f=0;f<eZ80_NO_CALLBACK;f++)
+ for(r=0;r<MAX_PER_CALLBACK;r++)
+ PRIV->callback[f][r]=NULL;
+
+ Z80Reset(cpu);
+ }
+ else
+ {
+ free(cpu);
+ cpu=NULL;
+ }
+ }
+
+ return cpu;
+}
+
+
+void Z80Reset(Z80 *cpu)
+{
+ PRIV->cycle=0;
+ cpu->PC=0;
+
+ cpu->AF.w=0xffff;
+ cpu->BC.w=0xffff;
+ cpu->DE.w=0xffff;
+ cpu->HL.w=0xffff;
+ cpu->AF_=0xffff;
+ cpu->BC_=0xffff;
+ cpu->DE_=0xffff;
+ cpu->HL_=0xffff;
+
+ cpu->IX.w=0xffff;
+ cpu->IY.w=0xffff;
+
+ cpu->SP=0xffff;
+ cpu->IFF1=0;
+ cpu->IFF2=0;
+ cpu->IM=0;
+ cpu->I=0;
+ cpu->R=0;
+ PRIV->halt=0;
+
+ PRIV->raise=FALSE;
+ PRIV->nmi=FALSE;
+}
+
+
+Z80Val Z80Cycles(Z80 *cpu)
+{
+ return PRIV->cycle;
+}
+
+
+void Z80ResetCycles(Z80 *cpu, Z80Val cycles)
+{
+ PRIV->cycle=cycles;
+}
+
+
+int Z80LodgeCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback)
+{
+ int f;
+
+ for(f=0;f<MAX_PER_CALLBACK;f++)
+ {
+ if (!PRIV->callback[reason][f])
+ {
+ PRIV->callback[reason][f]=callback;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+void Z80RemoveCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback)
+{
+ int f;
+
+ for(f=0;f<MAX_PER_CALLBACK;f++)
+ {
+ if (PRIV->callback[reason][f]==callback)
+ {
+ PRIV->callback[reason][f]=NULL;
+ }
+ }
+}
+
+
+void Z80Interrupt(Z80 *cpu, Z80Byte devbyte)
+{
+ PRIV->raise=TRUE;
+ PRIV->devbyte=devbyte;
+ PRIV->nmi=FALSE;
+}
+
+
+void Z80NMI(Z80 *cpu)
+{
+ PRIV->raise=TRUE;
+ PRIV->nmi=TRUE;
+}
+
+
+int Z80SingleStep(Z80 *cpu)
+{
+ Z80Byte opcode;
+
+ PRIV->last_cb=TRUE;
+ PRIV->shift=0;
+
+ Z80_CheckInterrupt(cpu);
+
+ CALLBACK(eZ80_Instruction,PRIV->cycle);
+
+ INC_R;
+
+ opcode=FETCH_BYTE;
+
+ Z80_Decode(cpu,opcode);
+
+ return PRIV->last_cb;
+}
+
+
+void Z80Exec(Z80 *cpu)
+{
+ while (Z80SingleStep(cpu));
+}
+
+
+void Z80SetLabels(Z80Label labels[])
+{
+ z80_labels=labels;
+}
+
+
+const char *Z80Disassemble(Z80 *cpu, Z80Word *pc)
+{
+#ifdef ENABLE_DISASSEM
+ Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc);
+ static char s[80];
+ Z80Word opc,npc;
+ Z80Byte op;
+ int f;
+
+ opc=*pc;
+ op=Z80_Dis_FetchByte(cpu,pc);
+ dis_opcode_z80[op](cpu,op,pc);
+ npc=*pc;
+
+ strcpy(s,Z80_Dis_Printf("%-5s",Z80_Dis_GetOp()));
+ strcat(s,Z80_Dis_Printf("%-40s ;",Z80_Dis_GetArg()));
+
+ for(f=0;f<5 && opc!=npc;f++)
+ {
+#ifdef ENABLE_ARRAY_MEMORY
+ strcat(s,Z80_Dis_Printf(" %.2x",(int)Z80_MEMORY[opc++]));
+#else
+ strcat(s,Z80_Dis_Printf(" %.2x",(int)PRIV->disread(cpu,opc++)));
+#endif
+ }
+
+ if (opc!=npc)
+ for(f=1;f<3;f++)
+ s[strlen(s)-f]='.';
+
+ return s;
+#else
+ (*pc)+=4;
+ return "NO DISASSEMBLER";
+#endif
+}
+
+
+void Z80SaveSnapshot(Z80 *cpu, FILE *fp)
+{
+ PUT_ULong(fp, cpu->PC);
+ PUT_ULong(fp, cpu->AF.w);
+ PUT_ULong(fp, cpu->BC.w);
+ PUT_ULong(fp, cpu->DE.w);
+ PUT_ULong(fp, cpu->HL.w);
+ PUT_ULong(fp, cpu->AF_);
+ PUT_ULong(fp, cpu->BC_);
+ PUT_ULong(fp, cpu->DE_);
+ PUT_ULong(fp, cpu->HL_);
+ PUT_ULong(fp, cpu->IX.w);
+ PUT_ULong(fp, cpu->IY.w);
+ PUT_ULong(fp, cpu->SP);
+ PUT_Byte(fp, cpu->IFF1);
+ PUT_Byte(fp, cpu->IFF2);
+ PUT_Byte(fp, cpu->IM);
+ PUT_Byte(fp, cpu->I);
+ PUT_Byte(fp, cpu->R);
+ PUT_Byte(fp, cpu->R);
+
+ PUT_ULong(fp, cpu->priv->cycle);
+ PUT_Long(fp, cpu->priv->halt);
+ PUT_Byte(fp, cpu->priv->shift);
+ PUT_Long(fp, cpu->priv->raise);
+ PUT_Byte(fp, cpu->priv->devbyte);
+ PUT_Long(fp, cpu->priv->nmi);
+ PUT_Long(fp, cpu->priv->last_cb);
+}
+
+void Z80LoadSnapshot(Z80 *cpu, FILE *fp)
+{
+ cpu->PC = GET_ULong(fp);
+ cpu->AF.w = GET_ULong(fp);
+ cpu->BC.w = GET_ULong(fp);
+ cpu->DE.w = GET_ULong(fp);
+ cpu->HL.w = GET_ULong(fp);
+ cpu->AF_ = GET_ULong(fp);
+ cpu->BC_ = GET_ULong(fp);
+ cpu->DE_ = GET_ULong(fp);
+ cpu->HL_ = GET_ULong(fp);
+ cpu->IX.w = GET_ULong(fp);
+ cpu->IY.w = GET_ULong(fp);
+ cpu->SP = GET_ULong(fp);
+ cpu->IFF1 = GET_Byte(fp);
+ cpu->IFF2 = GET_Byte(fp);
+ cpu->IM = GET_Byte(fp);
+ cpu->I = GET_Byte(fp);
+ cpu->R = GET_Byte(fp);
+ cpu->R = GET_Byte(fp);
+
+ cpu->priv->cycle = GET_ULong(fp);
+ cpu->priv->halt = GET_Long(fp);
+ cpu->priv->shift = GET_Byte(fp);
+ cpu->priv->raise = GET_Long(fp);
+ cpu->priv->devbyte = GET_Byte(fp);
+ cpu->priv->nmi = GET_Long(fp);
+ cpu->priv->last_cb = GET_Long(fp);
+}
+
+/* END OF FILE */
diff --git a/source/z80_decode.c b/source/z80_decode.c
new file mode 100644
index 0000000..992e1d1
--- /dev/null
+++ b/source/z80_decode.c
@@ -0,0 +1,2533 @@
+/*
+
+ z80 - Z80 Emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80_decode.c 4 2006-10-04 23:05:43Z ianc $
+
+*/
+#include <stdlib.h>
+#include <limits.h>
+
+#include "z80.h"
+#include "z80_private.h"
+
+static const char ident[]="$Id: z80_decode.c 4 2006-10-04 23:05:43Z ianc $";
+
+/* ---------------------------------------- TABLES AND INIT
+*/
+static Z80Byte PSZtable[512];
+static Z80Byte SZtable[512];
+static Z80Byte Ptable[512];
+static Z80Byte Stable[512];
+static Z80Byte Ztable[512];
+
+
+int Z80_HI_WORD;
+int Z80_LO_WORD;
+
+#define HI Z80_HI_WORD
+#define LO Z80_LO_WORD
+
+/* ---------------------------------------- MISC FUNCTIONS
+*/
+void Z80_InitialiseInternals(void)
+{
+ Z80Word f;
+ Z80Reg r;
+
+ /* Check endianness
+ */
+ r.w=0x1234;
+
+ if (r.b[0] == 0x12)
+ {
+ HI=0;
+ LO=1;
+ }
+ else if (r.b[1] == 0x12)
+ {
+ HI=1;
+ LO=0;
+ }
+ else
+ {
+ exit(1);
+ }
+
+ /* Check variable sizes
+ */
+ if (CHAR_BIT!=8 || sizeof(Z80Word)!=2)
+ {
+ exit(2);
+ }
+
+ /* Initialise flag tables
+ */
+ for(f=0;f<256;f++)
+ {
+ Z80Byte p,z,s;
+ int b;
+
+ p=0;
+
+ for(b=0;b<8;b++)
+ if (f&(1<<b))
+ p++;
+
+ if (p&1)
+ p=0;
+ else
+ p=P_Z80;
+
+ if (f)
+ z=0;
+ else
+ z=Z_Z80;
+
+ if (f&0x80)
+ s=S_Z80;
+ else
+ s=0;
+
+ Ptable[f]=p;
+ Stable[f]=s;
+ Ztable[f]=z;
+ SZtable[f]=z|s;
+ PSZtable[f]=z|s|p;
+
+ Ptable[f+256]=Ptable[f]|C_Z80;
+ Stable[f+256]=Stable[f]|C_Z80;
+ Ztable[f+256]=Ztable[f]|C_Z80;
+ SZtable[f+256]=SZtable[f]|C_Z80;
+ PSZtable[f+256]=PSZtable[f]|C_Z80;
+ }
+}
+
+#ifndef ENABLE_ARRAY_MEMORY
+static Z80Word FPEEKW(Z80 *cpu, Z80Word addr)
+{
+ return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8);
+}
+
+
+static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val)
+{
+ PRIV->mwrite(cpu,addr,val);
+ PRIV->mwrite(cpu,addr+1,val>>8);
+}
+#endif
+
+
+/* ---------------------------------------- GENERAL MACROS
+*/
+#define SWAP(A,B) \
+do { \
+ unsigned swap_tmp; \
+ swap_tmp=A; \
+ A=B; \
+ B=swap_tmp; \
+} while(0)
+
+
+/* ---------------------------------------- ARITHMETIC OPS
+*/
+#define ADD8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=cpu->AF.b[HI]+(unsigned)VAL; \
+ cpu->AF.b[LO]=SZtable[w]; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define ADC8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]+(unsigned)VAL+CARRY)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define SUB8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define CMP8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(VAL); \
+} while(0)
+
+
+#define SBC8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL-CARRY)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define ADD16(REG,ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)+(Z80Val)VAL; \
+ cpu->AF.b[LO]&=(S_Z80|Z_Z80|V_Z80); \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define ADC16(REG, ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)+(Z80Val)VAL+CARRY; \
+ cpu->AF.b[LO]=0; \
+ if ((w&0xffff)==0) cpu->AF.b[LO]=Z_Z80; \
+ if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if ((VAL^(REG)^0x8000)&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define SBC16(REG, ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)-(Z80Val)VAL-CARRY; \
+ cpu->AF.b[LO]=N_Z80; \
+ if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \
+ if ((w&0xffff)==0) cpu->AF.b[LO]|=Z_Z80; \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if ((VAL^(REG))&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define INC8(REG) \
+do { \
+ (REG)++; \
+ cpu->AF.b[LO]=CARRY|SZtable[(REG)]; \
+ if ((REG)==0x80) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)&0x0f)==0) cpu->AF.b[LO]|=H_Z80; \
+} while(0)
+
+
+#define DEC8(REG) \
+do { \
+ (REG)--; \
+ cpu->AF.b[LO]=N_Z80|CARRY; \
+ if ((REG)==0x7f) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)&0x0f)==0x0f) cpu->AF.b[LO]|=H_Z80; \
+ cpu->AF.b[LO]|=SZtable[(REG)]; \
+} while(0)
+
+
+#define OP_ON_MEM(OP,addr) \
+do { \
+ Z80Byte memop=PEEK(addr); \
+ OP(memop); \
+ POKE(addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_ARG(OP,addr,arg) \
+do { \
+ Z80Byte memop=PEEK(addr); \
+ OP(memop,arg); \
+ POKE(addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_COPY(OP,addr,copy) \
+do { \
+ Z80Byte memop=PEEK(addr); \
+ OP(memop); \
+ copy=memop; \
+ POKE(addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \
+do { \
+ Z80Byte memop=PEEK(addr); \
+ OP(memop,arg); \
+ copy=memop; \
+ POKE(addr,memop); \
+} while(0)
+
+
+/* ---------------------------------------- ROTATE AND SHIFT OPS
+*/
+#define RRCA \
+do { \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(cpu->AF.b[HI]<<7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RRA \
+do { \
+ Z80Byte c; \
+ c=CARRY; \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RRC(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|((REG)<<7); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RR(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|(CARRY<<7); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RLCA \
+do { \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RLA \
+do { \
+ Z80Byte c; \
+ c=CARRY; \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RLC(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|c; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|CARRY; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SRL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)>>=1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SRA(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|((REG)&0x80); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SLL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SLA(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=(REG)<<1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+/* ---------------------------------------- BOOLEAN OPS
+*/
+#define AND(VAL) \
+do { \
+ cpu->AF.b[HI]&=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define OR(VAL) \
+do { \
+ cpu->AF.b[HI]|=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define XOR(VAL) \
+do { \
+ cpu->AF.b[HI]^=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define BIT(REG,B) \
+do { \
+ cpu->AF.b[LO]=CARRY|H_Z80; \
+ if ((REG)&(1<<B)) \
+ { \
+ if (B==7 && (REG&S_Z80)) cpu->AF.b[LO]|=S_Z80; \
+ if (B==5 && (REG&B5_Z80)) cpu->AF.b[LO]|=B5_Z80; \
+ if (B==3 && (REG&B3_Z80)) cpu->AF.b[LO]|=B3_Z80; \
+ } \
+ else \
+ { \
+ cpu->AF.b[LO]|=Z_Z80; \
+ cpu->AF.b[LO]|=P_Z80; \
+ } \
+} while(0)
+
+#define BIT_SET(REG,B) (REG)|=(1<<B)
+#define BIT_RES(REG,B) (REG)&=~(1<<B)
+
+
+/* ---------------------------------------- JUMP OPERATIONS
+*/
+#define JR_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(12); \
+ JR; \
+ } \
+ else \
+ { \
+ TSTATE(7); \
+ NOJR; \
+ } \
+} while(0)
+
+
+#define JP_COND(COND) \
+do { \
+ TSTATE(10); \
+ if (COND) \
+ { \
+ JP; \
+ } \
+ else \
+ { \
+ NOJP; \
+ } \
+} while(0)
+
+
+#define CALL_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(17); \
+ CALL; \
+ } \
+ else \
+ { \
+ TSTATE(10); \
+ NOCALL; \
+ } \
+} while(0)
+
+
+#define RET_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(11); \
+ POP(cpu->PC); \
+ } \
+ else \
+ { \
+ TSTATE(5); \
+ } \
+} while(0)
+
+
+#define RST(ADDR) \
+ TSTATE(11); \
+ PUSH(cpu->PC); \
+ cpu->PC=ADDR
+
+/* ---------------------------------------- BLOCK OPERATIONS
+*/
+#define LDI \
+do { \
+ Z80Byte b; \
+ \
+ b=PEEK(cpu->HL.w); \
+ POKE(cpu->DE.w,b); \
+ cpu->DE.w++; \
+ cpu->HL.w++; \
+ cpu->BC.w--; \
+ \
+ CLRFLAG(H_Z80); \
+ CLRFLAG(N_Z80); \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+ \
+ SETHIDDEN(cpu->AF.b[HI]+b); \
+} while(0)
+
+#define LDD \
+do { \
+ Z80Byte b; \
+ \
+ b=PEEK(cpu->HL.w); \
+ POKE(cpu->DE.w,b); \
+ cpu->DE.w--; \
+ cpu->HL.w--; \
+ cpu->BC.w--; \
+ \
+ CLRFLAG(H_Z80); \
+ CLRFLAG(N_Z80); \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+ \
+ SETHIDDEN(cpu->AF.b[HI]+b); \
+} while(0)
+
+#define CPI \
+do { \
+ Z80Byte c,b; \
+ \
+ c=CARRY; \
+ b=PEEK(cpu->HL.w); \
+ \
+ CMP8(b); \
+ \
+ if (c) \
+ SETFLAG(C_Z80); \
+ else \
+ CLRFLAG(C_Z80); \
+ \
+ cpu->HL.w++; \
+ cpu->BC.w--; \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+} while(0)
+
+#define CPD \
+do { \
+ Z80Byte c,b; \
+ \
+ c=CARRY; \
+ b=PEEK(cpu->HL.w); \
+ \
+ CMP8(b); \
+ \
+ if (c) \
+ SETFLAG(C_Z80); \
+ else \
+ CLRFLAG(C_Z80); \
+ \
+ cpu->HL.w--; \
+ cpu->BC.w--; \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+} while(0)
+
+#define INI \
+do { \
+ Z80Word w; \
+ Z80Byte b; \
+ \
+ b=IN(cpu->BC.w); \
+ POKE(cpu->HL.w,b); \
+ \
+ cpu->BC.b[HI]--; \
+ cpu->HL.w++; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+ \
+ w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \
+ \
+ if (b&0x80) \
+ SETFLAG(N_Z80); \
+ \
+ if (w&0x100) \
+ { \
+ SETFLAG(C_Z80); \
+ SETFLAG(H_Z80); \
+ } \
+ else \
+ { \
+ CLRFLAG(C_Z80); \
+ CLRFLAG(H_Z80); \
+ } \
+} while(0)
+
+#define IND \
+do { \
+ Z80Word w; \
+ Z80Byte b; \
+ \
+ b=IN(cpu->BC.w); \
+ POKE(cpu->HL.w,b); \
+ \
+ cpu->BC.b[HI]--; \
+ cpu->HL.w--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+ \
+ w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \
+ \
+ if (b&0x80) \
+ SETFLAG(N_Z80); \
+ \
+ if (w&0x100) \
+ { \
+ SETFLAG(C_Z80); \
+ SETFLAG(H_Z80); \
+ } \
+ else \
+ { \
+ CLRFLAG(C_Z80); \
+ CLRFLAG(H_Z80); \
+ } \
+} while(0) \
+
+#define OUTI \
+do { \
+ OUT(cpu->BC.w,PEEK(cpu->HL.w)); \
+ \
+ cpu->HL.w++; \
+ cpu->BC.b[HI]--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+} while(0)
+
+#define OUTD \
+do { \
+ OUT(cpu->BC.w,PEEK(cpu->HL.w)); \
+ \
+ cpu->HL.w--; \
+ cpu->BC.b[HI]--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETFLAG(N_Z80); \
+ SETHIDDEN(cpu->BC.b[HI]); \
+} while(0)
+
+
+/* ---------------------------------------- BASE OPCODE SHORT-HAND BLOCKS
+*/
+
+#define LD_BLOCK(BASE,DEST,DEST2) \
+ case BASE: /* LD DEST,B */ \
+ TSTATE(4); \
+ DEST=cpu->BC.b[HI]; \
+ break; \
+ \
+ case BASE+1: /* LD DEST,C */ \
+ TSTATE(4); \
+ DEST=cpu->BC.b[LO]; \
+ break; \
+ \
+ case BASE+2: /* LD DEST,D */ \
+ TSTATE(4); \
+ DEST=cpu->DE.b[HI]; \
+ break; \
+ \
+ case BASE+3: /* LD DEST,E */ \
+ TSTATE(4); \
+ DEST=cpu->DE.b[LO]; \
+ break; \
+ \
+ case BASE+4: /* LD DEST,H */ \
+ TSTATE(4); \
+ DEST=*H; \
+ break; \
+ \
+ case BASE+5: /* LD DEST,L */ \
+ TSTATE(4); \
+ DEST=*L; \
+ break; \
+ \
+ case BASE+6: /* LD DEST,(HL) */ \
+ TSTATE(7); \
+ OFFSET(off); \
+ DEST2=PEEK(*HL+off); \
+ break; \
+ \
+ case BASE+7: /* LD DEST,A */ \
+ TSTATE(4); \
+ DEST=cpu->AF.b[HI]; \
+ break;
+
+#define ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP A,B */ \
+ TSTATE(4); \
+ OP(cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP A,C */ \
+ TSTATE(4); \
+ OP(cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP A,D */ \
+ TSTATE(4); \
+ OP(cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP A,E */ \
+ TSTATE(4); \
+ OP(cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP A,H */ \
+ TSTATE(4); \
+ OP(*H); \
+ break; \
+ \
+ case BASE+5: /* OP A,L */ \
+ TSTATE(4); \
+ OP(*L); \
+ break; \
+ \
+ case BASE+6: /* OP A,(HL) */ \
+ TSTATE(7); \
+ OFFSET(off); \
+ OP_ON_MEM(OP,*HL+off); \
+ break; \
+ \
+ case BASE+7: /* OP A,A */ \
+ TSTATE(4); \
+ OP(cpu->AF.b[HI]); \
+ break;
+
+
+/* ---------------------------------------- CB OPCODE SHORT-HAND BLOCKS
+*/
+
+#define CB_ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(15); \
+ OP_ON_MEM(OP,cpu->HL.w); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP(cpu->AF.b[HI]); \
+ break;
+
+#define CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(12); \
+ OP_ON_MEM_WITH_ARG(OP,cpu->HL.w,BIT_NO); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP(cpu->AF.b[HI],BIT_NO); \
+ break;
+
+/* ---------------------------------------- SHIFTED CB OPCODE SHORT-HAND BLOCKS
+*/
+
+#define SHIFTED_CB_ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(15); \
+ OP_ON_MEM(OP,addr); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->AF.b[HI]); \
+ break;
+
+#define SHIFTED_CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(12); \
+ OP_ON_MEM_WITH_ARG(OP,addr,BIT_NO); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->AF.b[HI]); \
+ break;
+
+/* ---------------------------------------- DAA
+*/
+
+/* This alogrithm is based on info from
+ http://www.worldofspectrum.org/faq/reference/z80reference.htm
+*/
+static void DAA (Z80 *cpu)
+{
+ Z80Byte add=0;
+ Z80Byte carry=0;
+ Z80Byte nf=cpu->AF.b[LO]&N_Z80;
+ Z80Byte acc=cpu->AF.b[HI];
+
+ if (acc>0x99 || IS_C)
+ {
+ add|=0x60;
+ carry=C_Z80;
+ }
+
+ if ((acc&0xf)>0x9 || IS_H)
+ {
+ add|=0x06;
+ }
+
+ if (nf)
+ {
+ cpu->AF.b[HI]-=add;
+ }
+ else
+ {
+ cpu->AF.b[HI]+=add;
+ }
+
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]
+ | carry
+ | nf
+ | ((acc^cpu->AF.b[HI])&H_Z80)
+ | (cpu->AF.b[HI]&(B3_Z80|B5_Z80));
+}
+
+/* ---------------------------------------- HANDLERS FOR ED OPCODES
+*/
+static void DecodeED(Z80 *cpu, Z80Byte opcode)
+{
+ switch(opcode)
+ {
+ case 0x40: /* IN B,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->BC.b[HI]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[HI]];
+ SETHIDDEN(cpu->BC.b[HI]);
+ break;
+
+ case 0x41: /* OUT (C),B */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[HI]);
+ break;
+
+ case 0x42: /* SBC HL,BC */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->BC.w);
+ break;
+
+ case 0x43: /* LD (nnnn),BC */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->BC.w);
+ break;
+
+ case 0x44: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x45: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x46: /* IM 0 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x47: /* LD I,A */
+ TSTATE(9);
+ cpu->I=cpu->AF.b[HI];
+ break;
+
+ case 0x48: /* IN C,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->BC.b[LO]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[LO]];
+ SETHIDDEN(cpu->BC.b[LO]);
+ break;
+
+ case 0x49: /* OUT (C),C */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[LO]);
+ break;
+
+ case 0x4a: /* ADC HL,BC */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->BC.w);
+ break;
+
+ case 0x4b: /* LD BC,(nnnn) */
+ TSTATE(20);
+ cpu->BC.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x4c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x4d: /* RETI */
+ TSTATE(14);
+ CALLBACK(eZ80_RETI,0);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x4e: /* IM 0/1 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x4f: /* LD R,A */
+ TSTATE(9);
+ cpu->R=cpu->AF.b[HI];
+ break;
+
+ case 0x50: /* IN D,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->DE.b[HI]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->DE.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[HI]];
+ SETHIDDEN(cpu->BC.b[HI]);
+ break;
+
+ case 0x51: /* OUT (C),D */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[HI]);
+ break;
+
+ case 0x52: /* SBC HL,DE */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->DE.w);
+ break;
+
+ case 0x53: /* LD (nnnn),DE */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->DE.w);
+ break;
+
+ case 0x54: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x55: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x56: /* IM 1 */
+ TSTATE(8);
+ cpu->IM=1;
+ break;
+
+ case 0x57: /* LD A,I */
+ TSTATE(9);
+ cpu->AF.b[HI]=cpu->I;
+ break;
+
+ case 0x58: /* IN E,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->DE.b[LO]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[LO]];
+ SETHIDDEN(cpu->DE.b[LO]);
+ break;
+
+ case 0x59: /* OUT (C),E */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[LO]);
+ break;
+
+ case 0x5a: /* ADC HL,DE */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->DE.w);
+ break;
+
+ case 0x5b: /* LD DE,(nnnn) */
+ TSTATE(20);
+ cpu->DE.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x5c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x5d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x5e: /* IM 2 */
+ TSTATE(8);
+ cpu->IM=2;
+ break;
+
+ case 0x5f: /* LD A,R */
+ TSTATE(9);
+ cpu->AF.b[HI]=cpu->R;
+ break;
+
+ case 0x60: /* IN H,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->HL.b[HI]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->HL.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[HI]];
+ SETHIDDEN(cpu->HL.b[HI]);
+ break;
+
+ case 0x61: /* OUT (C),H */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[HI]);
+ break;
+
+ case 0x62: /* SBC HL,HL */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->HL.w);
+ break;
+
+ case 0x63: /* LD (nnnn),HL */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->HL.w);
+ break;
+
+ case 0x64: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x65: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x66: /* IM 0 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x67: /* RRD */
+ {
+ Z80Byte b;
+
+ TSTATE(18);
+
+ b=PEEK(cpu->HL.w);
+
+ POKE(cpu->HL.w,(b>>4)|(cpu->AF.b[HI]<<4));
+ cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b&0x0f);
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+ }
+
+ case 0x68: /* IN L,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->HL.b[LO]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->HL.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[LO]];
+ SETHIDDEN(cpu->HL.b[LO]);
+ break;
+
+ case 0x69: /* OUT (C),L */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[LO]);
+ break;
+
+ case 0x6a: /* ADC HL,HL */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->HL.w);
+ break;
+
+ case 0x6b: /* LD HL,(nnnn) */
+ TSTATE(20);
+ cpu->HL.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x6c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x6d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x6e: /* IM 0/1 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x6f: /* RLD */
+ {
+ Z80Byte b;
+
+ TSTATE(18);
+
+ b=PEEK(cpu->HL.w);
+
+ POKE(cpu->HL.w,(b<<4)|(cpu->AF.b[HI]&0x0f));
+ cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b>>4);
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+ }
+
+ case 0x70: /* IN (C) */
+ {
+ Z80Byte b;
+
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ b=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ b=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[b];
+ SETHIDDEN(b);
+ break;
+ }
+
+ case 0x71: /* OUT (C) */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,0);
+ break;
+
+ case 0x72: /* SBC HL,SP */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->SP);
+ break;
+
+ case 0x73: /* LD (nnnn),SP */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->SP);
+ break;
+
+ case 0x74: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x75: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x76: /* IM 1 */
+ TSTATE(8);
+ cpu->IM=1;
+ break;
+
+ case 0x77: /* NOP */
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+
+ case 0x78: /* IN A,(C) */
+ TSTATE(12);
+
+ if (PRIV->pread)
+ {
+ cpu->AF.b[HI]=PRIV->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->AF.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ case 0x79: /* OUT (C),A */
+ TSTATE(12);
+ if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x7a: /* ADC HL,SP */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->SP);
+ break;
+
+ case 0x7b: /* LD SP,(nnnn) */
+ TSTATE(20);
+ cpu->SP=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x7c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x7d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x7e: /* IM 2 */
+ TSTATE(8);
+ cpu->IM=2;
+ break;
+
+ case 0x7f: /* NOP */
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+
+ case 0xa0: /* LDI */
+ TSTATE(16);
+ LDI;
+ break;
+
+ case 0xa1: /* CPI */
+ TSTATE(16);
+ CPI;
+ break;
+
+ case 0xa2: /* INI */
+ TSTATE(16);
+ INI;
+ break;
+
+ case 0xa3: /* OUTI */
+ TSTATE(16);
+ OUTI;
+ break;
+
+ case 0xa8: /* LDD */
+ TSTATE(16);
+ LDD;
+ break;
+
+ case 0xa9: /* CPD */
+ TSTATE(16);
+ CPD;
+ break;
+
+ case 0xaa: /* IND */
+ TSTATE(16);
+ IND;
+ break;
+
+ case 0xab: /* OUTD */
+ TSTATE(16);
+ OUTD;
+ break;
+
+ case 0xb0: /* LDIR */
+ TSTATE(16);
+ LDI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb1: /* CPIR */
+ TSTATE(16);
+ CPI;
+ if (cpu->BC.w && !IS_Z)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb2: /* INIR */
+ TSTATE(16);
+ INI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb3: /* OTIR */
+ TSTATE(16);
+ OUTI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb8: /* LDDR */
+ TSTATE(16);
+ LDD;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb9: /* CPDR */
+ TSTATE(16);
+ CPD;
+ if (cpu->BC.w && !IS_Z)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xba: /* INDR */
+ TSTATE(16);
+ IND;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xbb: /* OTDR */
+ TSTATE(16);
+ OUTD;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ /* All the rest are NOP/invalid
+ */
+ default:
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+ }
+}
+
+
+/* ---------------------------------------- HANDLERS FOR CB OPCODES
+*/
+static void DecodeCB(Z80 *cpu, Z80Byte opcode)
+{
+ switch(opcode)
+ {
+ CB_ALU_BLOCK(0x00,RLC)
+ CB_ALU_BLOCK(0x08,RRC)
+ CB_ALU_BLOCK(0x10,RL)
+ CB_ALU_BLOCK(0x18,RR)
+ CB_ALU_BLOCK(0x20,SLA)
+ CB_ALU_BLOCK(0x28,SRA)
+ CB_ALU_BLOCK(0x30,SLL)
+ CB_ALU_BLOCK(0x38,SRL)
+
+ CB_BITMANIP_BLOCK(0x40,BIT,0)
+ CB_BITMANIP_BLOCK(0x48,BIT,1)
+ CB_BITMANIP_BLOCK(0x50,BIT,2)
+ CB_BITMANIP_BLOCK(0x58,BIT,3)
+ CB_BITMANIP_BLOCK(0x60,BIT,4)
+ CB_BITMANIP_BLOCK(0x68,BIT,5)
+ CB_BITMANIP_BLOCK(0x70,BIT,6)
+ CB_BITMANIP_BLOCK(0x78,BIT,7)
+
+ CB_BITMANIP_BLOCK(0x80,BIT_RES,0)
+ CB_BITMANIP_BLOCK(0x88,BIT_RES,1)
+ CB_BITMANIP_BLOCK(0x90,BIT_RES,2)
+ CB_BITMANIP_BLOCK(0x98,BIT_RES,3)
+ CB_BITMANIP_BLOCK(0xa0,BIT_RES,4)
+ CB_BITMANIP_BLOCK(0xa8,BIT_RES,5)
+ CB_BITMANIP_BLOCK(0xb0,BIT_RES,6)
+ CB_BITMANIP_BLOCK(0xb8,BIT_RES,7)
+
+ CB_BITMANIP_BLOCK(0xc0,BIT_SET,0)
+ CB_BITMANIP_BLOCK(0xc8,BIT_SET,1)
+ CB_BITMANIP_BLOCK(0xd0,BIT_SET,2)
+ CB_BITMANIP_BLOCK(0xd8,BIT_SET,3)
+ CB_BITMANIP_BLOCK(0xe0,BIT_SET,4)
+ CB_BITMANIP_BLOCK(0xe8,BIT_SET,5)
+ CB_BITMANIP_BLOCK(0xf0,BIT_SET,6)
+ CB_BITMANIP_BLOCK(0xf8,BIT_SET,7)
+ }
+}
+
+
+static void ShiftedDecodeCB(Z80 *cpu, Z80Byte opcode, Z80Relative offset)
+{
+ Z80Word addr;
+
+ /* See if we've come here from a IX/IY shift.
+ */
+ switch (PRIV->shift)
+ {
+ case 0xdd:
+ addr=cpu->IX.w+offset;
+ break;
+ case 0xfd:
+ addr=cpu->IY.w+offset;
+ break;
+ default:
+ addr=cpu->HL.w; /* Play safe... */
+ break;
+ }
+
+ switch(opcode)
+ {
+ SHIFTED_CB_ALU_BLOCK(0x00,RLC)
+ SHIFTED_CB_ALU_BLOCK(0x08,RRC)
+ SHIFTED_CB_ALU_BLOCK(0x10,RL)
+ SHIFTED_CB_ALU_BLOCK(0x18,RR)
+ SHIFTED_CB_ALU_BLOCK(0x20,SLA)
+ SHIFTED_CB_ALU_BLOCK(0x28,SRA)
+ SHIFTED_CB_ALU_BLOCK(0x30,SLL)
+ SHIFTED_CB_ALU_BLOCK(0x38,SRL)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0x40,BIT,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT,7)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,7)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,7)
+ }
+}
+
+
+/* ---------------------------------------- NORMAL OPCODE DECODER
+*/
+void Z80_Decode(Z80 *cpu, Z80Byte opcode)
+{
+ Z80Word *HL;
+ Z80Byte *H;
+ Z80Byte *L;
+ Z80Relative off;
+
+ /* See if we've come here from a IX/IY shift
+ */
+ switch (PRIV->shift)
+ {
+ case 0xdd:
+ HL=&(cpu->IX.w);
+ L=cpu->IX.b+LO;
+ H=cpu->IX.b+HI;
+ break;
+ case 0xfd:
+ HL=&(cpu->IY.w);
+ L=cpu->IY.b+LO;
+ H=cpu->IY.b+HI;
+ break;
+ default:
+ HL=&(cpu->HL.w);
+ L=cpu->HL.b+LO;
+ H=cpu->HL.b+HI;
+ break;
+ }
+
+ switch(opcode)
+ {
+ case 0x00: /* NOP */
+ TSTATE(4);
+ break;
+
+ case 0x01: /* LD BC,nnnn */
+ TSTATE(10);
+ cpu->BC.w=FETCH_WORD;
+ break;
+
+ case 0x02: /* LD (BC),A */
+ TSTATE(7);
+ POKE(cpu->BC.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x03: /* INC BC */
+ TSTATE(6);
+ cpu->BC.w++;
+ break;
+
+ case 0x04: /* INC B */
+ TSTATE(4);
+ INC8(cpu->BC.b[HI]);
+ break;
+
+ case 0x05: /* DEC B */
+ TSTATE(4);
+ DEC8(cpu->BC.b[HI]);
+ break;
+
+ case 0x06: /* LD B,n */
+ TSTATE(7);
+ cpu->BC.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x07: /* RLCA */
+ TSTATE(4);
+ RLCA;
+ break;
+
+ case 0x08: /* EX AF,AF' */
+ TSTATE(4);
+ SWAP(cpu->AF.w,cpu->AF_);
+ break;
+
+ case 0x09: /* ADD HL,BC */
+ TSTATE(11);
+ ADD16(*HL,cpu->BC.w);
+ break;
+
+ case 0x0a: /* LD A,(BC) */
+ TSTATE(7);
+ cpu->AF.b[HI]=PEEK(cpu->BC.w);
+ break;
+
+ case 0x0b: /* DEC BC */
+ TSTATE(6);
+ cpu->BC.w--;
+ break;
+
+ case 0x0c: /* INC C */
+ TSTATE(4);
+ INC8(cpu->BC.b[LO]);
+ break;
+
+ case 0x0d: /* DEC C */
+ TSTATE(4);
+ DEC8(cpu->BC.b[LO]);
+ break;
+
+ case 0x0e: /* LD C,n */
+ TSTATE(7);
+ cpu->BC.b[LO]=FETCH_BYTE;
+ break;
+
+ case 0x0f: /* RRCA */
+ TSTATE(4);
+ RRCA;
+ break;
+
+ case 0x10: /* DJNZ */
+ if (--(cpu->BC.b[HI]))
+ {
+ TSTATE(13);
+ JR;
+ }
+ else
+ {
+ TSTATE(8);
+ NOJR;
+ }
+ break;
+
+ case 0x11: /* LD DE,nnnn */
+ TSTATE(10);
+ cpu->DE.w=FETCH_WORD;
+ break;
+
+ case 0x12: /* LD (DE),A */
+ TSTATE(7);
+ POKE(cpu->DE.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x13: /* INC DE */
+ TSTATE(6);
+ cpu->DE.w++;
+ break;
+
+ case 0x14: /* INC D */
+ TSTATE(4);
+ INC8(cpu->DE.b[HI]);
+ break;
+
+ case 0x15: /* DEC D */
+ TSTATE(4);
+ DEC8(cpu->DE.b[HI]);
+ break;
+
+ case 0x16: /* LD D,n */
+ TSTATE(7);
+ cpu->DE.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x17: /* RLA */
+ TSTATE(4);
+ RLA;
+ break;
+
+ case 0x18: /* JR d */
+ TSTATE(12);
+ JR;
+ break;
+
+ case 0x19: /* ADD HL,DE */
+ TSTATE(11);
+ ADD16(*HL,cpu->DE.w);
+ break;
+
+ case 0x1a: /* LD A,(DE) */
+ TSTATE(7);
+ cpu->AF.b[HI]=PEEK(cpu->DE.w);
+ break;
+
+ case 0x1b: /* DEC DE */
+ TSTATE(6);
+ cpu->DE.w--;
+ break;
+
+ case 0x1c: /* INC E */
+ TSTATE(4);
+ INC8(cpu->DE.b[LO]);
+ break;
+
+ case 0x1d: /* DEC E */
+ TSTATE(4);
+ DEC8(cpu->DE.b[LO]);
+ break;
+
+ case 0x1e: /* LD E,n */
+ TSTATE(7);
+ cpu->DE.b[LO]=FETCH_BYTE;
+ break;
+
+ case 0x1f: /* RRA */
+ TSTATE(4);
+ RRA;
+ break;
+
+ case 0x20: /* JR NZ,e */
+ JR_COND(!IS_Z);
+ break;
+
+ case 0x21: /* LD HL,nnnn */
+ TSTATE(10);
+ *HL=FETCH_WORD;
+ break;
+
+ case 0x22: /* LD (nnnn),HL */
+ TSTATE(16);
+ POKEW(FETCH_WORD,*HL);
+ break;
+
+ case 0x23: /* INC HL */
+ TSTATE(6);
+ (*HL)++;
+ break;
+
+ case 0x24: /* INC H */
+ TSTATE(4);
+ INC8(*H);
+ break;
+
+ case 0x25: /* DEC H */
+ TSTATE(4);
+ DEC8(*H);
+ break;
+
+ case 0x26: /* LD H,n */
+ TSTATE(7);
+ *H=FETCH_BYTE;
+ break;
+
+ case 0x27: /* DAA */
+ TSTATE(4);
+ DAA(cpu);
+ break;
+
+ case 0x28: /* JR Z,d */
+ JR_COND(IS_Z);
+ break;
+
+ case 0x29: /* ADD HL,HL */
+ TSTATE(11);
+ ADD16(*HL,*HL);
+ break;
+
+ case 0x2a: /* LD HL,(nnnn) */
+ TSTATE(7);
+ *HL=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x2b: /* DEC HL */
+ TSTATE(6);
+ (*HL)--;
+ break;
+
+ case 0x2c: /* INC L */
+ TSTATE(4);
+ INC8(*L);
+ break;
+
+ case 0x2d: /* DEC L */
+ TSTATE(4);
+ DEC8(*L);
+ break;
+
+ case 0x2e: /* LD L,n */
+ TSTATE(7);
+ *L=FETCH_BYTE;
+ break;
+
+ case 0x2f: /* CPL */
+ TSTATE(4);
+ cpu->AF.b[HI]^=0xff;
+ SETFLAG(H_Z80);
+ SETFLAG(N_Z80);
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ case 0x30: /* JR NC,d */
+ JR_COND(!IS_C);
+ break;
+
+ case 0x31: /* LD SP,nnnn */
+ TSTATE(10);
+ cpu->SP=FETCH_WORD;
+ break;
+
+ case 0x32: /* LD (nnnn),A */
+ TSTATE(13);
+ POKE(FETCH_WORD,cpu->AF.b[HI]);
+ break;
+
+ case 0x33: /* INC SP */
+ TSTATE(6);
+ cpu->SP++;
+ break;
+
+ case 0x34: /* INC (HL) */
+ TSTATE(11);
+ OFFSET(off);
+ OP_ON_MEM(INC8,*HL+off);
+ break;
+
+ case 0x35: /* DEC (HL) */
+ TSTATE(11);
+ OFFSET(off);
+ OP_ON_MEM(DEC8,*HL+off);
+ break;
+
+ case 0x36: /* LD (HL),n */
+ TSTATE(10);
+ OFFSET(off);
+ POKE(*HL+off,FETCH_BYTE);
+ break;
+
+ case 0x37: /* SCF */
+ TSTATE(4);
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))
+ | C_Z80
+ | (cpu->AF.b[HI]&(B3_Z80|B5_Z80));
+ break;
+
+ case 0x38: /* JR C,d */
+ JR_COND(IS_C);
+ break;
+
+ case 0x39: /* ADD HL,SP */
+ TSTATE(11);
+ ADD16(*HL,cpu->SP);
+ break;
+
+ case 0x3a: /* LD A,(nnnn) */
+ TSTATE(13);
+ cpu->AF.b[HI]=PEEK(FETCH_WORD);
+ break;
+
+ case 0x3b: /* DEC SP */
+ TSTATE(6);
+ cpu->SP--;
+ break;
+
+ case 0x3c: /* INC A */
+ TSTATE(4);
+ INC8(cpu->AF.b[HI]);
+ break;
+
+ case 0x3d: /* DEC A */
+ TSTATE(4);
+ DEC8(cpu->AF.b[HI]);
+ break;
+
+ case 0x3e: /* LD A,n */
+ TSTATE(7);
+ cpu->AF.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x3f: /* CCF */
+ TSTATE(4);
+
+ if (CARRY)
+ SETFLAG(H_Z80);
+ else
+ CLRFLAG(H_Z80);
+
+ cpu->AF.b[LO]^=C_Z80;
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ LD_BLOCK(0x40,cpu->BC.b[HI],cpu->BC.b[HI])
+ LD_BLOCK(0x48,cpu->BC.b[LO],cpu->BC.b[LO])
+ LD_BLOCK(0x50,cpu->DE.b[HI],cpu->DE.b[HI])
+ LD_BLOCK(0x58,cpu->DE.b[LO],cpu->DE.b[LO])
+ LD_BLOCK(0x60,*H,cpu->HL.b[HI])
+ LD_BLOCK(0x68,*L,cpu->HL.b[LO])
+
+ case 0x70: /* LD (HL),B */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->BC.b[HI]);
+ break;
+
+ case 0x71: /* LD (HL),C */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->BC.b[LO]);
+ break;
+
+ case 0x72: /* LD (HL),D */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->DE.b[HI]);
+ break;
+
+ case 0x73: /* LD (HL),E */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->DE.b[LO]);
+ break;
+
+ case 0x74: /* LD (HL),H */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->HL.b[HI]);
+ break;
+
+ case 0x75: /* LD (HL),L */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->HL.b[LO]);
+ break;
+
+ case 0x76: /* HALT */
+ TSTATE(4);
+ cpu->PC--;
+
+ if (!PRIV->halt)
+ CALLBACK(eZ80_Halt,1);
+
+ PRIV->halt=TRUE;
+ break;
+
+ case 0x77: /* LD (HL),A */
+ TSTATE(7);
+ OFFSET(off);
+ POKE(*HL+off,cpu->AF.b[HI]);
+ break;
+
+ LD_BLOCK(0x78,cpu->AF.b[HI],cpu->AF.b[HI])
+
+ ALU_BLOCK(0x80,ADD8)
+ ALU_BLOCK(0x88,ADC8)
+ ALU_BLOCK(0x90,SUB8)
+ ALU_BLOCK(0x98,SBC8)
+ ALU_BLOCK(0xa0,AND)
+ ALU_BLOCK(0xa8,XOR)
+ ALU_BLOCK(0xb0,OR)
+ ALU_BLOCK(0xb8,CMP8)
+
+ case 0xc0: /* RET NZ */
+ RET_COND(!IS_Z);
+ break;
+
+ case 0xc1: /* POP BC */
+ TSTATE(10);
+ POP(cpu->BC.w);
+ break;
+
+ case 0xc2: /* JP NZ,nnnn */
+ JP_COND(!IS_Z);
+ break;
+
+ case 0xc3: /* JP nnnn */
+ JP_COND(1);
+ break;
+
+ case 0xc4: /* CALL NZ,nnnn */
+ CALL_COND(!IS_Z);
+ break;
+
+ case 0xc5: /* PUSH BC */
+ TSTATE(10);
+ PUSH(cpu->BC.w);
+ break;
+
+ case 0xc6: /* ADD A,n */
+ TSTATE(7);
+ ADD8(FETCH_BYTE);
+ break;
+
+ case 0xc7: /* RST 0 */
+ RST(0);
+ break;
+
+ case 0xc8: /* RET Z */
+ RET_COND(IS_Z);
+ break;
+
+ case 0xc9: /* RET */
+ TSTATE(10);
+ POP(cpu->PC);
+ break;
+
+ case 0xca: /* JP Z,nnnn */
+ JP_COND(IS_Z);
+ break;
+
+ case 0xcb: /* CB PREFIX */
+ INC_R;
+
+ /* Check for previous IX/IY shift.
+ */
+ if (PRIV->shift!=0)
+ {
+ Z80Relative cb_offset;
+
+ TSTATE(4); /* Wild stab in the dark! */
+ cb_offset=FETCH_BYTE;
+ ShiftedDecodeCB(cpu,FETCH_BYTE,cb_offset);
+ }
+ else
+ {
+ DecodeCB(cpu,FETCH_BYTE);
+ }
+ break;
+
+ case 0xcc: /* CALL Z,nnnn */
+ CALL_COND(IS_Z);
+ break;
+
+ case 0xcd: /* CALL nnnn */
+ CALL_COND(1);
+ break;
+
+ case 0xce: /* ADC A,n */
+ ADC8(FETCH_BYTE);
+ break;
+
+ case 0xcf: /* RST 8 */
+ RST(8);
+ break;
+
+ case 0xd0: /* RET NC */
+ RET_COND(!IS_C);
+ break;
+
+ case 0xd1: /* POP DE */
+ TSTATE(10);
+ POP(cpu->DE.w);
+ break;
+
+ case 0xd2: /* JP NC,nnnn */
+ JP_COND(!IS_C);
+ break;
+
+ case 0xd3: /* OUT (n),A */
+ TSTATE(11);
+ if (PRIV->pwrite)
+ {
+ Z80Word port;
+
+ port=FETCH_BYTE;
+ port|=(Z80Word)cpu->AF.b[HI]<<8;
+ PRIV->pwrite(cpu,port,cpu->AF.b[HI]);
+ }
+ else
+ cpu->PC++;
+ break;
+
+ case 0xd4: /* CALL NC,nnnn */
+ CALL_COND(!IS_C);
+ break;
+
+ case 0xd5: /* PUSH DE */
+ TSTATE(11);
+ PUSH(cpu->DE.w);
+ break;
+
+ case 0xd6: /* SUB A,n */
+ TSTATE(7);
+ SUB8(FETCH_BYTE);
+ break;
+
+ case 0xd7: /* RST 10 */
+ RST(0x10);
+ break;
+
+ case 0xd8: /* RET C */
+ RET_COND(IS_C);
+ break;
+
+ case 0xd9: /* EXX */
+ TSTATE(4);
+ SWAP(cpu->BC.w,cpu->BC_);
+ SWAP(cpu->DE.w,cpu->DE_);
+ SWAP(cpu->HL.w,cpu->HL_);
+ break;
+
+ case 0xda: /* JP C,nnnn */
+ JP_COND(IS_C);
+ break;
+
+ case 0xdb: /* IN A,(n) */
+ TSTATE(11);
+ if (PRIV->pread)
+ {
+ Z80Word port;
+
+ port=FETCH_BYTE;
+ port|=(Z80Word)cpu->AF.b[HI]<<8;
+ cpu->AF.b[HI]=PRIV->pread(cpu,port);
+ }
+ else
+ cpu->PC++;
+ break;
+
+ case 0xdc: /* CALL C,nnnn */
+ CALL_COND(IS_C);
+ break;
+
+ case 0xdd: /* DD PREFIX */
+ TSTATE(4);
+ INC_R;
+
+ PRIV->shift=opcode;
+ Z80_Decode(cpu,FETCH_BYTE);
+ break;
+
+ case 0xde: /* SBC A,n */
+ TSTATE(7);
+ SBC8(FETCH_BYTE);
+ break;
+
+ case 0xdf: /* RST 18 */
+ RST(0x18);
+ break;
+
+ case 0xe0: /* RET PO */
+ RET_COND(!IS_P);
+ break;
+
+ case 0xe1: /* POP HL */
+ TSTATE(10);
+ POP(*HL);
+ break;
+
+ case 0xe2: /* JP PO,nnnn */
+ JP_COND(!IS_P);
+ break;
+
+ case 0xe3: /* EX (SP),HL */
+ {
+ Z80Word tmp;
+ TSTATE(19);
+ POP(tmp);
+ PUSH(*HL);
+ *HL=tmp;
+ }
+ break;
+
+ case 0xe4: /* CALL PO,nnnn */
+ CALL_COND(!IS_P);
+ break;
+
+ case 0xe5: /* PUSH HL */
+ TSTATE(10);
+ PUSH(*HL);
+ break;
+
+ case 0xe6: /* AND A,n */
+ TSTATE(7);
+ AND(FETCH_BYTE);
+ break;
+
+ case 0xe7: /* RST 20 */
+ RST(0x20);
+ break;
+
+ case 0xe8: /* RET PE */
+ RET_COND(IS_P);
+ break;
+
+ case 0xe9: /* JP (HL) */
+ TSTATE(4);
+ cpu->PC=*HL;
+ break;
+
+ case 0xea: /* JP PE,nnnn */
+ JP_COND(IS_P);
+ break;
+
+ case 0xeb: /* EX DE,HL */
+ TSTATE(4);
+ SWAP(cpu->DE.w,*HL);
+ break;
+
+ case 0xec: /* CALL PE,nnnn */
+ CALL_COND(IS_P);
+ break;
+
+ case 0xed: /* ED PREFIX */
+ INC_R;
+ DecodeED(cpu,FETCH_BYTE);
+ break;
+
+ case 0xee: /* XOR A,n */
+ TSTATE(7);
+ XOR(FETCH_BYTE);
+ break;
+
+ case 0xef: /* RST 28 */
+ RST(0x28);
+ break;
+
+ case 0xf0: /* RET P */
+ RET_COND(!IS_S);
+ break;
+
+ case 0xf1: /* POP AF */
+ TSTATE(10);
+ POP(cpu->AF.w);
+ break;
+
+ case 0xf2: /* JP P,nnnn */
+ JP_COND(!IS_S);
+ break;
+
+ case 0xf3: /* DI */
+ TSTATE(4);
+ cpu->IFF1=0;
+ cpu->IFF2=0;
+ break;
+
+ case 0xf4: /* CALL P,nnnn */
+ CALL_COND(!IS_S);
+ break;
+
+ case 0xf5: /* PUSH AF */
+ TSTATE(10);
+ PUSH(cpu->AF.w);
+ break;
+
+ case 0xf6: /* OR A,n */
+ TSTATE(7);
+ OR(FETCH_BYTE);
+ break;
+
+ case 0xf7: /* RST 30 */
+ RST(0x30);
+ break;
+
+ case 0xf8: /* RET M */
+ RET_COND(IS_S);
+ break;
+
+ case 0xf9: /* LD SP,HL */
+ TSTATE(6);
+ cpu->SP=*HL;
+ break;
+
+ case 0xfa: /* JP M,nnnn */
+ JP_COND(IS_S);
+ break;
+
+ case 0xfb: /* EI */
+ TSTATE(4);
+ cpu->IFF1=1;
+ cpu->IFF2=1;
+ break;
+
+ case 0xfc: /* CALL M,nnnn */
+ CALL_COND(IS_S);
+ break;
+
+ case 0xfd: /* FD PREFIX */
+ TSTATE(4);
+ INC_R;
+
+ PRIV->shift=opcode;
+ Z80_Decode(cpu,FETCH_BYTE);
+ break;
+
+ case 0xfe: /* CP A,n */
+ TSTATE(7);
+ CMP8(FETCH_BYTE);
+ break;
+
+ case 0xff: /* RST 38 */
+ RST(0x38);
+ break;
+
+ }
+}
+
+
+/* END OF FILE */
diff --git a/source/z80_dis.c b/source/z80_dis.c
new file mode 100644
index 0000000..28bc098
--- /dev/null
+++ b/source/z80_dis.c
@@ -0,0 +1,2494 @@
+/*
+
+ z80 - Z80 Emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id: z80_dis.c 4 2006-10-04 23:05:43Z ianc $
+
+*/
+static const char ident[]="$Id: z80_dis.c 4 2006-10-04 23:05:43Z ianc $";
+
+#include "z80_config.h"
+
+#ifdef ENABLE_DISASSEM
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "z80.h"
+#include "z80_private.h"
+
+static Z80Relative cb_off;
+
+/* ---------------------------------------- SHARED ROUTINES
+*/
+static const char *z80_dis_reg8[]={"b","c","d","e","h","l","(hl)","a"};
+static const char *z80_dis_reg16[]={"bc","de","hl","sp"};
+static const char *z80_dis_condition[]={"nz","z","nc","c","po","pe","p","m"};
+
+static const char *dis_op;
+static const char *dis_arg;
+
+const char *Z80_Dis_Printf(const char *format, ...)
+{
+ static int p=0;
+ static char s[16][80];
+ va_list arg;
+
+ va_start(arg,format);
+ p=(p+1)%16;
+ vsprintf(s[p],format,arg);
+ va_end(arg);
+
+ return s[p];
+}
+
+
+Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc)
+{
+#ifdef ENABLE_ARRAY_MEMORY
+ return Z80_MEMORY[(*pc)++];
+#else
+ return cpu->priv->disread(cpu,(*pc)++);
+#endif
+}
+
+
+Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc)
+{
+ Z80Byte l,h;
+
+ l=Z80_Dis_FetchByte(cpu,pc);
+ h=Z80_Dis_FetchByte(cpu,pc);
+
+ return ((Z80Word)h<<8)|l;
+}
+
+
+void Z80_Dis_Set(const char *op, const char *arg)
+{
+ dis_op=op;
+ dis_arg=arg;
+}
+
+
+const char *Z80_Dis_GetOp(void)
+{
+ return dis_op ? dis_op : "";
+}
+
+
+const char *Z80_Dis_GetArg(void)
+{
+ return dis_arg ? dis_arg : "";
+}
+
+
+static const char *GetLabel(Z80Word w)
+{
+ if (z80_labels)
+ {
+ int f;
+
+ for(f=0;z80_labels[f].label;f++)
+ {
+ if (z80_labels[f].address==w)
+ {
+ return z80_labels[f].label;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/* ---------------------------------------- CB xx BYTE OPCODES
+*/
+static void DIS_RLC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("rlc",reg);
+}
+
+static void DIS_RRC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("rrc",reg);
+}
+
+static void DIS_RL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("rl",reg);
+}
+
+static void DIS_RR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("rr",reg);
+}
+
+static void DIS_SLA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("sla",reg);
+}
+
+static void DIS_SRA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("sra",reg);
+}
+
+static void DIS_SLL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("sll",reg);
+}
+
+static void DIS_SRL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("srl",reg);
+}
+
+static void DIS_BIT_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+ int bit;
+
+ reg=z80_dis_reg8[op%8];
+ bit=(op-0x40)/8;
+ Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,reg));
+}
+
+static void DIS_RES_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+ int bit;
+
+ reg=z80_dis_reg8[op%8];
+ bit=(op-0x80)/8;
+ Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,reg));
+}
+
+static void DIS_SET_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+ int bit;
+
+ reg=z80_dis_reg8[op%8];
+ bit=(op-0xc0)/8;
+ Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,reg));
+}
+
+/* ---------------------------------------- DD OPCODES
+*/
+
+static const char *IX_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ static char s[80];
+ Z80Relative r;
+
+ r=(Z80Relative)Z80_Dis_FetchByte(z80,pc);
+
+ if (r<0)
+ sprintf(s,"(ix-$%.2x)",-r);
+ else
+ sprintf(s,"(ix+$%.2x)",r);
+
+ return(s);
+}
+
+
+static const char *IX_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ static char s[80];
+ Z80Relative r;
+
+ r=(Z80Relative)cb_off;
+
+ if (r<0)
+ sprintf(s,"(ix-$%.2x)",-r);
+ else
+ sprintf(s,"(ix+$%.2x)",r);
+
+ return(s);
+}
+
+
+static const char *XR8(Z80 *z80, int reg, Z80Word *pc)
+{
+ switch(reg)
+ {
+ case 0:
+ return("b");
+ break;
+ case 1:
+ return("c");
+ break;
+ case 2:
+ return("d");
+ break;
+ case 3:
+ return("e");
+ break;
+ case 4:
+ return("ixh");
+ break;
+ case 5:
+ return("ixl");
+ break;
+ case 6:
+ return(IX_RelStr(z80,0,pc));
+ break;
+ case 7:
+ return("a");
+ break;
+ default:
+ return(Z80_Dis_Printf("BUG %d",reg));
+ break;
+ }
+}
+
+static void DIS_DD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ dis_opcode_z80[op](z80,op,pc);
+}
+
+static void DIS_ADD_IX_BC(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","ix,bc");
+}
+
+static void DIS_ADD_IX_DE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","ix,de");
+}
+
+static void DIS_LD_IX_WORD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("ix,$%.4x",Z80_Dis_FetchWord(z80,pc)));
+}
+
+static void DIS_LD_ADDR_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),ix",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),ix",w));
+}
+
+static void DIS_INC_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","ix");
+}
+
+static void DIS_INC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","ixh");
+}
+
+static void DIS_DEC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","ixh");
+}
+
+static void DIS_LD_IXH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("ixh,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_ADD_IX_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","ix,ix");
+}
+
+static void DIS_LD_IX_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("ix,(%s)",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("ix,($%.4x)",w));
+}
+
+static void DIS_DEC_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","ix");
+}
+
+static void DIS_INC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","ixl");
+}
+
+static void DIS_DEC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","ixl");
+}
+
+static void DIS_LD_IXL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("ixl,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_INC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc)));
+}
+
+static void DIS_DEC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc)));
+}
+
+static void DIS_LD_IIX_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *rel;
+ int b;
+
+ rel=IX_RelStr(z80,op,pc);
+ b=Z80_Dis_FetchByte(z80,pc);
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b));
+}
+
+
+static void DIS_ADD_IX_SP(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","ix,sp");
+}
+
+static void DIS_XLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int src_r,dest_r;
+ const char *src,*dest;
+
+ dest_r=(op-0x40)/8;
+ src_r=op%8;
+
+ /* IX can't be used as source and destination when reading z80ory
+ */
+ if (dest_r==6)
+ {
+ dest=XR8(z80,dest_r,pc);
+ src=z80_dis_reg8[src_r];
+ }
+ else if (((dest_r==4)||(dest_r==5))&&(src_r==6))
+ {
+ dest=z80_dis_reg8[dest_r];
+ src=XR8(z80,src_r,pc);
+ }
+ else
+ {
+ dest=XR8(z80,dest_r,pc);
+ src=XR8(z80,src_r,pc);
+ }
+
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src));
+}
+
+static void DIS_XADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("and",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XXOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("xor",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_X_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("or",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_XCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cp",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc)));
+}
+
+static void DIS_POP_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("pop","ix");
+}
+
+static void DIS_EX_ISP_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ex","(sp),ix");
+}
+
+static void DIS_PUSH_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("push","ix");
+}
+
+static void DIS_JP_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("jp","(ix)");
+}
+
+static void DIS_LD_SP_IX(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","sp,ix");
+}
+
+static void DIS_DD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc);
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_DD_CB_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_DD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_DD_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_DD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_ED_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_DD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_FD_opcode[nop](z80,nop,pc);
+}
+
+
+/* ---------------------------------------- DD CB OPCODES
+*/
+
+static void DIS_RLC_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ {
+ Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+ }
+}
+
+static void DIS_RRC_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RL_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RR_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SLA_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SRA_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SRL_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SLL_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_BIT_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0x40)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RES_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0x80)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SET_IX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0xc0)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+
+/* ---------------------------------------- ED OPCODES
+*/
+
+static const char *ER8(int reg)
+{
+ switch(reg)
+ {
+ case 0:
+ return("b");
+ break;
+ case 1:
+ return("c");
+ break;
+ case 2:
+ return("d");
+ break;
+ case 3:
+ return("e");
+ break;
+ case 4:
+ return("h");
+ break;
+ case 5:
+ return("l");
+ break;
+ case 6:
+ return("0");
+ break;
+ case 7:
+ return("a");
+ break;
+ }
+
+ return "?";
+}
+
+/* Assumes illegal ED ops are being used for break points
+*/
+static void DIS_ED_NOP(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("brk",Z80_Dis_Printf("$%.2x",op));
+}
+
+static void DIS_IN_R8_C(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("in",Z80_Dis_Printf("%s,(c)",ER8((op-0x40)/8)));
+}
+
+static void DIS_OUT_C_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("out",Z80_Dis_Printf("(c),%s",ER8((op-0x40)/8)));
+}
+
+static void DIS_SBC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sbc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16]));
+}
+
+static void DIS_ED_LD_ADDR_R16(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),%s",p,z80_dis_reg16[(op-0x40)/16]));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),%s",w,z80_dis_reg16[(op-0x40)/16]));
+}
+
+static void DIS_NEG(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("neg",NULL);
+}
+
+static void DIS_RETN(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("retn",NULL);
+}
+
+static void DIS_IM_0(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("im","0");
+}
+
+static void DIS_LD_I_A(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","i,a");
+}
+
+static void DIS_ADC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("adc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16]));
+}
+
+static void DIS_ED_LD_R16_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,(%s)",z80_dis_reg16[(op-0x40)/16],p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,($%.4x)",z80_dis_reg16[(op-0x40)/16],w));
+}
+
+static void DIS_RETI(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("reti",NULL);
+}
+
+static void DIS_LD_R_A(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","r,a");
+}
+
+static void DIS_IM_1(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("im","1");
+}
+
+static void DIS_LD_A_I(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","a,i");
+}
+
+static void DIS_IM_2(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("im","2");
+}
+
+static void DIS_LD_A_R(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","a,r");
+}
+
+static void DIS_RRD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rrd",NULL);
+}
+
+static void DIS_RLD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rld",NULL);
+}
+
+static void DIS_LDI(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ldi",NULL);
+}
+
+static void DIS_CPI(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cpi",NULL);
+}
+
+static void DIS_INI(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ini",NULL);
+}
+
+static void DIS_OUTI(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("outi",NULL);
+}
+
+static void DIS_LDD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ldd",NULL);
+}
+
+static void DIS_CPD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cpd",NULL);
+}
+
+static void DIS_IND(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ind",NULL);
+}
+
+static void DIS_OUTD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("outd",NULL);
+}
+
+static void DIS_LDIR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ldir",NULL);
+}
+
+static void DIS_CPIR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cpir",NULL);
+}
+
+static void DIS_INIR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inir",NULL);
+}
+
+static void DIS_OTIR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("otir",NULL);
+}
+
+static void DIS_LDDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("lddr",NULL);
+}
+
+static void DIS_CPDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cpdr",NULL);
+}
+
+static void DIS_INDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("indr",NULL);
+}
+
+static void DIS_OTDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("otdr",NULL);
+}
+
+
+/* ---------------------------------------- FD OPCODES
+*/
+
+static const char *IY_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ static char s[80];
+ Z80Relative r;
+
+ r=(Z80Relative)Z80_Dis_FetchByte(z80,pc);
+
+ if (r<0)
+ sprintf(s,"(iy-$%.2x)",-r);
+ else
+ sprintf(s,"(iy+$%.2x)",r);
+
+ return(s);
+}
+
+
+static const char *IY_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ static char s[80];
+ Z80Relative r;
+
+ r=(Z80Relative)cb_off;
+
+ if (r<0)
+ sprintf(s,"(iy-$%.2x)",-r);
+ else
+ sprintf(s,"(iy+$%.2x)",r);
+
+ return(s);
+}
+
+
+static const char *YR8(Z80 *z80, int reg, Z80Word *pc)
+{
+ switch(reg)
+ {
+ case 0:
+ return("b");
+ break;
+ case 1:
+ return("c");
+ break;
+ case 2:
+ return("d");
+ break;
+ case 3:
+ return("e");
+ break;
+ case 4:
+ return("iyh");
+ break;
+ case 5:
+ return("iyl");
+ break;
+ case 6:
+ return(IY_RelStr(z80,0,pc));
+ break;
+ case 7:
+ return("a");
+ break;
+ default:
+ return(Z80_Dis_Printf("BUG %d",reg));
+ break;
+ }
+}
+
+static void DIS_FD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ dis_opcode_z80[op](z80,op,pc);
+}
+
+static void DIS_ADD_IY_BC(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","iy,bc");
+}
+
+static void DIS_ADD_IY_DE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","iy,de");
+}
+
+static void DIS_LD_IY_WORD(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("iy,$%.4x",Z80_Dis_FetchWord(z80,pc)));
+}
+
+static void DIS_LD_ADDR_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),iy",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),iy",w));
+}
+
+static void DIS_INC_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","iy");
+}
+
+static void DIS_INC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","iyh");
+}
+
+static void DIS_DEC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","iyh");
+}
+
+static void DIS_LD_IYH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("iyh,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_ADD_IY_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","iy,iy");
+}
+
+static void DIS_LD_IY_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("iy,(%s)",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("iy,($%.4x)",w));
+}
+
+static void DIS_DEC_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","iy");
+}
+
+static void DIS_INC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc","iyl");
+}
+
+static void DIS_DEC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec","iyl");
+}
+
+static void DIS_LD_IYL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld",Z80_Dis_Printf("iyl,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_INC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc)));
+}
+
+static void DIS_DEC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc)));
+}
+
+static void DIS_LD_IIY_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *rel;
+ int b;
+
+ rel=IY_RelStr(z80,op,pc);
+ b=Z80_Dis_FetchByte(z80,pc);
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b));
+}
+
+
+static void DIS_ADD_IY_SP(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add","iy,sp");
+}
+
+static void DIS_YLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int src_r,dest_r;
+ const char *src,*dest;
+
+ dest_r=(op-0x40)/8;
+ src_r=op%8;
+
+ /* IY can't be used as source and destination when reading z80ory
+ */
+ if (dest_r==6)
+ {
+ dest=YR8(z80,dest_r,pc);
+ src=z80_dis_reg8[src_r];
+ }
+ else if (((dest_r==4)||(dest_r==5))&&(src_r==6))
+ {
+ dest=z80_dis_reg8[dest_r];
+ src=YR8(z80,src_r,pc);
+ }
+ else
+ {
+ dest=YR8(z80,dest_r,pc);
+ src=YR8(z80,src_r,pc);
+ }
+
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src));
+}
+
+static void DIS_YADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("and",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YYOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("xor",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_Y_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("or",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_YCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cp",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc)));
+}
+
+static void DIS_POP_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("pop","iy");
+}
+
+static void DIS_EY_ISP_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ex","(sp),iy");
+}
+
+static void DIS_PUSH_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("push","iy");
+}
+
+static void DIS_JP_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("jp","(iy)");
+}
+
+static void DIS_LD_SP_IY(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","sp,iy");
+}
+
+static void DIS_FD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc);
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_FD_CB_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_FD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_DD_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_FD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_ED_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_FD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_FD_opcode[nop](z80,nop,pc);
+}
+
+
+/* ---------------------------------------- FD CB OPCODES
+*/
+
+static void DIS_RLC_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RRC_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RL_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RR_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SLA_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SRA_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SRL_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SLL_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+
+ reg=(op%8);
+
+ if (reg==6)
+ Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_BIT_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0x40)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_RES_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0x80)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+static void DIS_SET_IY (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int reg;
+ int bit;
+
+ reg=(op%8);
+ bit=(op-0xc0)/8;
+
+ if (reg==6)
+ Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc)));
+ else
+ Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg]));
+}
+
+
+/* ---------------------------------------- SINGLE BYTE OPCODES
+*/
+static void DIS_NOP (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("nop",NULL);
+}
+
+static void DIS_LD_R16_WORD (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.4x",reg,Z80_Dis_FetchWord(z80,pc)));
+}
+
+static void DIS_LD_R16_A (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",reg));
+}
+
+static void DIS_INC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("inc",reg);
+}
+
+static void DIS_INC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[(op&0x38)/0x8];
+ Z80_Dis_Set("inc",reg);
+}
+
+static void DIS_DEC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[(op&0x38)/0x8];
+ Z80_Dis_Set("dec",reg);
+}
+
+static void DIS_LD_R8_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[(op&0x38)/0x8];
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",reg,Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_RLCA (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rlca",NULL);
+}
+
+static void DIS_EX_AF_AF (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ex","af,af'");
+}
+
+static void DIS_ADD_HL_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("add",Z80_Dis_Printf("hl,%s",reg));
+}
+
+static void DIS_LD_A_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",reg));
+}
+
+static void DIS_DEC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op&0x30)/0x10];
+ Z80_Dis_Set("dec",reg);
+}
+
+static void DIS_RRCA (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rrca",NULL);
+}
+
+static void DIS_DJNZ (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word new;
+
+#ifdef ENABLE_ARRAY_MEMORY
+ new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1;
+#else
+ new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1;
+#endif
+ (*pc)++;
+ Z80_Dis_Set("djnz",Z80_Dis_Printf("$%.4x",new));
+}
+
+static void DIS_RLA (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rla",NULL);
+}
+
+static void DIS_JR (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word new;
+ const char *p;
+
+#ifdef ENABLE_ARRAY_MEMORY
+ new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1;
+#else
+ new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1;
+#endif
+ (*pc)++;
+
+ if ((p=GetLabel(new)))
+ Z80_Dis_Set("jr",Z80_Dis_Printf("%s",p));
+ else
+ Z80_Dis_Set("jr",Z80_Dis_Printf("$%.4x",new));
+}
+
+static void DIS_RRA (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("rra",NULL);
+}
+
+static void DIS_JR_CO (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *con;
+ Z80Word new;
+ const char *p;
+
+ con=z80_dis_condition[(op-0x20)/8];
+#ifdef ENABLE_ARRAY_MEMORY
+ new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1;
+#else
+ new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1;
+#endif
+ (*pc)++;
+
+ if ((p=GetLabel(new)))
+ Z80_Dis_Set("jr",Z80_Dis_Printf("%s,%s",con,p));
+ else
+ Z80_Dis_Set("jr",Z80_Dis_Printf("%s,$%.4x",con,new));
+}
+
+static void DIS_LD_ADDR_HL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),hl",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),hl",w));
+}
+
+static void DIS_DAA (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("daa",NULL);
+}
+
+static void DIS_LD_HL_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("hl,(%s)",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("hl,($%.4x)",w));
+}
+
+static void DIS_CPL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cpl",NULL);
+}
+
+static void DIS_LD_ADDR_A (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),a",w));
+}
+
+static void DIS_SCF (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("scf",NULL);
+}
+
+static void DIS_LD_A_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",p));
+ else
+ Z80_Dis_Set("ld",Z80_Dis_Printf("a,($%.4x)",w));
+}
+
+static void DIS_CCF (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ccf",NULL);
+}
+
+static void DIS_LD_R8_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *src,*dest;
+
+ dest=z80_dis_reg8[(op-0x40)/8];
+ src=z80_dis_reg8[op%8];
+ Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src));
+}
+
+static void DIS_HALT (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("halt",NULL);
+}
+
+static void DIS_ADD_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",reg));
+}
+
+static void DIS_ADC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",reg));
+}
+
+static void DIS_SUB_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",reg));
+}
+
+static void DIS_SBC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",reg));
+}
+
+static void DIS_AND_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("and",Z80_Dis_Printf("%s",reg));
+}
+
+static void DIS_XOR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("xor",Z80_Dis_Printf("%s",reg));
+}
+
+static void DIS_OR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("or",Z80_Dis_Printf("%s",reg));
+}
+
+static void DIS_CP_R8 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg8[op%8];
+ Z80_Dis_Set("cp",Z80_Dis_Printf("%s",reg));
+}
+
+
+static void DIS_RET_CO (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *con;
+
+ con=z80_dis_condition[(op-0xc0)/8];
+ Z80_Dis_Set("ret",con);
+}
+
+static void DIS_POP_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op-0xc0)/16];
+
+ if (!strcmp(reg,"sp"))
+ reg="af";
+
+ Z80_Dis_Set("pop",reg);
+}
+
+static void DIS_JP (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("jp",Z80_Dis_Printf("%s",p));
+ else
+ Z80_Dis_Set("jp",Z80_Dis_Printf("$%.4x",w));
+}
+
+static void DIS_PUSH_R16 (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *reg;
+
+ reg=z80_dis_reg16[(op-0xc0)/16];
+
+ if (!strcmp(reg,"sp"))
+ reg="af";
+
+ Z80_Dis_Set("push",reg);
+}
+
+static void DIS_ADD_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("add",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_RST (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int add;
+
+ add=(op&0x3f)-7;
+ Z80_Dis_Set("rst",Z80_Dis_Printf("%.2xh",add));
+}
+
+static void DIS_RET (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ret",NULL);
+}
+
+static void DIS_JP_CO (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *con;
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+ con=z80_dis_condition[(op-0xc0)/8];
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("jp",Z80_Dis_Printf("%s,%s",con,p));
+ else
+ Z80_Dis_Set("jp",Z80_Dis_Printf("%s,$%.4x",con,w));
+}
+
+static void DIS_CB_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_CB_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_CALL_CO (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ const char *con;
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+ con=z80_dis_condition[(op-0xc0)/8];
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("call",Z80_Dis_Printf("%s,%s",con,p));
+ else
+ Z80_Dis_Set("call",Z80_Dis_Printf("%s,$%.4x",con,w));
+}
+
+static void DIS_CALL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80Word w;
+ const char *p;
+
+ w=Z80_Dis_FetchWord(z80,pc);
+
+ if ((p=GetLabel(w)))
+ Z80_Dis_Set("call",Z80_Dis_Printf("%s",p));
+ else
+ Z80_Dis_Set("call",Z80_Dis_Printf("$%.4x",w));
+}
+
+static void DIS_ADC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("adc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_OUT_BYTE_A (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("out",Z80_Dis_Printf("($%.2x),a",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_SUB_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sub",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_EXX (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("exx",NULL);
+}
+
+static void DIS_IN_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("in",Z80_Dis_Printf("a,($%.2x)",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_DD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_DD_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_SBC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("sbc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+
+static void DIS_EX_ISP_HL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ex","(sp),hl");
+}
+
+static void DIS_AND_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("and",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_JP_HL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("jp","(hl)");
+}
+
+static void DIS_EX_DE_HL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ex","de,hl");
+}
+
+static void DIS_ED_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_ED_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_XOR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("xor",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_DI (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("di",NULL);
+}
+
+static void DIS_OR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("or",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+static void DIS_LD_SP_HL (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ld","sp,hl");
+}
+
+static void DIS_EI (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("ei",NULL);
+}
+
+static void DIS_FD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ int nop;
+
+ nop=Z80_Dis_FetchByte(z80,pc);
+ dis_FD_opcode[nop](z80,nop,pc);
+}
+
+static void DIS_CP_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc)
+{
+ Z80_Dis_Set("cp",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc)));
+}
+
+
+/* ---------------------------------------- TABLES
+*/
+
+/* CB opcodes
+*/
+DIS_OP_CALLBACK dis_CB_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8,
+/* 0x04 - 0x07 */ DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8,
+/* 0x08 - 0x0b */ DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8,
+/* 0x0c - 0x0f */ DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8,
+
+/* 0x10 - 0x13 */ DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, DIS_RL_R8,
+/* 0x14 - 0x17 */ DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, DIS_RL_R8,
+/* 0x18 - 0x1b */ DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, DIS_RR_R8,
+/* 0x1c - 0x1f */ DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, DIS_RR_R8,
+
+/* 0x20 - 0x23 */ DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8,
+/* 0x24 - 0x27 */ DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8,
+/* 0x28 - 0x2b */ DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8,
+/* 0x2c - 0x2f */ DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8,
+
+/* 0x30 - 0x33 */ DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8,
+/* 0x34 - 0x37 */ DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8,
+/* 0x38 - 0x3b */ DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8,
+/* 0x3c - 0x3f */ DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8,
+
+/* 0x40 - 0x43 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x44 - 0x47 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x48 - 0x4b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x4c - 0x4f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+
+/* 0x50 - 0x53 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x54 - 0x57 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x58 - 0x5b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x5c - 0x5f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+
+/* 0x60 - 0x63 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x64 - 0x67 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x68 - 0x6b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x6c - 0x6f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+
+/* 0x70 - 0x73 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x74 - 0x77 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x78 - 0x7b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+/* 0x7c - 0x7f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8,
+
+/* 0x80 - 0x83 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x84 - 0x87 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x88 - 0x8b */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x8c - 0x8f */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+
+/* 0x90 - 0x93 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x94 - 0x97 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x98 - 0x9b */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0x9c - 0x9f */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+
+/* 0xa0 - 0xa3 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xa4 - 0xa7 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xa8 - 0xab */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xac - 0xaf */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+
+/* 0xb0 - 0xb3 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xb4 - 0xb7 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xb8 - 0xbb */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+/* 0xbc - 0xbf */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8,
+
+/* 0xc0 - 0xc3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xc4 - 0xc7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xc8 - 0xcb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xcc - 0xcf */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+
+/* 0xd0 - 0xd3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xd4 - 0xd7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xd8 - 0xdb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xdc - 0xdf */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+
+/* 0xe0 - 0xe3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xe4 - 0xe7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xe8 - 0xeb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xec - 0xef */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+
+/* 0xf0 - 0xf3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xf4 - 0xf7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xf8 - 0xfb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+/* 0xfc - 0xff */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8,
+ };
+
+/* DIS_DD opcodes
+*/
+DIS_OP_CALLBACK dis_DD_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x04 - 0x07 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x08 - 0x0b */ DIS_DD_NOP, DIS_ADD_IX_BC, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x0c - 0x0f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0x10 - 0x13 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x14 - 0x17 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x18 - 0x1b */ DIS_DD_NOP, DIS_ADD_IX_DE, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x1c - 0x1f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0x20 - 0x23 */ DIS_DD_NOP, DIS_LD_IX_WORD, DIS_LD_ADDR_IX, DIS_INC_IX,
+/* 0x24 - 0x27 */ DIS_INC_IXH, DIS_DEC_IXH, DIS_LD_IXH_BYTE, DIS_DD_NOP,
+/* 0x28 - 0x2b */ DIS_DD_NOP, DIS_ADD_IX_IX, DIS_LD_IX_ADDR, DIS_DEC_IX,
+/* 0x2c - 0x2f */ DIS_INC_IXL, DIS_DEC_IXL, DIS_LD_IXL_BYTE, DIS_DD_NOP,
+
+/* 0x30 - 0x33 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x34 - 0x37 */ DIS_INC_IIX, DIS_DEC_IIX, DIS_LD_IIX_BYTE, DIS_DD_NOP,
+/* 0x38 - 0x3b */ DIS_DD_NOP, DIS_ADD_IX_SP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x3c - 0x3f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0x40 - 0x43 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x44 - 0x47 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP,
+/* 0x48 - 0x4b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x4c - 0x4f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP,
+
+/* 0x50 - 0x53 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x54 - 0x57 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP,
+/* 0x58 - 0x5b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x5c - 0x5f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP,
+
+/* 0x60 - 0x63 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8,
+/* 0x64 - 0x67 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8,
+/* 0x68 - 0x6b */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8,
+/* 0x6c - 0x6f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8,
+
+/* 0x70 - 0x73 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8,
+/* 0x74 - 0x77 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, DIS_XLD_R8_R8,
+/* 0x78 - 0x7b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x7c - 0x7f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP,
+
+/* 0x80 - 0x83 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x84 - 0x87 */ DIS_XADD_R8, DIS_XADD_R8, DIS_XADD_R8, DIS_DD_NOP,
+/* 0x88 - 0x8b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x8c - 0x8f */ DIS_XADC_R8, DIS_XADC_R8, DIS_XADC_R8, DIS_DD_NOP,
+
+/* 0x90 - 0x93 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x94 - 0x97 */ DIS_XSUB_R8, DIS_XSUB_R8, DIS_XSUB_R8, DIS_DD_NOP,
+/* 0x98 - 0x9b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0x9c - 0x9f */ DIS_XSBC_R8, DIS_XSBC_R8, DIS_XSBC_R8, DIS_DD_NOP,
+
+/* 0xa0 - 0xa3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xa4 - 0xa7 */ DIS_XAND_R8, DIS_XAND_R8, DIS_XAND_R8, DIS_DD_NOP,
+/* 0xa8 - 0xab */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xac - 0xaf */ DIS_XXOR_R8, DIS_XXOR_R8, DIS_XXOR_R8, DIS_DD_NOP,
+
+/* 0xb0 - 0xb3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xb4 - 0xb7 */ DIS_X_OR_R8, DIS_X_OR_R8, DIS_X_OR_R8, DIS_DD_NOP,
+/* 0xb8 - 0xbb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xbc - 0xbf */ DIS_XCP_R8, DIS_XCP_R8, DIS_XCP_R8, DIS_DD_NOP,
+
+/* 0xc0 - 0xc3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xc4 - 0xc7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xc8 - 0xcb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_CB_DECODE,
+/* 0xcc - 0xcf */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0xd0 - 0xd3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xd4 - 0xd7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xd8 - 0xdb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xdc - 0xdf */ DIS_DD_NOP, DIS_DD_DD_DECODE, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0xe0 - 0xe3 */ DIS_DD_NOP, DIS_POP_IX, DIS_DD_NOP, DIS_EX_ISP_IX,
+/* 0xe4 - 0xe7 */ DIS_DD_NOP, DIS_PUSH_IX, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xe8 - 0xeb */ DIS_DD_NOP, DIS_JP_IX, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xec - 0xef */ DIS_DD_NOP, DIS_DD_ED_DECODE, DIS_DD_NOP, DIS_DD_NOP,
+
+/* 0xf0 - 0xf3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xf4 - 0xf7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xf8 - 0xfb */ DIS_DD_NOP, DIS_LD_SP_IX, DIS_DD_NOP, DIS_DD_NOP,
+/* 0xfc - 0xff */ DIS_DD_NOP, DIS_DD_FD_DECODE, DIS_DD_NOP, DIS_DD_NOP,
+ };
+
+
+/* DIS_DD DIS_CB opcodes
+*/
+DIS_OP_CALLBACK dis_DD_CB_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX,
+/* 0x04 - 0x07 */ DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX,
+/* 0x08 - 0x0b */ DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX,
+/* 0x0c - 0x0f */ DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX,
+
+/* 0x10 - 0x13 */ DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, DIS_RL_IX,
+/* 0x14 - 0x17 */ DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, DIS_RL_IX,
+/* 0x18 - 0x1b */ DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, DIS_RR_IX,
+/* 0x1c - 0x1f */ DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, DIS_RR_IX,
+
+/* 0x20 - 0x23 */ DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX,
+/* 0x24 - 0x27 */ DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX,
+/* 0x28 - 0x2b */ DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX,
+/* 0x2c - 0x2f */ DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX,
+
+/* 0x30 - 0x33 */ DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX,
+/* 0x34 - 0x37 */ DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX,
+/* 0x38 - 0x3b */ DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX,
+/* 0x3c - 0x3f */ DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX,
+
+/* 0x40 - 0x43 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x44 - 0x47 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x48 - 0x4b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x4c - 0x4f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+
+/* 0x50 - 0x53 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x54 - 0x57 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x58 - 0x5b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x5c - 0x5f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+
+/* 0x60 - 0x63 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x64 - 0x67 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x68 - 0x6b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x6c - 0x6f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+
+/* 0x70 - 0x73 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x74 - 0x77 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x78 - 0x7b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+/* 0x7c - 0x7f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX,
+
+/* 0x80 - 0x83 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x84 - 0x87 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x88 - 0x8b */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x8c - 0x8f */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+
+/* 0x90 - 0x93 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x94 - 0x97 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x98 - 0x9b */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0x9c - 0x9f */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+
+/* 0xa0 - 0xa3 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xa4 - 0xa7 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xa8 - 0xab */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xac - 0xaf */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+
+/* 0xb0 - 0xb3 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xb4 - 0xb7 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xb8 - 0xbb */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+/* 0xbc - 0xbf */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX,
+
+/* 0xc0 - 0xc3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xc4 - 0xc7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xc8 - 0xcb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xcc - 0xcf */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+
+/* 0xd0 - 0xd3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xd4 - 0xd7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xd8 - 0xdb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xdc - 0xdf */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+
+/* 0xe0 - 0xe3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xe4 - 0xe7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xe8 - 0xeb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xec - 0xef */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+
+/* 0xf0 - 0xf3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xf4 - 0xf7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xf8 - 0xfb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+/* 0xfc - 0xff */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX,
+ };
+
+/* DIS_ED opcodes
+*/
+DIS_OP_CALLBACK dis_ED_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x04 - 0x07 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x08 - 0x0b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x0c - 0x0f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0x10 - 0x13 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x14 - 0x17 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x18 - 0x1b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x1c - 0x1f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0x20 - 0x23 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x24 - 0x27 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x28 - 0x2b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x2c - 0x2f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0x30 - 0x33 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x34 - 0x37 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x38 - 0x3b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x3c - 0x3f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0x40 - 0x43 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16,
+/* 0x44 - 0x47 */ DIS_NEG, DIS_RETN, DIS_IM_0, DIS_LD_I_A,
+/* 0x48 - 0x4b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR,
+/* 0x4c - 0x4f */ DIS_NEG, DIS_RETI, DIS_IM_0, DIS_LD_R_A,
+
+/* 0x50 - 0x53 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16,
+/* 0x54 - 0x57 */ DIS_NEG, DIS_RETN, DIS_IM_1, DIS_LD_A_I,
+/* 0x58 - 0x5b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR,
+/* 0x5c - 0x5f */ DIS_NEG, DIS_RETI, DIS_IM_2, DIS_LD_A_R,
+
+/* 0x60 - 0x63 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16,
+/* 0x64 - 0x67 */ DIS_NEG, DIS_RETN, DIS_IM_0, DIS_RRD,
+/* 0x68 - 0x6b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR,
+/* 0x6c - 0x6f */ DIS_NEG, DIS_RETI, DIS_IM_0, DIS_RLD,
+
+/* 0x70 - 0x73 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16,
+/* 0x74 - 0x77 */ DIS_NEG, DIS_RETN, DIS_IM_1, DIS_ED_NOP,
+/* 0x78 - 0x7b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR,
+/* 0x7c - 0x7f */ DIS_NEG, DIS_RETI, DIS_IM_2, DIS_ED_NOP,
+
+/* 0x80 - 0x83 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x84 - 0x87 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x88 - 0x8b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x8c - 0x8f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0x90 - 0x93 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x94 - 0x97 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x98 - 0x9b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0x9c - 0x9f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xa0 - 0xa3 */ DIS_LDI, DIS_CPI, DIS_INI, DIS_OUTI,
+/* 0xa4 - 0xa7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xa8 - 0xab */ DIS_LDD, DIS_CPD, DIS_IND, DIS_OUTD,
+/* 0xac - 0xaf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xb0 - 0xb3 */ DIS_LDIR, DIS_CPIR, DIS_INIR, DIS_OTIR,
+/* 0xb4 - 0xb7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xb8 - 0xbb */ DIS_LDDR, DIS_CPDR, DIS_INDR, DIS_OTDR,
+/* 0xbc - 0xbf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xc0 - 0xc3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xc4 - 0xc7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xc8 - 0xcb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xcc - 0xcf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xd0 - 0xd3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xd4 - 0xd7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xd8 - 0xdb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xdc - 0xdf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xe0 - 0xe3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xe4 - 0xe7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xe8 - 0xeb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xec - 0xef */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+
+/* 0xf0 - 0xf3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xf4 - 0xf7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xf8 - 0xfb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+/* 0xfc - 0xff */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP,
+ };
+
+/* DIS_FD opcodes
+*/
+DIS_OP_CALLBACK dis_FD_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x04 - 0x07 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x08 - 0x0b */ DIS_FD_NOP, DIS_ADD_IY_BC, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x0c - 0x0f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0x10 - 0x13 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x14 - 0x17 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x18 - 0x1b */ DIS_FD_NOP, DIS_ADD_IY_DE, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x1c - 0x1f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0x20 - 0x23 */ DIS_FD_NOP, DIS_LD_IY_WORD, DIS_LD_ADDR_IY, DIS_INC_IY,
+/* 0x24 - 0x27 */ DIS_INC_IYH, DIS_DEC_IYH, DIS_LD_IYH_BYTE, DIS_FD_NOP,
+/* 0x28 - 0x2b */ DIS_FD_NOP, DIS_ADD_IY_IY, DIS_LD_IY_ADDR, DIS_DEC_IY,
+/* 0x2c - 0x2f */ DIS_INC_IYL, DIS_DEC_IYL, DIS_LD_IYL_BYTE, DIS_FD_NOP,
+
+/* 0x30 - 0x33 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x34 - 0x37 */ DIS_INC_IIY, DIS_DEC_IIY, DIS_LD_IIY_BYTE, DIS_FD_NOP,
+/* 0x38 - 0x3b */ DIS_FD_NOP, DIS_ADD_IY_SP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x3c - 0x3f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0x40 - 0x43 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x44 - 0x47 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP,
+/* 0x48 - 0x4b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x4c - 0x4f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP,
+
+/* 0x50 - 0x53 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x54 - 0x57 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP,
+/* 0x58 - 0x5b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x5c - 0x5f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP,
+
+/* 0x60 - 0x63 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8,
+/* 0x64 - 0x67 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8,
+/* 0x68 - 0x6b */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8,
+/* 0x6c - 0x6f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8,
+
+/* 0x70 - 0x73 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8,
+/* 0x74 - 0x77 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, DIS_YLD_R8_R8,
+/* 0x78 - 0x7b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x7c - 0x7f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP,
+
+/* 0x80 - 0x83 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x84 - 0x87 */ DIS_YADD_R8, DIS_YADD_R8, DIS_YADD_R8, DIS_FD_NOP,
+/* 0x88 - 0x8b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x8c - 0x8f */ DIS_YADC_R8, DIS_YADC_R8, DIS_YADC_R8, DIS_FD_NOP,
+
+/* 0x90 - 0x93 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x94 - 0x97 */ DIS_YSUB_R8, DIS_YSUB_R8, DIS_YSUB_R8, DIS_FD_NOP,
+/* 0x98 - 0x9b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0x9c - 0x9f */ DIS_YSBC_R8, DIS_YSBC_R8, DIS_YSBC_R8, DIS_FD_NOP,
+
+/* 0xa0 - 0xa3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xa4 - 0xa7 */ DIS_YAND_R8, DIS_YAND_R8, DIS_YAND_R8, DIS_FD_NOP,
+/* 0xa8 - 0xab */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xac - 0xaf */ DIS_YYOR_R8, DIS_YYOR_R8, DIS_YYOR_R8, DIS_FD_NOP,
+
+/* 0xb0 - 0xb3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xb4 - 0xb7 */ DIS_Y_OR_R8, DIS_Y_OR_R8, DIS_Y_OR_R8, DIS_FD_NOP,
+/* 0xb8 - 0xbb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xbc - 0xbf */ DIS_YCP_R8, DIS_YCP_R8, DIS_YCP_R8, DIS_FD_NOP,
+
+/* 0xc0 - 0xc3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xc4 - 0xc7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xc8 - 0xcb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_CB_DECODE,
+/* 0xcc - 0xcf */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0xd0 - 0xd3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xd4 - 0xd7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xd8 - 0xdb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xdc - 0xdf */ DIS_FD_NOP, DIS_FD_DD_DECODE, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0xe0 - 0xe3 */ DIS_FD_NOP, DIS_POP_IY, DIS_FD_NOP, DIS_EY_ISP_IY,
+/* 0xe4 - 0xe7 */ DIS_FD_NOP, DIS_PUSH_IY, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xe8 - 0xeb */ DIS_FD_NOP, DIS_JP_IY, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xec - 0xef */ DIS_FD_NOP, DIS_FD_ED_DECODE, DIS_FD_NOP, DIS_FD_NOP,
+
+/* 0xf0 - 0xf3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xf4 - 0xf7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xf8 - 0xfb */ DIS_FD_NOP, DIS_LD_SP_IY, DIS_FD_NOP, DIS_FD_NOP,
+/* 0xfc - 0xff */ DIS_FD_NOP, DIS_FD_FD_DECODE, DIS_FD_NOP, DIS_FD_NOP,
+ };
+
+
+/* DIS_FD DIS_CB opcodes
+*/
+DIS_OP_CALLBACK dis_FD_CB_opcode[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY,
+/* 0x04 - 0x07 */ DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY,
+/* 0x08 - 0x0b */ DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY,
+/* 0x0c - 0x0f */ DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY,
+
+/* 0x10 - 0x13 */ DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, DIS_RL_IY,
+/* 0x14 - 0x17 */ DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, DIS_RL_IY,
+/* 0x18 - 0x1b */ DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, DIS_RR_IY,
+/* 0x1c - 0x1f */ DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, DIS_RR_IY,
+
+/* 0x20 - 0x23 */ DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY,
+/* 0x24 - 0x27 */ DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY,
+/* 0x28 - 0x2b */ DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY,
+/* 0x2c - 0x2f */ DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY,
+
+/* 0x30 - 0x33 */ DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY,
+/* 0x34 - 0x37 */ DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY,
+/* 0x38 - 0x3b */ DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY,
+/* 0x3c - 0x3f */ DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY,
+
+/* 0x40 - 0x43 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x44 - 0x47 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x48 - 0x4b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x4c - 0x4f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+
+/* 0x50 - 0x53 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x54 - 0x57 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x58 - 0x5b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x5c - 0x5f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+
+/* 0x60 - 0x63 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x64 - 0x67 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x68 - 0x6b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x6c - 0x6f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+
+/* 0x70 - 0x73 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x74 - 0x77 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x78 - 0x7b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+/* 0x7c - 0x7f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY,
+
+/* 0x80 - 0x83 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x84 - 0x87 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x88 - 0x8b */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x8c - 0x8f */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+
+/* 0x90 - 0x93 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x94 - 0x97 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x98 - 0x9b */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0x9c - 0x9f */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+
+/* 0xa0 - 0xa3 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xa4 - 0xa7 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xa8 - 0xab */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xac - 0xaf */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+
+/* 0xb0 - 0xb3 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xb4 - 0xb7 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xb8 - 0xbb */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+/* 0xbc - 0xbf */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY,
+
+/* 0xc0 - 0xc3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xc4 - 0xc7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xc8 - 0xcb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xcc - 0xcf */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+
+/* 0xd0 - 0xd3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xd4 - 0xd7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xd8 - 0xdb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xdc - 0xdf */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+
+/* 0xe0 - 0xe3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xe4 - 0xe7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xe8 - 0xeb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xec - 0xef */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+
+/* 0xf0 - 0xf3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xf4 - 0xf7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xf8 - 0xfb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+/* 0xfc - 0xff */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY,
+ };
+
+/* DIS_First/single byte opcodes
+*/
+DIS_OP_CALLBACK dis_opcode_z80[0x100]=
+ {
+/* 0x00 - 0x03 */ DIS_NOP, DIS_LD_R16_WORD, DIS_LD_R16_A, DIS_INC_R16,
+/* 0x04 - 0x07 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RLCA,
+/* 0x08 - 0x0b */ DIS_EX_AF_AF, DIS_ADD_HL_R16, DIS_LD_A_R16, DIS_DEC_R16,
+/* 0x0c - 0x0f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RRCA,
+
+/* 0x10 - 0x13 */ DIS_DJNZ, DIS_LD_R16_WORD, DIS_LD_R16_A, DIS_INC_R16,
+/* 0x14 - 0x17 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RLA,
+/* 0x18 - 0x1b */ DIS_JR, DIS_ADD_HL_R16, DIS_LD_A_R16, DIS_DEC_R16,
+/* 0x1c - 0x1f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RRA,
+
+/* 0x20 - 0x23 */ DIS_JR_CO, DIS_LD_R16_WORD, DIS_LD_ADDR_HL, DIS_INC_R16,
+/* 0x24 - 0x27 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_DAA,
+/* 0x28 - 0x2b */ DIS_JR_CO, DIS_ADD_HL_R16, DIS_LD_HL_ADDR, DIS_DEC_R16,
+/* 0x2c - 0x2f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_CPL,
+
+/* 0x30 - 0x33 */ DIS_JR_CO, DIS_LD_R16_WORD, DIS_LD_ADDR_A, DIS_INC_R16,
+/* 0x34 - 0x37 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_SCF,
+/* 0x38 - 0x3b */ DIS_JR_CO, DIS_ADD_HL_R16, DIS_LD_A_ADDR, DIS_DEC_R16,
+/* 0x3c - 0x3f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_CCF,
+
+/* 0x40 - 0x43 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x44 - 0x47 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x48 - 0x4b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x4c - 0x4f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+
+/* 0x50 - 0x53 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x54 - 0x57 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x58 - 0x5b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x5c - 0x5f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+
+/* 0x60 - 0x63 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x64 - 0x67 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x68 - 0x6b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x6c - 0x6f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+
+/* 0x70 - 0x73 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x74 - 0x77 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_HALT, DIS_LD_R8_R8,
+/* 0x78 - 0x7b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+/* 0x7c - 0x7f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8,
+
+/* 0x80 - 0x83 */ DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8,
+/* 0x84 - 0x87 */ DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8,
+/* 0x88 - 0x8b */ DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8,
+/* 0x8c - 0x8f */ DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8,
+
+/* 0x90 - 0x93 */ DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8,
+/* 0x94 - 0x97 */ DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8,
+/* 0x98 - 0x9b */ DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8,
+/* 0x9c - 0x9f */ DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8,
+
+/* 0xa0 - 0xa3 */ DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, DIS_AND_R8,
+/* 0xa4 - 0xa7 */ DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, DIS_AND_R8,
+/* 0xa8 - 0xab */ DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8,
+/* 0xac - 0xaf */ DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8,
+
+/* 0xb0 - 0xb3 */ DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, DIS_OR_R8,
+/* 0xb4 - 0xb7 */ DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, DIS_OR_R8,
+/* 0xb8 - 0xbb */ DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, DIS_CP_R8,
+/* 0xbc - 0xbf */ DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, DIS_CP_R8,
+
+/* 0xc0 - 0xc3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_JP,
+/* 0xc4 - 0xc7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_ADD_A_BYTE, DIS_RST,
+/* 0xc8 - 0xcb */ DIS_RET_CO, DIS_RET, DIS_JP_CO, DIS_CB_DECODE,
+/* 0xcc - 0xcf */ DIS_CALL_CO, DIS_CALL, DIS_ADC_A_BYTE, DIS_RST,
+
+/* 0xd0 - 0xd3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_OUT_BYTE_A,
+/* 0xd4 - 0xd7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_SUB_A_BYTE, DIS_RST,
+/* 0xd8 - 0xdb */ DIS_RET_CO, DIS_EXX, DIS_JP_CO, DIS_IN_A_BYTE,
+/* 0xdc - 0xdf */ DIS_CALL_CO, DIS_DD_DECODE, DIS_SBC_A_BYTE, DIS_RST,
+
+/* 0xe0 - 0xe3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_EX_ISP_HL,
+/* 0xe4 - 0xe7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_AND_A_BYTE, DIS_RST,
+/* 0xe8 - 0xeb */ DIS_RET_CO, DIS_JP_HL, DIS_JP_CO, DIS_EX_DE_HL,
+/* 0xec - 0xef */ DIS_CALL_CO, DIS_ED_DECODE, DIS_XOR_A_BYTE, DIS_RST,
+
+/* 0xf0 - 0xf3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_DI,
+/* 0xf4 - 0xf7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_OR_A_BYTE, DIS_RST,
+/* 0xf8 - 0xfb */ DIS_RET_CO, DIS_LD_SP_HL, DIS_JP_CO, DIS_EI,
+/* 0xfc - 0xff */ DIS_CALL_CO, DIS_FD_DECODE, DIS_CP_A_BYTE, DIS_RST,
+ };
+
+
+#endif
+
+/* END OF FILE */
diff --git a/source/zx81.c b/source/zx81.c
new file mode 100644
index 0000000..7aa5380
--- /dev/null
+++ b/source/zx81.c
@@ -0,0 +1,1171 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Provides the emulation for the ZX81
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <nds.h>
+
+#include "zx81.h"
+#include "gui.h"
+
+#include "stream.h"
+
+#include "config.h"
+
+#include "zx81_bin.h"
+
+#include "ds81_debug.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* ---------------------------------------- STATICS
+*/
+#define ROMLEN 0x2000
+#define ROM_SAVE 0x2fc
+#define ROM_LOAD 0x347
+
+#define ED_SAVE 0xf0
+#define ED_LOAD 0xf1
+#define ED_WAITKEY 0xf2
+#define ED_ENDWAITKEY 0xf3
+#define ED_PAUSE 0xf4
+
+#define SLOW_TSTATES 16000
+#define FAST_TSTATES 64000
+
+#define E_LINE 16404
+#define LASTK1 16421
+#define LASTK2 16422
+#define MARGIN 16424
+#define FRAMES 16436
+#define CDFLAG 16443
+
+static Z80Val FRAME_TSTATES=FAST_TSTATES;
+
+/* The ZX81 screen and memory
+*/
+static void (*DrawScreen)(Z80 *z80);
+
+static int waitkey=FALSE;
+static int started=FALSE;
+
+static int hires=FALSE;
+static int hires_dfile;
+static int last_I;
+
+static unsigned prev_lk1;
+static unsigned prev_lk2;
+
+#define SCR_W 256
+#define SCR_H 192
+#define TXT_W 32
+#define TXT_H 24
+
+static Z80Byte mem[0x10000];
+
+static Z80Byte scr_mirror[7000];
+
+static Z80Word RAMBOT=0;
+static Z80Word RAMTOP=0;
+
+#define DFILE 0x400c
+
+#define WORD(a) (mem[a] | (Z80Word)mem[a+1]<<8)
+
+/* Tape
+*/
+static int enable_filesystem;
+static int allow_save;
+static const Z80Byte *tape_image;
+static int tape_len;
+
+static char last_dir[FILENAME_MAX] = "/";
+
+/* GFX vars
+*/
+static uint16 *txt_screen;
+static uint16 *bmp_screen;
+
+/* The keyboard
+*/
+static Z80Byte matrix[8];
+
+static struct
+{
+ int row;
+ int bit;
+} key_matrix[]=
+ {
+ {3,0x01}, {3,0x02}, {3,0x04}, {3,0x08}, {3,0x10}, /* 1 - 5 */
+ {4,0x10}, {4,0x08}, {4,0x04}, {4,0x02}, {4,0x01}, /* 6 - 0 */
+ {2,0x01}, {2,0x02}, {2,0x04}, {2,0x08}, {2,0x10}, /* Q - T */
+ {5,0x10}, {5,0x08}, {5,0x04}, {5,0x02}, {5,0x01}, /* Y - P */
+ {1,0x01}, {1,0x02}, {1,0x04}, {1,0x08}, {1,0x10}, /* A - G */
+ {6,0x10}, {6,0x08}, {6,0x04}, {6,0x02}, {6,0x01}, /* H - NL */
+ {0,0x01}, {0,0x02}, {0,0x04}, {0,0x08}, {0,0x10}, /* CAPS - V */
+ {7,0x10}, {7,0x08}, {7,0x04}, {7,0x02}, {7,0x01} /* B - SPACE */
+ };
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+#define PEEKW(addr) (mem[addr] | (Z80Word)mem[addr+1]<<8)
+
+#define POKEW(addr,val) do \
+ { \
+ Z80Word wa=addr; \
+ Z80Word wv=val; \
+ mem[wa]=wv; \
+ mem[wa+1]=wv>>8; \
+ } while(0)
+
+static void RomPatch(void)
+{
+ static const Z80Byte save[]=
+ {
+ 0xed, ED_SAVE, /* (SAVE) */
+ 0xc3, 0x07, 0x02, /* JP $0207 */
+ 0xff /* End of patch */
+ };
+
+ static const Z80Byte load[]=
+ {
+ 0xed, ED_LOAD, /* (LOAD) */
+ 0xc3, 0x07, 0x02, /* JP $0207 */
+ 0xff /* End of patch */
+ };
+
+ static const Z80Byte fast_hack[]=
+ {
+ 0xed, ED_WAITKEY, /* (START KEY WAIT) */
+ 0xcb,0x46, /* L: bit 0,(hl) */
+ 0x28,0xfc, /* jr z,L */
+ 0xed, ED_ENDWAITKEY, /* (END KEY WAIT) */
+ 0x00, /* nop */
+ 0xff /* End of patch */
+ };
+
+ static const Z80Byte kbd_hack[]=
+ {
+ 0x2a,0x25,0x40, /* ld hl,(LASTK) */
+ 0xc9, /* ret */
+ 0xff /* End of patch */
+ };
+
+ static const Z80Byte pause_hack[]=
+ {
+ 0xed, ED_PAUSE, /* (PAUSE) */
+ 0x00, /* nop */
+ 0xff /* End of patch */
+ };
+
+ int f;
+
+ for(f=0;save[f]!=0xff;f++)
+ {
+ mem[ROM_SAVE+f]=save[f];
+ }
+
+ for(f=0;load[f]!=0xff;f++)
+ {
+ mem[ROM_LOAD+f]=load[f];
+ }
+
+ for(f=0;fast_hack[f]!=0xff;f++)
+ {
+ mem[0x4ca+f]=fast_hack[f];
+ }
+
+ for(f=0;kbd_hack[f]!=0xff;f++)
+ {
+ mem[0x2bb+f]=kbd_hack[f];
+ }
+
+ for(f=0;pause_hack[f]!=0xff;f++)
+ {
+ mem[0xf3a+f]=pause_hack[f];
+ }
+
+ /* Trust me, we have a ZX81... Honestly.
+ */
+ mem[0x21c]=0x00;
+ mem[0x21d]=0x00;
+
+ /* Remove HALTs as we don't do interrupts
+ */
+ mem[0x0079]=0;
+ mem[0x02ec]=0;
+}
+
+static Z80Byte FromASCII(char c)
+{
+ static const char *charset =
+ /* 0123456789 */
+ " _________"
+ "_\"#$:?()><"
+ "=+-*/:,.01"
+ "23456789ab"
+ "cdefghijkl"
+ "mnopqrstuv"
+ "wxyz";
+
+ int f;
+
+ c = tolower(c);
+
+ for(f = 0; charset[f]; f++)
+ {
+ if (charset[f] == c)
+ {
+ return f;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Open a tape file the passed address
+*/
+static FILE *OpenTapeFile(Z80Word addr, int *cancelled, const char *mode)
+{
+ static const char zx_chars[] = "\"#$:?()><=+-*/;,."
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ FILE *fp;
+ char full_fn[FILENAME_MAX] = DEFAULT_SNAPDIR;
+ char fn[FILENAME_MAX];
+ int f;
+ int done;
+
+ fp = NULL;
+ f = 0;
+ done = FALSE;
+ *cancelled = FALSE;
+
+ while(f<(FILENAME_MAX-3) && !done)
+ {
+ int ch;
+
+ ch = mem[addr++];
+
+ if (ch&0x80)
+ {
+ done = TRUE;
+ ch &= 0x7f;
+ }
+
+ if (ch>=11 && ch<=63)
+ {
+ fn[f++] = zx_chars[ch-11];
+ }
+ }
+
+ if (fn[0] == '*')
+ {
+ if (GUI_FileSelect(last_dir,fn,".P"))
+ {
+ fp = fopen(fn, mode);
+ }
+ else
+ {
+ *cancelled = TRUE;
+ }
+
+ SK_DisplayKeyboard();
+ }
+ else
+ {
+ fn[f++] = '.';
+ fn[f++] = 'P';
+ fn[f] = 0;
+
+ strcat(full_fn,fn);
+
+ if (!(fp = fopen(full_fn, mode)))
+ {
+ fp = fopen(fn, mode);
+ }
+ }
+
+ return fp;
+}
+
+
+static void LoadInternalTape(Z80 *z80)
+{
+ memcpy(mem+0x4009,tape_image,tape_len);
+}
+
+
+static void LoadExternalTape(FILE *tape, Z80 *z80)
+{
+ int c;
+ Z80Byte *a;
+
+ a=mem+0x4009;
+
+ while((c=getc(tape))!=EOF)
+ {
+ *a++=c;
+ }
+}
+
+
+static void SaveExternalTape(FILE *tape, Z80 *z80)
+{
+ int f;
+ int end;
+
+ f = 0x4009;
+ end = WORD(E_LINE);
+
+ while(f <= end)
+ {
+ fputc(mem[f++], tape);
+ }
+}
+
+
+static void ClearBitmap(void)
+{
+ uint16 *s;
+ uint16 p;
+ int f;
+
+ s = bmp_screen;
+ p = 0x8000|RGB15(31,31,31);
+
+ for(f=0;f<SCREEN_WIDTH*SCREEN_HEIGHT;f++)
+ {
+ *s++=p;
+ }
+}
+
+
+static void ClearText(void)
+{
+ uint16 *s;
+ int f;
+
+ s = txt_screen;
+
+ for(f=0;f<TXT_W*TXT_H;f++)
+ {
+ *s++=0;
+ }
+}
+
+
+static void DrawScreen_HIRES_Dirty(Z80 *z80)
+{
+ uint16 *bmp;
+ Z80Byte *scr;
+ Z80Byte *mirror;
+ int x,y;
+ int table;
+ int c;
+ int v;
+ int b;
+
+ scr = mem + hires_dfile;
+ mirror = scr_mirror;
+ bmp = bmp_screen;
+ table = z80->I << 8;
+
+ /* scr is increment in both loops so that it can skip the end-of-line
+ character
+ */
+ for(y=0; y<192; y++)
+ {
+ for(x=0; x<32; x++)
+ {
+ c = *scr;
+
+ if (c != *mirror)
+ {
+ *mirror++ = c;
+
+ v = mem[table + (c&0x3f)*8];
+
+ if (c & 0x80)
+ {
+ v ^= 0xff;
+ }
+
+ for(b=0;b<8;b++)
+ {
+ if (v & 0x80)
+ {
+ *bmp++ = 0x8000;
+ }
+ else
+ {
+ *bmp++ = 0xffff;
+ }
+
+ v=v<<1;
+ }
+ }
+ else
+ {
+ mirror++;
+ bmp+=8;
+ }
+
+ scr++;
+ }
+
+ scr++;
+ }
+}
+
+
+static void DrawScreen_HIRES_Full(Z80 *z80)
+{
+ uint16 *bmp;
+ Z80Byte *scr;
+ Z80Byte *mirror;
+ int x,y;
+ int table;
+
+ scr = mem + hires_dfile;
+ mirror = scr_mirror;
+ bmp = bmp_screen;
+ table = z80->I << 8;
+
+ /* scr is increment in both loops so that it can skip the end-of-line
+ character
+ */
+ for(y=0; y<192; y++)
+ {
+ for(x=0; x<32; x++)
+ {
+ int c;
+ int v;
+ int b;
+
+ c = *mirror++ = *scr;
+
+ v = mem[table + (c&0x3f)*8];
+
+ if (c & 0x80)
+ {
+ v ^= 0xff;
+ }
+
+ for(b=0;b<8;b++)
+ {
+ if (v & 0x80)
+ {
+ *bmp++ = 0x8000;
+ }
+ else
+ {
+ *bmp++ = 0xffff;
+ }
+
+ v=v<<1;
+ }
+
+ scr++;
+ }
+
+ scr++;
+ }
+
+ DrawScreen = DrawScreen_HIRES_Dirty;
+}
+
+
+static void DrawScreen_TEXT(Z80 *z80)
+{
+ Z80Byte *scr=mem+WORD(DFILE);
+ int x,y;
+
+ x=0;
+ y=0;
+
+ while(y<TXT_H)
+ {
+ scr++;
+ x=0;
+
+ while((*scr!=118)&&(x<TXT_W))
+ {
+ Z80Byte ch = *scr++;
+
+ if (ch&0x80)
+ {
+ txt_screen[x+y*32]=(ch&0x3f)|0x40;
+ }
+ else
+ {
+ txt_screen[x+y*32]=(ch&0x3f);
+ }
+
+ x++;
+ }
+
+ while (x<TXT_W)
+ {
+ txt_screen[x+y*32]=0;
+ x++;
+ }
+
+ y++;
+ }
+}
+
+
+static void DrawSnow(Z80 *z80)
+{
+ uint16 *s;
+ int f;
+
+ s = txt_screen;
+
+ for(f=0;f<TXT_W*TXT_H;f++)
+ {
+ *s++=8;
+ }
+}
+
+
+static void FindHiresDFILE(void)
+{
+ /* Somewhat based on the code from xz81, an X-based ZX81 emulator,
+ (C) 1994 Ian Collier. Search the ZX81's RAM until we find what looks
+ like a hi-res display file.
+
+ Bizarrely the original code used 'f' for a loop counter too... Another
+ poor soul forever damaged by the ZX81's keyword entry system...
+ */
+ int f;
+
+ for(f=0x8000-(33*192); f>0x4000 ; f--)
+ {
+ int v;
+
+ v = mem[f+32];
+
+ if (v&0x40)
+ {
+ int ok = TRUE;
+ int n;
+
+ for(n=0;n<192 && ok;n++)
+ {
+ if (mem[f+33*n]&0x40)
+ {
+ ok = FALSE;
+ }
+
+ if (mem[f+32+33*n] != v)
+ {
+ ok = FALSE;
+ }
+ }
+
+ if (ok)
+ {
+ hires_dfile = f;
+ return;
+ }
+ }
+ }
+
+ /* All else fails, put the hires dfile at 0x4000 -- at least it should be
+ obvious that the hires won't work for whatever is being run.
+ */
+ hires_dfile = 0x4000;
+}
+
+
+/* Perform ZX81 housekeeping functions like updating FRAMES and updating LASTK
+*/
+static void ZX81HouseKeeping(Z80 *z80)
+{
+ unsigned row;
+ unsigned lastk1;
+ unsigned lastk2;
+
+ /* British ZX81
+ */
+ mem[MARGIN]=55;
+
+ /* Update FRAMES
+ */
+ if (FRAME_TSTATES==SLOW_TSTATES)
+ {
+ Z80Word frame=PEEKW(FRAMES)&0x7fff;
+
+ if (frame)
+ {
+ frame--;
+ }
+
+ POKEW(FRAMES,frame|0x8000);
+ }
+
+ if (!started)
+ {
+ prev_lk1=0;
+ prev_lk2=0;
+ return;
+ }
+
+ /* Update LASTK
+ */
+ lastk1=0;
+ lastk2=0;
+
+ for(row=0;row<8;row++)
+ {
+ unsigned b;
+
+ b=(~matrix[row]&0x1f)<<1;
+
+ if (row==0)
+ {
+ unsigned shift;
+
+ shift=b&2;
+ b&=~2;
+ b|=(shift>>1);
+ }
+
+ if (b)
+ {
+ if (b>1)
+ {
+ lastk1|=(1<<row);
+ }
+
+ lastk2|=b;
+ }
+ }
+
+ if (lastk1 && (lastk1!=prev_lk1 || lastk2!=prev_lk2))
+ {
+ mem[CDFLAG]|=1;
+ }
+ else
+ {
+ mem[CDFLAG]&=~1;
+ }
+
+ mem[LASTK1]=lastk1^0xff;
+ mem[LASTK2]=lastk2^0xff;
+
+ prev_lk1=lastk1;
+ prev_lk2=lastk2;
+}
+
+
+static int CheckTimers(Z80 *z80, Z80Val val)
+{
+ if (val>=FRAME_TSTATES)
+ {
+ /* Check for hi-res modes
+ */
+ if (z80->I && z80->I != last_I)
+ {
+ last_I = z80->I;
+
+ if (z80->I == 0x1e)
+ {
+ hires = FALSE;
+ DrawScreen = DrawScreen_TEXT;
+ ClearBitmap();
+ }
+ else
+ {
+ hires = TRUE;
+ DrawScreen = DrawScreen_HIRES_Full;
+ ClearBitmap();
+ ClearText();
+ FindHiresDFILE();
+ }
+ }
+
+ Z80ResetCycles(z80,val-FRAME_TSTATES);
+
+ /* Kludge warning - We assume that a hires display will not be in
+ FAST mode!
+ */
+ if (started && ((mem[CDFLAG] & 0x80) || waitkey || hires))
+ {
+ DrawScreen(z80);
+ FRAME_TSTATES=SLOW_TSTATES;
+ }
+ else
+ {
+ DrawSnow(z80);
+ FRAME_TSTATES=FAST_TSTATES;
+ }
+
+ /* Update FRAMES (if in SLOW) and scan the keyboard. This only happens
+ once we've got to a decent point in the boot cycle (detected with
+ a valid stack pointer).
+ */
+ if (z80->SP<0x8000)
+ {
+ ZX81HouseKeeping(z80);
+ }
+
+ swiWaitForVBlank();
+
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+
+static int EDCallback(Z80 *z80, Z80Val data)
+{
+ Z80Word pause;
+
+ switch((Z80Byte)data)
+ {
+ case ED_SAVE:
+ if (allow_save && z80->DE.w<0x8000)
+ {
+ FILE *fp;
+ int cancel;
+
+ if ((fp=OpenTapeFile(z80->HL.w, &cancel, "wb")))
+ {
+ SaveExternalTape(fp,z80);
+ fclose(fp);
+ }
+ }
+ break;
+
+ case ED_LOAD:
+ /* Try and load the external file if a name given. Otherwise, we
+ try the internal one. Some of this is slightly dodgy -- it was
+ never intended for the emulator to be doing any GUI related
+ nonsense (like the alerts) but simply emulating.
+ */
+ if (enable_filesystem && z80->DE.w<0x8000)
+ {
+ FILE *fp;
+ int cancel;
+
+ if ((fp=OpenTapeFile(z80->DE.w, &cancel, "rb")))
+ {
+ LoadExternalTape(fp,z80);
+ fclose(fp);
+ }
+ else
+ {
+ if (!cancel)
+ {
+ GUI_Alert(FALSE,"Couldn't open tape");
+ SK_DisplayKeyboard();
+ }
+ }
+ }
+ else
+ {
+ if (tape_image)
+ {
+ LoadInternalTape(z80);
+ }
+ else
+ {
+ GUI_Alert(FALSE,"No tape image selected");
+ SK_DisplayKeyboard();
+ }
+ }
+
+ mem[CDFLAG]=0xc0;
+ break;
+
+ case ED_WAITKEY:
+ waitkey=TRUE;
+ started=TRUE;
+ break;
+
+ case ED_ENDWAITKEY:
+ waitkey=FALSE;
+ break;
+
+ case ED_PAUSE:
+ waitkey=TRUE;
+
+ pause=z80->BC.w;
+
+ while(pause-- && !(mem[CDFLAG]&1))
+ {
+ SoftKeyEvent ev;
+
+ while (SK_GetEvent(&ev))
+ {
+ ZX81HandleKey(ev.key,ev.pressed);
+ }
+
+ CheckTimers(z80,FRAME_TSTATES);
+ }
+
+ waitkey=FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void ZX81Init(uint16 *text_vram, uint16* bitmap_vram, Z80 *z80)
+{
+ Z80Word f;
+
+ txt_screen = text_vram;
+ bmp_screen = bitmap_vram;
+
+ hires = FALSE;
+ hires_dfile = 0;
+ last_I = 0x1e;
+ DrawScreen = DrawScreen_TEXT;
+
+ ClearBitmap();
+
+ /* Load the ROM
+ */
+ memcpy(mem,zx81_bin,ROMLEN);
+
+ /* Patch the ROM
+ */
+ RomPatch();
+ Z80LodgeCallback(z80,eZ80_EDHook,EDCallback);
+ Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers);
+
+ /* Mirror the ROM
+ */
+ memcpy(mem+ROMLEN,mem,ROMLEN);
+
+ /* Memory size (16K)
+ */
+ RAMBOT=0x4000;
+ RAMTOP=RAMBOT+0x4000;
+
+ for(f = RAMBOT; f <= RAMTOP; f++)
+ {
+ mem[f] = 0;
+ }
+
+ for(f = 0; f < 8; f++)
+ {
+ matrix[f] = 0x1f;
+ }
+
+ /* Fill the upper 32K with RET opcodes -- hopefully by simply returning
+ RET for ULA reads we save a lot of ROM patching shenanigans.
+
+ Note that this check used to be in ZX81ReadMem, but obviously this
+ should cut down on a *lot* of pointless expression evaluation!
+ */
+ for(f = 0x8000; f <= RAMTOP; f++)
+ {
+ mem[f] = 0xc9;
+ }
+
+}
+
+
+void ZX81HandleKey(SoftKey key, int is_pressed)
+{
+ if (key<SK_CONFIG)
+ {
+ if (is_pressed)
+ {
+ matrix[key_matrix[key].row]&=~key_matrix[key].bit;
+ }
+ else
+ {
+ matrix[key_matrix[key].row]|=key_matrix[key].bit;
+ }
+ }
+ else
+ {
+ /* TODO: Joysticks? Were there any common ones for the 81? */
+ }
+}
+
+
+Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr)
+{
+ return mem[addr];
+}
+
+
+void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
+{
+ if (addr>=RAMBOT && addr<=RAMTOP)
+ {
+ mem[addr]=val;
+ }
+}
+
+
+Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port)
+{
+ Z80Byte b=0;
+
+ switch(port&0xff)
+ {
+ case 0xfe: /* ULA */
+ /* Key matrix
+ */
+ switch(port&0xff00)
+ {
+ case 0xfe00:
+ b=matrix[0];
+ break;
+ case 0xfd00:
+ b=matrix[1];
+ break;
+ case 0xfb00:
+ b=matrix[2];
+ break;
+ case 0xf700:
+ b=matrix[3];
+ break;
+ case 0xef00:
+ b=matrix[4];
+ break;
+ case 0xdf00:
+ b=matrix[5];
+ break;
+ case 0xbf00:
+ b=matrix[6];
+ break;
+ case 0x7f00:
+ b=matrix[7];
+ break;
+ }
+
+ /* Some code expects some of the top bits set... Of course, whether
+ or not this may be worse as other code doesn't expect the bits,
+ we shall find out!
+ */
+ b |= 0x60;
+
+ break;
+
+ default:
+ b = 0xff; /* Idle bus */
+ break;
+ }
+
+ return b;
+}
+
+
+void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val)
+{
+ switch(port&0xff)
+ {
+ case 0xfd:
+ break;
+
+ case 0xfe:
+ break;
+ }
+}
+
+
+void ZX81Reset(Z80 *z80)
+{
+ int f;
+
+ for(f=0;f<8;f++)
+ matrix[f]=0x1f;
+
+ Z80Reset(z80);
+ Z80ResetCycles(z80,0);
+
+ started=FALSE;
+
+ hires = FALSE;
+ hires_dfile = 0;
+ last_I = 0x1e;
+ DrawScreen = DrawScreen_TEXT;
+
+ ClearBitmap();
+}
+
+
+void ZX81EnableFileSystem(int enable)
+{
+ enable_filesystem=enable;
+}
+
+
+void ZX81SetTape(const Z80Byte *image, int len)
+{
+ tape_image=image;
+ tape_len=len;
+}
+
+
+void ZX81SuspendDisplay(void)
+{
+ ClearBitmap();
+ ClearText();
+}
+
+
+void ZX81ResumeDisplay(void)
+{
+ ClearText();
+
+ /* Reset last_I to force hi/lo res detection
+ */
+ last_I = 0;
+}
+
+
+void ZX81DisplayString(const char *p)
+{
+ uint16 *s;
+ uint16 inv=0;
+ int f;
+
+ ClearText();
+
+ s = txt_screen;
+ f = 0;
+
+ while(*p)
+ {
+ switch(*p)
+ {
+ case '\n':
+ s+=32;
+ f=0;
+ break;
+
+ case '%':
+ inv^=0x40;
+ break;
+
+ default:
+ s[f++]=FromASCII(*p)|inv;
+ break;
+ }
+
+ p++;
+ }
+}
+
+
+void ZX81Reconfigure(void)
+{
+ if (DS81_Config[DS81_STATIC_RAM_AT_0x2000])
+ {
+ RAMBOT = 0x2000;
+ }
+ else
+ {
+ RAMBOT = 0x4000;
+ memcpy(mem+ROMLEN,mem,ROMLEN);
+ }
+
+ allow_save = enable_filesystem && DS81_Config[DS81_ALLOW_TAPE_SAVE];
+}
+
+
+void ZX81SaveSnapshot(FILE *fp)
+{
+ int f;
+
+ for(f=0; f<sizeof mem; f++)
+ {
+ PUT_Byte(fp, mem[f]);
+ }
+
+ for(f=0; f<sizeof matrix; f++)
+ {
+ PUT_Byte(fp, matrix[f]);
+ }
+
+ PUT_Long(fp, waitkey);
+ PUT_Long(fp, started);
+
+ PUT_ULong(fp, RAMBOT);
+ PUT_ULong(fp, RAMTOP);
+
+ PUT_ULong(fp, prev_lk1);
+ PUT_ULong(fp, prev_lk2);
+}
+
+
+void ZX81LoadSnapshot(FILE *fp)
+{
+ int f;
+
+ for(f=0; f<sizeof mem; f++)
+ {
+ mem[f] = GET_Byte(fp);
+ }
+
+ for(f=0; f<sizeof matrix; f++)
+ {
+ matrix[f] = GET_Byte(fp);
+ }
+
+ waitkey = GET_Long(fp);
+ started = GET_Long(fp);
+
+ RAMBOT = GET_ULong(fp);
+ RAMTOP = GET_ULong(fp);
+
+ prev_lk1 = GET_ULong(fp);
+ prev_lk2 = GET_ULong(fp);
+
+ /* Reset last_I to force hi/lo res detection
+ */
+ last_I = 0;
+}
+
+
+/* END OF FILE */
diff --git a/version b/version
new file mode 100644
index 0000000..fe96b09
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+V1.3