* [Qemu-devel] [PATCH] Z80 emulation updated again!
@ 2009-05-31 15:20 Stuart Brady
2010-12-20 22:45 ` Alexander Graf
0 siblings, 1 reply; 27+ messages in thread
From: Stuart Brady @ 2009-05-31 15:20 UTC (permalink / raw)
To: qemu-devel, Ulrich Hecht
[-- Attachment #1: Type: text/plain, Size: 2149 bytes --]
Hi!
Here's an update of the Z80 system emulator, which currently emulates
the ZX Spectrum only. Significant changes since Ulrich Hecht's updated
version are as follows:
* Converted CPU emulation core to TCG
* Fixed emulation of 'bright' display attribute
* Fixed display output for pixel formats besides 32-bit RGB
* Improved keyboard handling, with support for cursor keys, etc.
* Removed dead code
* Now supports libspectrum 0.5 (for snapshot loading)
* Numerous cleanups
The emulation has not yet been optimised, but should achieve something
between 100 and 200 times the performance of real hardware.
Thanks go to Ulrich for adding support for snapshot loading, and for
porting the 'HALT' hack from xz80, in his updated version!
BTW, I have also written some experimental 128K emulation -- however,
this only achieves ~10 times the speed of real hardware, as the 128K
makes heavy use of bank switching.
I can split the patch up if wanted, although only 44 insertions are in
existing files.
Cheers,
--
Stuart Brady
diffstat:
Makefile | 3
Makefile.target | 13
configure | 16
cpu-exec.c | 10
dis-asm.h | 1
disas.c | 2
hw/pixel_ops_dup.h | 61 +
hw/zx_glyphs.h | 37
hw/zx_key_template.h | 50 +
hw/zx_spectrum.c | 443 +++++++++
hw/zx_video.c | 375 ++++++++
hw/zx_video.h | 8
target-z80/TODO | 13
target-z80/cpu.h | 259 +++++
target-z80/exec.h | 196 ++++
target-z80/genreg_template.h | 65 +
target-z80/genreg_template_af.h | 83 +
target-z80/helper.c | 211 ++++
target-z80/helper.h | 89 +
target-z80/machine.c | 11
target-z80/op_helper.c | 947 ++++++++++++++++++++
target-z80/translate.c | 1834 ++++++++++++++++++++++++++++++++++++++++
z80-dis.c | 621 +++++++++++++
23 files changed, 5347 insertions(+), 1 deletion(-)
[-- Attachment #2: qemu-z80.diff --]
[-- Type: text/x-diff, Size: 154072 bytes --]
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 <stuart.brady@gmail.com>
+ * 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 <libspectrum.h>
+#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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#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 <stuart.brady@gmail.com>
+ *
+ * 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 <stuart.brady@gmail.com>
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#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 <arnold_m@operamail.com>
+
+ 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 <stdio.h>
+
+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 "
+} ;
+\f
+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;
+}
+
+\f
+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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+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;
+}
+\f
+/* 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;
+}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2009-05-31 15:20 [Qemu-devel] [PATCH] Z80 emulation updated again! Stuart Brady
@ 2010-12-20 22:45 ` Alexander Graf
2010-12-21 0:06 ` Andreas Färber
2010-12-29 19:57 ` Stuart Brady
0 siblings, 2 replies; 27+ messages in thread
From: Alexander Graf @ 2010-12-20 22:45 UTC (permalink / raw)
To: Stuart Brady; +Cc: Andreas Färber, qemu-devel Developers
On 31.05.2009, at 17:20, Stuart Brady wrote:
> Hi!
>
> Here's an update of the Z80 system emulator, which currently emulates
> the ZX Spectrum only. Significant changes since Ulrich Hecht's updated
> version are as follows:
>
> * Converted CPU emulation core to TCG
> * Fixed emulation of 'bright' display attribute
> * Fixed display output for pixel formats besides 32-bit RGB
> * Improved keyboard handling, with support for cursor keys, etc.
> * Removed dead code
> * Now supports libspectrum 0.5 (for snapshot loading)
> * Numerous cleanups
>
> The emulation has not yet been optimised, but should achieve something
> between 100 and 200 times the performance of real hardware.
>
> Thanks go to Ulrich for adding support for snapshot loading, and for
> porting the 'HALT' hack from xz80, in his updated version!
>
> BTW, I have also written some experimental 128K emulation -- however,
> this only achieves ~10 times the speed of real hardware, as the 128K
> makes heavy use of bank switching.
>
> I can split the patch up if wanted, although only 44 insertions are in
> existing files.
Since this just came up again - are you still working on this? It's be a shame to see this target bitrot to extinction. Also, do you think it's a valuable target to have in upstream qemu? If so, please create a proper patch set out of it, so it can be reviewed.
Alex
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-20 22:45 ` Alexander Graf
@ 2010-12-21 0:06 ` Andreas Färber
2010-12-21 0:10 ` Alexander Graf
2010-12-21 9:59 ` Artyom Tarasenko
2010-12-29 19:57 ` Stuart Brady
1 sibling, 2 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-21 0:06 UTC (permalink / raw)
To: Alexander Graf; +Cc: Stuart Brady, qemu-devel Developers
Am 20.12.2010 um 23:45 schrieb Alexander Graf:
> On 31.05.2009, at 17:20, Stuart Brady wrote:
>
>> Here's an update of the Z80 system emulator, which currently emulates
>> the ZX Spectrum only. [...]
>
> [...] do you think it's a valuable target to have in upstream qemu?
The z80 was also used in the more modern TI-83 Plus programmable
calculator [1], for instance (chosen for school use in Baden-
Württemberg in the early 2000s). There was an assembler toolchain
integrated with Zilog Studio on Windows iirc.
Apparently there's also an open source C compiler toolchain at [2] for
these and other targets.
No Linux that I'm aware of. ;)
Cheers,
Andreas
[1] http://en.wikipedia.org/wiki/TI-83_series
[2] http://www.z88dk.org/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 0:06 ` Andreas Färber
@ 2010-12-21 0:10 ` Alexander Graf
2010-12-21 1:24 ` Andreas Färber
2010-12-21 9:59 ` Artyom Tarasenko
1 sibling, 1 reply; 27+ messages in thread
From: Alexander Graf @ 2010-12-21 0:10 UTC (permalink / raw)
To: Andreas Färber; +Cc: Stuart Brady, qemu-devel Developers
On 21.12.2010, at 01:06, Andreas Färber wrote:
> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>
>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>
>>> Here's an update of the Z80 system emulator, which currently emulates
>>> the ZX Spectrum only. [...]
>>
>> [...] do you think it's a valuable target to have in upstream qemu?
>
> The z80 was also used in the more modern TI-83 Plus programmable calculator [1], for instance (chosen for school use in Baden-Württemberg in the early 2000s). There was an assembler toolchain integrated with Zilog Studio on Windows iirc.
> Apparently there's also an open source C compiler toolchain at [2] for these and other targets.
> No Linux that I'm aware of. ;)
Heh ;). You make it sound as if qemu was a Linux emulator. The general I/O framework is heavily geared towards server and desktop use. The main use case of the Z80 that I'm aware of is the GameBoy. Not sure that one fits in there too well :).
The Spectrum however does fit the desktop case, so it certainly has my blessings.
Alex
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 0:10 ` Alexander Graf
@ 2010-12-21 1:24 ` Andreas Färber
2010-12-21 2:38 ` Natalia Portillo
2010-12-21 9:25 ` [Qemu-devel] [PATCH] Z80 emulation updated again! Alexander Graf
0 siblings, 2 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-21 1:24 UTC (permalink / raw)
To: Alexander Graf; +Cc: Stuart Brady, qemu-devel Developers
Am 21.12.2010 um 01:10 schrieb Alexander Graf:
> On 21.12.2010, at 01:06, Andreas Färber wrote:
>
>> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>>
>>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>>
>>>> Here's an update of the Z80 system emulator, which currently
>>>> emulates
>>>> the ZX Spectrum only. [...]
>>>
>>> [...] do you think it's a valuable target to have in upstream qemu?
>>
>> The z80 was also used in the more modern TI-83 Plus programmable
>> calculator [1], for instance
>
> The general I/O framework is heavily geared towards server and
> desktop use. The main use case of the Z80 that I'm aware of is the
> GameBoy. Not sure that one fits in there too well :).
>
> The Spectrum however does fit the desktop case, so it certainly has
> my blessings.
Knowing the ZX Spectrum only from the attic, I agree that emulating
game consoles is not the primary purpose or strength of QEMU.
(Although I wouldn't mind if someone wanted to contribute a PS3
machine for Cell B.E. emulation!)
Fwiw mips, arm, m68k, cris, microblaze seem to form a growing third
category of QEMU targets though, embedded systems.
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 1:24 ` Andreas Färber
@ 2010-12-21 2:38 ` Natalia Portillo
2010-12-21 2:47 ` John Williams
2010-12-21 17:20 ` Stefan Weil
2010-12-21 9:25 ` [Qemu-devel] [PATCH] Z80 emulation updated again! Alexander Graf
1 sibling, 2 replies; 27+ messages in thread
From: Natalia Portillo @ 2010-12-21 2:38 UTC (permalink / raw)
To: Andreas Färber; +Cc: Stuart Brady, Alexander Graf, qemu-devel Developers
Hi all,
The Z80 CPU and its variants and clones are not only used in dozens of computers (ranging from a full range of CP/M compatible ones, and minicomputers mostly seen as general public as gaming devices -Amstrad, Speccy-), but also in hunders of embedded systems and even on Adaptec SCSI cards.
I vote for inclusion on mainstream 100%, and maybe from that code an i8080 emulation can be easily extracted to cover the rest of 80s desktop/minis/micros ?
Regards,
Natalia Portillo
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 2:38 ` Natalia Portillo
@ 2010-12-21 2:47 ` John Williams
2010-12-21 17:24 ` Andreas Färber
2010-12-21 17:20 ` Stefan Weil
1 sibling, 1 reply; 27+ messages in thread
From: John Williams @ 2010-12-21 2:47 UTC (permalink / raw)
To: Natalia Portillo
Cc: qemu-devel Developers, Andreas Färber, Stuart Brady,
Alexander Graf
[-- Attachment #1: Type: text/plain, Size: 1329 bytes --]
On Tue, Dec 21, 2010 at 12:38 PM, Natalia Portillo <claunia@claunia.com>wrote:
> Hi all,
>
> The Z80 CPU and its variants and clones are not only used in dozens of
> computers (ranging from a full range of CP/M compatible ones, and
> minicomputers mostly seen as general public as gaming devices -Amstrad,
> Speccy-), but also in hunders of embedded systems and even on Adaptec SCSI
> cards.
>
> I vote for inclusion on mainstream 100%, and maybe from that code an i8080
> emulation can be easily extracted to cover the rest of 80s
> desktop/minis/micros ?
>
This is a really interesting discussion which goes to the heart of QEMU's
identity. A contemporary emulation and virtualisation platform (modern
embedded, KVM etc)? An emulation platform for retro-computing nostalgia?
How about as a unifying platform for MAME?
No reason of course it can't be both, unless those roles start pulling in
competing directions.
Commercially my company is an active user and supporter of MicroBlaze and
PPC440 platforms, while personally the Sinclair Spectrum was my first ever
home computing experience and will always have a special place in my geek
heart. So, I vote 'both'!
John
--
John Williams, PhD, B.Eng, B.IT
PetaLogix - Linux Solutions for a Reconfigurable World
w: www.petalogix.com p: +61-7-30090663 f: +61-7-30090663
[-- Attachment #2: Type: text/html, Size: 1783 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 1:24 ` Andreas Färber
2010-12-21 2:38 ` Natalia Portillo
@ 2010-12-21 9:25 ` Alexander Graf
2010-12-21 11:14 ` Artyom Tarasenko
1 sibling, 1 reply; 27+ messages in thread
From: Alexander Graf @ 2010-12-21 9:25 UTC (permalink / raw)
To: Andreas Färber; +Cc: Stuart Brady, qemu-devel Developers
On 21.12.2010, at 02:24, Andreas Färber wrote:
> Am 21.12.2010 um 01:10 schrieb Alexander Graf:
>
>> On 21.12.2010, at 01:06, Andreas Färber wrote:
>>
>>> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>>>
>>>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>>>
>>>>> Here's an update of the Z80 system emulator, which currently emulates
>>>>> the ZX Spectrum only. [...]
>>>>
>>>> [...] do you think it's a valuable target to have in upstream qemu?
>>>
>>> The z80 was also used in the more modern TI-83 Plus programmable calculator [1], for instance
>>
>> The general I/O framework is heavily geared towards server and desktop use. The main use case of the Z80 that I'm aware of is the GameBoy. Not sure that one fits in there too well :).
>>
>> The Spectrum however does fit the desktop case, so it certainly has my blessings.
>
> Knowing the ZX Spectrum only from the attic, I agree that emulating game consoles is not the primary purpose or strength of QEMU.
> (Although I wouldn't mind if someone wanted to contribute a PS3 machine for Cell B.E. emulation!)
>
> Fwiw mips, arm, m68k, cris, microblaze seem to form a growing third category of QEMU targets though, embedded systems.
Oh, sure. I'd count in embedded systems here too. My main point was that we don't have frameworks to deal with Joysticks, 3D or other stuff real game system emulation would need.
To be honest, maybe creating a library out of the CPU emulation code that projects like MAME could then use might prove more beneficial. I've thought about this for plenty other projects too. GBA emulation could use ARM TCG, Dolphin could use PPC TCG, etc. But none of these actually require our device model - they already have their own.
Alex
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 0:06 ` Andreas Färber
2010-12-21 0:10 ` Alexander Graf
@ 2010-12-21 9:59 ` Artyom Tarasenko
1 sibling, 0 replies; 27+ messages in thread
From: Artyom Tarasenko @ 2010-12-21 9:59 UTC (permalink / raw)
To: Andreas Färber; +Cc: Stuart Brady, Alexander Graf, qemu-devel Developers
On Tue, Dec 21, 2010 at 1:06 AM, Andreas Färber <andreas.faerber@web.de> wrote:
> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>
>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>
>>> Here's an update of the Z80 system emulator, which currently emulates
>>> the ZX Spectrum only. [...]
>>
>> [...] do you think it's a valuable target to have in upstream qemu?
>
> The z80 was also used in the more modern TI-83 Plus programmable calculator
> [1], for instance (chosen for school use in Baden-Württemberg in the early
> 2000s). There was an assembler toolchain integrated with Zilog Studio on
> Windows iirc.
> Apparently there's also an open source C compiler toolchain at [2] for these
> and other targets.
> No Linux that I'm aware of. ;)
But there are UZI and UZIX - unix like environments with TCP/IP stack
and Bourne Shell.
UZIX requires a MSX2 computer though.
--
Regards,
Artyom Tarasenko
solaris/sparc under qemu blog: http://tyom.blogspot.com/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 9:25 ` [Qemu-devel] [PATCH] Z80 emulation updated again! Alexander Graf
@ 2010-12-21 11:14 ` Artyom Tarasenko
2010-12-21 11:49 ` Alexander Graf
0 siblings, 1 reply; 27+ messages in thread
From: Artyom Tarasenko @ 2010-12-21 11:14 UTC (permalink / raw)
To: Alexander Graf; +Cc: Andreas Färber, Stuart Brady, qemu-devel Developers
On Tue, Dec 21, 2010 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>
> On 21.12.2010, at 02:24, Andreas Färber wrote:
>
>> Am 21.12.2010 um 01:10 schrieb Alexander Graf:
>>
>>> On 21.12.2010, at 01:06, Andreas Färber wrote:
>>>
>>>> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>>>>
>>>>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>>>>
>>>>>> Here's an update of the Z80 system emulator, which currently emulates
>>>>>> the ZX Spectrum only. [...]
>>>>>
>>>>> [...] do you think it's a valuable target to have in upstream qemu?
>>>>
>>>> The z80 was also used in the more modern TI-83 Plus programmable calculator [1], for instance
>>>
>>> The general I/O framework is heavily geared towards server and desktop use. The main use case of the Z80 that I'm aware of is the GameBoy. Not sure that one fits in there too well :).
>>>
>>> The Spectrum however does fit the desktop case, so it certainly has my blessings.
>>
>> Knowing the ZX Spectrum only from the attic, I agree that emulating game consoles is not the primary purpose or strength of QEMU.
>> (Although I wouldn't mind if someone wanted to contribute a PS3 machine for Cell B.E. emulation!)
>>
>> Fwiw mips, arm, m68k, cris, microblaze seem to form a growing third category of QEMU targets though, embedded systems.
>
> Oh, sure. I'd count in embedded systems here too. My main point was that we don't have frameworks to deal with Joysticks, 3D or other stuff real game system emulation would need.
With the emulation of the ancient machine based game platform it is
even more complicated: games expect some certain timings from the CPU,
graphic and sound cards. So, I'm not sure if TCG can be used for it.
> To be honest, maybe creating a library out of the CPU emulation code that projects like MAME could then use might prove more beneficial. I've thought about this for plenty other projects too. GBA emulation could use ARM TCG, Dolphin could use PPC TCG, etc. But none of these actually require our device model - they already have their own.
>
>
> Alex
>
>
>
--
Regards,
Artyom Tarasenko
solaris/sparc under qemu blog: http://tyom.blogspot.com/
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 11:14 ` Artyom Tarasenko
@ 2010-12-21 11:49 ` Alexander Graf
0 siblings, 0 replies; 27+ messages in thread
From: Alexander Graf @ 2010-12-21 11:49 UTC (permalink / raw)
To: Artyom Tarasenko; +Cc: Andreas Färber, Stuart Brady, qemu-devel Developers
On 21.12.2010, at 12:14, Artyom Tarasenko wrote:
> On Tue, Dec 21, 2010 at 10:25 AM, Alexander Graf <agraf@suse.de> wrote:
>>
>> On 21.12.2010, at 02:24, Andreas Färber wrote:
>>
>>> Am 21.12.2010 um 01:10 schrieb Alexander Graf:
>>>
>>>> On 21.12.2010, at 01:06, Andreas Färber wrote:
>>>>
>>>>> Am 20.12.2010 um 23:45 schrieb Alexander Graf:
>>>>>
>>>>>> On 31.05.2009, at 17:20, Stuart Brady wrote:
>>>>>>
>>>>>>> Here's an update of the Z80 system emulator, which currently emulates
>>>>>>> the ZX Spectrum only. [...]
>>>>>>
>>>>>> [...] do you think it's a valuable target to have in upstream qemu?
>>>>>
>>>>> The z80 was also used in the more modern TI-83 Plus programmable calculator [1], for instance
>>>>
>>>> The general I/O framework is heavily geared towards server and desktop use. The main use case of the Z80 that I'm aware of is the GameBoy. Not sure that one fits in there too well :).
>>>>
>>>> The Spectrum however does fit the desktop case, so it certainly has my blessings.
>>>
>>> Knowing the ZX Spectrum only from the attic, I agree that emulating game consoles is not the primary purpose or strength of QEMU.
>>> (Although I wouldn't mind if someone wanted to contribute a PS3 machine for Cell B.E. emulation!)
>>>
>>> Fwiw mips, arm, m68k, cris, microblaze seem to form a growing third category of QEMU targets though, embedded systems.
>>
>> Oh, sure. I'd count in embedded systems here too. My main point was that we don't have frameworks to deal with Joysticks, 3D or other stuff real game system emulation would need.
>
> With the emulation of the ancient machine based game platform it is
> even more complicated: games expect some certain timings from the CPU,
> graphic and sound cards. So, I'm not sure if TCG can be used for it.
Yup, old ones probably won't work. More recent ones should. Uli actually did create a GBA emulator using TCG a few years back, so it definitely does work for some stuff. I'm fairly sure that the more recent the systems become, the more event driven they also are - which is good for dynamic recompilation.
Either way, those really don't belong inside the Qemu source tree IMHO as development models don't match in general. Instead, a libtcg would be a lot more fitting for those cases.
Alex
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 2:38 ` Natalia Portillo
2010-12-21 2:47 ` John Williams
@ 2010-12-21 17:20 ` Stefan Weil
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
1 sibling, 1 reply; 27+ messages in thread
From: Stefan Weil @ 2010-12-21 17:20 UTC (permalink / raw)
To: Natalia Portillo
Cc: qemu-devel Developers, Andreas Färber, Stuart Brady,
Alexander Graf
Am 21.12.2010 03:38, schrieb Natalia Portillo:
> Hi all,
>
> The Z80 CPU and its variants and clones are not only used in dozens of
> computers (ranging from a full range of CP/M compatible ones, and
> minicomputers mostly seen as general public as gaming devices
> -Amstrad, Speccy-), but also in hunders of embedded systems and even
> on Adaptec SCSI cards.
>
> I vote for inclusion on mainstream 100%, and maybe from that code an
> i8080 emulation can be easily extracted to cover the rest of 80s
> desktop/minis/micros ?
>
> Regards,
> Natalia Portillo
I support this inclusion, too.
Maybe I'll even add a system emulation for TRS-80 one day.
Regards,
Stefan Weil
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-21 2:47 ` John Williams
@ 2010-12-21 17:24 ` Andreas Färber
0 siblings, 0 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-21 17:24 UTC (permalink / raw)
To: John Williams; +Cc: qemu-devel Developers, Stuart Brady, Alexander Graf
Am 21.12.2010 um 03:47 schrieb John Williams:
> This is a really interesting discussion which goes to the heart of
> QEMU's identity.
Right...
> A contemporary emulation and virtualisation platform (modern
> embedded, KVM etc)? An emulation platform for retro-computing
> nostalgia? How about as a unifying platform for MAME?
The way I see it, QEMU has shifted from the "packaged" desktop
emulation to a much more diversified emulation platform, say, a
library of qdev devices of which boards are pieced together. So if
someone contributes one particular machine, its devices can likely
find reuse for other boards and archs as well. In the PReP case, for
example the 40p's i82378.
In the case at hands, I was seeing possible reuse for target-z80/ bits
beyond nostalgia.
QEMU can be a backend for many use cases as long as cycle-accurateness
is not needed. The (lack of) frontends are its weekness though, which
I guess makes it unsuitable for gaming. Game emulators on the contrary
often oppose attempts to add more serious emulation features (e.g.,
LPT printing support in DOSBox).
Cheers,
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* [Qemu-devel] QEMU forks survey
2010-12-21 17:20 ` Stefan Weil
@ 2010-12-21 18:28 ` Andreas Färber
2010-12-21 18:38 ` Alexander Graf
` (5 more replies)
0 siblings, 6 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-21 18:28 UTC (permalink / raw)
To: Stefan Weil, François Revol
Cc: qemu-devel Developers, Stuart Brady, Alexander Graf
Since Christmas and the New Year with its good intensions are
approaching, apart from z80 there's some more feature forks around:
http://repo.or.cz/w/qemu.git/forks?o=age
- hpoussin.git ppc contains the 40p machine that I'm reviewing for
upstream inclusion currently.
* qemu-loongson.git I guess was fully upstreamed recently?
* ar7.git: Stefan, what's the state and scope of your work? What about
TCI?
Apparently abandoned (no recent activity):
* avr32.git
* es40.git (alpha)
* hppa.git
* openrisc.git
* mmix.git
Unclear to me:
* mini2440.git
* qemu-JZ.git
http://wiki.qemu.org/Links
- OpenSolaris support was merged so can be disregarded.
* I heard from François that one of the downstreams has added support
for the arm Beagle board? Maemo?
There's also many more forks on gitorious.com and github.com...
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
@ 2010-12-21 18:38 ` Alexander Graf
2010-12-21 19:04 ` Peter Maydell
` (4 subsequent siblings)
5 siblings, 0 replies; 27+ messages in thread
From: Alexander Graf @ 2010-12-21 18:38 UTC (permalink / raw)
To: Andreas Färber
Cc: Stuart Brady, qemu-devel Developers, François Revol
On 21.12.2010, at 19:28, Andreas Färber wrote:
> Since Christmas and the New Year with its good intensions are approaching, apart from z80 there's some more feature forks around:
>
> http://repo.or.cz/w/qemu.git/forks?o=age
>
> - hpoussin.git ppc contains the 40p machine that I'm reviewing for upstream inclusion currently.
>
> * qemu-loongson.git I guess was fully upstreamed recently?
>
> * ar7.git: Stefan, what's the state and scope of your work? What about TCI?
>
> Apparently abandoned (no recent activity):
> * avr32.git
> * es40.git (alpha)
> * hppa.git
> * openrisc.git
> * mmix.git
>
> Unclear to me:
> * mini2440.git
> * qemu-JZ.git
>
>
> http://wiki.qemu.org/Links
>
> - OpenSolaris support was merged so can be disregarded.
>
> * I heard from François that one of the downstreams has added support for the arm Beagle board? Maemo?
>
>
> There's also many more forks on gitorious.com and github.com...
* s390x emulation
I'm currently working on that one. Already did some cleanups to the code and am now trying to get a kernel booting.
Alex
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
2010-12-21 18:38 ` Alexander Graf
@ 2010-12-21 19:04 ` Peter Maydell
2010-12-21 21:16 ` Andreas Färber
2010-12-21 19:21 ` M P
` (3 subsequent siblings)
5 siblings, 1 reply; 27+ messages in thread
From: Peter Maydell @ 2010-12-21 19:04 UTC (permalink / raw)
To: Andreas Färber
Cc: Stuart Brady, François Revol, qemu-devel Developers,
Alexander Graf
On 21 December 2010 18:28, Andreas Färber <andreas.faerber@web.de> wrote:
> Since Christmas and the New Year with its good intensions are approaching,
> apart from z80 there's some more feature forks around:
> * I heard from François that one of the downstreams has added support for
> the arm Beagle board? Maemo?
Yes (well it's Meego these days):
http://meego.gitorious.org/qemu-maemo/qemu
That fork includes OMAP3 support (needed for beagle) and also a large
set of bugfixes for various ARM TCG issues which I've been trying to
get reviewed and into upstream. (If anybody has suggestions on the
best way to move forward with that I'd welcome them. So far I have been
working on the "start at one end, test and submit patch series" basis...)
-- PMM
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
2010-12-21 18:38 ` Alexander Graf
2010-12-21 19:04 ` Peter Maydell
@ 2010-12-21 19:21 ` M P
2010-12-21 20:27 ` François Revol
` (2 subsequent siblings)
5 siblings, 0 replies; 27+ messages in thread
From: M P @ 2010-12-21 19:21 UTC (permalink / raw)
To: Andreas Färber
Cc: Stuart Brady, François Revol, qemu-devel Developers,
Alexander Graf
On Tue, Dec 21, 2010 at 6:28 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Since Christmas and the New Year with its good intensions are approaching,
> apart from z80 there's some more feature forks around:
>
> http://repo.or.cz/w/qemu.git/forks?o=age
>
> - hpoussin.git ppc contains the 40p machine that I'm reviewing for upstream
> inclusion currently.
>
> * qemu-loongson.git I guess was fully upstreamed recently?
>
> * ar7.git: Stefan, what's the state and scope of your work? What about TCI?
>
> Apparently abandoned (no recent activity):
> * avr32.git
> * es40.git (alpha)
> * hppa.git
> * openrisc.git
> * mmix.git
>
> Unclear to me:
> * mini2440.git
I did that fully working mini2440 port, since last year or so. that
include s3c2440 and many associated peripherals. Unfortunately it's
hard to follow qemu's tree and I decided to keep my port as is instead
of constantly trying to keep it up to date... I still use it a lot
tho...
Michael
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
` (2 preceding siblings ...)
2010-12-21 19:21 ` M P
@ 2010-12-21 20:27 ` François Revol
2010-12-21 21:49 ` Stefan Weil
2010-12-22 7:47 ` Bastien ROUCARIES
5 siblings, 0 replies; 27+ messages in thread
From: François Revol @ 2010-12-21 20:27 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel Developers, Stuart Brady, Alexander Graf
Le 21 déc. 2010 à 19:28, Andreas Färber a écrit :
> Since Christmas and the New Year with its good intensions are approaching, apart from z80 there's some more feature forks around:
There is also a 68k trunk around IIRC:
http://gitorious.org/qemu-m68k/qemu-m68k
> * I heard from François that one of the downstreams has added support for the arm Beagle board? Maemo?
Yes it seemed to start booting Haiku's loader built for overo btw (also an OMAP IIRC).
François.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 19:04 ` Peter Maydell
@ 2010-12-21 21:16 ` Andreas Färber
0 siblings, 0 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-21 21:16 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel Developers
Peter,
Am 21.12.2010 um 20:04 schrieb Peter Maydell:
> http://meego.gitorious.org/qemu-maemo/qemu
>
> That fork includes OMAP3 support (needed for beagle) and also a large
> set of bugfixes for various ARM TCG issues which I've been trying to
> get reviewed and into upstream. (If anybody has suggestions on the
> best way to move forward with that I'd welcome them. So far I have
> been
> working on the "start at one end, test and submit patch series"
> basis...)
Your work is much appreciated. ARM patches seem to have been neglected
for some time.
My suggestion would be to set up an official feature repository
somewhere (like Kevin's "block" branch) and queue the patches there
for Anthony or someone to pull and to let downstreams rebase against
that. If you don't get review comments within, say, two weeks, just
queue them for the next pull. That should keep things moving.
You should also submit a patch to add yourself to MAINTAINERS [1] to
be cc'ed on future ARM patches.
Regards,
Andreas
[1] While the file header documents the 'T:' section, nobody seems to
be using it yet. Would be nice to document that info there as well.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
` (3 preceding siblings ...)
2010-12-21 20:27 ` François Revol
@ 2010-12-21 21:49 ` Stefan Weil
2010-12-22 7:47 ` Bastien ROUCARIES
5 siblings, 0 replies; 27+ messages in thread
From: Stefan Weil @ 2010-12-21 21:49 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel Developers
Am 21.12.2010 19:28, schrieb Andreas Färber:
> Since Christmas and the New Year with its good intensions are
> approaching, apart from z80 there's some more feature forks around:
>
> http://repo.or.cz/w/qemu.git/forks?o=age
>
> - hpoussin.git ppc contains the 40p machine that I'm reviewing for
> upstream inclusion currently.
>
> * qemu-loongson.git I guess was fully upstreamed recently?
>
> * ar7.git: Stefan, what's the state and scope of your work? What about
> TCI?
ar7.git (see http://wiki.qemu.org/User:Stefan_Weil) contains
* mips ar7 emulation (telekom sinus dsl and avm fritz box), working.
This was my first qemu application used to debug openwrt ar7 code,
and I still run it often.
* tci, working (I'm still looking for new hosts to run tests),
disassembler is work in progress (but maybe less important for tci).
* several arm based system emulations (partially collected from qemu-devel,
qdev support / bug fixes / updates / enhancements from me)
* new ethernet drivers
Regards,
Stefan
>
> Apparently abandoned (no recent activity):
> * avr32.git
> * es40.git (alpha)
> * hppa.git
> * openrisc.git
> * mmix.git
>
> Unclear to me:
> * mini2440.git
> * qemu-JZ.git
>
>
> http://wiki.qemu.org/Links
>
> - OpenSolaris support was merged so can be disregarded.
>
> * I heard from François that one of the downstreams has added support
> for the arm Beagle board? Maemo?
>
>
> There's also many more forks on gitorious.com and github.com...
>
> Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
` (4 preceding siblings ...)
2010-12-21 21:49 ` Stefan Weil
@ 2010-12-22 7:47 ` Bastien ROUCARIES
2010-12-22 15:28 ` Andreas Färber
5 siblings, 1 reply; 27+ messages in thread
From: Bastien ROUCARIES @ 2010-12-22 7:47 UTC (permalink / raw)
To: Andreas Färber
Cc: Stuart Brady, François Revol, qemu-devel Developers,
Alexander Graf
On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Since Christmas and the New Year with its good intensions are approaching,
> apart from z80 there's some more feature forks around:
>
> http://repo.or.cz/w/qemu.git/forks?o=age
They are also the gold plateform aka the android qemu port (see a
previous thread)
Bastien
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-22 7:47 ` Bastien ROUCARIES
@ 2010-12-22 15:28 ` Andreas Färber
2010-12-26 22:19 ` Bastien ROUCARIES
0 siblings, 1 reply; 27+ messages in thread
From: Andreas Färber @ 2010-12-22 15:28 UTC (permalink / raw)
To: Bastien ROUCARIES; +Cc: qemu-devel Developers
Am 22.12.2010 um 08:47 schrieb Bastien ROUCARIES:
> On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber <andreas.faerber@web.de
> > wrote:
>> Since Christmas and the New Year with its good intensions are
>> approaching,
>> apart from z80 there's some more feature forks around:
>>
>> http://repo.or.cz/w/qemu.git/forks?o=age
>
> They are also the gold plateform aka the android qemu port (see a
> previous thread)
Thanks. I'd like to document all these on wiki.qemu.org in some form.
Unfortunately the site failed to email me a new password, so that'll
have to wait another 24h...
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-22 15:28 ` Andreas Färber
@ 2010-12-26 22:19 ` Bastien ROUCARIES
2010-12-26 23:44 ` Andreas Färber
0 siblings, 1 reply; 27+ messages in thread
From: Bastien ROUCARIES @ 2010-12-26 22:19 UTC (permalink / raw)
To: Andreas Färber; +Cc: qemu-devel Developers
On Wed, Dec 22, 2010 at 4:28 PM, Andreas Färber <andreas.faerber@web.de> wrote:
> Am 22.12.2010 um 08:47 schrieb Bastien ROUCARIES:
>
>> On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber <andreas.faerber@web.de>
>> wrote:
>>>
>>> Since Christmas and the New Year with its good intensions are
>>> approaching,
>>> apart from z80 there's some more feature forks around:
>>>
>>> http://repo.or.cz/w/qemu.git/forks?o=age
>>
>> They are also the gold plateform aka the android qemu port (see a
>> previous thread)
>
> Thanks. I'd like to document all these on wiki.qemu.org in some form.
> Unfortunately the site failed to email me a new password, so that'll have to
> wait another 24h...
Any news ?
Bastien
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-26 22:19 ` Bastien ROUCARIES
@ 2010-12-26 23:44 ` Andreas Färber
2010-12-27 8:08 ` Stefan Weil
0 siblings, 1 reply; 27+ messages in thread
From: Andreas Färber @ 2010-12-26 23:44 UTC (permalink / raw)
To: Bastien ROUCARIES; +Cc: qemu-devel Developers
Am 26.12.2010 um 23:19 schrieb Bastien ROUCARIES:
> On Wed, Dec 22, 2010 at 4:28 PM, Andreas Färber <andreas.faerber@web.de
> > wrote:
>> Am 22.12.2010 um 08:47 schrieb Bastien ROUCARIES:
>>
>>> On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber <andreas.faerber@web.de
>>> >
>>> wrote:
>>>>
>>>> Since Christmas and the New Year with its good intensions are
>>>> approaching,
>>>> apart from z80 there's some more feature forks around:
>>>>
>>>> http://repo.or.cz/w/qemu.git/forks?o=age
>>>
>>> They are also the gold plateform aka the android qemu port (see a
>>> previous thread)
>>
>> Thanks. I'd like to document all these on wiki.qemu.org in some form.
>> Unfortunately the site failed to email me a new password, so
>> that'll have to
>> wait another 24h...
>
> Any news ?
No luck on my side, and Anthony seems to be on holiday.
But it's a Wiki. :) Feel free to add to the feature pages, with
pointers to the repositories where they're available.
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-26 23:44 ` Andreas Färber
@ 2010-12-27 8:08 ` Stefan Weil
2010-12-27 18:06 ` Andreas Färber
0 siblings, 1 reply; 27+ messages in thread
From: Stefan Weil @ 2010-12-27 8:08 UTC (permalink / raw)
To: qemu-devel Developers
Am 27.12.2010 00:44, schrieb Andreas Färber:
> Am 26.12.2010 um 23:19 schrieb Bastien ROUCARIES:
>
>> On Wed, Dec 22, 2010 at 4:28 PM, Andreas Färber
>> <andreas.faerber@web.de> wrote:
>>> Am 22.12.2010 um 08:47 schrieb Bastien ROUCARIES:
>>>
>>>> On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber
>>>> <andreas.faerber@web.de>
>>>> wrote:
>>>>>
>>>>> Since Christmas and the New Year with its good intensions are
>>>>> approaching,
>>>>> apart from z80 there's some more feature forks around:
>>>>>
>>>>> http://repo.or.cz/w/qemu.git/forks?o=age
>>>>
>>>> They are also the gold plateform aka the android qemu port (see a
>>>> previous thread)
>>>
>>> Thanks. I'd like to document all these on wiki.qemu.org in some form.
>>> Unfortunately the site failed to email me a new password, so that'll
>>> have to
>>> wait another 24h...
>>
>> Any news ?
>
> No luck on my side, and Anthony seems to be on holiday.
> But it's a Wiki. :) Feel free to add to the feature pages, with
> pointers to the repositories where they're available.
>
> Andreas
There are already some links here:
http://wiki.qemu.org/Links#Alternate_QEMU_repositories
Regards,
Stefan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] QEMU forks survey
2010-12-27 8:08 ` Stefan Weil
@ 2010-12-27 18:06 ` Andreas Färber
0 siblings, 0 replies; 27+ messages in thread
From: Andreas Färber @ 2010-12-27 18:06 UTC (permalink / raw)
To: Stefan Weil; +Cc: qemu-devel Developers
Am 27.12.2010 um 09:08 schrieb Stefan Weil:
> Am 27.12.2010 00:44, schrieb Andreas Färber:
>> Am 26.12.2010 um 23:19 schrieb Bastien ROUCARIES:
>>
>>> On Wed, Dec 22, 2010 at 4:28 PM, Andreas Färber <andreas.faerber@web.de
>>> > wrote:
>>>> Am 22.12.2010 um 08:47 schrieb Bastien ROUCARIES:
>>>>
>>>>> On Tue, Dec 21, 2010 at 7:28 PM, Andreas Färber <andreas.faerber@web.de
>>>>> >
>>>>> wrote:
>>>>>>
>>>>>> Since Christmas and the New Year with its good intensions are
>>>>>> approaching,
>>>>>> apart from z80 there's some more feature forks around:
>>>>>>
>>>>>> http://repo.or.cz/w/qemu.git/forks?o=age
>>>>>
>>>>> They are also the gold plateform aka the android qemu port (see a
>>>>> previous thread)
>>>>
>>>> Thanks. I'd like to document all these on wiki.qemu.org in some
>>>> form.
>>>> Unfortunately the site failed to email me a new password, so
>>>> that'll have to
>>>> wait another 24h...
>>>
>>> Any news ?
>>
>> No luck on my side, and Anthony seems to be on holiday.
>> But it's a Wiki. :) Feel free to add to the feature pages, with
>> pointers to the repositories where they're available.
>>
>> Andreas
>
>
> There are already some links here:
>
> http://wiki.qemu.org/Links#Alternate_QEMU_repositories
Yes, some, but neither complete nor fully up-to-date, as demonstrated
earlier in this thread.
We can either extend that list to include more feature information or
add separate feature pages with details. I intended both.
Andreas
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [Qemu-devel] [PATCH] Z80 emulation updated again!
2010-12-20 22:45 ` Alexander Graf
2010-12-21 0:06 ` Andreas Färber
@ 2010-12-29 19:57 ` Stuart Brady
1 sibling, 0 replies; 27+ messages in thread
From: Stuart Brady @ 2010-12-29 19:57 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-devel Developers
On Mon, Dec 20, 2010 at 11:45:08PM +0100, Alexander Graf wrote:
>
> Since this just came up again - are you still working on this? It's be a shame to see this target bitrot to extinction. Also, do you think it's a valuable target to have in upstream qemu? If so, please create a proper patch set out of it, so it can be reviewed.
I've placed a page on the status of this at:
* http://wiki.qemu.org/Features/Z80
There are quite a few items on the TODO list that I feel would need to
be one for the target to be suitable for inclusion. In particular,
execution from RAM that might be used for video is essential, but I'm
not really sure how to deal with that. Also, not implementing flags
optimisation would be somewhat silly, really...
I feel that the main emphasis of a Z80 target would be on systems
running CP/M, or for CP/M user emulation.
For gaming and similar, most emulators can get by just fine without
dynamic translation, and dedicated emulators seem to do a better job
anyway (regarding UI, accuracy of emulation, and feature-completeness),
so whilst it'd be interesting to see whether dynamic translation could
help to reduce power consumption on mobile devices, this would more
likely be a matter of integrating TCG into existing emulators.
I won't let the Z80 target bitrot too badly, and do plan to merge back
into the fork pretty soon... but there's still quite a bit to do.
Cheers,
--
Stuart Brady
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2010-12-29 19:57 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-31 15:20 [Qemu-devel] [PATCH] Z80 emulation updated again! Stuart Brady
2010-12-20 22:45 ` Alexander Graf
2010-12-21 0:06 ` Andreas Färber
2010-12-21 0:10 ` Alexander Graf
2010-12-21 1:24 ` Andreas Färber
2010-12-21 2:38 ` Natalia Portillo
2010-12-21 2:47 ` John Williams
2010-12-21 17:24 ` Andreas Färber
2010-12-21 17:20 ` Stefan Weil
2010-12-21 18:28 ` [Qemu-devel] QEMU forks survey Andreas Färber
2010-12-21 18:38 ` Alexander Graf
2010-12-21 19:04 ` Peter Maydell
2010-12-21 21:16 ` Andreas Färber
2010-12-21 19:21 ` M P
2010-12-21 20:27 ` François Revol
2010-12-21 21:49 ` Stefan Weil
2010-12-22 7:47 ` Bastien ROUCARIES
2010-12-22 15:28 ` Andreas Färber
2010-12-26 22:19 ` Bastien ROUCARIES
2010-12-26 23:44 ` Andreas Färber
2010-12-27 8:08 ` Stefan Weil
2010-12-27 18:06 ` Andreas Färber
2010-12-21 9:25 ` [Qemu-devel] [PATCH] Z80 emulation updated again! Alexander Graf
2010-12-21 11:14 ` Artyom Tarasenko
2010-12-21 11:49 ` Alexander Graf
2010-12-21 9:59 ` Artyom Tarasenko
2010-12-29 19:57 ` Stuart Brady
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).