diff --git a/Makefile b/Makefile
index d7b9985..3ef706b 100644
--- a/Makefile
+++ b/Makefile
@@ -271,7 +271,7 @@ ifdef INSTALL_BLOBS
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-ne2k_pci.bin pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin \
-bamboo.dtb
+bamboo.dtb zx-rom.bin
else
BLOBS=
endif
@@ -386,6 +386,7 @@ tarbin:
$(bindir)/qemu-system-sh4 \
$(bindir)/qemu-system-sh4eb \
$(bindir)/qemu-system-sparc \
+ $(bindir)/qemu-system-z80 \
$(bindir)/qemu-i386 \
$(bindir)/qemu-x86_64 \
$(bindir)/qemu-alpha \
diff --git a/Makefile.target b/Makefile.target
index 445d55f..a97ca05 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -168,6 +168,12 @@ LIBOBJS+= mmu.o
endif
endif
+ifeq ($(TARGET_BASE_ARCH), z80)
+ifdef CONFIG_LIBSPECTRUM
+LIBS+=-lspectrum
+endif
+endif
+
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -212,6 +218,9 @@ endif
ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390)
LIBOBJS+=s390-dis.o
endif
+ifeq ($(findstring z80, $(TARGET_ARCH) $(ARCH)),z80)
+LIBOBJS+=z80-dis.o
+endif
# libqemu
@@ -686,6 +695,10 @@ ifeq ($(TARGET_BASE_ARCH), m68k)
OBJS+= an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
OBJS+= m68k-semi.o dummy_m68k.o
endif
+ifeq ($(TARGET_BASE_ARCH), z80)
+OBJS+= zx_spectrum.o zx_video.o dma.o
+OBJS+= serial.o i8259.o
+endif
ifdef CONFIG_COCOA
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
ifdef CONFIG_COREAUDIO
diff --git a/configure b/configure
index 21c0633..fdd9493 100755
--- a/configure
+++ b/configure
@@ -163,6 +163,7 @@ bigendian="no"
mingw32="no"
EXESUF=""
slirp="yes"
+libspectrum="no"
vde="yes"
fmod_lib=""
fmod_inc=""
@@ -397,6 +398,8 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
+ --enable-libspectrum) libspectrum="yes"
+ ;;
--fmod-lib=*) fmod_lib="$optarg"
;;
--fmod-inc=*) fmod_inc="$optarg"
@@ -595,6 +598,7 @@ echo " --disable-strip disable stripping binaries"
echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-cocoa enable COCOA (Mac OS X only)"
+echo " --enable-libspectrum enable ZX Spectrum snapshot loading"
echo " --audio-drv-list=LIST set audio drivers list:"
echo " Available drivers: $audio_possible_drivers"
echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_list]"
@@ -694,6 +698,7 @@ ppc64-softmmu \
sh4-softmmu \
sh4eb-softmmu \
sparc-softmmu \
+z80-softmmu \
"
fi
# the following are Linux specific
@@ -1355,6 +1360,7 @@ fi
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
+echo "libspec. support $libspectrum"
echo "kqemu support $kqemu"
echo "xen support $xen"
echo "brlapi support $brlapi"
@@ -1595,6 +1601,10 @@ if test "$mixemu" = "yes" ; then
echo "CONFIG_MIXEMU=yes" >> $config_mak
echo "#define CONFIG_MIXEMU 1" >> $config_h
fi
+if test "$libspectrum" = "yes" ; then
+ echo "CONFIG_LIBSPECTRUM=yes" >> $config_mak
+ echo "#define CONFIG_LIBSPECTRUM 1" >> $config_h
+fi
if test "$vnc_tls" = "yes" ; then
echo "CONFIG_VNC_TLS=yes" >> $config_mak
echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak
@@ -2038,6 +2048,12 @@ case "$target_cpu" in
echo "#define TARGET_ABI32 1" >> $config_h
target_phys_bits=64
;;
+ z80)
+ echo "TARGET_ARCH=z80" >> $config_mak
+ echo "#define TARGET_ARCH \"z80\"" >> $config_h
+ echo "#define TARGET_Z80 1" >> $config_h
+ target_phys_bits=32
+ ;;
*)
echo "Unsupported target CPU"
exit 1
diff --git a/cpu-exec.c b/cpu-exec.c
index 8734337..d614c42 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -250,6 +250,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
+#elif defined(TARGET_Z80)
/* XXXXX */
#else
#error unsupported target CPU
@@ -543,6 +544,12 @@ int cpu_exec(CPUState *env1)
do_interrupt(1);
next_tb = 0;
}
+#elif defined(TARGET_Z80)
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ /* TODO: Add support for NMIs */
+ do_interrupt(env);
+ }
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
@@ -588,6 +595,8 @@ int cpu_exec(CPUState *env1)
log_cpu_state(env, 0);
#elif defined(TARGET_CRIS)
log_cpu_state(env, 0);
+#elif defined(TARGET_Z80)
+ log_cpu_state(env, 0);
#else
#error unsupported target CPU
#endif
@@ -702,6 +711,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_SH4)
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_CRIS)
+#elif defined(TARGET_Z80)
/* XXXXX */
#else
#error unsupported target CPU
diff --git a/dis-asm.h b/dis-asm.h
index 251c490..0a00f7b 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -402,6 +402,7 @@ extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_crisv32 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_microblaze PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_z80 PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
diff --git a/disas.c b/disas.c
index af5a9ea..5ca873e 100644
--- a/disas.c
+++ b/disas.c
@@ -198,6 +198,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
#elif defined(TARGET_MICROBLAZE)
disasm_info.mach = bfd_arch_microblaze;
print_insn = print_insn_microblaze;
+#elif defined(TARGET_Z80)
+ print_insn = print_insn_z80;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
diff --git a/hw/pixel_ops_dup.h b/hw/pixel_ops_dup.h
new file mode 100644
index 0000000..da74d5d
--- /dev/null
+++ b/hw/pixel_ops_dup.h
@@ -0,0 +1,61 @@
+static inline unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel8(r, g, b);
+ col |= col << 8;
+ col |= col << 16;
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel15bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel16bgr(r, g, b);
+ col |= col << 16;
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32(r, g, b);
+ return col;
+}
+
+static inline unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g,
+ unsigned int b)
+{
+ unsigned int col;
+ col = rgb_to_pixel32bgr(r, g, b);
+ return col;
+}
diff --git a/hw/zx_glyphs.h b/hw/zx_glyphs.h
new file mode 100644
index 0000000..dd1ade2
--- /dev/null
+++ b/hw/zx_glyphs.h
@@ -0,0 +1,37 @@
+#if DEPTH == 8
+#define BPP 1
+#elif DEPTH == 16
+#define BPP 2
+#elif DEPTH == 32
+#define BPP 4
+#else
+#error unsupport depth
+#endif
+
+static inline void glue(zx_draw_glyph_line_, DEPTH)(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+#if BPP == 1
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+ ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+#undef DEPTH
+#undef BPP
diff --git a/hw/zx_key_template.h b/hw/zx_key_template.h
new file mode 100644
index 0000000..35305ce
--- /dev/null
+++ b/hw/zx_key_template.h
@@ -0,0 +1,50 @@
+/*
+ * ZX Spectrum Keyboard Layout
+ */
+
+ /* Name, Row, Column */
+DEF_ZX_KEY(1, 3, 0)
+DEF_ZX_KEY(2, 3, 1)
+DEF_ZX_KEY(3, 3, 2)
+DEF_ZX_KEY(4, 3, 3)
+DEF_ZX_KEY(5, 3, 4)
+DEF_ZX_KEY(6, 4, 4)
+DEF_ZX_KEY(7, 4, 3)
+DEF_ZX_KEY(8, 4, 2)
+DEF_ZX_KEY(9, 4, 1)
+DEF_ZX_KEY(0, 4, 0)
+
+DEF_ZX_KEY(Q, 2, 0)
+DEF_ZX_KEY(W, 2, 1)
+DEF_ZX_KEY(E, 2, 2)
+DEF_ZX_KEY(R, 2, 3)
+DEF_ZX_KEY(T, 2, 4)
+DEF_ZX_KEY(Y, 5, 4)
+DEF_ZX_KEY(U, 5, 3)
+DEF_ZX_KEY(I, 5, 2)
+DEF_ZX_KEY(O, 5, 1)
+DEF_ZX_KEY(P, 5, 0)
+
+DEF_ZX_KEY(A, 1, 0)
+DEF_ZX_KEY(S, 1, 1)
+DEF_ZX_KEY(D, 1, 2)
+DEF_ZX_KEY(F, 1, 3)
+DEF_ZX_KEY(G, 1, 4)
+DEF_ZX_KEY(H, 6, 4)
+DEF_ZX_KEY(J, 6, 3)
+DEF_ZX_KEY(K, 6, 2)
+DEF_ZX_KEY(L, 6, 1)
+DEF_ZX_KEY(ENTER, 6, 0)
+
+DEF_ZX_KEY(CAPSSHIFT, 0, 0)
+DEF_ZX_KEY(Z, 0, 1)
+DEF_ZX_KEY(X, 0, 2)
+DEF_ZX_KEY(C, 0, 3)
+DEF_ZX_KEY(V, 0, 4)
+DEF_ZX_KEY(B, 7, 4)
+DEF_ZX_KEY(N, 7, 3)
+DEF_ZX_KEY(M, 7, 2)
+DEF_ZX_KEY(SYMBSHIFT, 7, 1)
+DEF_ZX_KEY(SPACE, 7, 0)
+
+#undef DEF_ZX_KEY
diff --git a/hw/zx_spectrum.c b/hw/zx_spectrum.c
new file mode 100644
index 0000000..4ccb887
--- /dev/null
+++ b/hw/zx_spectrum.c
@@ -0,0 +1,443 @@
+/*
+ * QEMU ZX Spectrum Emulator
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ * Copyright (c) 2007 Ulrich Hecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "isa.h"
+#include "sysemu.h"
+#include "zx_video.h"
+#include "boards.h"
+
+#ifdef CONFIG_LIBSPECTRUM
+#include
+#endif
+
+#define ROM_FILENAME "zx-rom.bin"
+
+//#define DEBUG_ZX_SPECTRUM
+
+#ifdef DEBUG_ZX_SPECTRUM
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static int keystate[8];
+
+static uint32_t io_keyboard_read(void *opaque, uint32_t addr)
+{
+ int r = 0;
+ uint8_t colbits = 0xff;
+
+ uint32_t rowbits = ((addr >> 8) & 0xff);
+
+ for (r = 0; r < 8; r++) {
+ if (!(rowbits & (1 << r))) {
+ colbits &= keystate[r];
+ }
+ }
+ return colbits;
+}
+
+static uint32_t io_spectrum_read(void *opaque, uint32_t addr)
+{
+ if (addr & 1) {
+ return 0xff;
+ }
+
+ return io_keyboard_read(opaque, addr);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ cpu_reset(env);
+}
+
+static QEMUTimer *zx_ula_timer;
+
+static void zx_50hz_timer(void *opaque)
+{
+ int64_t next_time;
+
+ CPUState *env = opaque;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+
+ /* FIXME: not exactly 50 Hz */
+ next_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec, 50);
+ qemu_mod_timer(zx_ula_timer, next_time);
+
+ zx_video_do_retrace();
+}
+
+static CPUState *zx_env;
+
+static void zx_timer_init(void)
+{
+ int64_t t = qemu_get_clock(vm_clock);
+ zx_ula_timer = qemu_new_timer(vm_clock, zx_50hz_timer, zx_env);
+ qemu_mod_timer(zx_ula_timer, t);
+}
+
+typedef struct {
+ int row;
+ int column;
+} ZXKeypos;
+
+#define DEF_ZX_KEY(name, row, column) ZX_KEY_ ## name,
+enum zx_keys {
+#include "zx_key_template.h"
+ZX_MAX_KEYS
+};
+
+#define DEF_ZX_KEY(name, row, column) [ZX_KEY_ ## name] = {row, column},
+static const ZXKeypos keypos[ZX_MAX_KEYS] = {
+#include "zx_key_template.h"
+};
+
+static int zx_keypressed[ZX_MAX_KEYS];
+static int qemu_keypressed[0x100];
+
+static const int map[0x100][2] = {
+ [0 ... 0xff] = {-1, -1}, /* Unmapped by default */
+
+ [0x01] = {ZX_KEY_CAPSSHIFT, ZX_KEY_SPACE}, /* Escape */
+
+ [0x02] = {ZX_KEY_1, -1},
+ [0x03] = {ZX_KEY_2, -1},
+ [0x04] = {ZX_KEY_3, -1},
+ [0x05] = {ZX_KEY_4, -1},
+ [0x06] = {ZX_KEY_5, -1},
+ [0x07] = {ZX_KEY_6, -1},
+ [0x08] = {ZX_KEY_7, -1},
+ [0x09] = {ZX_KEY_8, -1},
+ [0x0a] = {ZX_KEY_9, -1},
+ [0x0b] = {ZX_KEY_0, -1},
+
+ [0x0c] = {ZX_KEY_SYMBSHIFT, ZX_KEY_J}, /* Minus */
+
+ [0x0e] = {ZX_KEY_CAPSSHIFT, ZX_KEY_0}, /* Backspace */
+
+ [0x10] = {ZX_KEY_Q, -1},
+ [0x11] = {ZX_KEY_W, -1},
+ [0x12] = {ZX_KEY_E, -1},
+ [0x13] = {ZX_KEY_R, -1},
+ [0x14] = {ZX_KEY_T, -1},
+ [0x15] = {ZX_KEY_Y, -1},
+ [0x16] = {ZX_KEY_U, -1},
+ [0x17] = {ZX_KEY_I, -1},
+ [0x18] = {ZX_KEY_O, -1},
+ [0x19] = {ZX_KEY_P, -1},
+
+ [0x0d] = {ZX_KEY_SYMBSHIFT, ZX_KEY_L}, /* Equals */
+ [0x0f] = {ZX_KEY_CAPSSHIFT, ZX_KEY_1}, /* Tab */
+
+ [0x1c] = {ZX_KEY_ENTER, -1}, /* Enter */
+
+ [0x1d] = {ZX_KEY_SYMBSHIFT, -1}, /* Left Control */
+
+ [0x1e] = {ZX_KEY_A, -1},
+ [0x1f] = {ZX_KEY_S, -1},
+ [0x20] = {ZX_KEY_D, -1},
+ [0x21] = {ZX_KEY_F, -1},
+ [0x22] = {ZX_KEY_G, -1},
+ [0x23] = {ZX_KEY_H, -1},
+ [0x24] = {ZX_KEY_J, -1},
+ [0x25] = {ZX_KEY_K, -1},
+ [0x26] = {ZX_KEY_L, -1},
+
+ [0x27] = {ZX_KEY_SYMBSHIFT, ZX_KEY_O}, /* Semicolon */
+ [0x28] = {ZX_KEY_SYMBSHIFT, ZX_KEY_7}, /* Apostrophe */
+
+ [0x2a] = {ZX_KEY_CAPSSHIFT, -1}, /* Left Shift */
+
+ [0x2b] = {ZX_KEY_SYMBSHIFT, ZX_KEY_3}, /* Hash */
+
+ [0x2c] = {ZX_KEY_Z, -1},
+ [0x2d] = {ZX_KEY_X, -1},
+ [0x2e] = {ZX_KEY_C, -1},
+ [0x2f] = {ZX_KEY_V, -1},
+ [0x30] = {ZX_KEY_B, -1},
+ [0x31] = {ZX_KEY_N, -1},
+ [0x32] = {ZX_KEY_M, -1},
+
+ [0x33] = {ZX_KEY_SYMBSHIFT, ZX_KEY_N}, /* Period */
+ [0x34] = {ZX_KEY_SYMBSHIFT, ZX_KEY_M}, /* Comma */
+ [0x35] = {ZX_KEY_SYMBSHIFT, ZX_KEY_V}, /* Slash */
+
+ [0x36] = {ZX_KEY_CAPSSHIFT, -1}, /* Right Shift */
+ [0x37] = {ZX_KEY_SYMBSHIFT, ZX_KEY_B}, /* * (Numpad) */
+ [0x38] = {ZX_KEY_SYMBSHIFT, -1}, /* Left Alt */
+ [0x39] = {ZX_KEY_SPACE, -1}, /* Space Bar */
+
+ [0x47] = {ZX_KEY_7, -1}, /* 7 (Numpad) */
+ [0x48] = {ZX_KEY_8, -1}, /* 8 (Numpad) */
+ [0x49] = {ZX_KEY_9, -1}, /* 9 (Numpad) */
+ [0x4a] = {ZX_KEY_SYMBSHIFT, ZX_KEY_J}, /* Minus (Numpad) */
+ [0x4b] = {ZX_KEY_4, -1}, /* 4 (Numpad) */
+ [0x4c] = {ZX_KEY_5, -1}, /* 5 (Numpad) */
+ [0x4d] = {ZX_KEY_6, -1}, /* 6 (Numpad) */
+ [0x4e] = {ZX_KEY_SYMBSHIFT, ZX_KEY_K}, /* Plus (Numpad) */
+ [0x4f] = {ZX_KEY_1, -1}, /* 1 (Numpad) */
+ [0x50] = {ZX_KEY_2, -1}, /* 2 (Numpad) */
+ [0x51] = {ZX_KEY_3, -1}, /* 3 (Numpad) */
+ [0x52] = {ZX_KEY_0, -1}, /* 0 (Numpad) */
+ [0x53] = {ZX_KEY_SYMBSHIFT, ZX_KEY_M}, /* Period (Numpad) */
+
+ [0x9c] = {ZX_KEY_SYMBSHIFT, -1}, /* Enter (Numpad) */
+ [0x9d] = {ZX_KEY_SYMBSHIFT, -1}, /* Right Control */
+ [0xb5] = {ZX_KEY_SYMBSHIFT, ZX_KEY_V}, /* Slash (Numpad) */
+ [0xb8] = {ZX_KEY_SYMBSHIFT, -1}, /* Right Alt */
+
+ [0xc8] = {ZX_KEY_CAPSSHIFT, ZX_KEY_7}, /* Up Arrow */
+ [0xcb] = {ZX_KEY_CAPSSHIFT, ZX_KEY_5}, /* Left Arrow */
+ [0xcd] = {ZX_KEY_CAPSSHIFT, ZX_KEY_8}, /* Right Arrow */
+ [0xd0] = {ZX_KEY_CAPSSHIFT, ZX_KEY_6}, /* Down Arrow */
+
+ [0xdb] = {ZX_KEY_CAPSSHIFT, ZX_KEY_SYMBSHIFT}, /* Left Meta */
+ [0xdc] = {ZX_KEY_CAPSSHIFT, ZX_KEY_SYMBSHIFT}, /* Menu */
+ [0xdd] = {ZX_KEY_CAPSSHIFT, ZX_KEY_SYMBSHIFT}, /* Right Meta */
+};
+
+/* FIXME:
+ * Need to mappings from stepping on each other...
+ * or at least make them step on one another in a consistent manner?
+ * Could use separate state arrays for surpressing/adding keys
+ * and allow only one change to the modifier keys at a time...
+ *
+ * Also need to implement shifted mappings.
+ */
+
+static void zx_put_keycode(void *opaque, int keycode)
+{
+ int release = keycode & 0x80;
+ int key, row, col;
+ static int ext_keycode = 0;
+ int i;
+ int valid;
+
+ if (keycode == 0xe0) {
+ ext_keycode = 1;
+ } else {
+ if (ext_keycode) {
+ keycode |= 0x80;
+ } else {
+ keycode &= 0x7f;
+ }
+ ext_keycode = 0;
+
+ DPRINTF("Keycode 0x%02x (%s)\n", keycode, release ? "release" : "press");
+
+ if (release && qemu_keypressed[keycode]) {
+ valid = 1;
+ qemu_keypressed[keycode] = 0;
+ } else if (!release && !qemu_keypressed[keycode]) {
+ valid = 1;
+ qemu_keypressed[keycode] = 1;
+ } else {
+ valid = 0;
+ }
+
+ if (valid) {
+ for (i = 0; i < 2; i++) {
+ key = map[keycode][i];
+ if (key != -1) {
+ row = keypos[key].row;
+ col = keypos[key].column;
+ if (release) {
+ if (--zx_keypressed[key] <= 0) {
+ DPRINTF("Releasing 0x%02x\n", key);
+ zx_keypressed[key] = 0;
+ keystate[row] |= 1 << col;
+ }
+ } else {
+ DPRINTF("Pressing 0x%02x\n", key);
+ zx_keypressed[key]++;
+ keystate[row] &= ~(1 << col);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void zx_keyboard_init(void)
+{
+ int i;
+ for (i=0; i<8; i++) {
+ keystate[i] = 0xff;
+ }
+ memset(zx_keypressed, 0, sizeof(zx_keypressed));
+ memset(qemu_keypressed, 0, sizeof(qemu_keypressed));
+ qemu_add_kbd_event_handler(zx_put_keycode, NULL);
+}
+
+static const uint8_t halthack_oldip[16] =
+ {253, 203, 1,110, 200, 58, 8, 92, 253, 203, 1, 174};
+static const uint8_t halthack_newip[16] =
+ {33, 59, 92, 118, 203, 110, 200, 58, 8, 92, 203, 174};
+
+/* ZX Spectrum initialisation */
+static void zx_spectrum_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ char buf[1024];
+ uint8_t halthack_curip[12];
+ int ret;
+ ram_addr_t ram_offset, rom_offset;
+ int rom_size;
+ CPUState *env;
+
+ /* init CPUs */
+ if (!cpu_model) {
+ cpu_model = "z80";
+ }
+ env = cpu_init(cpu_model);
+ zx_env = env; // XXX
+ register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
+ qemu_register_reset(main_cpu_reset, 0, env);
+ main_cpu_reset(env);
+
+ /* allocate RAM */
+ ram_offset = qemu_ram_alloc(0xc000);
+ cpu_register_physical_memory(0x4000, 0xc000, ram_offset | IO_MEM_RAM);
+
+ /* ROM load */
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, ROM_FILENAME);
+ rom_size = get_image_size(buf);
+ if (rom_size <= 0 ||
+ (rom_size % 0x4000) != 0) {
+ goto rom_error;
+ }
+ rom_offset = qemu_ram_alloc(rom_size);
+ cpu_register_physical_memory(0x0000, 0x4000, rom_offset | IO_MEM_ROM);
+ ret = load_image_targphys(buf, 0, rom_size);
+ if (ret != rom_size) {
+ rom_error:
+ fprintf(stderr, "qemu: could not load ZX Spectrum ROM '%s'\n", buf);
+ exit(1);
+ }
+
+ /* hack from xz80 adding HALT to the keyboard input loop to save CPU */
+ cpu_physical_memory_read(0x10b0, halthack_curip, 12);
+ if (!memcmp(halthack_curip, halthack_oldip, 12)) {
+ cpu_physical_memory_write_rom(0x10b0, halthack_newip, 12);
+ }
+
+ /* map entire I/O space */
+ register_ioport_read(0, 0x10000, 1, io_spectrum_read, NULL);
+
+ zx_video_init(ram_offset);
+
+ zx_keyboard_init();
+ zx_timer_init();
+
+#ifdef CONFIG_LIBSPECTRUM
+ /* load a snapshot */
+ if (kernel_filename) {
+ libspectrum_id_t type;
+ libspectrum_class_t cls;
+ libspectrum_snap* snap;
+ uint8_t* snapmem;
+ libspectrum_byte* page;
+ int length;
+ int i;
+ if (libspectrum_init() != LIBSPECTRUM_ERROR_NONE ||
+ libspectrum_identify_file(&type, kernel_filename, NULL, 0) != LIBSPECTRUM_ERROR_NONE ||
+ libspectrum_identify_class(&cls, type) != LIBSPECTRUM_ERROR_NONE) {
+ fprintf(stderr, "%s: libspectrum error\n", __FUNCTION__);
+ exit(1);
+ }
+ snap = libspectrum_snap_alloc();
+ if (cls != LIBSPECTRUM_CLASS_SNAPSHOT) {
+ fprintf(stderr, "%s: %s is not a snapshot\n", __FUNCTION__, kernel_filename);
+ exit(1);
+ }
+ snapmem = qemu_mallocz(0x10000);
+ length = load_image(kernel_filename, snapmem);
+ //printf("loaded %d bytes from %s\n",length, kernel_filename);
+ if (libspectrum_snap_read(snap, snapmem, length, type, NULL) != LIBSPECTRUM_ERROR_NONE) {
+ fprintf(stderr, "%s: failed to load snapshot %s\n", __FUNCTION__, kernel_filename);
+ exit(1);
+ }
+ //printf("snap pc = %d\n",libspectrum_snap_pc(snap));
+
+ /* fill memory */
+ page = libspectrum_snap_pages(snap, 5);
+ for (i = 0x4000; i < 0x8000; i++) {
+ //printf("storing 0x%x in 0x%x\n",page[i-0x4000],i);
+ stb_phys(i, page[i - 0x4000]);
+ }
+ page = libspectrum_snap_pages(snap, 2);
+ for (i = 0x8000; i < 0xc000; i++) {
+ stb_phys(i, page[i - 0x8000]);
+ }
+ page = libspectrum_snap_pages(snap, 0);
+ for (i = 0xc000; i < 0x10000; i++) {
+ stb_phys(i, page[i - 0xc000]);
+ }
+
+ /* restore registers */
+ env->regs[R_A] = libspectrum_snap_a(snap);
+ env->regs[R_F] = libspectrum_snap_f(snap);
+ env->regs[R_BC] = libspectrum_snap_bc(snap);
+ env->regs[R_DE] = libspectrum_snap_de(snap);
+ env->regs[R_HL] = libspectrum_snap_hl(snap);
+ env->regs[R_AX] = libspectrum_snap_a_(snap);
+ env->regs[R_FX] = libspectrum_snap_f_(snap);
+ env->regs[R_BCX] = libspectrum_snap_bc_(snap);
+ env->regs[R_DEX] = libspectrum_snap_de_(snap);
+ env->regs[R_HLX] = libspectrum_snap_hl_(snap);
+ env->regs[R_IX] = libspectrum_snap_ix(snap);
+ env->regs[R_IY] = libspectrum_snap_iy(snap);
+ env->regs[R_I] = libspectrum_snap_i(snap);
+ env->regs[R_R] = libspectrum_snap_r(snap);
+ env->regs[R_SP] = libspectrum_snap_sp(snap);
+ env->pc = libspectrum_snap_pc(snap);
+ env->iff1 = libspectrum_snap_iff1(snap);
+ env->iff2 = libspectrum_snap_iff2(snap);
+ env->imode = libspectrum_snap_im(snap);
+
+ qemu_free(snapmem);
+ }
+#endif
+}
+
+static QEMUMachine zxspec_machine = {
+ .name = "zxspec",
+ .desc = "ZX Spectrum",
+ .init = zx_spectrum_init,
+ .is_default = 1,
+};
+
+static void zxspec_machine_init(void) {
+ qemu_register_machine(&zxspec_machine);
+}
+
+machine_init(zxspec_machine_init);
diff --git a/hw/zx_video.c b/hw/zx_video.c
new file mode 100644
index 0000000..6015608
--- /dev/null
+++ b/hw/zx_video.c
@@ -0,0 +1,375 @@
+/*
+ * ZX Spectrum Video Emulation
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * Uses code from VGA emulation
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "isa.h"
+#include "console.h"
+#include "zx_video.h"
+#include "pixel_ops.h"
+#include "pixel_ops_dup.h"
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r,
+ unsigned int g,
+ unsigned int b);
+
+typedef struct {
+ DisplayState *ds;
+ uint8_t *vram_ptr;
+
+ int bwidth;
+ int bheight;
+ int swidth;
+ int sheight;
+ int twidth;
+ int theight;
+
+ int border;
+ int prevborder;
+
+ int flash;
+ int flashcount;
+
+ int invalidate;
+ uint32_t palette[16];
+ rgb_to_pixel_dup_func *rgb_to_pixel;
+} ZXVState;
+
+static const uint32_t zx_cols[16] = {
+ 0x00000000, /* 0: Black */
+ 0x000000c0, /* 1: Blue */
+ 0x00c00000, /* 2: Red */
+ 0x00c000c0, /* 3: Magenta */
+ 0x0000c000, /* 4: Green */
+ 0x0000c0c0, /* 5: Cyan */
+ 0x00c0c000, /* 6: Yellow */
+ 0x00c0c0c0, /* 7: Light grey */
+
+ 0x00000000, /* 8: Black */
+ 0x000000ff, /* 9: Bright blue */
+ 0x00ff0000, /* 10: Bright red */
+ 0x00ff00ff, /* 11: Bright magenta */
+ 0x0000ff00, /* 12: Bright green */
+ 0x0000ffff, /* 13: Bright cyan */
+ 0x00ffff00, /* 14: Bright yellow */
+ 0x00ffffff, /* 15: White */
+};
+
+/* copied from vga.c / vga_template.h */
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+ PAT(0x00000000),
+ PAT(0x000000ff),
+ PAT(0x0000ff00),
+ PAT(0x0000ffff),
+ PAT(0x00ff0000),
+ PAT(0x00ff00ff),
+ PAT(0x00ffff00),
+ PAT(0x00ffffff),
+ PAT(0xff000000),
+ PAT(0xff0000ff),
+ PAT(0xff00ff00),
+ PAT(0xff00ffff),
+ PAT(0xffff0000),
+ PAT(0xffff00ff),
+ PAT(0xffffff00),
+ PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+ PAT(0x00000000),
+ PAT(0x0000ffff),
+ PAT(0xffff0000),
+ PAT(0xffffffff),
+};
+
+typedef void zx_draw_line_func(uint8_t *d, uint32_t font_data,
+ uint32_t xorcol, uint32_t bgcol);
+
+#define DEPTH 8
+#include "zx_glyphs.h"
+
+#define DEPTH 16
+#include "zx_glyphs.h"
+
+#define DEPTH 32
+#include "zx_glyphs.h"
+
+enum {
+ zx_pixfmt_8 = 0,
+ zx_pixfmt_15rgb,
+ zx_pixfmt_16rgb,
+ zx_pixfmt_32rgb,
+ zx_pixfmt_32bgr,
+ NB_DEPTHS
+};
+
+static zx_draw_line_func *zx_draw_line_table[NB_DEPTHS] = {
+ zx_draw_glyph_line_8,
+ zx_draw_glyph_line_16,
+ zx_draw_glyph_line_16,
+ zx_draw_glyph_line_32,
+ zx_draw_glyph_line_32,
+};
+
+static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
+ rgb_to_pixel8_dup,
+ rgb_to_pixel15_dup,
+ rgb_to_pixel16_dup,
+ rgb_to_pixel32_dup,
+ rgb_to_pixel32bgr_dup,
+};
+
+static inline int get_pixfmt_index(DisplayState *s)
+{
+ switch(ds_get_bits_per_pixel(s)) {
+ default:
+ case 8:
+ return zx_pixfmt_8;
+ case 15:
+ return zx_pixfmt_15rgb;
+ case 16:
+ return zx_pixfmt_16rgb;
+ case 32:
+ if (is_surface_bgr(s->surface)) {
+ return zx_pixfmt_32bgr;
+ } else {
+ return zx_pixfmt_32rgb;
+ }
+ }
+}
+
+/* end of code copied from vga.c / vga_template.h */
+
+static ZXVState *zxvstate;
+
+void zx_video_do_retrace(void)
+{
+ ZXVState *s = zxvstate;
+
+ if (++s->flashcount == 16) {
+ s->flashcount = 0;
+ s->invalidate = 1;
+ s->flash = !s->flash;
+ }
+}
+
+static void zx_draw_scanline(ZXVState *s1, uint8_t *d,
+ const uint8_t *s, const uint8_t *as)
+{
+ int x, x_incr;
+ zx_draw_line_func *zx_draw_line;
+
+ zx_draw_line = zx_draw_line_table[get_pixfmt_index(s1->ds)];
+ x_incr = (ds_get_bits_per_pixel(s1->ds) + 7) >> 3;
+
+ for (x = 0; x < 32; x++) {
+ int attrib, fg, bg, bright, flash;
+
+ attrib = *as;
+ bright = (attrib & 0x40) >> 3;
+ flash = (attrib & 0x80) && s1->flash;
+ if (flash) {
+ fg = (attrib >> 3) & 0x07;
+ bg = attrib & 0x07;
+ } else {
+ fg = attrib & 0x07;
+ bg = (attrib >> 3) & 0x07;
+ }
+ fg |= bright;
+ bg |= bright;
+
+ zx_draw_line(d, *s, s1->palette[fg] ^ s1->palette[bg], s1->palette[bg]);
+
+ d += 8 * x_incr;
+ s++; as++;
+ }
+}
+
+static void zx_border_row(ZXVState *s, uint8_t *d)
+{
+ int x, x_incr;
+ zx_draw_line_func *zx_draw_line;
+
+ zx_draw_line = zx_draw_line_table[get_pixfmt_index(s->ds)];
+ x_incr = (ds_get_bits_per_pixel(s->ds) + 7) >> 3;
+
+ for (x = 0; x < s->twidth / 8; x++) {
+ zx_draw_line(d, 0xff, s->palette[s->border], 0);
+ d += 8 * x_incr;
+ }
+}
+
+static void zx_border_sides(ZXVState *s, uint8_t *d)
+{
+ int x, x_incr;
+ zx_draw_line_func *zx_draw_line;
+
+ zx_draw_line = zx_draw_line_table[get_pixfmt_index(s->ds)];
+ x_incr = (ds_get_bits_per_pixel(s->ds) + 7) >> 3;
+
+ for (x = 0; x < s->bwidth / 8; x++) {
+ zx_draw_line(d, 0xff, s->palette[s->border], 0);
+ d += 8 * x_incr;
+ }
+ d += s->swidth * x_incr;
+ for (x = 0; x < s->bwidth / 8; x++) {
+ zx_draw_line(d, 0xff, s->palette[s->border], 0);
+ d += 8 * x_incr;
+ }
+}
+
+static void update_palette(ZXVState *s)
+{
+ int i, r, g, b;
+ for(i = 0; i < 16; i++) {
+ r = (zx_cols[i] >> 16) & 0xff;
+ g = (zx_cols[i] >> 8) & 0xff;
+ b = zx_cols[i] & 0xff;
+ s->palette[i] = s->rgb_to_pixel(r, g, b);
+ }
+}
+
+static void zx_update_display(void *opaque)
+{
+ int y;
+ uint8_t *d;
+ ZXVState *s = (ZXVState *)opaque;
+ uint32_t addr, attrib;
+ int x_incr;
+ int dirty = s->invalidate;
+ static int inited = 0;
+
+ x_incr = (ds_get_bits_per_pixel(s->ds) + 7) >> 3;
+
+ if (unlikely(inited == 0)) {
+ s->rgb_to_pixel = rgb_to_pixel_dup_table[get_pixfmt_index(s->ds)];
+ update_palette(s);
+ inited = 1;
+ }
+
+ if (unlikely(ds_get_width(s->ds) != s->twidth ||
+ ds_get_height(s->ds) != s->theight)) {
+ qemu_console_resize(s->ds, s->twidth, s->theight);
+ s->invalidate = 1;
+ s->prevborder = -1;
+ }
+
+ if (!dirty) {
+ for (addr = 0; addr < 0x1b00; addr += TARGET_PAGE_SIZE) {
+ if (cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG)) {
+ dirty = 1;
+ }
+ }
+ }
+
+ if (dirty) {
+ d = ds_get_data(s->ds);
+ d += s->bheight * ds_get_linesize(s->ds);
+ d += s->bwidth * x_incr;
+
+ for (y = 0; y < 192; y++) {
+ addr = ((y & 0x07) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5);
+ attrib = 0x1800 | ((y & 0xf8) << 2);
+ zx_draw_scanline(s, d, s->vram_ptr + addr, s->vram_ptr + attrib);
+ d += ds_get_linesize(s->ds);
+ }
+
+ s->invalidate = 0;
+ cpu_physical_memory_reset_dirty(0, 0x1b00, VGA_DIRTY_FLAG);
+ }
+
+ if (s->border != s->prevborder) {
+ d = ds_get_data(s->ds);
+ for (y = 0; y < s->bheight; y++) {
+ zx_border_row(s, d + (y * ds_get_linesize(s->ds)));
+ }
+ for (y = s->bheight; y < s->theight - s->bheight; y++) {
+ zx_border_sides(s, d + (y * ds_get_linesize(s->ds)));
+ }
+ for (y = s->theight - s->bheight; y < s->theight; y++) {
+ zx_border_row(s, d + (y * ds_get_linesize(s->ds)));
+ }
+ s->prevborder = s->border;
+ }
+
+ dpy_update(s->ds, 0, 0, s->twidth, s->theight);
+}
+
+static void zx_invalidate_display(void *opaque)
+{
+ ZXVState *s = (ZXVState *)opaque;
+ s->invalidate = 1;
+ s->prevborder = -1;
+}
+
+static void io_spectrum_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ ZXVState *s = (ZXVState *)opaque;
+
+ /* port xxfe */
+ if (!(addr & 1)) {
+ s->border = data & 0x07;
+ }
+};
+
+void zx_video_init(ram_addr_t zx_vram_offset)
+{
+ ZXVState *s = qemu_mallocz(sizeof(ZXVState));
+ zxvstate = s;
+ s->invalidate = 1;
+ s->prevborder = -1;
+ s->flashcount = 0;
+ s->vram_ptr = qemu_get_ram_ptr(zx_vram_offset);
+
+ s->ds = graphic_console_init(zx_update_display, zx_invalidate_display,
+ NULL, NULL, s);
+
+ s->bwidth = 32;
+ s->bheight = 24;
+ s->swidth = 256;
+ s->sheight = 192;
+ s->twidth = s->swidth + s->bwidth * 2;
+ s->theight = s->sheight + s->bheight * 2;
+ s->border = 0;
+ s->flash = 0;
+
+ /* ZX Spectrum ULA */
+ register_ioport_write(0, 0x10000, 1, io_spectrum_write, s);
+}
diff --git a/hw/zx_video.h b/hw/zx_video.h
new file mode 100644
index 0000000..b53dc36
--- /dev/null
+++ b/hw/zx_video.h
@@ -0,0 +1,8 @@
+#ifndef HW_ZX_VIDEO_H
+#define HW_ZX_VIDEO_H
+/* ZX Spectrum Video */
+
+void zx_video_init(ram_addr_t zx_vram_offset);
+void zx_video_do_retrace(void);
+
+#endif
diff --git a/target-z80/TODO b/target-z80/TODO
new file mode 100644
index 0000000..7698cd2
--- /dev/null
+++ b/target-z80/TODO
@@ -0,0 +1,13 @@
+TODO
+----
+
+- remove unused x86 code
+- allow execution from video RAM
+- don't accept interrupts immediately after EI
+- emulate I and R registers
+- GDB support
+- CP/M emulation
+- R800 emulation:
+ - TST instruction
+ - MULUB/MULUW flags
+ - flags 3 and 5
diff --git a/target-z80/cpu.h b/target-z80/cpu.h
new file mode 100644
index 0000000..f724e16
--- /dev/null
+++ b/target-z80/cpu.h
@@ -0,0 +1,259 @@
+/*
+ * Z80 virtual CPU header
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#ifndef CPU_Z80_H
+#define CPU_Z80_H
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 32
+
+/* target supports implicit self modifying code */
+#define TARGET_HAS_SMC
+/* support for self modifying code even if the modified instruction is
+ close to the modifying instruction */
+#define TARGET_HAS_PRECISE_SMC
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_NONE
+
+#define CPUState struct CPUZ80State
+
+#include "cpu-defs.h"
+
+#include "softfloat.h"
+
+/* Z80 registers */
+
+#define R_A 0
+#define R_F 1
+
+#define R_BC 2
+#define R_DE 3
+#define R_HL 4
+#define R_IX 5
+#define R_IY 6
+#define R_SP 7
+
+#define R_I 8
+#define R_R 9
+
+#define R_AX 10
+#define R_FX 11
+#define R_BCX 12
+#define R_DEX 13
+#define R_HLX 14
+
+#define CPU_NB_REGS 15
+
+/* flags masks */
+#define CC_C 0x0001
+#define CC_N 0x0002
+#define CC_P 0x0004
+#define CC_X 0x0008
+#define CC_H 0x0010
+#define CC_Y 0x0020
+#define CC_Z 0x0040
+#define CC_S 0x0080
+
+/* hidden flags - used internally by qemu to represent additionnal cpu
+ states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid
+ using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
+ with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT 0
+/* true if soft mmu is being used */
+#define HF_SOFTMMU_SHIFT 2
+/* true if hardware interrupts must be disabled for next instruction */
+#define HF_INHIBIT_IRQ_SHIFT 3
+/* 16 or 32 segments */
+#define HF_CS32_SHIFT 4
+#define HF_SS32_SHIFT 5
+/* zero base for DS, ES and SS : can be '0' only in 32 bit CS segment */
+#define HF_ADDSEG_SHIFT 6
+/* copy of CR0.PE (protected mode) */
+#define HF_PE_SHIFT 7
+#define HF_TF_SHIFT 8 /* must be same as eflags */
+#define HF_MP_SHIFT 9 /* the order must be MP, EM, TS */
+#define HF_EM_SHIFT 10
+#define HF_TS_SHIFT 11
+#define HF_IOPL_SHIFT 12 /* must be same as eflags */
+#define HF_LMA_SHIFT 14 /* only used on x86_64: long mode active */
+#define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */
+#define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */
+#define HF_VM_SHIFT 17 /* must be same as eflags */
+#define HF_SMM_SHIFT 19 /* CPU in SMM mode */
+
+#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
+#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
+#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
+#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
+#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
+#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
+#define HF_PE_MASK (1 << HF_PE_SHIFT)
+#define HF_TF_MASK (1 << HF_TF_SHIFT)
+#define HF_MP_MASK (1 << HF_MP_SHIFT)
+#define HF_EM_MASK (1 << HF_EM_SHIFT)
+#define HF_TS_MASK (1 << HF_TS_SHIFT)
+#define HF_LMA_MASK (1 << HF_LMA_SHIFT)
+#define HF_CS64_MASK (1 << HF_CS64_SHIFT)
+#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
+#define HF_SMM_MASK (1 << HF_SMM_SHIFT)
+
+#define EXCP00_DIVZ 0
+#define EXCP01_SSTP 1
+#define EXCP02_NMI 2
+#define EXCP03_INT3 3
+#define EXCP04_INTO 4
+#define EXCP05_BOUND 5
+#define EXCP06_ILLOP 6
+#define EXCP07_PREX 7
+#define EXCP08_DBLE 8
+#define EXCP09_XERR 9
+#define EXCP0A_TSS 10
+#define EXCP0B_NOSEG 11
+#define EXCP0C_STACK 12
+#define EXCP0D_GPF 13
+#define EXCP0E_PAGE 14
+#define EXCP10_COPR 16
+#define EXCP11_ALGN 17
+#define EXCP12_MCHK 18
+
+#define NB_MMU_MODES 2
+
+typedef struct CPUZ80State {
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+ /* temporaries if we cannot store them in host registers */
+ target_ulong t0, t1;
+#endif
+ target_ulong a0;
+
+ /* Z80 registers */
+ uint16_t pc;
+ /* not sure if this is messy: */
+ target_ulong regs[CPU_NB_REGS];
+
+ int iff1;
+ int iff2;
+ int imode;
+
+ int ir;
+
+ /* standard registers */
+ target_ulong eflags; /* eflags register. During CPU emulation, CC
+ flags are set to zero because they are
+ stored elsewhere */
+
+ /* emulator internal eflags handling */
+ uint32_t hflags; /* hidden flags, see HF_xxx constants */
+
+ target_ulong cr[5]; /* NOTE: cr1 is unused */
+
+ /* sysenter registers */
+ uint64_t efer;
+ uint64_t star;
+
+ uint64_t pat;
+
+ /* exception/interrupt handling */
+ int error_code;
+ int exception_is_int;
+ target_ulong exception_next_pc;
+ target_ulong dr[8]; /* debug registers */
+ uint32_t smbase;
+
+ CPU_COMMON
+
+ int model;
+
+ /* in order to simplify APIC support, we leave this pointer to the
+ user */
+ struct APICState *apic_state;
+} CPUZ80State;
+
+CPUZ80State *cpu_z80_init(const char *cpu_model);
+void z80_translate_init(void);
+int cpu_z80_exec(CPUZ80State *s);
+void cpu_z80_close(CPUZ80State *s);
+int cpu_get_pic_interrupt(CPUZ80State *s);
+
+/* wrapper, just in case memory mappings must be changed */
+static inline void cpu_z80_set_cpl(CPUZ80State *s, int cpl)
+{
+#if HF_CPL_MASK == 3
+ s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
+#else
+#error HF_CPL_MASK is hardcoded
+#endif
+}
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+ signal handlers to inform the virtual CPU of exceptions. non zero
+ is returned if the signal was handled by the virtual CPU. */
+struct siginfo;
+int cpu_z80_signal_handler(int host_signum, struct siginfo *info,
+ void *puc);
+
+uint64_t cpu_get_tsc(CPUZ80State *env);
+
+int cpu_z80_handle_mmu_fault(CPUZ80State *env1, target_ulong address, int rw,
+ int mmu_idx, int is_softmmu);
+
+void z80_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+
+#define Z80_CPU_Z80 1
+#define Z80_CPU_R800 2
+
+#define TARGET_PAGE_BITS 12
+
+#define cpu_init cpu_z80_init
+#define cpu_exec cpu_z80_exec
+#define cpu_gen_code cpu_z80_gen_code
+#define cpu_signal_handler cpu_z80_signal_handler
+#define cpu_list z80_cpu_list
+
+/* MMU modes definitions */
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_USER_IDX 1
+static inline int cpu_mmu_index (CPUState *env)
+{
+ /* return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; */
+ return 0;
+}
+
+#include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+ env->pc = tb->pc;
+ env->hflags = tb->flags;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+{
+ *pc = env->pc;
+ *cs_base = 0;
+ *flags = env->hflags;
+}
+
+#endif /* CPU_Z80_H */
diff --git a/target-z80/exec.h b/target-z80/exec.h
new file mode 100644
index 0000000..570afa8
--- /dev/null
+++ b/target-z80/exec.h
@@ -0,0 +1,196 @@
+/*
+ * Z80 execution defines
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include "config.h"
+#include "dyngen-exec.h"
+
+#define TARGET_LONG_BITS 32
+
+#include "cpu-defs.h"
+
+/* at least 4 register variables are defined */
+register struct CPUZ80State *env asm(AREG0);
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+
+#else
+
+/* XXX: use unsigned long instead of target_ulong - better code will
+ be generated for 64 bit CPUs */
+register target_ulong T0 asm(AREG1);
+register target_ulong T1 asm(AREG2);
+
+#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */
+
+#define A0 (env->a0)
+
+#define A (env->regs[R_A])
+#define F (env->regs[R_F])
+#define BC (env->regs[R_BC])
+#define DE (env->regs[R_DE])
+#define HL (env->regs[R_HL])
+#define IX (env->regs[R_IX])
+#define IY (env->regs[R_IY])
+#define SP (env->regs[R_SP])
+#define I (env->regs[R_I])
+#define R (env->regs[R_R])
+#define AX (env->regs[R_AX])
+#define FX (env->regs[R_FX])
+#define BCX (env->regs[R_BCX])
+#define DEX (env->regs[R_DEX])
+#define HLX (env->regs[R_HLX])
+
+#define PC (env->pc)
+
+#include "cpu.h"
+#include "exec-all.h"
+
+void do_interrupt(CPUZ80State *env);
+void raise_interrupt(int intno, int is_int, int error_code,
+ int next_eip_addend);
+void raise_exception_err(int exception_index, int error_code);
+void raise_exception(int exception_index);
+
+#if !defined(CONFIG_USER_ONLY)
+
+#include "softmmu_exec.h"
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+extern const uint8_t parity_table[256];
+
+static inline void env_to_regs(void)
+{
+#ifdef reg_A
+ A = env->regs[R_A];
+#endif
+#ifdef reg_F
+ F = env->regs[R_F];
+#endif
+#ifdef reg_BC
+ BC = env->regs[R_BC];
+#endif
+#ifdef reg_DE
+ DE = env->regs[R_DE];
+#endif
+#ifdef reg_HL
+ HL = env->regs[R_HL];
+#endif
+#ifdef reg_IX
+ IX = env->regs[R_IX];
+#endif
+#ifdef reg_IY
+ IY = env->regs[R_IY];
+#endif
+#ifdef reg_SP
+ SP = env->regs[R_SP];
+#endif
+#ifdef reg_I
+ I = env->regs[R_I];
+#endif
+#ifdef reg_R
+ R = env->regs[R_R];
+#endif
+#ifdef reg_AX
+ AX = env->regs[R_AX];
+#endif
+#ifdef reg_FX
+ FX = env->regs[R_FX];
+#endif
+#ifdef reg_BCX
+ BCX = env->regs[R_BCX];
+#endif
+#ifdef reg_DEX
+ DEX = env->regs[R_DEX];
+#endif
+#ifdef reg_HLX
+ HLX = env->regs[R_HLX];
+#endif
+}
+
+static inline void regs_to_env(void)
+{
+#ifdef reg_A
+ env->regs[R_A] = A;
+#endif
+#ifdef reg_F
+ env->regs[R_F] = F;
+#endif
+#ifdef reg_BC
+ env->regs[R_BC] = BC;
+#endif
+#ifdef reg_DE
+ env->regs[R_DE] = DE;
+#endif
+#ifdef reg_HL
+ env->regs[R_HL] = HL;
+#endif
+#ifdef reg_IX
+ env->regs[R_IX] = IX;
+#endif
+#ifdef reg_IY
+ env->regs[R_IY] = IY;
+#endif
+#ifdef reg_SP
+ env->regs[R_SP] = SP;
+#endif
+#ifdef reg_I
+ env->regs[R_I] = I;
+#endif
+#ifdef reg_R
+ env->regs[R_R] = R;
+#endif
+#ifdef reg_AX
+ env->regs[R_AX] = AX;
+#endif
+#ifdef reg_FX
+ env->regs[R_FX] = FX;
+#endif
+#ifdef reg_BCX
+ env->regs[R_BCX] = BCX;
+#endif
+#ifdef reg_DEX
+ env->regs[R_DEX] = DEX;
+#endif
+#ifdef reg_HLX
+ env->regs[R_HLX] = HLX;
+#endif
+}
+
+static inline int cpu_has_work(CPUState *env)
+{
+ return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+ if (!env->halted) {
+ return 0;
+ }
+ //printf("%s: at PC 0x%x halted == %d, irq %d\n",__FUNCTION__, env->pc, env->halted,env->interrupt_request);
+ if (cpu_has_work(env)) {
+ env->halted = 0;
+ return 0;
+ }
+ return EXCP_HALTED;
+}
diff --git a/target-z80/genreg_template.h b/target-z80/genreg_template.h
new file mode 100644
index 0000000..6be8ac8
--- /dev/null
+++ b/target-z80/genreg_template.h
@@ -0,0 +1,65 @@
+/*
+ * Z80 translation (templates for various register related operations)
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+/* Loads */
+
+static inline void glue(gen_movb_v_,REGHIGH)(TCGv v)
+{
+ tcg_gen_ld8u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ BYTE_OFFSET(cpu_env->regs[], 1));
+}
+
+static inline void glue(gen_movb_v_,REGLOW)(TCGv v)
+{
+ tcg_gen_ld8u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
+
+static inline void glue(gen_movw_v_,REGPAIR)(TCGv v)
+{
+ tcg_gen_ld16u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ WORD_OFFSET(cpu_env->regs[], 0));
+}
+
+/* Stores */
+
+static inline void glue(glue(gen_movb_,REGHIGH),_v)(TCGv v)
+{
+ tcg_gen_st8_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ BYTE_OFFSET(cpu_env->regs[], 1));
+}
+
+static inline void glue(glue(gen_movb_,REGLOW),_v)(TCGv v)
+{
+ tcg_gen_st8_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
+
+static inline void glue(glue(gen_movw_,REGPAIR),_v)(TCGv v)
+{
+ tcg_gen_st16_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGPAIR)]) +
+ WORD_OFFSET(cpu_env->regs[], 0));
+}
diff --git a/target-z80/genreg_template_af.h b/target-z80/genreg_template_af.h
new file mode 100644
index 0000000..2bf326c
--- /dev/null
+++ b/target-z80/genreg_template_af.h
@@ -0,0 +1,83 @@
+/*
+ * Z80 translation (templates for various register related operations)
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+/* Loads */
+
+static inline void glue(gen_movw_v_,REGPAIR)(TCGv v)
+{
+ TCGv tmp1 = tcg_temp_new();
+
+ tcg_gen_ld8u_tl(tmp1, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGHIGH)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+ tcg_gen_shli_tl(tmp1, tmp1, 8);
+ tcg_gen_ld8u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGLOW)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+ tcg_gen_or_tl(v, tmp1, v);
+
+ tcg_temp_free(tmp1);
+}
+
+static inline void glue(gen_movb_v_,REGHIGH)(TCGv v)
+{
+ tcg_gen_ld8u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGHIGH)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
+
+static inline void glue(gen_movb_v_,REGLOW)(TCGv v)
+{
+ tcg_gen_ld8u_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGLOW)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
+
+/* Stores */
+
+static inline void glue(glue(gen_movw_,REGPAIR),_v)(TCGv v)
+{
+ TCGv tmp1 = tcg_temp_new();
+
+ tcg_gen_shri_tl(tmp1, v, 8);
+ tcg_gen_st8_tl(tmp1, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGHIGH)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+ tcg_gen_ext8u_tl(tmp1, v);
+ tcg_gen_st8_tl(tmp1, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGLOW)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+
+ tcg_temp_free(tmp1);
+}
+
+static inline void glue(glue(gen_movb_,REGHIGH),_v)(TCGv v)
+{
+ tcg_gen_st8_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGHIGH)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
+
+static inline void glue(glue(gen_movb_,REGLOW),_v)(TCGv v)
+{
+ tcg_gen_st8_tl(v, cpu_env,
+ offsetof(CPUState, regs[glue(R_,REGLOW)]) +
+ BYTE_OFFSET(cpu_env->regs[], 0));
+}
diff --git a/target-z80/helper.c b/target-z80/helper.c
new file mode 100644
index 0000000..4022f94
--- /dev/null
+++ b/target-z80/helper.c
@@ -0,0 +1,211 @@
+/*
+ * Z80 helpers (without register variable usage)
+ *
+ * Copyright (c) 2007 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "qemu-common.h"
+
+//#define DEBUG_MMU
+
+static int cpu_z80_find_by_name(const char *name);
+
+CPUZ80State *cpu_z80_init(const char *model)
+{
+ CPUZ80State *env;
+ static int inited;
+ int id;
+
+ id = cpu_z80_find_by_name(model);
+ if (id == 0) {
+ return NULL;
+ }
+ env = qemu_mallocz(sizeof(CPUZ80State));
+ cpu_exec_init(env);
+
+ /* init various static tables */
+ if (!inited) {
+ inited = 1;
+ z80_translate_init();
+ }
+ env->model = id;
+ cpu_reset(env);
+ qemu_init_vcpu(env);
+ return env;
+}
+
+typedef struct {
+ int id;
+ const char *name;
+} Z80CPUModel;
+
+static const Z80CPUModel z80_cpu_names[] = {
+ { Z80_CPU_Z80, "z80" },
+ { Z80_CPU_R800, "r800" },
+ { 0, NULL }
+};
+
+void z80_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+ int i;
+
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ for (i = 0; z80_cpu_names[i].name; i++) {
+ (*cpu_fprintf)(f, " %s\n", z80_cpu_names[i].name);
+ }
+}
+
+/* return 0 if not found */
+static int cpu_z80_find_by_name(const char *name)
+{
+ int i;
+ int id;
+
+ id = 0;
+ for (i = 0; z80_cpu_names[i].name; i++) {
+ if (strcmp(name, z80_cpu_names[i].name) == 0) {
+ id = z80_cpu_names[i].id;
+ break;
+ }
+ }
+ return id;
+}
+
+/* NOTE: must be called outside the CPU execute loop */
+void cpu_reset(CPUZ80State *env)
+{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ memset(env, 0, offsetof(CPUZ80State, breakpoints));
+
+ tlb_flush(env, 1);
+
+ /* init to reset state */
+
+#ifdef CONFIG_SOFTMMU
+ env->hflags |= HF_SOFTMMU_MASK;
+#endif
+
+ env->pc = 0x0000;
+ env->iff1 = 0;
+ env->iff2 = 0;
+ env->imode = 0;
+ env->regs[R_A] = 0xff;
+ env->regs[R_F] = 0xff;
+ env->regs[R_SP] = 0xffff;
+}
+
+void cpu_z80_close(CPUZ80State *env)
+{
+ free(env);
+}
+
+/***********************************************************/
+/* x86 debug */
+
+void cpu_dump_state(CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+ int fl = env->regs[R_F];
+
+ cpu_fprintf(f, "AF =%04x BC =%04x DE =%04x HL =%04x IX=%04x\n"
+ "AF'=%04x BC'=%04x DE'=%04x HL'=%04x IY=%04x\n"
+ "PC =%04x SP =%04x F=[%c%c%c%c%c%c%c%c]\n"
+ "IM=%i IFF1=%i IFF2=%i I=%02x R=%02x\n",
+ (env->regs[R_A] << 8) | env->regs[R_F],
+ env->regs[R_BC],
+ env->regs[R_DE],
+ env->regs[R_HL],
+ env->regs[R_IX],
+ (env->regs[R_AX] << 8) | env->regs[R_FX],
+ env->regs[R_BCX],
+ env->regs[R_DEX],
+ env->regs[R_HLX],
+ env->regs[R_IY],
+ env->pc, /* pc == -1 ? env->pc : pc, */
+ env->regs[R_SP],
+ fl & 0x80 ? 'S' : '-',
+ fl & 0x40 ? 'Z' : '-',
+ fl & 0x20 ? 'Y' : '-',
+ fl & 0x10 ? 'H' : '-',
+ fl & 0x08 ? 'X' : '-',
+ fl & 0x04 ? 'P' : '-',
+ fl & 0x02 ? 'N' : '-',
+ fl & 0x01 ? 'C' : '-',
+ env->imode, env->iff1, env->iff2, env->regs[R_I], env->regs[R_R]);
+}
+
+/***********************************************************/
+static void cpu_z80_flush_tlb(CPUZ80State *env, target_ulong addr)
+{
+ tlb_flush_page(env, addr);
+}
+
+/* return value:
+ -1 = cannot handle fault
+ 0 = nothing more to do
+ 1 = generate PF fault
+ 2 = soft MMU activation required for this block
+*/
+int cpu_z80_handle_mmu_fault(CPUZ80State *env, target_ulong addr,
+ int is_write1, int is_user, int is_softmmu)
+{
+ int prot, page_size, ret, is_write;
+ unsigned long paddr, page_offset;
+ target_ulong vaddr, virt_addr;
+
+#if defined(DEBUG_MMU)
+ printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d pc=" TARGET_FMT_lx "\n",
+ addr, is_write1, is_user, env->pc);
+#endif
+ is_write = is_write1 & 1;
+
+ virt_addr = addr & TARGET_PAGE_MASK;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = TARGET_PAGE_SIZE;
+
+ page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
+ paddr = (addr & TARGET_PAGE_MASK) + page_offset;
+ vaddr = virt_addr + page_offset;
+
+ ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
+ return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ uint32_t pte, paddr, page_offset, page_size;
+
+ pte = addr;
+ page_size = TARGET_PAGE_SIZE;
+
+ page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
+ paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+ return paddr;
+}
diff --git a/target-z80/helper.h b/target-z80/helper.h
new file mode 100644
index 0000000..0784e81
--- /dev/null
+++ b/target-z80/helper.h
@@ -0,0 +1,89 @@
+#include "def-helper.h"
+
+DEF_HELPER_0(debug, void)
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(set_inhibit_irq, void)
+DEF_HELPER_0(reset_inhibit_irq, void)
+
+DEF_HELPER_1(movl_pc_im, void, i32)
+
+DEF_HELPER_0(halt, void)
+
+/* In / Out */
+DEF_HELPER_1(in_T0_im, void, i32)
+DEF_HELPER_0(in_T0_bc_cc, void)
+DEF_HELPER_1(out_T0_im, void, i32)
+DEF_HELPER_0(out_T0_bc, void)
+
+/* Misc */
+DEF_HELPER_1(bit_T0, void, i32)
+DEF_HELPER_0(jmp_T0, void)
+DEF_HELPER_2(djnz, void, i32, i32)
+
+/* 8-bit arithmetic */
+DEF_HELPER_0(add_cc, void)
+DEF_HELPER_0(adc_cc, void)
+DEF_HELPER_0(sub_cc, void)
+DEF_HELPER_0(sbc_cc, void)
+DEF_HELPER_0(and_cc, void)
+DEF_HELPER_0(xor_cc, void)
+DEF_HELPER_0(or_cc, void)
+DEF_HELPER_0(cp_cc, void)
+
+/* Rotation/shifts */
+DEF_HELPER_0(rlc_T0_cc, void)
+DEF_HELPER_0(rrc_T0_cc, void)
+DEF_HELPER_0(rl_T0_cc, void)
+DEF_HELPER_0(rr_T0_cc, void)
+DEF_HELPER_0(sla_T0_cc, void)
+DEF_HELPER_0(sra_T0_cc, void)
+DEF_HELPER_0(sll_T0_cc, void)
+DEF_HELPER_0(srl_T0_cc, void)
+DEF_HELPER_0(rld_cc, void)
+DEF_HELPER_0(rrd_cc, void)
+
+/* Block instructions */
+DEF_HELPER_0(bli_ld_inc_cc, void)
+DEF_HELPER_0(bli_ld_dec_cc, void)
+DEF_HELPER_1(bli_ld_rep, void, i32)
+DEF_HELPER_0(bli_cp_cc, void)
+DEF_HELPER_0(bli_cp_inc_cc, void)
+DEF_HELPER_0(bli_cp_dec_cc, void)
+DEF_HELPER_1(bli_cp_rep, void, i32)
+DEF_HELPER_0(bli_io_inc, void)
+DEF_HELPER_0(bli_io_dec, void)
+DEF_HELPER_1(bli_io_rep, void, i32)
+
+/* Misc */
+DEF_HELPER_0(rlca_cc, void)
+DEF_HELPER_0(rrca_cc, void)
+DEF_HELPER_0(rla_cc, void)
+DEF_HELPER_0(rra_cc, void)
+DEF_HELPER_0(daa_cc, void)
+DEF_HELPER_0(cpl_cc, void)
+DEF_HELPER_0(scf_cc, void)
+DEF_HELPER_0(ccf_cc, void)
+DEF_HELPER_0(neg_cc, void)
+
+/* 16-bit arithmetic */
+DEF_HELPER_0(sbcw_T0_T1_cc, void)
+DEF_HELPER_0(addw_T0_T1_cc, void)
+DEF_HELPER_0(adcw_T0_T1_cc, void)
+DEF_HELPER_0(incb_T0_cc, void)
+DEF_HELPER_0(decb_T0_cc, void)
+
+/* Interrupt handling / IR registers */
+DEF_HELPER_1(imode, void, i32)
+DEF_HELPER_0(ei, void)
+DEF_HELPER_0(di, void)
+DEF_HELPER_0(ri, void)
+DEF_HELPER_0(ld_R_A, void)
+DEF_HELPER_0(ld_I_A, void)
+DEF_HELPER_0(ld_A_R, void)
+DEF_HELPER_0(ld_A_I, void)
+
+/* R800 */
+DEF_HELPER_0(mulub_cc, void)
+DEF_HELPER_0(muluw_cc, void)
+
+#include "def-helper.h"
diff --git a/target-z80/machine.c b/target-z80/machine.c
new file mode 100644
index 0000000..1be1c35
--- /dev/null
+++ b/target-z80/machine.c
@@ -0,0 +1,11 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return 0;
+}
diff --git a/target-z80/op_helper.c b/target-z80/op_helper.c
new file mode 100644
index 0000000..899520c
--- /dev/null
+++ b/target-z80/op_helper.c
@@ -0,0 +1,947 @@
+/*
+ * Z80 helpers
+ *
+ * Copyright (c) 2007 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include "exec.h"
+#include "helper.h"
+
+const uint8_t parity_table[256] = {
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+};
+
+void do_interrupt(CPUZ80State *env)
+{
+// printf("z80: do_interrupt()\n");
+
+ if (!env->iff1) {
+ return;
+ }
+
+ env->iff1 = 0;
+ env->iff2 = 0; /* XXX: Unchanged for NMI */
+
+ {
+ target_ulong sp;
+ sp = (uint16_t)(env->regs[R_SP] - 2);
+ env->regs[R_SP] = sp;
+ stw_kernel(sp, env->pc);
+ }
+
+ /* IM0 = execute data on bus (0xff == rst $38) */
+ /* IM1 = execute rst $38 (ROM uses this)*/
+ /* IM2 = indirect jump -- address is held at (I << 8) | DATA */
+
+ /* value on data bus is 0xff for the zx spectrum */
+
+ /* when an interrupt occurs, iff1 and iff2 are reset, disabling interrupts */
+ /* when an NMI occurs, iff1 is reset. iff2 is left unchanged */
+
+ uint8_t d;
+ switch (env->imode) {
+ case 0:
+ /* XXX: assuming 0xff on data bus */
+ case 1:
+ env->pc = 0x0038;
+ break;
+ case 2:
+ /* XXX: assuming 0xff on data bus */
+ d = 0xff;
+ env->pc = lduw_kernel((env->regs[R_I] << 8) | d);
+ break;
+ }
+}
+
+/*
+ * Signal an interruption. It is executed in the main CPU loop.
+ * is_int is TRUE if coming from the int instruction. next_eip is the
+ * EIP value AFTER the interrupt instruction. It is only relevant if
+ * is_int is TRUE.
+ */
+void raise_interrupt(int intno, int is_int, int error_code,
+ int next_eip_addend)
+{
+ env->exception_index = intno;
+ env->error_code = error_code;
+ env->exception_is_int = is_int;
+ env->exception_next_pc = env->pc + next_eip_addend;
+ cpu_loop_exit();
+}
+
+/* same as raise_exception_err, but do not restore global registers */
+static void raise_exception_err_norestore(int exception_index, int error_code)
+{
+ env->exception_index = exception_index;
+ env->error_code = error_code;
+ env->exception_is_int = 0;
+ env->exception_next_pc = 0;
+ longjmp(env->jmp_env, 1);
+}
+
+/* shortcuts to generate exceptions */
+
+void (raise_exception_err)(int exception_index, int error_code)
+{
+ raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+void raise_exception(int exception_index)
+{
+ raise_interrupt(exception_index, 0, 0, 0);
+}
+
+void HELPER(debug)(void)
+{
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit();
+}
+
+void HELPER(raise_exception)(uint32_t exception_index)
+{
+ raise_exception(exception_index);
+}
+
+void HELPER(set_inhibit_irq)(void)
+{
+ env->hflags |= HF_INHIBIT_IRQ_MASK;
+}
+
+void HELPER(reset_inhibit_irq)(void)
+{
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+}
+
+void HELPER(movl_pc_im)(uint32_t new_pc)
+{
+ PC = (uint16_t)new_pc;
+}
+
+/* Z80 instruction-specific helpers */
+
+/* Halt */
+
+void HELPER(halt)(void)
+{
+ //printf("halting at PC 0x%x\n",env->pc);
+ env->halted = 1;
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+}
+
+/* In / Out */
+
+void HELPER(in_T0_im)(uint32_t val)
+{
+ T0 = cpu_inb(env, (A << 8) | val);
+}
+
+void HELPER(in_T0_bc_cc)(void)
+{
+ int sf, zf, pf;
+
+ T0 = cpu_inb(env, BC);
+
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[(uint8_t)T0];
+ F = (F & CC_C) | sf | zf | pf;
+}
+
+void HELPER(out_T0_im)(uint32_t val)
+{
+ cpu_outb(env, (A << 8) | val, T0);
+}
+
+void HELPER(out_T0_bc)(void)
+{
+ cpu_outb(env, BC, T0);
+}
+
+/* Misc */
+
+void HELPER(bit_T0)(uint32_t val)
+{
+ int sf, zf, pf;
+
+ sf = (T0 & val & 0x80) ? CC_S : 0;
+ zf = (T0 & val) ? 0 : CC_Z;
+ pf = (T0 & val) ? 0 : CC_P;
+ F = (F & CC_C) | sf | zf | CC_H | pf;
+}
+
+void HELPER(jmp_T0)(void)
+{
+ PC = T0;
+}
+
+void HELPER(djnz)(uint32_t pc1, uint32_t pc2)
+{
+ BC = (uint16_t)(BC - 0x0100);
+ if (BC & 0xff00) {
+ PC = (uint16_t)pc1;
+ } else {
+ PC = (uint16_t)pc2;
+ }
+}
+
+/* Arithmetic/logic operations */
+
+#define signed_overflow_add(op1, op2, res, size) \
+ (!!((~(op1 ^ op2) & (op1 ^ res)) >> (size - 1)))
+
+#define signed_overflow_sub(op1, op2, res, size) \
+ (!!(((op1 ^ op2) & (op1 ^ res)) >> (size - 1)))
+
+void HELPER(add_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = A;
+ int carry;
+
+ A = (uint8_t)(A + T0);
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_add(tmp, T0, A, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | cf;
+}
+
+void HELPER(adc_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = A;
+ int carry;
+
+ A = (uint8_t)(A + T0 + !!(F & CC_C));
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_add(tmp, T0, A, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | cf;
+}
+
+void HELPER(sub_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = A;
+ int carry;
+
+ A = (uint8_t)(A - T0);
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ carry = (~tmp & T0) | (~(tmp ^ T0) & A);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | CC_N | cf;
+}
+
+void HELPER(sbc_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = A;
+ int carry;
+
+ A = (uint8_t)(A - T0 - !!(F & CC_C));
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ carry = (~tmp & T0) | (~(tmp ^ T0) & A);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | CC_N | cf;
+}
+
+void HELPER(and_cc)(void)
+{
+ int sf, zf, pf;
+ A = (uint8_t)(A & T0);
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = parity_table[(uint8_t)A];
+ F = sf | zf | CC_H | pf;
+}
+
+void HELPER(xor_cc)(void)
+{
+ int sf, zf, pf;
+ A = (uint8_t)(A ^ T0);
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = parity_table[(uint8_t)A];
+ F = sf | zf | pf;
+}
+
+void HELPER(or_cc)(void)
+{
+ int sf, zf, pf;
+ A = (uint8_t)(A | T0);
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = parity_table[(uint8_t)A];
+ F = sf | zf | pf;
+}
+
+void HELPER(cp_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int res, carry;
+
+ res = (uint8_t)(A - T0);
+ sf = (res & 0x80) ? CC_S : 0;
+ zf = res ? 0 : CC_Z;
+ carry = (~A & T0) | (~(A ^ T0) & res);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_sub(A, T0, res, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | CC_N | cf;
+// CC_DST = (uint8_t)(A - T0);
+}
+
+/* Rotation/shift operations */
+
+void HELPER(rlc_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 << 1) | !!(T0 & 0x80));
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(rrc_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 >> 1) | ((tmp & 0x01) ? 0x80 : 0));
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(rl_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 << 1) | !!(F & CC_C));
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(rr_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 >> 1) | ((F & CC_C) ? 0x80 : 0));
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(sla_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)(T0 << 1);
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(sra_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 >> 1) | (T0 & 0x80));
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+/* Z80-specific: R800 has tst instruction */
+void HELPER(sll_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)((T0 << 1) | 1); /* Yes -- bit 0 is *set* */
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(srl_T0_cc)(void)
+{
+ int sf, zf, pf, cf;
+ int tmp;
+
+ tmp = T0;
+ T0 = (uint8_t)(T0 >> 1);
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ pf = parity_table[T0];
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = sf | zf | pf | cf;
+}
+
+void HELPER(rld_cc)(void)
+{
+ int sf, zf, pf;
+ int tmp = A & 0x0f;
+ A = (A & 0xf0) | ((T0 >> 4) & 0x0f);
+ T0 = ((T0 << 4) & 0xf0) | tmp;
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = parity_table[A];
+
+ F = (F & CC_C) | sf | zf | pf;
+}
+
+void HELPER(rrd_cc)(void)
+{
+ int sf, zf, pf;
+ int tmp = A & 0x0f;
+ A = (A & 0xf0) | (T0 & 0x0f);
+ T0 = (T0 >> 4) | (tmp << 4);
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = parity_table[A];
+
+ F = (F & CC_C) | sf | zf | pf;
+}
+
+/* Block instructions */
+
+void HELPER(bli_ld_inc_cc)(void)
+{
+ int pf;
+
+ BC = (uint16_t)(BC - 1);
+ DE = (uint16_t)(DE + 1);
+ HL = (uint16_t)(HL + 1);
+
+ pf = BC ? CC_P : 0;
+ F = (F & (CC_S | CC_Z | CC_C)) | pf;
+}
+
+void HELPER(bli_ld_dec_cc)(void)
+{
+ int pf;
+
+ BC = (uint16_t)(BC - 1);
+ DE = (uint16_t)(DE - 1);
+ HL = (uint16_t)(HL - 1);
+
+ pf = BC ? CC_P : 0;
+ F = (F & (CC_S | CC_Z | CC_C)) | pf;
+}
+
+void HELPER(bli_ld_rep)(uint32_t next_pc)
+{
+ if (BC) {
+ PC = (uint16_t)(next_pc - 2);
+ } else {
+ PC = next_pc;
+ }
+}
+
+void HELPER(bli_cp_cc)(void)
+{
+ int sf, zf, hf, pf;
+ int res, carry;
+
+ res = (uint8_t)(A - T0);
+ sf = (res & 0x80) ? CC_S : 0;
+ zf = res ? 0 : CC_Z;
+ carry = (~A & T0) | (~(A ^ T0) & res);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = BC ? CC_P : 0;
+
+ F = (F & CC_C) | sf | zf | hf | pf | CC_N;
+}
+
+void HELPER(bli_cp_inc_cc)(void)
+{
+ int pf;
+
+ BC = (uint16_t)(BC - 1);
+ HL = (uint16_t)(HL + 1);
+
+ pf = BC ? CC_P : 0;
+ F = (F & ~CC_P) | pf;
+}
+
+void HELPER(bli_cp_dec_cc)(void)
+{
+ int pf;
+
+ BC = (uint16_t)(BC - 1);
+ HL = (uint16_t)(HL - 1);
+
+ pf = BC ? CC_P : 0;
+ F = (F & ~CC_P) | pf;
+}
+
+void HELPER(bli_cp_rep)(uint32_t next_pc)
+{
+ if (BC && T0 != A) {
+ PC = (uint16_t)(next_pc - 2);
+ } else {
+ PC = next_pc;
+ }
+}
+
+void HELPER(bli_io_inc)(void)
+{
+ HL = (uint16_t)(HL + 1);
+ BC = (uint16_t)BC - 0x0100;
+}
+
+void HELPER(bli_io_dec)(void)
+{
+ HL = (uint16_t)(HL - 1);
+ BC = (uint16_t)BC - 0x0100;
+}
+
+void HELPER(bli_io_rep)(uint32_t next_pc)
+{
+ if (BC & 0xff00) {
+ PC = (uint16_t)(next_pc - 2);
+ } else {
+ PC = next_pc;
+ }
+}
+
+/* misc */
+
+void HELPER(rlca_cc)(void)
+{
+ int cf;
+ int tmp;
+
+ tmp = A;
+ A = (uint8_t)((A << 1) | !!(tmp & 0x80));
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
+}
+
+void HELPER(rrca_cc)(void)
+{
+ int cf;
+ int tmp;
+
+ tmp = A;
+ A = (A >> 1) | ((tmp & 0x01) ? 0x80 : 0);
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
+}
+
+void HELPER(rla_cc)(void)
+{
+ int cf;
+ int tmp;
+
+ tmp = A;
+ A = (uint8_t)((A << 1) | !!(F & CC_C));
+ cf = (tmp & 0x80) ? CC_C : 0;
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
+}
+
+void HELPER(rra_cc)(void)
+{
+ int cf;
+ int tmp;
+
+ tmp = A;
+ A = (A >> 1) | ((F & CC_C) ? 0x80 : 0);
+ cf = (tmp & 0x01) ? CC_C : 0;
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
+}
+
+/* TODO */
+void HELPER(daa_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int cor = 0;
+ int tmp = A;
+
+ if (A > 0x99 || (F & CC_C)) {
+ cor |= 0x60;
+ cf = CC_C;
+ } else {
+ cf = 0;
+ }
+
+ if ((A & 0x0f) > 0x09 || (F & CC_H)) {
+ cor |= 0x06;
+ }
+
+ if (!(F & CC_N)) {
+ A = (uint8_t)(A + cor);
+ } else {
+ A = (uint8_t)(A - cor);
+ }
+
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ hf = ((tmp ^ A) & 0x10) ? CC_H : 0;
+ pf = parity_table[(uint8_t)A];
+
+ F = (F & CC_N) | sf | zf | hf | pf | cf;
+}
+
+void HELPER(cpl_cc)(void)
+{
+ A = (uint8_t)~A;
+ F |= CC_H | CC_N;
+}
+
+void HELPER(scf_cc)(void)
+{
+ F = (F & (CC_S | CC_Z | CC_P)) | CC_C;
+}
+
+void HELPER(ccf_cc)(void)
+{
+ int hf, cf;
+
+ hf = (F & CC_C) ? CC_H : 0;
+ cf = (F & CC_C) ^ CC_C;
+ F = (F & (CC_S | CC_Z | CC_P)) | hf | cf;
+}
+
+/* misc */
+
+void HELPER(neg_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = A;
+ int carry;
+
+ A = (uint8_t)-A;
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
+ cf = (carry & 0x80) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | CC_N | cf;
+}
+
+/* word operations -- HL only? */
+
+void HELPER(sbcw_T0_T1_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = T0;
+ int carry;
+
+ T0 = (uint16_t)(T0 - T1 - !!(F & CC_C));
+ sf = (T0 & 0x8000) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ carry = (~tmp & T1) | (~(tmp ^ T1) & T0);
+ hf = (carry & 0x0800) ? CC_H : 0;
+ pf = signed_overflow_sub(tmp, T1, T0, 16) ? CC_P : 0;
+ cf = (carry & 0x8000) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | CC_N | cf;
+}
+
+void HELPER(addw_T0_T1_cc)(void)
+{
+ int hf, cf;
+ int tmp = T0;
+ int carry;
+
+ T0 = (uint16_t)(T0 + T1);
+ carry = (tmp & T1) | ((tmp | T1) & ~T0);
+ hf = (carry & 0x0800) ? CC_H : 0;
+ cf = (carry & 0x8000) ? CC_C : 0;
+
+ F = (F & (CC_S | CC_Z | CC_P)) | hf | cf;
+}
+
+void HELPER(adcw_T0_T1_cc)(void)
+{
+ int sf, zf, hf, pf, cf;
+ int tmp = T0;
+ int carry;
+
+ T0 = (uint16_t)(T0 + T1 + !!(F & CC_C));
+ sf = (T0 & 0x8000) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+ carry = (tmp & T1) | ((tmp | T1) & ~T0);
+ hf = (carry & 0x0800) ? CC_H : 0;
+ pf = signed_overflow_add(tmp, T1, T0, 8) ? CC_P : 0;
+ cf = (carry & 0x8000) ? CC_C : 0;
+
+ F = sf | zf | hf | pf | cf;
+}
+
+/* misc */
+
+void HELPER(incb_T0_cc)(void)
+{
+ int sf, zf, hf, pf;
+ int tmp;
+ int carry;
+
+ tmp = T0;
+ T0 = (uint8_t)(T0 + 1);
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+
+ carry = (tmp & 1) | ((tmp | 1) & ~T0);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_add(tmp, 1, T0, 8) ? CC_P : 0;
+
+ F = (F & CC_C) | sf | zf | hf | pf;
+}
+
+void HELPER(decb_T0_cc)(void)
+{
+ int sf, zf, hf, pf;
+ int tmp;
+ int carry;
+
+ tmp = T0;
+ T0 = (uint8_t)(T0 - 1);
+ sf = (T0 & 0x80) ? CC_S : 0;
+ zf = T0 ? 0 : CC_Z;
+
+ carry = (~tmp & 1) | (~(tmp ^ 1) & T0);
+ hf = (carry & 0x08) ? CC_H : 0;
+ pf = signed_overflow_sub(tmp, 1, T0, 8) ? CC_P : 0;
+
+ F = (F & CC_C) | sf | zf | hf | CC_N | pf;
+ /* TODO: check CC_N is set */
+}
+
+/* value on data bus is 0xff for speccy */
+/* IM0 = execute data on bus (rst $38 on speccy) */
+/* IM1 = execute rst $38 (ROM uses this)*/
+/* IM2 = indirect jump -- address is held at (I << 8) | DATA */
+
+/* when an interrupt occurs, iff1 and iff2 are reset, disabling interrupts */
+/* when an NMI occurs, iff1 is reset. iff2 is left unchanged */
+
+void HELPER(imode)(uint32_t imode)
+{
+ env->imode = imode;
+}
+
+/* enable interrupts */
+void HELPER(ei)(void)
+{
+ env->iff1 = 1;
+ env->iff2 = 1;
+}
+
+/* disable interrupts */
+void HELPER(di)(void)
+{
+ env->iff1 = 0;
+ env->iff2 = 0;
+}
+
+/* reenable interrupts if enabled */
+void HELPER(ri)(void)
+{
+ env->iff1 = env->iff2;
+}
+
+void HELPER(ld_R_A)(void)
+{
+ R = A;
+}
+
+void HELPER(ld_I_A)(void)
+{
+ I = A;
+}
+
+void HELPER(ld_A_R)(void)
+{
+ int sf, zf, pf;
+
+ A = R;
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = env->iff2 ? CC_P : 0;
+
+ F = (F & CC_C) | sf | zf | pf;
+}
+
+void HELPER(ld_A_I)(void)
+{
+ int sf, zf, pf;
+
+ A = I;
+ sf = (A & 0x80) ? CC_S : 0;
+ zf = A ? 0 : CC_Z;
+ pf = env->iff2 ? CC_P : 0;
+
+ F = (F & CC_C) | sf | zf | pf;
+}
+
+void HELPER(mulub_cc)(void)
+{
+ /* TODO: flags */
+
+ HL = A * T0;
+}
+
+void HELPER(muluw_cc)(void)
+{
+ /* TODO: flags */
+ uint32_t tmp;
+
+ tmp = HL * T0;
+ DE = tmp >> 16;
+ HL = tmp & 0xff;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+#endif
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+ TranslationBlock *tb;
+ int ret;
+ unsigned long pc;
+ CPUZ80State *saved_env;
+
+ /* XXX: hack to restore env in all cases, even if not called from
+ generated code */
+ saved_env = env;
+ env = cpu_single_env;
+
+ ret = cpu_z80_handle_mmu_fault(env, addr, is_write, is_user, 1);
+ if (ret) {
+ if (retaddr) {
+ /* now we have a real cpu fault */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, NULL);
+ }
+ }
+ if (retaddr) {
+ raise_exception_err(env->exception_index, env->error_code);
+ } else {
+ raise_exception_err_norestore(env->exception_index, env->error_code);
+ }
+ }
+ env = saved_env;
+}
diff --git a/target-z80/translate.c b/target-z80/translate.c
new file mode 100644
index 0000000..846ec03
--- /dev/null
+++ b/target-z80/translate.c
@@ -0,0 +1,1834 @@
+/*
+ * Z80 translation
+ *
+ * Copyright (c) 2007-2009 Stuart Brady
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+#include "tcg-op.h"
+
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define PREFIX_CB 0x01
+#define PREFIX_DD 0x02
+#define PREFIX_ED 0x04
+#define PREFIX_FD 0x08
+
+#define MODE_NORMAL 0
+#define MODE_DD 1
+#define MODE_FD 2
+
+#define zprintf(...)
+//#define zprintf printf
+
+/* global register indexes */
+static TCGv cpu_env, cpu_T[3], cpu_A0;
+
+#include "gen-icount.h"
+
+#define MEM_INDEX 0
+
+typedef struct DisasContext {
+ /* current insn context */
+ int override; /* -1 if no override */
+ int prefix;
+ uint16_t pc; /* pc = pc + cs_base */
+ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
+ static state change (stop translation) */
+ int model;
+ /* current block context */
+ target_ulong cs_base; /* base of CS segment */
+ int singlestep_enabled; /* "hardware" single step enabled */
+ int jmp_opt; /* use direct block chaining for direct jumps */
+ int flags; /* all execution flags */
+ struct TranslationBlock *tb;
+} DisasContext;
+
+static void gen_eob(DisasContext *s);
+static void gen_jmp(DisasContext *s, target_ulong pc);
+static void gen_jmp_tb(DisasContext *s, target_ulong pc, int tb_num);
+
+enum {
+ /* 8-bit registers */
+ OR_B,
+ OR_C,
+ OR_D,
+ OR_E,
+ OR_H,
+ OR_L,
+ OR_HLmem,
+ OR_A,
+
+ OR_IXh,
+ OR_IXl,
+
+ OR_IYh,
+ OR_IYl,
+
+ OR_IXmem,
+ OR_IYmem,
+};
+
+static const char *const regnames[] = {
+ [OR_B] = "b",
+ [OR_C] = "c",
+ [OR_D] = "d",
+ [OR_E] = "e",
+ [OR_H] = "h",
+ [OR_L] = "l",
+ [OR_HLmem] = "(hl)",
+ [OR_A] = "a",
+
+ [OR_IXh] = "ixh",
+ [OR_IXl] = "ixl",
+
+ [OR_IYh] = "iyh",
+ [OR_IYl] = "iyl",
+
+ [OR_IXmem] = "(ix+d)",
+ [OR_IYmem] = "(iy+d)",
+};
+
+static const char *const idxnames[] = {
+ [OR_IXmem] = "ix",
+ [OR_IYmem] = "iy",
+};
+
+/* signed hex byte value for printf */
+#define shexb(val) (val < 0 ? '-' : '+'), (abs(val))
+
+/* Register accessor functions */
+
+#if defined(WORDS_BIGENDIAN)
+#define UNIT_OFFSET(type, units, num) (sizeof(type) - ((num + 1) * units))
+#else
+#define UNIT_OFFSET(type, units, num) (num * units)
+#endif
+
+#define BYTE_OFFSET(type, num) UNIT_OFFSET(type, 1, num)
+#define WORD_OFFSET(type, num) UNIT_OFFSET(type, 2, num)
+
+#define REGPAIR AF
+#define REGHIGH A
+#define REGLOW F
+#include "genreg_template_af.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR BC
+#define REGHIGH B
+#define REGLOW C
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR DE
+#define REGHIGH D
+#define REGLOW E
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR HL
+#define REGHIGH H
+#define REGLOW L
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR IX
+#define REGHIGH IXh
+#define REGLOW IXl
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR IY
+#define REGHIGH IYh
+#define REGLOW IYl
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR AFX
+#define REGHIGH AX
+#define REGLOW FX
+#include "genreg_template_af.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR BCX
+#define REGHIGH BX
+#define REGLOW CX
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR DEX
+#define REGHIGH DX
+#define REGLOW EX
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR HLX
+#define REGHIGH HX
+#define REGLOW LX
+#include "genreg_template.h"
+#undef REGPAIR
+#undef REGHIGH
+#undef REGLOW
+
+#define REGPAIR SP
+#include "genreg_template.h"
+#undef REGPAIR
+
+typedef void (gen_mov_func)(TCGv v);
+typedef void (gen_mov_func_idx)(TCGv v, uint16_t ofs);
+
+static inline void gen_movb_v_HLmem(TCGv v)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_HL(addr);
+ tcg_gen_qemu_ld8u(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_movb_HLmem_v(TCGv v)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_HL(addr);
+ tcg_gen_qemu_st8(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_movb_v_IXmem(TCGv v, uint16_t ofs)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_IX(addr);
+ tcg_gen_addi_tl(addr, addr, ofs);
+ tcg_gen_ext16u_tl(addr, addr);
+ tcg_gen_qemu_ld8u(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_movb_v_IYmem(TCGv v, uint16_t ofs)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_IY(addr);
+ tcg_gen_addi_tl(addr, addr, ofs);
+ tcg_gen_ext16u_tl(addr, addr);
+ tcg_gen_qemu_ld8u(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_movb_IXmem_v(TCGv v, uint16_t ofs)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_IX(addr);
+ tcg_gen_addi_tl(addr, addr, ofs);
+ tcg_gen_ext16u_tl(addr, addr);
+ tcg_gen_qemu_st8(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_movb_IYmem_v(TCGv v, uint16_t ofs)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_IY(addr);
+ tcg_gen_addi_tl(addr, addr, ofs);
+ tcg_gen_ext16u_tl(addr, addr);
+ tcg_gen_qemu_st8(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_pushw(TCGv v)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_SP(addr);
+ tcg_gen_subi_i32(addr, addr, 2);
+ tcg_gen_ext16u_i32(addr, addr);
+ gen_movw_SP_v(addr);
+ tcg_gen_qemu_st16(v, addr, MEM_INDEX);
+ tcg_temp_free(addr);
+}
+
+static inline void gen_popw(TCGv v)
+{
+ TCGv addr = tcg_temp_new();
+ gen_movw_v_SP(addr);
+ tcg_gen_qemu_ld16u(v, addr, MEM_INDEX);
+ tcg_gen_addi_i32(addr, addr, 2);
+ tcg_gen_ext16u_i32(addr, addr);
+ gen_movw_SP_v(addr);
+ tcg_temp_free(addr);
+}
+
+static gen_mov_func *const gen_movb_v_reg_tbl[] = {
+ [OR_B] = gen_movb_v_B,
+ [OR_C] = gen_movb_v_C,
+ [OR_D] = gen_movb_v_D,
+ [OR_E] = gen_movb_v_E,
+ [OR_H] = gen_movb_v_H,
+ [OR_L] = gen_movb_v_L,
+ [OR_HLmem] = gen_movb_v_HLmem,
+ [OR_A] = gen_movb_v_A,
+
+ [OR_IXh] = gen_movb_v_IXh,
+ [OR_IXl] = gen_movb_v_IXl,
+
+ [OR_IYh] = gen_movb_v_IYh,
+ [OR_IYl] = gen_movb_v_IYl,
+};
+
+static inline void gen_movb_v_reg(TCGv v, int reg)
+{
+ gen_movb_v_reg_tbl[reg](v);
+}
+
+static gen_mov_func_idx *const gen_movb_v_idx_tbl[] = {
+ [OR_IXmem] = gen_movb_v_IXmem,
+ [OR_IYmem] = gen_movb_v_IYmem,
+};
+
+static inline void gen_movb_v_idx(TCGv v, int idx, int ofs)
+{
+ gen_movb_v_idx_tbl[idx](v, ofs);
+}
+
+static gen_mov_func *const gen_movb_reg_v_tbl[] = {
+ [OR_B] = gen_movb_B_v,
+ [OR_C] = gen_movb_C_v,
+ [OR_D] = gen_movb_D_v,
+ [OR_E] = gen_movb_E_v,
+ [OR_H] = gen_movb_H_v,
+ [OR_L] = gen_movb_L_v,
+ [OR_HLmem] = gen_movb_HLmem_v,
+ [OR_A] = gen_movb_A_v,
+
+ [OR_IXh] = gen_movb_IXh_v,
+ [OR_IXl] = gen_movb_IXl_v,
+
+ [OR_IYh] = gen_movb_IYh_v,
+ [OR_IYl] = gen_movb_IYl_v,
+};
+
+static inline void gen_movb_reg_v(int reg, TCGv v)
+{
+ gen_movb_reg_v_tbl[reg](v);
+}
+
+static gen_mov_func_idx *const gen_movb_idx_v_tbl[] = {
+ [OR_IXmem] = gen_movb_IXmem_v,
+ [OR_IYmem] = gen_movb_IYmem_v,
+};
+
+static inline void gen_movb_idx_v(int idx, TCGv v, int ofs)
+{
+ gen_movb_idx_v_tbl[idx](v, ofs);
+}
+
+static inline int regmap(int reg, int m)
+{
+ switch (m) {
+ case MODE_DD:
+ switch (reg) {
+ case OR_H:
+ return OR_IXh;
+ case OR_L:
+ return OR_IXl;
+ case OR_HLmem:
+ return OR_IXmem;
+ default:
+ return reg;
+ }
+ case MODE_FD:
+ switch (reg) {
+ case OR_H:
+ return OR_IYh;
+ case OR_L:
+ return OR_IYl;
+ case OR_HLmem:
+ return OR_IYmem;
+ default:
+ return reg;
+ }
+ case MODE_NORMAL:
+ default:
+ return reg;
+ }
+}
+
+static inline int is_indexed(int reg)
+{
+ if (reg == OR_IXmem || reg == OR_IYmem) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static const int reg[8] = {
+ OR_B,
+ OR_C,
+ OR_D,
+ OR_E,
+ OR_H,
+ OR_L,
+ OR_HLmem,
+ OR_A,
+};
+
+enum {
+ /* 16-bit registers and register pairs */
+ OR2_AF,
+ OR2_BC,
+ OR2_DE,
+ OR2_HL,
+
+ OR2_IX,
+ OR2_IY,
+ OR2_SP,
+
+ OR2_AFX,
+ OR2_BCX,
+ OR2_DEX,
+ OR2_HLX,
+};
+
+static const char *const regpairnames[] = {
+ [OR2_AF] = "af",
+ [OR2_BC] = "bc",
+ [OR2_DE] = "de",
+ [OR2_HL] = "hl",
+
+ [OR2_IX] = "ix",
+ [OR2_IY] = "iy",
+ [OR2_SP] = "sp",
+
+ [OR2_AFX] = "afx",
+ [OR2_BCX] = "bcx",
+ [OR2_DEX] = "dex",
+ [OR2_HLX] = "hlx",
+};
+
+static gen_mov_func *const gen_movw_v_reg_tbl[] = {
+ [OR2_AF] = gen_movw_v_AF,
+ [OR2_BC] = gen_movw_v_BC,
+ [OR2_DE] = gen_movw_v_DE,
+ [OR2_HL] = gen_movw_v_HL,
+
+ [OR2_IX] = gen_movw_v_IX,
+ [OR2_IY] = gen_movw_v_IY,
+ [OR2_SP] = gen_movw_v_SP,
+
+ [OR2_AFX] = gen_movw_v_AFX,
+ [OR2_BCX] = gen_movw_v_BCX,
+ [OR2_DEX] = gen_movw_v_DEX,
+ [OR2_HLX] = gen_movw_v_HLX,
+};
+
+static inline void gen_movw_v_reg(TCGv v, int regpair)
+{
+ gen_movw_v_reg_tbl[regpair](v);
+}
+
+static gen_mov_func *const gen_movw_reg_v_tbl[] = {
+ [OR2_AF] = gen_movw_AF_v,
+ [OR2_BC] = gen_movw_BC_v,
+ [OR2_DE] = gen_movw_DE_v,
+ [OR2_HL] = gen_movw_HL_v,
+
+ [OR2_IX] = gen_movw_IX_v,
+ [OR2_IY] = gen_movw_IY_v,
+ [OR2_SP] = gen_movw_SP_v,
+
+ [OR2_AFX] = gen_movw_AFX_v,
+ [OR2_BCX] = gen_movw_BCX_v,
+ [OR2_DEX] = gen_movw_DEX_v,
+ [OR2_HLX] = gen_movw_HLX_v,
+};
+
+static inline void gen_movw_reg_v(int regpair, TCGv v)
+{
+ gen_movw_reg_v_tbl[regpair](v);
+}
+
+static inline int regpairmap(int regpair, int m)
+{
+ switch (regpair) {
+ case OR2_HL:
+ switch (m) {
+ case MODE_DD:
+ return OR2_IX;
+ case MODE_FD:
+ return OR2_IY;
+ case MODE_NORMAL:
+ default:
+ return OR2_HL;
+ }
+ default:
+ return regpair;
+ }
+}
+
+static const int regpair[4] = {
+ OR2_BC,
+ OR2_DE,
+ OR2_HL,
+ OR2_SP,
+};
+
+static const int regpair2[4] = {
+ OR2_BC,
+ OR2_DE,
+ OR2_HL,
+ OR2_AF,
+};
+
+static inline void gen_jmp_im(target_ulong pc)
+{
+ gen_helper_movl_pc_im(tcg_const_tl(pc));
+}
+
+static void gen_debug(DisasContext *s, target_ulong cur_pc)
+{
+ gen_jmp_im(cur_pc);
+ gen_helper_debug();
+ s->is_jmp = 3;
+}
+
+static void gen_eob(DisasContext *s)
+{
+ if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
+ gen_helper_reset_inhibit_irq();
+ }
+ if (s->singlestep_enabled) {
+ gen_helper_debug();
+ } else {
+ tcg_gen_exit_tb(0);
+ }
+ s->is_jmp = 3;
+}
+
+static void gen_exception(DisasContext *s, int trapno, target_ulong cur_pc)
+{
+ gen_jmp_im(cur_pc);
+ gen_helper_raise_exception(trapno);
+ s->is_jmp = 3;
+}
+
+/* Conditions */
+
+static const char *const cc[8] = {
+ "nz",
+ "z",
+ "nc",
+ "c",
+ "po",
+ "pe",
+ "p",
+ "m",
+};
+
+enum {
+ COND_NZ = 0,
+ COND_Z,
+ COND_NC,
+ COND_C,
+ COND_PO,
+ COND_PE,
+ COND_P,
+ COND_M,
+};
+
+static const int cc_flags[4] = {
+ CC_Z,
+ CC_C,
+ CC_P,
+ CC_S,
+};
+
+/* Arithmetic/logic operations */
+
+static const char *const alu[8] = {
+ "add a,",
+ "adc a,",
+ "sub ",
+ "sbc a,",
+ "and ",
+ "xor ",
+ "or ",
+ "cp ",
+};
+
+typedef void (alu_helper_func)(void);
+
+static alu_helper_func *const gen_alu[8] = {
+ gen_helper_add_cc,
+ gen_helper_adc_cc,
+ gen_helper_sub_cc,
+ gen_helper_sbc_cc,
+ gen_helper_and_cc,
+ gen_helper_xor_cc,
+ gen_helper_or_cc,
+ gen_helper_cp_cc,
+};
+
+/* Rotation/shift operations */
+
+static const char *const rot[8] = {
+ "rlc",
+ "rrc",
+ "rl",
+ "rr",
+ "sla",
+ "sra",
+ "sll",
+ "srl",
+};
+
+typedef void (rot_helper_func)(void);
+
+static rot_helper_func *const gen_rot_T0[8] = {
+ gen_helper_rlc_T0_cc,
+ gen_helper_rrc_T0_cc,
+ gen_helper_rl_T0_cc,
+ gen_helper_rr_T0_cc,
+ gen_helper_sla_T0_cc,
+ gen_helper_sra_T0_cc,
+ gen_helper_sll_T0_cc,
+ gen_helper_srl_T0_cc,
+};
+
+/* Block instructions */
+
+static const char *const bli[4][4] = {
+ { "ldi", "cpi", "ini", "outi", },
+ { "ldd", "cpd", "ind", "outd", },
+ { "ldir", "cpir", "inir", "otir", },
+ { "lddr", "cpdr", "indr", "otdr", },
+};
+
+static const int imode[8] = {
+ 0, 0, 1, 2, 0, 0, 1, 2,
+};
+
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc)
+{
+ gen_jmp_im(pc);
+ gen_eob(s);
+}
+
+static inline void gen_cond_jump(int cc, int l1)
+{
+ gen_movb_v_F(cpu_T[0]);
+
+ tcg_gen_andi_tl(cpu_T[0], cpu_T[0], cc_flags[cc >> 1]);
+
+ tcg_gen_brcondi_tl((cc & 1) ? TCG_COND_NE : TCG_COND_EQ, cpu_T[0], 0, l1);
+}
+
+static inline void gen_jcc(DisasContext *s, int cc,
+ target_ulong val, target_ulong next_pc)
+{
+ TranslationBlock *tb;
+ int l1;
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+
+ gen_cond_jump(cc, l1);
+
+ gen_goto_tb(s, 0, next_pc);
+
+ gen_set_label(l1);
+ gen_goto_tb(s, 1, val);
+
+ s->is_jmp = 3;
+}
+
+static inline void gen_callcc(DisasContext *s, int cc,
+ target_ulong val, target_ulong next_pc)
+{
+ TranslationBlock *tb;
+ int l1;
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+
+ gen_cond_jump(cc, l1);
+
+ gen_goto_tb(s, 0, next_pc);
+
+ gen_set_label(l1);
+ tcg_gen_movi_tl(cpu_T[0], next_pc);
+ gen_pushw(cpu_T[0]);
+ gen_goto_tb(s, 1, val);
+
+ s->is_jmp = 3;
+}
+
+static inline void gen_retcc(DisasContext *s, int cc,
+ target_ulong next_pc)
+{
+ TranslationBlock *tb;
+ int l1;
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+
+ gen_cond_jump(cc, l1);
+
+ gen_goto_tb(s, 0, next_pc);
+
+ gen_set_label(l1);
+ gen_popw(cpu_T[0]);
+ gen_helper_jmp_T0();
+ gen_eob(s);
+
+ s->is_jmp = 3;
+}
+
+static inline void gen_ex(int regpair1, int regpair2)
+{
+ TCGv tmp1 = tcg_temp_new();
+ TCGv tmp2 = tcg_temp_new();
+ gen_movw_v_reg(tmp1, regpair1);
+ gen_movw_v_reg(tmp2, regpair2);
+ gen_movw_reg_v(regpair2, tmp1);
+ gen_movw_reg_v(regpair1, tmp2);
+ tcg_temp_free(tmp1);
+ tcg_temp_free(tmp2);
+}
+
+/* TODO: condition code optimisation */
+
+/* micro-ops that modify condition codes should end in _cc */
+
+/* convert one instruction. s->is_jmp is set if the translation must
+ be stopped. Return the next pc value */
+static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
+{
+ int b, prefixes;
+ int rex_w, rex_r;
+ int m;
+
+ s->pc = pc_start;
+ prefixes = 0;
+ s->override = -1;
+ rex_w = -1;
+ rex_r = 0;
+
+ //printf("PC = %04x: ", s->pc);
+next_byte:
+ s->prefix = prefixes;
+
+/* START */
+
+ if (prefixes & PREFIX_DD) {
+ m = MODE_DD;
+ } else if (prefixes & PREFIX_FD) {
+ m = MODE_FD;
+ } else {
+ m = MODE_NORMAL;
+ }
+
+ /* unprefixed opcodes */
+
+ if ((prefixes & (PREFIX_CB | PREFIX_ED)) == 0) {
+ b = ldub_code(s->pc);
+ s->pc++;
+
+ int x, y, z, p, q;
+ int n, d;
+ int r1, r2;
+
+ x = (b >> 6) & 0x03;
+ y = (b >> 3) & 0x07;
+ z = b & 0x07;
+ p = y >> 1;
+ q = y & 0x01;
+
+ switch (x) {
+ case 0:
+ switch (z) {
+
+ case 0:
+ switch (y) {
+ case 0:
+ zprintf("nop\n");
+ break;
+ case 1:
+ gen_ex(OR2_AF, OR2_AFX);
+ zprintf("ex af,af'\n");
+ break;
+ case 2:
+ n = ldsb_code(s->pc);
+ s->pc++;
+ gen_helper_djnz(tcg_const_tl(s->pc + n), tcg_const_tl(s->pc));
+ gen_eob(s);
+ s->is_jmp = 3;
+ zprintf("djnz $%02x\n", n);
+ break;
+ case 3:
+ n = ldsb_code(s->pc);
+ s->pc++;
+ gen_jmp_im(s->pc + n);
+ gen_eob(s);
+ s->is_jmp = 3;
+ zprintf("jr $%02x\n", n);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ n = ldsb_code(s->pc);
+ s->pc++;
+ zprintf("jr %s,$%04x\n", cc[y-4], (s->pc + n) & 0xffff);
+ gen_jcc(s, y-4, s->pc + n, s->pc);
+ break;
+ }
+ break;
+
+ case 1:
+ switch (q) {
+ case 0:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ tcg_gen_movi_tl(cpu_T[0], n);
+ r1 = regpairmap(regpair[p], m);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("ld %s,$%04x\n", regpairnames[r1], n);
+ break;
+ case 1:
+ r1 = regpairmap(regpair[p], m);
+ r2 = regpairmap(OR2_HL, m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_movw_v_reg(cpu_T[1], r2);
+ gen_helper_addw_T0_T1_cc();
+ gen_movw_reg_v(r2, cpu_T[0]);
+ zprintf("add %s,%s\n", regpairnames[r2], regpairnames[r1]);
+ break;
+ }
+ break;
+
+ case 2:
+ switch (q) {
+ case 0:
+ switch (p) {
+ case 0:
+ gen_movb_v_A(cpu_T[0]);
+ gen_movw_v_BC(cpu_A0);
+ tcg_gen_qemu_st8(cpu_T[0], cpu_A0, MEM_INDEX);
+ zprintf("ld (bc),a\n");
+ break;
+ case 1:
+ gen_movb_v_A(cpu_T[0]);
+ gen_movw_v_DE(cpu_A0);
+ tcg_gen_qemu_st8(cpu_T[0], cpu_A0, MEM_INDEX);
+ zprintf("ld (de),a\n");
+ break;
+ case 2:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(OR2_HL, m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_st16(cpu_T[0], cpu_A0, MEM_INDEX);
+ zprintf("ld ($%04x),%s\n", n, regpairnames[r1]);
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_movb_v_A(cpu_T[0]);
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_st8(cpu_T[0], cpu_A0, MEM_INDEX);
+ zprintf("ld ($%04x),a\n", n);
+ break;
+ }
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ gen_movw_v_BC(cpu_A0);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movb_A_v(cpu_T[0]);
+ zprintf("ld a,(bc)\n");
+ break;
+ case 1:
+ gen_movw_v_DE(cpu_A0);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movb_A_v(cpu_T[0]);
+ zprintf("ld a,(de)\n");
+ break;
+ case 2:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(OR2_HL, m);
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_ld16u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("ld %s,($%04x)\n", regpairnames[r1], n);
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movb_A_v(cpu_T[0]);
+ zprintf("ld a,($%04x)\n", n);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 3:
+ switch (q) {
+ case 0:
+ r1 = regpairmap(regpair[p], m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("inc %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ r1 = regpairmap(regpair[p], m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ tcg_gen_subi_tl(cpu_T[0], cpu_T[0], 1);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("dec %s\n", regpairnames[r1]);
+ break;
+ }
+ break;
+
+ case 4:
+ r1 = regmap(reg[y], m);
+ if (is_indexed(r1)) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ gen_movb_v_idx(cpu_T[0], r1, d);
+ } else {
+ gen_movb_v_reg(cpu_T[0], r1);
+ }
+ gen_helper_incb_T0_cc();
+ if (is_indexed(r1)) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ if (is_indexed(r1)) {
+ zprintf("inc (%s%c$%02x)\n", idxnames[r1], shexb(d));
+ } else {
+ zprintf("inc %s\n", regnames[r1]);
+ }
+ break;
+
+ case 5:
+ r1 = regmap(reg[y], m);
+ if (is_indexed(r1)) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ gen_movb_v_idx(cpu_T[0], r1, d);
+ } else {
+ gen_movb_v_reg(cpu_T[0], r1);
+ }
+ gen_helper_decb_T0_cc();
+ if (is_indexed(r1)) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ if (is_indexed(r1)) {
+ zprintf("dec (%s%c$%02x)\n", idxnames[r1], shexb(d));
+ } else {
+ zprintf("dec %s\n", regnames[r1]);
+ }
+ break;
+
+ case 6:
+ r1 = regmap(reg[y], m);
+ if (is_indexed(r1)) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ }
+ n = ldub_code(s->pc);
+ s->pc++;
+ tcg_gen_movi_tl(cpu_T[0], n);
+ if (is_indexed(r1)) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ if (is_indexed(r1)) {
+ zprintf("ld (%s%c$%02x),$%02x\n", idxnames[r1], shexb(d), n);
+ } else {
+ zprintf("ld %s,$%02x\n", regnames[r1], n);
+ }
+ break;
+
+ case 7:
+ switch (y) {
+ case 0:
+ gen_helper_rlca_cc();
+ zprintf("rlca\n");
+ break;
+ case 1:
+ gen_helper_rrca_cc();
+ zprintf("rrca\n");
+ break;
+ case 2:
+ gen_helper_rla_cc();
+ zprintf("rla\n");
+ break;
+ case 3:
+ gen_helper_rra_cc();
+ zprintf("rra\n");
+ break;
+ case 4:
+ gen_helper_daa_cc();
+ zprintf("daa\n");
+ break;
+ case 5:
+ gen_helper_cpl_cc();
+ zprintf("cpl\n");
+ break;
+ case 6:
+ gen_helper_scf_cc();
+ zprintf("scf\n");
+ break;
+ case 7:
+ gen_helper_ccf_cc();
+ zprintf("ccf\n");
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 1:
+ if (z == 6 && y == 6) {
+ gen_jmp_im(s->pc);
+ gen_helper_halt();
+ zprintf("halt\n");
+ } else {
+ if (z == 6) {
+ r1 = regmap(reg[z], m);
+ r2 = regmap(reg[y], 0);
+ } else if (y == 6) {
+ r1 = regmap(reg[z], 0);
+ r2 = regmap(reg[y], m);
+ } else {
+ r1 = regmap(reg[z], m);
+ r2 = regmap(reg[y], m);
+ }
+ if (is_indexed(r1) || is_indexed(r2)) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ }
+ if (is_indexed(r1)) {
+ gen_movb_v_idx(cpu_T[0], r1, d);
+ } else {
+ gen_movb_v_reg(cpu_T[0], r1);
+ }
+ if (is_indexed(r2)) {
+ gen_movb_idx_v(r2, cpu_T[0], d);
+ } else {
+ gen_movb_reg_v(r2, cpu_T[0]);
+ }
+ if (is_indexed(r1)) {
+ zprintf("ld %s,(%s%c$%02x)\n", regnames[r2], idxnames[r1], shexb(d));
+ } else if (is_indexed(r2)) {
+ zprintf("ld (%s%c$%02x),%s\n", idxnames[r2], shexb(d), regnames[r1]);
+ } else {
+ zprintf("ld %s,%s\n", regnames[r2], regnames[r1]);
+ }
+ }
+ break;
+
+ case 2:
+ r1 = regmap(reg[z], m);
+ if (is_indexed(r1)) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ gen_movb_v_idx(cpu_T[0], r1, d);
+ } else {
+ gen_movb_v_reg(cpu_T[0], r1);
+ }
+ gen_alu[y](); /* places output in A */
+ if (is_indexed(r1)) {
+ zprintf("%s(%s%c$%02x)\n", alu[y], idxnames[r1], shexb(d));
+ } else {
+ zprintf("%s%s\n", alu[y], regnames[r1]);
+ }
+ break;
+
+ case 3:
+ switch (z) {
+ case 0:
+ gen_retcc(s, y, s->pc);
+ zprintf("ret %s\n", cc[y]);
+ break;
+
+ case 1:
+ switch (q) {
+ case 0:
+ r1 = regpairmap(regpair2[p], m);
+ gen_popw(cpu_T[0]);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("pop %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ gen_popw(cpu_T[0]);
+ gen_helper_jmp_T0();
+ zprintf("ret\n");
+ gen_eob(s);
+ s->is_jmp = 3;
+// s->is_ei = 1;
+ break;
+ case 1:
+ gen_ex(OR2_BC, OR2_BCX);
+ gen_ex(OR2_DE, OR2_DEX);
+ gen_ex(OR2_HL, OR2_HLX);
+ zprintf("exx\n");
+ break;
+ case 2:
+ r1 = regpairmap(OR2_HL, m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_helper_jmp_T0();
+ zprintf("jp %s\n", regpairnames[r1]);
+ gen_eob(s);
+ s->is_jmp = 3;
+ break;
+ case 3:
+ r1 = regpairmap(OR2_HL, m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_movw_SP_v(cpu_T[0]);
+ zprintf("ld sp,%s\n", regpairnames[r1]);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 2:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_jcc(s, y, n, s->pc);
+ zprintf("jp %s,$%04x\n", cc[y], n);
+ break;
+
+ case 3:
+ switch (y) {
+ case 0:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_jmp_im(n);
+ zprintf("jp $%04x\n", n);
+ gen_eob(s);
+ s->is_jmp = 3;
+ break;
+ case 1:
+ zprintf("cb prefix\n");
+ prefixes |= PREFIX_CB;
+ goto next_byte;
+ break;
+ case 2:
+ n = ldub_code(s->pc);
+ s->pc++;
+ gen_movb_v_A(cpu_T[0]);
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_out_T0_im(tcg_const_tl(n));
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp_im(s->pc);
+ }
+ zprintf("out ($%02x),a\n", n);
+ break;
+ case 3:
+ n = ldub_code(s->pc);
+ s->pc++;
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_in_T0_im(tcg_const_tl(n));
+ gen_movb_A_v(cpu_T[0]);
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp_im(s->pc);
+ }
+ zprintf("in a,($%02x)\n", n);
+ break;
+ case 4:
+ r1 = regpairmap(OR2_HL, m);
+ gen_popw(cpu_T[1]);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_pushw(cpu_T[0]);
+ gen_movw_reg_v(r1, cpu_T[1]);
+ zprintf("ex (sp),%s\n", regpairnames[r1]);
+ break;
+ case 5:
+ gen_ex(OR2_DE, OR2_HL);
+ zprintf("ex de,hl\n");
+ break;
+ case 6:
+ gen_helper_di();
+ zprintf("di\n");
+ break;
+ case 7:
+ gen_helper_ei();
+ zprintf("ei\n");
+// gen_eob(s);
+// s->is_ei = 1;
+ break;
+ }
+ break;
+
+ case 4:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_callcc(s, y, n, s->pc);
+ zprintf("call %s,$%04x\n", cc[y], n);
+ break;
+
+ case 5:
+ switch (q) {
+ case 0:
+ r1 = regpairmap(regpair2[p], m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_pushw(cpu_T[0]);
+ zprintf("push %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ tcg_gen_movi_tl(cpu_T[0], s->pc);
+ gen_pushw(cpu_T[0]);
+ gen_jmp_im(n);
+ zprintf("call $%04x\n", n);
+ gen_eob(s);
+ s->is_jmp = 3;
+ break;
+ case 1:
+ zprintf("dd prefix\n");
+ prefixes |= PREFIX_DD;
+ goto next_byte;
+ break;
+ case 2:
+ zprintf("ed prefix\n");
+ prefixes |= PREFIX_ED;
+ goto next_byte;
+ break;
+ case 3:
+ zprintf("fd prefix\n");
+ prefixes |= PREFIX_FD;
+ goto next_byte;
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 6:
+ n = ldub_code(s->pc);
+ s->pc++;
+ tcg_gen_movi_tl(cpu_T[0], n);
+ gen_alu[y](); /* places output in A */
+ zprintf("%s$%02x\n", alu[y], n);
+ break;
+
+ case 7:
+ tcg_gen_movi_tl(cpu_T[0], s->pc);
+ gen_pushw(cpu_T[0]);
+ gen_jmp_im(y*8);
+ zprintf("rst $%02x\n", y*8);
+ gen_eob(s);
+ s->is_jmp = 3;
+ break;
+ }
+ break;
+ }
+ } else if (prefixes & PREFIX_CB) {
+ /* cb mode: */
+
+ int x, y, z, p, q;
+ int d;
+ int r1, r2;
+
+ if (m != MODE_NORMAL) {
+ d = ldsb_code(s->pc);
+ s->pc++;
+ }
+
+ b = ldub_code(s->pc);
+ s->pc++;
+
+ x = (b >> 6) & 0x03;
+ y = (b >> 3) & 0x07;
+ z = b & 0x07;
+ p = y >> 1;
+ q = y & 0x01;
+
+ if (m != MODE_NORMAL) {
+ r1 = regmap(OR_HLmem, m);
+ gen_movb_v_idx(cpu_T[0], r1, d);
+ if (z != 6) {
+ r2 = regmap(reg[z], 0);
+ }
+ } else {
+ r1 = regmap(reg[z], m);
+ gen_movb_v_reg(cpu_T[0], r1);
+ }
+
+ switch (x) {
+ case 0:
+ /* TODO: TST instead of SLL for R800 */
+ gen_rot_T0[y]();
+ if (m != MODE_NORMAL) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ if (z != 6) {
+ gen_movb_reg_v(r2, cpu_T[0]);
+ }
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ zprintf("%s %s\n", rot[y], regnames[r1]);
+ break;
+ case 1:
+ gen_helper_bit_T0(tcg_const_tl(1 << y));
+ zprintf("bit %i,%s\n", y, regnames[r1]);
+ break;
+ case 2:
+ tcg_gen_andi_tl(cpu_T[0], cpu_T[0], ~(1 << y));
+ if (m != MODE_NORMAL) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ if (z != 6) {
+ gen_movb_reg_v(r2, cpu_T[0]);
+ }
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ zprintf("res %i,%s\n", y, regnames[r1]);
+ break;
+ case 3:
+ tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 1 << y);
+ if (m != MODE_NORMAL) {
+ gen_movb_idx_v(r1, cpu_T[0], d);
+ if (z != 6) {
+ gen_movb_reg_v(r2, cpu_T[0]);
+ }
+ } else {
+ gen_movb_reg_v(r1, cpu_T[0]);
+ }
+ zprintf("set %i,%s\n", y, regnames[r1]);
+ break;
+ }
+
+ } else if (prefixes & PREFIX_ED) {
+ /* ed mode: */
+
+ b = ldub_code(s->pc);
+ s->pc++;
+
+ int x, y, z, p, q;
+ int n;
+ int r1, r2;
+
+ x = (b >> 6) & 0x03;
+ y = (b >> 3) & 0x07;
+ z = b & 0x07;
+ p = y >> 1;
+ q = y & 0x01;
+
+ switch (x) {
+ case 0:
+ zprintf("nop\n");
+ break;
+ case 3:
+ if (s->model == Z80_CPU_R800) {
+ switch (z) {
+ case 1:
+ /* does mulub work with r1 == h, l, (hl) or a? */
+ r1 = regmap(reg[y], m);
+ gen_movb_v_reg(cpu_T[0], r1);
+ gen_helper_mulub_cc();
+ zprintf("mulub a,%s\n", regnames[r1]);
+ break;
+ case 3:
+ if (q == 0) {
+ /* does muluw work with r1 == de or hl? */
+ /* what is the effect of DD/FD prefixes here? */
+ r1 = regpairmap(regpair[p], m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_helper_muluw_cc();
+ zprintf("muluw hl,%s\n", regpairnames[r1]);
+ } else {
+ zprintf("nop\n");
+ }
+ break;
+ default:
+ zprintf("nop\n");
+ break;
+ }
+ } else {
+ zprintf("nop\n");
+ }
+ break;
+
+ case 1:
+ switch (z) {
+ case 0:
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_in_T0_bc_cc();
+ if (y != 6) {
+ r1 = regmap(reg[y], m);
+ gen_movb_reg_v(r1, cpu_T[0]);
+ zprintf("in %s,(c)\n", regnames[r1]);
+ } else {
+ zprintf("in (c)\n");
+ }
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp_im(s->pc);
+ }
+ break;
+ case 1:
+ if (y != 6) {
+ r1 = regmap(reg[y], m);
+ gen_movb_v_reg(cpu_T[0], r1);
+ zprintf("out (c),%s\n", regnames[r1]);
+ } else {
+ tcg_gen_movi_tl(cpu_T[0], 0);
+ zprintf("out (c),0\n");
+ }
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_out_T0_bc();
+ if (use_icount) {
+ gen_io_end();
+ gen_jmp_im(s->pc);
+ }
+ break;
+ case 2:
+ r1 = regpairmap(OR2_HL, m);
+ r2 = regpairmap(regpair[p], m);
+ gen_movw_v_reg(cpu_T[0], r1);
+ gen_movw_v_reg(cpu_T[1], r2);
+ if (q == 0) {
+ zprintf("sbc %s,%s\n", regpairnames[r1], regpairnames[r2]);
+ gen_helper_sbcw_T0_T1_cc();
+ } else {
+ zprintf("adc %s,%s\n", regpairnames[r1], regpairnames[r2]);
+ gen_helper_adcw_T0_T1_cc();
+ }
+ gen_movw_reg_v(r1, cpu_T[0]);
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(regpair[p], m);
+ if (q == 0) {
+ gen_movw_v_reg(cpu_T[0], r1);
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_st16(cpu_T[0], cpu_A0, MEM_INDEX);
+ zprintf("ld ($%02x),%s\n", n, regpairnames[r1]);
+ } else {
+ tcg_gen_movi_i32(cpu_A0, n);
+ tcg_gen_qemu_ld16u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movw_reg_v(r1, cpu_T[0]);
+ zprintf("ld %s,($%02x)\n", regpairnames[r1], n);
+ }
+ break;
+ case 4:
+ zprintf("neg\n");
+ gen_helper_neg_cc();
+ break;
+ case 5:
+ /* FIXME */
+ gen_popw(cpu_T[0]);
+ gen_helper_jmp_T0();
+ gen_helper_ri();
+ if (q == 0) {
+ zprintf("retn\n");
+ } else {
+ zprintf("reti\n");
+ }
+ gen_eob(s);
+ s->is_jmp = 3;
+// s->is_ei = 1;
+ break;
+ case 6:
+ gen_helper_imode(tcg_const_tl(imode[y]));
+ zprintf("im im[%i]\n", imode[y]);
+// gen_eob(s);
+// s->is_ei = 1;
+ break;
+ case 7:
+ switch (y) {
+ case 0:
+ gen_helper_ld_I_A();
+ zprintf("ld i,a\n");
+ break;
+ case 1:
+ gen_helper_ld_R_A();
+ zprintf("ld r,a\n");
+ break;
+ case 2:
+ gen_helper_ld_A_I();
+ zprintf("ld a,i\n");
+ break;
+ case 3:
+ gen_helper_ld_A_R();
+ zprintf("ld a,r\n");
+ break;
+ case 4:
+ gen_movb_v_HLmem(cpu_T[0]);
+ gen_helper_rrd_cc();
+ gen_movb_HLmem_v(cpu_T[0]);
+ zprintf("rrd\n");
+ break;
+ case 5:
+ gen_movb_v_HLmem(cpu_T[0]);
+ gen_helper_rld_cc();
+ gen_movb_HLmem_v(cpu_T[0]);
+ zprintf("rld\n");
+ break;
+ case 6:
+ case 7:
+ zprintf("nop2\n");
+ /* nop */
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 2:
+ /* FIXME */
+ if (y >= 4) {
+ switch (z) {
+ case 0: /* ldi/ldd/ldir/lddr */
+ gen_movw_v_HL(cpu_A0);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_movw_v_DE(cpu_A0);
+ tcg_gen_qemu_st8(cpu_T[0], cpu_A0, MEM_INDEX);
+
+ if (!(y & 1)) {
+ gen_helper_bli_ld_inc_cc();
+ } else {
+ gen_helper_bli_ld_dec_cc();
+ }
+ if ((y & 2)) {
+ gen_helper_bli_ld_rep(tcg_const_tl(s->pc));
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ break;
+
+ case 1: /* cpi/cpd/cpir/cpdr */
+ gen_movw_v_HL(cpu_A0);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ gen_helper_bli_cp_cc();
+
+ if (!(y & 1)) {
+ gen_helper_bli_cp_inc_cc();
+ } else {
+ gen_helper_bli_cp_dec_cc();
+ }
+ if ((y & 2)) {
+ gen_helper_bli_cp_rep(tcg_const_tl(s->pc));
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ break;
+
+ case 2: /* ini/ind/inir/indr */
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_in_T0_bc_cc();
+ if (use_icount) {
+ gen_io_end();
+ }
+ gen_movw_v_HL(cpu_A0);
+ tcg_gen_qemu_st8(cpu_T[0], cpu_A0, MEM_INDEX);
+ if (!(y & 1)) {
+ gen_helper_bli_io_inc();
+ } else {
+ gen_helper_bli_io_dec();
+ }
+ if ((y & 2)) {
+ gen_helper_bli_io_rep(tcg_const_tl(s->pc));
+ gen_eob(s);
+ s->is_jmp = 3;
+ } else if (use_icount) {
+ gen_jmp_im(s->pc);
+ }
+ break;
+
+ case 3: /* outi/outd/otir/otdr */
+ gen_movw_v_HL(cpu_A0);
+ tcg_gen_qemu_ld8u(cpu_T[0], cpu_A0, MEM_INDEX);
+ if (use_icount) {
+ gen_io_start();
+ }
+ gen_helper_out_T0_bc();
+ if (use_icount) {
+ gen_io_end();
+ }
+ if (!(y & 1)) {
+ gen_helper_bli_io_inc();
+ } else {
+ gen_helper_bli_io_dec();
+ }
+ if ((y & 2)) {
+ gen_helper_bli_io_rep(tcg_const_tl(s->pc));
+ gen_eob(s);
+ s->is_jmp = 3;
+ } else if (use_icount) {
+ gen_jmp_im(s->pc);
+ }
+ break;
+ }
+
+ zprintf("%s\n", bli[y-4][z]);
+ break;
+ }
+ }
+ }
+
+ prefixes = 0;
+
+ /* now check op code */
+// switch (b) {
+// default:
+// goto illegal_op;
+// }
+ /* lock generation */
+ return s->pc;
+ illegal_op:
+ /* XXX: ensure that no lock was generated */
+ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
+ return s->pc;
+}
+
+#define CC_SZHPNC (CC_S | CC_Z | CC_H | CC_P | CC_N | CC_C)
+#define CC_SZHPN (CC_S | CC_Z | CC_H | CC_P | CC_N)
+
+void z80_translate_init(void)
+{
+ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+ cpu_T[0] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, t0), "T0");
+ cpu_T[1] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, t1), "T1");
+#else
+ cpu_T[0] = tcg_global_reg_new_i32(TCG_AREG1, "T0");
+ cpu_T[1] = tcg_global_reg_new_i32(TCG_AREG2, "T1");
+#endif
+ cpu_A0 = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, a0), "A0");
+
+ /* register helpers */
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
+ basic block 'tb'. If search_pc is TRUE, also generate PC
+ information for each intermediate instruction. */
+static inline int gen_intermediate_code_internal(CPUState *env,
+ TranslationBlock *tb,
+ int search_pc)
+{
+ DisasContext dc1, *dc = &dc1;
+ target_ulong pc_ptr;
+ uint16_t *gen_opc_end;
+ CPUBreakpoint *bp;
+ int flags, j, lj, cflags;
+ target_ulong pc_start;
+ target_ulong cs_base;
+ int num_insns;
+ int max_insns;
+
+ /* generate intermediate code */
+ pc_start = tb->pc;
+ cs_base = tb->cs_base;
+ flags = tb->flags;
+ cflags = tb->cflags;
+
+ dc->singlestep_enabled = env->singlestep_enabled;
+ dc->cs_base = cs_base;
+ dc->tb = tb;
+ dc->flags = flags;
+ dc->jmp_opt = !(env->singlestep_enabled ||
+ (flags & HF_INHIBIT_IRQ_MASK)
+#ifndef CONFIG_SOFTMMU
+ || (flags & HF_SOFTMMU_MASK)
+#endif
+ );
+
+ gen_opc_ptr = gen_opc_buf;
+ gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+ gen_opparam_ptr = gen_opparam_buf;
+
+ dc->is_jmp = DISAS_NEXT;
+ pc_ptr = pc_start;
+ lj = -1;
+ dc->model = env->model;
+
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0) {
+ max_insns = CF_COUNT_MASK;
+ }
+
+ gen_icount_start();
+ for (;;) {
+ if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
+ TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+ if (bp->pc == pc_ptr) {
+ gen_debug(dc, pc_ptr - dc->cs_base);
+ break;
+ }
+ }
+ }
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ if (lj < j) {
+ lj++;
+ while (lj < j) {
+ gen_opc_instr_start[lj++] = 0;
+ }
+ }
+ gen_opc_pc[lj] = pc_ptr;
+ gen_opc_instr_start[lj] = 1;
+ gen_opc_icount[lj] = num_insns;
+ }
+ if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+ gen_io_start();
+ }
+
+ pc_ptr = disas_insn(dc, pc_ptr);
+ num_insns++;
+ /* stop translation if indicated */
+ if (dc->is_jmp) {
+ break;
+ }
+ /* if single step mode, we generate only one instruction and
+ generate an exception */
+ /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
+ the flag and abort the translation to give the irqs a
+ change to be happen */
+ if (dc->singlestep_enabled ||
+ (flags & HF_INHIBIT_IRQ_MASK)) {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+ /* if too long translation, stop generation too */
+ if (gen_opc_ptr >= gen_opc_end ||
+ (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
+ num_insns >= max_insns) {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+ if (singlestep) {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+ }
+ if (tb->cflags & CF_LAST_IO) {
+ gen_io_end();
+ }
+ gen_icount_end(tb, num_insns);
+ *gen_opc_ptr = INDEX_op_end;
+ /* we don't forget to fill the last values */
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ lj++;
+ while (lj <= j) {
+ gen_opc_instr_start[lj++] = 0;
+ }
+ }
+
+#ifdef DEBUG_DISAS
+ log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0);
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ qemu_log("----------------\n");
+ qemu_log("IN: %s\n", lookup_symbol(pc_start));
+ log_target_disas(pc_start, pc_ptr - pc_start, 0);
+ qemu_log("\n");
+ }
+#endif
+
+ if (!search_pc) {
+ tb->size = pc_ptr - pc_start;
+ tb->icount = num_insns;
+ }
+ return 0;
+}
+
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+ gen_intermediate_code_internal(env, tb, 0);
+}
+
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+ gen_intermediate_code_internal(env, tb, 1);
+}
+
+void gen_pc_load(CPUState *env, TranslationBlock *tb,
+ unsigned long searched_pc, int pc_pos, void *puc)
+{
+ env->pc = gen_opc_pc[pc_pos];
+}
diff --git a/z80-dis.c b/z80-dis.c
new file mode 100644
index 0000000..4af3c62
--- /dev/null
+++ b/z80-dis.c
@@ -0,0 +1,621 @@
+/* Print Z80 and R800 instructions
+ Copyright 2005 Free Software Foundation, Inc.
+ Contributed by Arnold Metselaar
+
+ Taken from GDB
+
+ This file 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., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "dis-asm.h"
+#include
+
+struct buffer
+{
+ bfd_vma base;
+ int n_fetch;
+ int n_used;
+ signed char data[4];
+} ;
+
+typedef int (*func)(struct buffer *, disassemble_info *, char *);
+
+struct tab_elt
+{
+ unsigned char val;
+ unsigned char mask;
+ func fp;
+ char * text;
+} ;
+
+#define TXTSIZ 24
+/* Names of 16-bit registers. */
+static char * rr_str[] = { "bc", "de", "hl", "sp" };
+/* Names of 8-bit registers. */
+static char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" };
+/* Texts for condition codes. */
+static char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" };
+/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */
+static char * arit_str[] =
+{
+ "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp "
+} ;
+
+static int
+fetch_data (struct buffer *buf, disassemble_info * info, int n)
+{
+ int r;
+
+ if (buf->n_fetch + n > 4)
+ abort ();
+
+ r = info->read_memory_func (buf->base + buf->n_fetch,
+ (unsigned char*) buf->data + buf->n_fetch,
+ n, info);
+ if (r == 0)
+ buf->n_fetch += n;
+ return !r;
+}
+
+static int
+prt (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s", txt);
+ buf->n_used = buf->n_fetch;
+ return 1;
+}
+
+static int
+prt_e (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char e;
+ int target_addr;
+
+ if (fetch_data (buf, info, 1))
+ {
+ e = buf->data[1];
+ target_addr = (buf->base + 2 + e) & 0xffff;
+ buf->n_used = buf->n_fetch;
+ info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+jr_cc (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]);
+ return prt_e (buf, info, mytxt);
+}
+
+static int
+prt_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int nn;
+ unsigned char *p;
+
+ p = (unsigned char*) buf->data + buf->n_fetch;
+ if (fetch_data (buf, info, 2))
+ {
+ nn = p[0] + (p[1] << 8);
+ info->fprintf_func (info->stream, txt, nn);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+ return buf->n_used;
+}
+
+static int
+prt_rr_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, rr_str[(buf->data[0] >> 4) & 3]);
+ return prt_nn (buf, info, mytxt);
+}
+
+static int
+prt_rr (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s%s", txt,
+ rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+prt_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int n;
+ unsigned char *p;
+
+ p = (unsigned char*) buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ n = p[0];
+ info->fprintf_func (info->stream, txt, n);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+ld_r_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[0] >> 3) & 7]);
+ return prt_n (buf, info, mytxt);
+}
+
+static int
+prt_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+ld_r_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+arit_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ arit_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+prt_cc (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s%s", txt,
+ cc_str[(buf->data[0] >> 3) & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+pop_rr (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ static char *rr_stack[] = { "bc","de","hl","af"};
+
+ info->fprintf_func (info->stream, "%s %s", txt,
+ rr_stack[(buf->data[0] >> 4) & 3]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+
+static int
+jp_cc_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt,TXTSIZ,
+ "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]);
+ return prt_nn (buf, info, mytxt);
+}
+
+static int
+arit_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt,TXTSIZ, txt, arit_str[(buf->data[0] >> 3) & 7]);
+ return prt_n (buf, info, mytxt);
+}
+
+static int
+rst (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt, buf->data[0] & 0x38);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+
+static int
+cis (struct buffer *buf, disassemble_info * info, char *txt ATTRIBUTE_UNUSED)
+{
+ static char * opar[] = { "ld", "cp", "in", "out" };
+ char * op;
+ char c;
+
+ c = buf->data[1];
+ op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]);
+ info->fprintf_func (info->stream,
+ "%s%c%s", op,
+ (c & 0x08) ? 'd' : 'i',
+ (c & 0x10) ? "r" : "");
+ buf->n_used = 2;
+ return buf->n_used;
+}
+
+static int
+dump (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int i;
+
+ info->fprintf_func (info->stream, "defb ");
+ for (i = 0; txt[i]; ++i)
+ info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x",
+ (unsigned char) buf->data[i]);
+ buf->n_used = i;
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes with prefix 0xED. */
+struct tab_elt opc_ed[] =
+{
+ { 0x70, 0xFF, prt, "in f,(c)" },
+ { 0x70, 0xFF, dump, "xx" },
+ { 0x40, 0xC7, prt_r, "in %s,(c)" },
+ { 0x71, 0xFF, prt, "out (c),0" },
+ { 0x70, 0xFF, dump, "xx" },
+ { 0x41, 0xC7, prt_r, "out (c),%s" },
+ { 0x42, 0xCF, prt_rr, "sbc hl," },
+ { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s" },
+ { 0x44, 0xFF, prt, "neg" },
+ { 0x45, 0xFF, prt, "retn" },
+ { 0x46, 0xFF, prt, "im 0" },
+ { 0x47, 0xFF, prt, "ld i,a" },
+ { 0x4A, 0xCF, prt_rr, "adc hl," },
+ { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)" },
+ { 0x4D, 0xFF, prt, "reti" },
+ { 0x56, 0xFF, prt, "im 1" },
+ { 0x57, 0xFF, prt, "ld a,i" },
+ { 0x5E, 0xFF, prt, "im 2" },
+ { 0x67, 0xFF, prt, "rrd" },
+ { 0x6F, 0xFF, prt, "rld" },
+ { 0xA0, 0xE4, cis, "" },
+ { 0xC3, 0xFF, prt, "muluw hl,bc" },
+ { 0xC5, 0xE7, prt_r, "mulub a,%s" },
+ { 0xF3, 0xFF, prt, "muluw hl,sp" },
+ { 0x00, 0x00, dump, "xx" }
+};
+
+static int
+pref_ed (struct buffer * buf, disassemble_info * info,
+ char* txt ATTRIBUTE_UNUSED)
+{
+ struct tab_elt *p;
+
+ if (fetch_data(buf, info, 1))
+ {
+ for (p = opc_ed; p->val != (buf->data[1] & p->mask); ++p)
+ ;
+ p->fp (buf, info, p->text);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Instruction names for the instructions addressing single bits. */
+static char *cb1_str[] = { "", "bit", "res", "set"};
+/* Instruction names for shifts and rotates. */
+static char *cb2_str[] =
+{
+ "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl"
+};
+
+static int
+pref_cb (struct buffer * buf, disassemble_info * info,
+ char* txt ATTRIBUTE_UNUSED)
+{
+ if (fetch_data (buf, info, 1))
+ {
+ buf->n_used = 2;
+ if ((buf->data[1] & 0xc0) == 0)
+ info->fprintf_func (info->stream, "%s %s",
+ cb2_str[(buf->data[1] >> 3) & 7],
+ r_str[buf->data[1] & 7]);
+ else
+ info->fprintf_func (info->stream, "%s %d,%s",
+ cb1_str[(buf->data[1] >> 6) & 3],
+ (buf->data[1] >> 3) & 7,
+ r_str[buf->data[1] & 7]);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+addvv (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ info->fprintf_func (info->stream, "add %s,%s", txt, txt);
+
+ return buf->n_used = buf->n_fetch;
+}
+
+static int
+ld_v_v (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt);
+ return ld_r_r (buf, info, mytxt);
+}
+
+static int
+prt_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int d;
+ signed char *p;
+
+ p = buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ d = p[0];
+ info->fprintf_func (info->stream, txt, d);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+prt_d_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ int d;
+ signed char *p;
+
+ p = buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ d = p[0];
+ snprintf (mytxt, TXTSIZ, txt, d);
+ return prt_n (buf, info, mytxt);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+arit_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, arit_str[(c >> 3) & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+ld_r_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+ld_d_r(struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+pref_xd_cb (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ if (fetch_data (buf, info, 2))
+ {
+ int d;
+ char arg[TXTSIZ];
+ signed char *p;
+
+ buf->n_used = 4;
+ p = buf->data;
+ d = p[2];
+
+ if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06))
+ snprintf (arg, TXTSIZ, "(%s%+d)", txt, d);
+ else
+ snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]);
+
+ if ((p[3] & 0xc0) == 0)
+ info->fprintf_func (info->stream, "%s %s",
+ cb2_str[(buf->data[3] >> 3) & 7],
+ arg);
+ else
+ info->fprintf_func (info->stream, "%s %d,%s",
+ cb1_str[(buf->data[3] >> 6) & 3],
+ (buf->data[3] >> 3) & 7,
+ arg);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
+static struct tab_elt opc_ind[] =
+{
+ { 0x24, 0xF7, prt_r, "inc %s%%s" },
+ { 0x25, 0xF7, prt_r, "dec %s%%s" },
+ { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x" },
+ { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x" },
+ { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s" },
+ { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)" },
+ { 0x23, 0xFF, prt, "inc %s" },
+ { 0x2B, 0xFF, prt, "dec %s" },
+ { 0x29, 0xFF, addvv, "%s" },
+ { 0x09, 0xCF, prt_rr, "add %s," },
+ { 0x34, 0xFF, prt_d, "inc (%s%%+d)" },
+ { 0x35, 0xFF, prt_d, "dec (%s%%+d)" },
+ { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x" },
+
+ { 0x76, 0xFF, dump, "h" },
+ { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)" },
+ { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s" },
+ { 0x64, 0xF6, ld_v_v, "%s" },
+ { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s" },
+ { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s" },
+
+ { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)" },
+ { 0x84, 0xC6, arit_r, "%%s%s%%s" },
+
+ { 0xE1, 0xFF, prt, "pop %s" },
+ { 0xE5, 0xFF, prt, "push %s" },
+ { 0xCB, 0xFF, pref_xd_cb, "%s" },
+ { 0xE3, 0xFF, prt, "ex (sp),%s" },
+ { 0xE9, 0xFF, prt, "jp (%s)" },
+ { 0xF9, 0xFF, prt, "ld sp,%s" },
+ { 0x00, 0x00, dump, "?" },
+} ;
+
+static int
+pref_ind (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ if (fetch_data (buf, info, 1))
+ {
+ char mytxt[TXTSIZ];
+ struct tab_elt *p;
+
+ for (p = opc_ind; p->val != (buf->data[1] & p->mask); ++p)
+ ;
+ snprintf (mytxt, TXTSIZ, p->text, txt);
+ p->fp (buf, info, mytxt);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes without prefix. */
+static struct tab_elt opc_main[] =
+{
+ { 0x00, 0xFF, prt, "nop" },
+ { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x" },
+ { 0x02, 0xFF, prt, "ld (bc),a" },
+ { 0x03, 0xCF, prt_rr, "inc " },
+ { 0x04, 0xC7, prt_r, "inc %s" },
+ { 0x05, 0xC7, prt_r, "dec %s" },
+ { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x" },
+ { 0x07, 0xFF, prt, "rlca" },
+ { 0x08, 0xFF, prt, "ex af,af'" },
+ { 0x09, 0xCF, prt_rr, "add hl," },
+ { 0x0A, 0xFF, prt, "ld a,(bc)" },
+ { 0x0B, 0xCF, prt_rr, "dec " },
+ { 0x0F, 0xFF, prt, "rrca" },
+ { 0x10, 0xFF, prt_e, "djnz " },
+ { 0x12, 0xFF, prt, "ld (de),a" },
+ { 0x17, 0xFF, prt, "rla" },
+ { 0x18, 0xFF, prt_e, "jr "},
+ { 0x1A, 0xFF, prt, "ld a,(de)" },
+ { 0x1F, 0xFF, prt, "rra" },
+ { 0x20, 0xE7, jr_cc, "jr %s,"},
+ { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl" },
+ { 0x27, 0xFF, prt, "daa"},
+ { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)" },
+ { 0x2F, 0xFF, prt, "cpl" },
+ { 0x32, 0xFF, prt_nn, "ld (0x%04x),a" },
+ { 0x37, 0xFF, prt, "scf" },
+ { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)" },
+ { 0x3F, 0xFF, prt, "ccf" },
+
+ { 0x76, 0xFF, prt, "halt" },
+ { 0x40, 0xC0, ld_r_r, "ld %s,%s"},
+
+ { 0x80, 0xC0, arit_r, "%s%s" },
+
+ { 0xC0, 0xC7, prt_cc, "ret " },
+ { 0xC1, 0xCF, pop_rr, "pop" },
+ { 0xC2, 0xC7, jp_cc_nn, "jp " },
+ { 0xC3, 0xFF, prt_nn, "jp 0x%04x" },
+ { 0xC4, 0xC7, jp_cc_nn, "call " },
+ { 0xC5, 0xCF, pop_rr, "push" },
+ { 0xC6, 0xC7, arit_n, "%s0x%%02x" },
+ { 0xC7, 0xC7, rst, "rst 0x%02x" },
+ { 0xC9, 0xFF, prt, "ret" },
+ { 0xCB, 0xFF, pref_cb, "" },
+ { 0xCD, 0xFF, prt_nn, "call 0x%04x" },
+ { 0xD3, 0xFF, prt_n, "out (0x%02x),a" },
+ { 0xD9, 0xFF, prt, "exx" },
+ { 0xDB, 0xFF, prt_n, "in a,(0x%02x)" },
+ { 0xDD, 0xFF, pref_ind, "ix" },
+ { 0xE3, 0xFF, prt, "ex (sp),hl" },
+ { 0xE9, 0xFF, prt, "jp (hl)" },
+ { 0xEB, 0xFF, prt, "ex de,hl" },
+ { 0xED, 0xFF, pref_ed, ""},
+ { 0xF3, 0xFF, prt, "di" },
+ { 0xF9, 0xFF, prt, "ld sp,hl" },
+ { 0xFB, 0xFF, prt, "ei" },
+ { 0xFD, 0xFF, pref_ind, "iy" },
+ { 0x00, 0x00, prt, "????" },
+} ;
+
+int
+print_insn_z80 (bfd_vma addr, disassemble_info * info)
+{
+ struct buffer buf;
+ struct tab_elt *p;
+
+ buf.base = addr;
+ buf.n_fetch = 0;
+ buf.n_used = 0;
+
+ if (! fetch_data (& buf, info, 1))
+ return -1;
+
+ for (p = opc_main; p->val != (buf.data[0] & p->mask); ++p)
+ ;
+ p->fp (& buf, info, p->text);
+
+ return buf.n_used;
+}