From 5601353fc9cd66dbcca4d06fc7068af853317442 Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 26 Nov 2010 15:00:08 +0000 Subject: Copied DS81 files as a baseline --- BUILDING | 18 + CHANGES | 8 + COPYING | 341 +++++++ Makefile | 137 +++ README | 22 + fat_patch.sh | 4 + include/config.h | 55 ++ include/ds81_debug.h | 43 + include/framebuffer.h | 90 ++ include/gui.h | 32 + include/keyboard.h | 142 +++ include/monitor.h | 29 + include/snapshot.h | 37 + include/stream.h | 35 + include/tapes.h | 27 + include/textmode.h | 37 + include/touchwrap.h | 38 + include/z80.h | 257 +++++ include/z80_config.h | 59 ++ include/z80_private.h | 276 ++++++ include/zx81.h | 93 ++ instructions.txt | 180 ++++ mkrelease.sh | 16 + source/config.c | 145 +++ source/framebuffer.c | 386 ++++++++ source/gui.c | 862 +++++++++++++++++ source/keyboard.c | 483 ++++++++++ source/main.c | 461 +++++++++ source/monitor.c | 362 +++++++ source/snapshot.c | 195 ++++ source/stream.c | 86 ++ source/tapes.c | 282 ++++++ source/textmode.c | 157 +++ source/touchwrap.c | 55 ++ source/z80.c | 394 ++++++++ source/z80_decode.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++ source/z80_dis.c | 2494 ++++++++++++++++++++++++++++++++++++++++++++++++ source/zx81.c | 1171 +++++++++++++++++++++++ version | 1 + 39 files changed, 12043 insertions(+) create mode 100644 BUILDING create mode 100644 CHANGES create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100644 fat_patch.sh create mode 100644 include/config.h create mode 100644 include/ds81_debug.h create mode 100644 include/framebuffer.h create mode 100644 include/gui.h create mode 100644 include/keyboard.h create mode 100644 include/monitor.h create mode 100644 include/snapshot.h create mode 100644 include/stream.h create mode 100644 include/tapes.h create mode 100644 include/textmode.h create mode 100644 include/touchwrap.h create mode 100644 include/z80.h create mode 100644 include/z80_config.h create mode 100644 include/z80_private.h create mode 100644 include/zx81.h create mode 100644 instructions.txt create mode 100644 mkrelease.sh create mode 100644 source/config.c create mode 100644 source/framebuffer.c create mode 100644 source/gui.c create mode 100644 source/keyboard.c create mode 100644 source/main.c create mode 100644 source/monitor.c create mode 100644 source/snapshot.c create mode 100644 source/stream.c create mode 100644 source/tapes.c create mode 100644 source/textmode.c create mode 100644 source/touchwrap.c create mode 100644 source/z80.c create mode 100644 source/z80_decode.c create mode 100644 source/z80_dis.c create mode 100644 source/zx81.c create mode 100644 version 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. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 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. + + , 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=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 + + 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 + + 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 + + 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 + + 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 + + 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 + +/* 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 + + 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 + + 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 + + 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 + +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 + + 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 + + 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 + + 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 + + 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 + +/* 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 + + 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;fcallback[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 + +#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 +--------------------------------- + + + + 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. + + + 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. + + + 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 + + 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 +#include +#include + +#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 + + 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 +#include +#include +#include + +#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<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 + + 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 +#include +#include +#include + +#include + +#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=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=0 && nsel (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+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 + + 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 + +#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; fkey = 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>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 + + 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 +#include +#include +#include +#include + +#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 + + 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 +#include + +#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 + + 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 +#include +#include +#include +#include + +#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 + + 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 + + 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 + +#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;fimg,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 + + 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 +#include +#include +#include + +#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 + + 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 +#include + +#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 + + 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 +#include + +#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;fcallback[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;fcallback[reason][f]) + { + PRIV->callback[reason][f]=callback; + return TRUE; + } + } + + return FALSE; +} + + +void Z80RemoveCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ + int f; + + for(f=0;fcallback[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 + + 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 +#include + +#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<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<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<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 + + 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 +#include +#include + +#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 + + 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 +#include +#include +#include +#include + +#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;fI << 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(y0x4000 ; 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<=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=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