qemu/qemu-z80.diff

5637 lines
144 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -urN qemu-0.9.0/configure qemu-z80/configure
--- qemu-0.9.0/configure 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/configure 2007-03-27 21:07:11.000000000 +0100
@@ -415,7 +415,7 @@
if test -z "$target_list" ; then
# these targets are portable
if [ "$softmmu" = "yes" ] ; then
- target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
+ target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu z80-softmmu"
fi
# the following are Linux specific
if [ "$linux_user" = "yes" ] ; then
@@ -911,6 +911,11 @@
echo "#define TARGET_ARCH \"m68k\"" >> $config_h
echo "#define TARGET_M68K 1" >> $config_h
bflt="yes"
+elif test "$target_cpu" = "z80" ; then
+ echo "TARGET_ARCH=z80" >> $config_mak
+ echo "#define TARGET_ARCH \"z80\"" >> $config_h
+ echo "#define TARGET_Z80 1" >> $config_h
+ bflt="yes"
else
echo "Unsupported target CPU"
exit 1
diff -urN qemu-0.9.0/cpu-all.h qemu-z80/cpu-all.h
--- qemu-0.9.0/cpu-all.h 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/cpu-all.h 2007-03-27 21:07:11.000000000 +0100
@@ -746,6 +746,13 @@
#define cpu_gen_code cpu_sh4_gen_code
#define cpu_signal_handler cpu_sh4_signal_handler
+#elif defined(TARGET_Z80)
+#define CPUState CPUZ80State
+#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
+
#else
#error unsupported target CPU
diff -urN qemu-0.9.0/cpu-exec.c qemu-z80/cpu-exec.c
--- qemu-0.9.0/cpu-exec.c 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/cpu-exec.c 2007-04-17 21:14:13.000000000 +0100
@@ -202,6 +202,10 @@
flags = env->sr & (SR_MD | SR_RB);
cs_base = 0; /* XXXXX */
pc = env->pc;
+#elif defined(TARGET_Z80)
+ flags = env->hflags;
+ cs_base = 0;
+ pc = env->pc;
#else
#error unsupported CPU
#endif
@@ -325,6 +329,12 @@
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
+#elif defined(TARGET_Z80)
+ env_to_regs();
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_S | CC_Z | CC_P | CC_C);
+ CC_OP = CC_OP_EFLAGS;
+ env->eflags &= ~(CC_S | CC_Z | CC_P | CC_C);
#else
#error unsupported target CPU
#endif
@@ -525,6 +535,13 @@
}
#elif defined(TARGET_SH4)
/* XXXXX */
+#elif defined(TARGET_Z80)
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+// Z80 FIXME Z80
+// env->exception_index = EXCP_IRQ;
+ do_interrupt(env);
+ }
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
@@ -593,6 +610,8 @@
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_SH4)
cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_Z80)
+ cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
@@ -785,6 +804,9 @@
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
+#elif defined(TARGET_Z80)
+ /* restore flags in standard format */
+// env->eflags = env->eflags | cc_table[CC_OP].compute_all();
#else
#error unsupported target CPU
#endif
diff -urN qemu-0.9.0/disas.c qemu-z80/disas.c
--- qemu-0.9.0/disas.c 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/disas.c 2007-03-27 21:07:11.000000000 +0100
@@ -197,6 +197,8 @@
#elif defined(TARGET_SH4)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
+#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 -urN qemu-0.9.0/dis-asm.h qemu-z80/dis-asm.h
--- qemu-0.9.0/dis-asm.h 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/dis-asm.h 2007-03-27 21:07:11.000000000 +0100
@@ -377,6 +377,7 @@
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ppc 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 -urN qemu-0.9.0/exec-all.h qemu-z80/exec-all.h
--- qemu-0.9.0/exec-all.h 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/exec-all.h 2007-04-17 21:26:41.000000000 +0100
@@ -69,7 +69,7 @@
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
-#if defined(TARGET_I386)
+#if defined(TARGET_I386) | defined(TARGET_Z80)
void optimize_flags_init(void);
@@ -572,6 +572,8 @@
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
#elif defined (TARGET_SH4)
is_user = ((env->sr & SR_MD) == 0);
+#elif defined (TARGET_Z80)
+ is_user = 0; /* no user-mode */
#else
#error unimplemented CPU
#endif
diff -urN qemu-0.9.0/exec.c qemu-z80/exec.c
--- qemu-0.9.0/exec.c 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/exec.c 2007-04-15 22:54:52.000000000 +0100
@@ -679,6 +679,9 @@
current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
current_cs_base = (target_ulong)env->segs[R_CS].base;
current_pc = current_cs_base + env->eip;
+#elif defined(TARGET_Z80)
+ current_flags = env->hflags;
+ current_pc = env->pc;
#else
#error unsupported CPU
#endif
diff -urN qemu-0.9.0/gdbstub.c qemu-z80/gdbstub.c
--- qemu-0.9.0/gdbstub.c 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/gdbstub.c 2007-04-04 21:35:14.000000000 +0100
@@ -700,6 +700,34 @@
LOAD (env->macl);
LOAD (env->sr);
}
+#elif defined(TARGET_Z80)
+/* Z80 FIXME Z80 TODO Z80 */
+/* GDB doesn't define this yet */
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+{
+ uint32_t *registers = (uint32_t *)mem_buf;
+ int i, fpus;
+
+ for(i = 0; i < 8; i++) {
+ registers[i] = env->regs[i];
+ }
+ registers[8] = env->pc;
+ registers[9] = env->imode;
+
+ return 10 * 4;
+}
+
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+{
+ uint32_t *registers = (uint32_t *)mem_buf;
+ int i;
+
+ for(i = 0; i < 8; i++) {
+ env->regs[i] = tswapl(registers[i]);
+ }
+ env->pc = tswapl(registers[8]);
+ env->imode = tswapl(registers[9]);
+}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
diff -urN qemu-0.9.0/hw/zx_spectrum.c qemu-z80/hw/zx_spectrum.c
--- qemu-0.9.0/hw/zx_spectrum.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/hw/zx_spectrum.c 2007-04-17 20:27:16.000000000 +0100
@@ -0,0 +1,236 @@
+/*
+ * QEMU ZX Spectrum Emulator
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003-2004 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 "vl.h"
+
+/* output Bochs bios info messages */
+//#define DEBUG_BIOS
+
+#define ROM_FILENAME "zx-rom.bin"
+
+#define KERNEL_LOAD_ADDR 0x00100000
+#define INITRD_LOAD_ADDR 0x00600000
+#define KERNEL_PARAMS_ADDR 0x00090000
+#define KERNEL_CMDLINE_ADDR 0x00099000
+
+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);
+}
+
+/* MSDOS compatibility mode FPU exception support */
+/* XXX: add IGNNE support */
+void cpu_set_ferr(CPUZ80State *s)
+{
+ pic_set_irq(13, 1);
+}
+
+/* TSC handling */
+uint64_t cpu_get_tsc(CPUZ80State *env)
+{
+ return cpu_get_ticks();
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ cpu_reset(env);
+}
+
+QEMUTimer *zx_ulatimer;
+int zx_flash = 0;
+
+void zx_50hz_timer(void *opaque)
+{
+// printf("zx_irq_timer()\n");
+ int64_t next_time;
+
+ CPUState *env = opaque;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+
+ /* FIXME: 50 Hz */
+ next_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec, 50);
+ qemu_mod_timer(zx_ulatimer, next_time);
+
+ zx_flash++;
+ zx_flash %= 32;
+ if ((zx_flash % 16) == 0) {
+ zx_set_flash_dirty();
+ }
+}
+
+CPUState *zx_env;
+
+void zx_timer_init(DisplayState *ds) {
+ /* FIXME */
+
+ int64_t t = qemu_get_clock(vm_clock);
+ zx_ulatimer = qemu_new_timer(vm_clock, zx_50hz_timer, zx_env);
+ qemu_mod_timer(zx_ulatimer, t);
+}
+
+static const uint8_t keycodes[128] = {
+ 0x00, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x45,
+ 0x44, 0x43, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x55, 0x54, 0x53,
+ 0x52, 0x51, 0x00, 0x00, 0x61, 0x72, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x65, 0x64, 0x63, 0x62, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05,
+ 0x75, 0x74, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static void zx_put_keycode(void *opaque, int keycode) {
+ int release = keycode & 0x80;
+ keycode &= 0x7f;
+
+ //printf("Keycode %d (%s)\n", keycode, release? "release" : "press");
+
+ keycode = keycodes[keycode];
+
+ if (keycode) {
+ int row = keycode >> 4;
+ int col = 1 << ((keycode & 0xf) - 1);
+ if (release) {
+ keystate[row] |= col;
+ } else {
+ keystate[row] &= ~col;
+ }
+ }
+}
+
+static void zx_keyboard_init()
+{
+ int i;
+ for (i=0; i<8; i++) {
+ keystate[i] = 0xff;
+ }
+ qemu_add_kbd_event_handler(zx_put_keycode, NULL);
+}
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+/* ZX Spectrum initialisation */
+static void zx_init1(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename,
+ int pci_enabled)
+{
+ char buf[1024];
+ int ret;
+ ram_addr_t ram_addr, vga_ram_addr, rom_offset;
+ int rom_size;
+ CPUState *env;
+
+ /* init CPUs */
+ env = cpu_init();
+ zx_env = env; // XXX
+ register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
+ qemu_register_reset(main_cpu_reset, env);
+
+ cpu_register_physical_memory(0, 0x10000, 0);
+
+ /* allocate RAM */
+// ram_addr = qemu_ram_alloc(0x10000 - 0x5b00);
+// cpu_register_physical_memory(0x5b00, 0x10000 - 0x5b00, 0);
+ //ram_addr = qemu_ram_alloc(0x10000 - 0x4000);
+ //cpu_register_physical_memory(0x4000, 0x10000 - 0x4000, ram_addr);
+
+// cpu_register_physical_memory(0x6000, 0x10000 - 0x6000, 0);
+
+ /* ROM load */
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, ROM_FILENAME);
+ rom_size = get_image_size(buf);
+ if (rom_size <= 0 ||
+ (rom_size % 16384) != 0) {
+ goto rom_error;
+ }
+// rom_offset = qemu_ram_alloc(rom_size);
+ rom_offset = 0x10000;
+ ret = load_image(buf, phys_ram_base + rom_offset);
+ if (ret != rom_size) {
+ rom_error:
+ fprintf(stderr, "qemu: could not load ZX Spectrum ROM '%s'\n", buf);
+ exit(1);
+ }
+
+ cpu_register_physical_memory(0x0000, 0x4000, rom_offset | IO_MEM_ROM);
+
+ /* map entire I/O space */
+ register_ioport_read(0, 0x10000, 1, io_spectrum_read, NULL);
+
+ zx_ula_init(ds, phys_ram_base + ram_size, ram_size);
+ zx_keyboard_init();
+ zx_timer_init(ds);
+}
+
+static void zx_spectrum_init(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename)
+{
+ zx_init1(ram_size, vga_ram_size, boot_device,
+ ds, fd_filename, snapshot,
+ kernel_filename, kernel_cmdline,
+ initrd_filename, 0);
+}
+
+QEMUMachine z80pc_machine = {
+ "z80pc",
+ "Z80 Machine",
+ zx_spectrum_init,
+};
diff -urN qemu-0.9.0/hw/zx_ula.c qemu-z80/hw/zx_ula.c
--- qemu-0.9.0/hw/zx_ula.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/hw/zx_ula.c 2007-04-17 20:55:28.000000000 +0100
@@ -0,0 +1,355 @@
+/*
+ * QEMU ZX Spectrum Video Emulation.
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * 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 "vl.h"
+
+typedef struct {
+ DisplayState *ds;
+ uint8_t *vram_ptr;
+ unsigned long vram_offset;
+
+ int bwidth;
+ int bheight;
+ int swidth;
+ int sheight;
+ int twidth;
+ int theight;
+
+ int border;
+
+ int dirty;
+} ZXVState;
+
+char *colnames[8] = {
+ "black",
+ "blue",
+ "red",
+ "magenta",
+ "green",
+ "cyan",
+ "yellow",
+ "white"
+};
+
+uint32_t cols[16] = {
+ 0x00000000,
+ 0x000000c0,
+ 0x00c00000,
+ 0x00c000c0,
+ 0x0000c000,
+ 0x0000c0c0,
+ 0x00c0c000,
+ 0x00c0c0c0,
+ 0x00000000,
+ 0x000000ff,
+ 0x00ff0000,
+ 0x00ff00ff,
+ 0x0000ff00,
+ 0x0000ffff,
+ 0x00ffff00,
+ 0x00ffffff,
+};
+
+/* copied from 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),
+};
+
+static inline void zx_draw_line_8(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+}
+
+static inline void zx_draw_line_16(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+ ((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;
+}
+
+static inline void zx_draw_line_32(uint8_t *d,
+ uint32_t font_data,
+ uint32_t xorcol,
+ uint32_t bgcol)
+{
+ ((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;
+}
+
+extern int zx_flash;
+static ZXVState *zxvstate;
+
+void zx_set_flash_dirty(void) {
+ ZXVState *s = zxvstate;
+ s->dirty = 1;
+}
+
+static void zx_draw_line(ZXVState *s1, uint8_t *d,
+ const uint8_t *s, const uint8_t *as)
+{
+ int x;
+ for (x = 0; x < 32; x++) {
+ int attrib, fg, bg, bright, flash;
+
+ attrib = *as;
+ bright = (attrib & 0x40) >> 4;
+ flash = (attrib & 0x80) && (zx_flash >= 16);
+ if (flash) {
+ fg = (attrib >> 3) & 0x07;
+ bg = attrib & 0x07;
+ } else {
+ fg = attrib & 0x07;
+ bg = (attrib >> 3) & 0x07;
+ }
+ fg |= bright;
+ bg |= bright;
+
+ zx_draw_line_32(d, *s, cols[fg] ^ cols[bg], cols[bg]);
+ d += 8 * 4;
+ s++; as++;
+ }
+}
+
+static void zx_border_row(ZXVState *s, uint8_t *d)
+{
+ int x;
+ for (x = 0; x < s->twidth; x++) {
+ *((uint32_t *)d) = cols[s->border];
+ d += 4;
+ }
+}
+
+static void zx_border_sides(ZXVState *s, uint8_t *d)
+{
+ int x;
+ for (x = 0; x < s->bwidth; x++) {
+ *((uint32_t *)d) = cols[s->border];
+ d += 4;
+ }
+ d += s->swidth * 4;
+ for (x = 0; x < s->bwidth; x++) {
+ *((uint32_t *)d) = cols[s->border];
+ d += 4;
+ }
+}
+
+static void zx_update_display(void *opaque)
+{
+ int y;
+ uint8_t *d;
+ ZXVState *s = (ZXVState *)opaque;
+ uint32_t addr, attrib;
+
+ if (!s->dirty)
+ return;
+
+ d = s->ds->data;
+ d += s->bheight * s->ds->linesize;
+ d += s->bwidth * 4;
+
+ for (y = 0; y < 192; y++) {
+ addr = ((y & 0x07) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5);
+ attrib = 0x1800 | ((y & 0xf8) << 2);
+ zx_draw_line(s, d, s->vram_ptr + addr, s->vram_ptr + attrib);
+ d += s->ds->linesize;
+ }
+
+ d = s->ds->data;
+ for (y = 0; y < s->bheight; y++) {
+ zx_border_row(s, d + y * s->ds->linesize);
+ }
+ for (y = s->bheight; y < s->theight - s->bheight; y++) {
+ zx_border_sides(s, d + y * s->ds->linesize);
+ }
+ for (y = s->theight - s->bheight; y < s->theight; y++) {
+ zx_border_row(s, d + y * s->ds->linesize);
+ }
+
+ dpy_update(s->ds, 0, 0, s->twidth, s->theight);
+ s->dirty = 0;
+}
+
+static void zx_invalidate_display(void *opaque)
+{
+}
+
+static void zx_screen_dump(void *opaque, const char *filename)
+{
+}
+
+uint32_t zx_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+ ZXVState *s = opaque;
+
+ addr -= 0x4000;
+ return s->vram_ptr[addr];
+}
+
+uint32_t zx_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+ return (zx_mem_readb(opaque, addr + 1) << 8) | zx_mem_readb(opaque, addr);
+}
+
+uint32_t zx_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ return (zx_mem_readb(opaque, addr + 3) << 24) |
+ (zx_mem_readb(opaque, addr + 2) << 16) |
+ (zx_mem_readb(opaque, addr + 1) << 8) |
+ zx_mem_readb(opaque, addr);
+}
+
+void zx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ ZXVState *s = opaque;
+
+ if (addr < 0x5b00) // XXX
+ s->dirty = 1;
+ addr -= 0x4000;
+ s->vram_ptr[addr] = val;
+
+ cpu_physical_memory_set_dirty(s->vram_offset + addr);
+}
+
+void zx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ zx_mem_writeb(opaque, addr, val & 0xff);
+ zx_mem_writeb(opaque, addr + 1, val >> 8);
+}
+
+void zx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ zx_mem_writeb(opaque, addr, val & 0xff);
+ zx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+ zx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+ zx_mem_writeb(opaque, addr + 3, val >> 24);
+}
+
+static CPUReadMemoryFunc *zx_mem_read[3] = {
+ zx_mem_readb,
+ zx_mem_readw,
+ zx_mem_readl,
+};
+
+static CPUWriteMemoryFunc *zx_mem_write[3] = {
+ zx_mem_writeb,
+ zx_mem_writew,
+ zx_mem_writel,
+};
+
+static void io_spectrum_write(void *opaque, uint32_t addr, uint32_t data)
+{
+ ZXVState *s = (ZXVState *)opaque;
+
+/* port xxfe */
+ s->border = data & 0x07;
+ s->dirty = 1;
+};
+
+void zx_ula_init(DisplayState *ds, uint8_t *zx_screen_base,
+ unsigned long ula_ram_offset)
+{
+ int zx_io_memory;
+
+ ZXVState *s = qemu_mallocz(sizeof(ZXVState));
+ if (!s)
+ return;
+ zxvstate = s;
+ s->ds = ds;
+ s->dirty = 1;
+// s->vram_ptr = zx_screen_base;
+// s->vram_offset = ula_ram_offset;
+
+ graphic_console_init(ds, zx_update_display, zx_invalidate_display,
+ zx_screen_dump, 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;
+ dpy_resize(s->ds, s->twidth, s->theight);
+
+ zx_io_memory = cpu_register_io_memory(0, zx_mem_read, zx_mem_write, s);
+ cpu_register_physical_memory(0x4000, 0x1b00, zx_io_memory);
+// cpu_register_physical_memory(0x4000, 0x2000, zx_io_memory);
+// cpu_register_physical_memory(0x4000, 0xc000, zx_io_memory);
+ s->vram_ptr = phys_ram_base + zx_io_memory;
+ s->vram_offset = zx_io_memory;
+
+ /* ZX Spectrum ULA */
+ register_ioport_write(0, 0x10000, 1, io_spectrum_write, s);
+}
diff -urN qemu-0.9.0/Makefile qemu-z80/Makefile
--- qemu-0.9.0/Makefile 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/Makefile 2007-03-27 21:07:11.000000000 +0100
@@ -79,7 +79,7 @@
mkdir -p "$(DESTDIR)$(datadir)"
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
- pxe-rtl8139.bin pxe-pcnet.bin; do \
+ pxe-rtl8139.bin pxe-pcnet.bin zx-rom.bin ; do \
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
done
ifndef CONFIG_WIN32
diff -urN qemu-0.9.0/Makefile.target qemu-z80/Makefile.target
--- qemu-0.9.0/Makefile.target 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/Makefile.target 2007-04-15 19:35:13.000000000 +0100
@@ -271,6 +271,10 @@
LIBOBJS+= helper.o
endif
+ifeq ($(TARGET_BASE_ARCH), z80)
+LIBOBJS+=helper.o helper2.o
+endif
+
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -303,6 +307,9 @@
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
LIBOBJS+=sh4-dis.o
endif
+ifeq ($(findstring z80, $(TARGET_ARCH) $(ARCH)),z80)
+LIBOBJS+=z80-dis.o
+endif
ifdef CONFIG_GDBSTUB
OBJS+=gdbstub.o
@@ -407,6 +414,10 @@
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
endif
+ifeq ($(TARGET_BASE_ARCH), z80)
+VL_OBJS+= zx_spectrum.o zx_ula.o dma.o $(AUDIODRV)
+VL_OBJS+= serial.o i8259.o mixeng.o
+endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
@@ -514,9 +525,15 @@
helper.o: helper.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
else
+ifeq ($(TARGET_BASE_ARCH), z80)
+# XXX: rename helper.c to op_helper.c
+helper.o: helper.c
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
+else
op_helper.o: op_helper.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
endif
+endif
cpu-exec.o: cpu-exec.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
@@ -529,6 +546,9 @@
ifeq ($(TARGET_BASE_ARCH), i386)
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
endif
+ifeq ($(TARGET_BASE_ARCH), z80)
+op.o: op.c opreg_template.h ops_mem.h
+endif
ifeq ($(TARGET_ARCH), arm)
op.o: op.c op_template.h
Binary files qemu-0.9.0/pc-bios/zx-rom.bin and qemu-z80/pc-bios/zx-rom.bin differ
diff -urN qemu-0.9.0/softmmu_header.h qemu-z80/softmmu_header.h
--- qemu-0.9.0/softmmu_header.h 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/softmmu_header.h 2007-03-27 21:07:11.000000000 +0100
@@ -63,6 +63,8 @@
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
#elif defined (TARGET_SH4)
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
+#elif defined (TARGET_Z80)
+#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#else
#error unsupported CPU
#endif
@@ -82,6 +84,8 @@
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
#elif defined (TARGET_SH4)
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
+#elif defined (TARGET_Z80)
+#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#else
#error unsupported CPU
#endif
diff -urN qemu-0.9.0/target-z80/cpu.h qemu-z80/target-z80/cpu.h
--- qemu-0.9.0/target-z80/cpu.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/cpu.h 2007-04-17 21:05:57.000000000 +0100
@@ -0,0 +1,235 @@
+/*
+ * Z80 virtual CPU header
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+
+#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_AFX 10
+#define R_BCX 11
+#define R_DEX 12
+#define R_HLX 13
+
+/* 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, INHIBIT_IRQ and HALTED 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_HALTED_SHIFT 18 /* CPU halted */
+#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_HALTED_MASK (1 << HF_HALTED_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
+
+enum {
+ CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
+ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
+
+ CC_OP_NB,
+};
+
+#define CPU_NB_REGS 14
+
+typedef struct CPUZ80State {
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+ /* temporaries if we cannot store them in host registers */
+ target_ulong t0, t1, t2;
+#endif
+
+ /* 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 */
+ target_ulong cc_src;
+ target_ulong cc_dst;
+ uint32_t cc_op;
+ 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 */
+ jmp_buf jmp_env;
+ int exception_index;
+ int error_code;
+ int exception_is_int;
+ target_ulong exception_next_pc;
+ target_ulong dr[8]; /* debug registers */
+ uint32_t smbase;
+ int interrupt_request;
+ int user_mode_only; /* user mode only simulation */
+
+ CPU_COMMON
+
+ /* in order to simplify APIC support, we leave this pointer to the
+ user */
+ struct APICState *apic_state;
+} CPUZ80State;
+
+CPUZ80State *cpu_z80_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);
+
+void cpu_set_apic_base(CPUZ80State *env, uint64_t val);
+uint64_t cpu_get_apic_base(CPUZ80State *env);
+void cpu_set_apic_tpr(CPUZ80State *env, uint8_t val);
+#ifndef NO_CPU_IO_DEFS
+uint8_t cpu_get_apic_tpr(CPUZ80State *env);
+#endif
+void cpu_smm_update(CPUZ80State *env);
+
+#define TARGET_PAGE_BITS 12
+#include "cpu-all.h"
+
+#endif /* CPU_Z80_H */
diff -urN qemu-0.9.0/target-z80/exec.h qemu-z80/target-z80/exec.h
--- qemu-0.9.0/target-z80/exec.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/exec.h 2007-04-17 21:02:26.000000000 +0100
@@ -0,0 +1,361 @@
+/*
+ * Z80 execution defines
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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)
+#define T2 (env->t2)
+
+#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);
+register target_ulong T2 asm(AREG3);
+
+/* if more registers are available, we define some registers too */
+#ifdef AREG4
+register target_ulong A asm(AREG4);
+#define reg_A
+#endif
+
+#ifdef AREG5
+register target_ulong F asm(AREG5);
+#define reg_F
+#endif
+
+#ifdef AREG6
+register target_ulong BC asm(AREG6);
+#define reg_BC
+#endif
+
+#ifdef AREG7
+register target_ulong DE asm(AREG7);
+#define reg_DE
+#endif
+
+#ifdef AREG8
+register target_ulong HL asm(AREG8);
+#define reg_HL
+#endif
+
+#ifdef AREG9
+register target_ulong IX asm(AREG9);
+#define reg_IX
+#endif
+
+#ifdef AREG10
+register target_ulong IY asm(AREG10);
+#define reg_IY
+#endif
+
+#ifdef AREG11
+register target_ulong R asm(AREG11);
+#define reg_R
+#endif
+
+#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */
+
+#define A0 T2
+
+extern FILE *logfile;
+extern int loglevel;
+
+#ifndef reg_A
+#define A (env->regs[R_A])
+#endif
+#ifndef reg_F
+#define F (env->regs[R_F])
+#endif
+#ifndef reg_BC
+#define BC (env->regs[R_BC])
+#endif
+#ifndef reg_DE
+#define DE (env->regs[R_DE])
+#endif
+#ifndef reg_HL
+#define HL (env->regs[R_HL])
+#endif
+#ifndef reg_IX
+#define IX (env->regs[R_IX])
+#endif
+#ifndef reg_IY
+#define IY (env->regs[R_IY])
+#endif
+#ifndef reg_SP
+#define SP (env->regs[R_SP])
+#endif
+#ifndef reg_I
+#define I (env->regs[R_I])
+#endif
+#ifndef reg_R
+#define R (env->regs[R_R])
+#endif
+#ifndef reg_AFX
+#define AFX (env->regs[R_AFX])
+#endif
+#ifndef reg_BCX
+#define BCX (env->regs[R_BCX])
+#endif
+#ifndef reg_DEX
+#define DEX (env->regs[R_DEX])
+#endif
+#ifndef reg_HLX
+#define HLX (env->regs[R_HLX])
+#endif
+
+#define PC (env->pc)
+
+#define CC_SRC (env->cc_src)
+#define CC_DST (env->cc_dst)
+#define CC_OP (env->cc_op)
+
+/* float macros */
+#if 0
+#define FT0 (env->ft0)
+#define ST0 (env->fpregs[env->fpstt].d)
+#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d)
+#define ST1 ST(1)
+
+#ifdef USE_FP_CONVERT
+#define FP_CONVERT (env->fp_convert)
+#endif
+#endif
+
+#include "cpu.h"
+#include "exec-all.h"
+
+typedef struct CCTable {
+ int (*compute_all)(void); /* return all the flags */
+ int (*compute_c)(void); /* return the C flag */
+} CCTable;
+
+extern CCTable cc_table[];
+
+void load_seg(int seg_reg, int selector);
+void helper_ljmp_protected_T0_T1(int next_eip);
+void helper_lcall_real_T0_T1(int shift, int next_eip);
+void helper_lcall_protected_T0_T1(int shift, int next_eip);
+void helper_iret_real(int shift);
+void helper_iret_protected(int shift, int next_eip);
+void helper_lret_protected(int shift, int addend);
+void helper_lldt_T0(void);
+void helper_ltr_T0(void);
+void helper_movl_crN_T0(int reg);
+void helper_movl_drN_T0(int reg);
+void helper_invlpg(target_ulong addr);
+
+int cpu_z80_handle_mmu_fault(CPUZ80State *env, target_ulong addr,
+ int is_write, int is_user, int is_softmmu);
+void tlb_fill(target_ulong addr, int is_write, int is_user,
+ void *retaddr);
+void __hidden cpu_lock(void);
+void __hidden cpu_unlock(void);
+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);
+void do_smm_enter(void);
+void __hidden cpu_loop_exit(void);
+
+void OPPROTO op_movl_eflags_T0(void);
+void OPPROTO op_movl_T0_eflags(void);
+
+void helper_dump_registers(int pc);
+void helper_in_debug(int port);
+
+#if !defined(CONFIG_USER_ONLY)
+
+#include "softmmu_exec.h"
+
+static inline double ldfq(target_ulong ptr)
+{
+ union {
+ double d;
+ uint64_t i;
+ } u;
+ u.i = ldq(ptr);
+ return u.d;
+}
+
+static inline void stfq(target_ulong ptr, double v)
+{
+ union {
+ double d;
+ uint64_t i;
+ } u;
+ u.d = v;
+ stq(ptr, u.i);
+}
+
+static inline float ldfl(target_ulong ptr)
+{
+ union {
+ float f;
+ uint32_t i;
+ } u;
+ u.i = ldl(ptr);
+ return u.f;
+}
+
+static inline void stfl(target_ulong ptr, float v)
+{
+ union {
+ float f;
+ uint32_t i;
+ } u;
+ u.f = v;
+ stl(ptr, u.i);
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#define RC_MASK 0xc00
+#define RC_NEAR 0x000
+#define RC_DOWN 0x400
+#define RC_UP 0x800
+#define RC_CHOP 0xc00
+
+void helper_hlt(void);
+void helper_monitor(void);
+void helper_mwait(void);
+
+extern const uint8_t parity_table[256];
+extern const uint8_t rclw_table[32];
+extern const uint8_t rclb_table[32];
+
+static inline uint32_t compute_eflags(void)
+{
+ return env->eflags | cc_table[CC_OP].compute_all();
+}
+
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
+static inline void load_eflags(int eflags, int update_mask)
+{
+ CC_SRC = eflags & (CC_S | CC_Z | CC_P | CC_C);
+ env->eflags = (env->eflags & ~update_mask) |
+ (eflags & update_mask);
+}
+
+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_AFX
+ AFX = env->regs[R_AFX];
+#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_AFX
+ env->regs[R_AFX] = AFX;
+#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
+}
diff -urN qemu-0.9.0/target-z80/helper2.c qemu-z80/target-z80/helper2.c
--- qemu-0.9.0/target-z80/helper2.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/helper2.c 2007-04-17 21:29:49.000000000 +0100
@@ -0,0 +1,170 @@
+/*
+ * Z80 helpers (without register variable usage)
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+//#define DEBUG_MMU
+
+CPUZ80State *cpu_z80_init(void)
+{
+ CPUZ80State *env;
+ static int inited;
+
+ env = qemu_mallocz(sizeof(CPUZ80State));
+ if (!env)
+ return NULL;
+ cpu_exec_init(env);
+
+ /* init various static tables */
+ if (!inited) {
+ inited = 1;
+ optimize_flags_init();
+ }
+ cpu_reset(env);
+ return env;
+}
+
+/* NOTE: must be called outside the CPU execute loop */
+void cpu_reset(CPUZ80State *env)
+{
+ 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 */
+
+static const char *cc_op_str[] = {
+ "DYNAMIC",
+ "EFLAGS",
+};
+
+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_AFX],
+ env->regs[R_BCX],
+ env->regs[R_DEX],
+ env->regs[R_HLX],
+ env->regs[R_IY],
+ env->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]);
+}
+
+/***********************************************************/
+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 = 4096;
+
+ /* Even if 4MB pages, we map only one 4KB page in the cache to
+ avoid filling it too fast */
+ 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_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ uint32_t pte, paddr, page_offset, page_size;
+
+ pte = addr;
+ page_size = 4096;
+
+ page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
+ paddr = (pte & TARGET_PAGE_MASK) + page_offset;
+ return paddr;
+}
diff -urN qemu-0.9.0/target-z80/helper.c qemu-z80/target-z80/helper.c
--- qemu-0.9.0/target-z80/helper.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/helper.c 2007-04-25 17:54:06.000000000 +0100
@@ -0,0 +1,283 @@
+/*
+ * Z80 helpers
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "exec.h"
+
+//#define DEBUG_PCALL
+
+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,
+};
+
+/* modulo 17 table */
+const uint8_t rclw_table[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9,10,11,12,13,14,15,
+ 16, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9,10,11,12,13,14,
+};
+
+/* modulo 9 table */
+const uint8_t rclb_table[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 0, 1, 2, 3, 4,
+};
+
+
+/* thread support */
+
+spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void cpu_lock(void)
+{
+ spin_lock(&global_cpu_lock);
+}
+
+void cpu_unlock(void)
+{
+ spin_unlock(&global_cpu_lock);
+}
+
+void cpu_loop_exit(void)
+{
+ /* NOTE: the register at this point must be saved by hand because
+ longjmp restore them */
+ regs_to_env();
+ longjmp(env->jmp_env, 1);
+}
+
+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_hlt(void)
+{
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+ env->hflags |= HF_HALTED_MASK;
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+}
+
+void helper_monitor(void)
+{
+}
+
+void helper_mwait(void)
+{
+}
+
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+#define GETPC() (__builtin_return_address(0))
+
+#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;
+}
+
+void helper_in_debug(int port)
+{
+// printf("IN with port %02x\n", port);
+}
+
+void helper_dump_registers(int pc)
+{
+ int fl = env->regs[R_F];
+ printf("--------------\n"
+ "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_AFX],
+ env->regs[R_BCX],
+ env->regs[R_DEX],
+ env->regs[R_HLX],
+ env->regs[R_IY],
+ pc == -1 ? env->pc : pc,
+ env->regs[R_SP],
+ fl & 0x80 ? 'S' : '-',
+ fl & 0x40 ? 'Z' : '-',
+ fl & 0x20 ? '5' : '-',
+ fl & 0x10 ? 'H' : '-',
+ fl & 0x08 ? '3' : '-',
+ fl & 0x04 ? 'P' : '-',
+ fl & 0x02 ? 'N' : '-',
+ fl & 0x01 ? 'C' : '-',
+ env->imode, env->iff1, env->iff2, env->regs[R_I], env->regs[R_R]);
+}
diff -urN qemu-0.9.0/target-z80/op.c qemu-z80/target-z80/op.c
--- qemu-0.9.0/target-z80/op.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/op.c 2007-04-25 17:41:33.000000000 +0100
@@ -0,0 +1,1175 @@
+/*
+ * Z80 micro operations
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define ASM_SOFTMMU
+#include "exec.h"
+
+#define REGHIGH A
+#define REGLOW F
+#define REGPAIRNAME _AF
+#define REGHIGHNAME _A
+#define REGLOWNAME _F
+#include "opreg_template2.h"
+#undef REGHIGH
+#undef REGLOW
+#undef REGPAIRNAME
+#undef REGHIGHNAME
+#undef REGLOWNAME
+
+#define REG BC
+#define REGNAME _BC
+#define REGHIGH _B
+#define REGLOW _C
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+#undef REGHIGH
+#undef REGLOW
+
+#define REG DE
+#define REGNAME _DE
+#define REGHIGH _D
+#define REGLOW _E
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+#undef REGHIGH
+#undef REGLOW
+
+#define REG HL
+#define REGNAME _HL
+#define REGHIGH _H
+#define REGLOW _L
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+#undef REGHIGH
+#undef REGLOW
+
+#define REG IX
+#define REGNAME _IX
+#define REGHIGH _IXh
+#define REGLOW _IXl
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+#undef REGHIGH
+#undef REGLOW
+
+#define REG IY
+#define REGNAME _IY
+#define REGHIGH _IYh
+#define REGLOW _IYl
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+#undef REGHIGH
+#undef REGLOW
+
+#define REG SP
+#define REGNAME _SP
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG AFX
+#define REGNAME _AFX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG BCX
+#define REGNAME _BCX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG DEX
+#define REGNAME _DEX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG HLX
+#define REGNAME _HLX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+void OPPROTO op_movl_pc_im(void)
+{
+ PC = (uint16_t)PARAM1;
+}
+
+void OPPROTO op_debug(void)
+{
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit();
+}
+
+void OPPROTO op_raise_exception(void)
+{
+ int exception_index;
+ exception_index = PARAM1;
+ raise_exception(exception_index);
+}
+
+void OPPROTO op_set_inhibit_irq(void)
+{
+ env->hflags |= HF_INHIBIT_IRQ_MASK;
+}
+
+void OPPROTO op_reset_inhibit_irq(void)
+{
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+}
+
+void OPPROTO op_movl_T0_0(void)
+{
+ T0 = 0;
+}
+
+void OPPROTO op_exit_tb(void)
+{
+ EXIT_TB();
+}
+
+/************ Z80 MICRO-OPS ***********/
+
+/* Loads/stores */
+
+void OPPROTO op_mov_T0_im(void)
+{
+ T0 = (uint16_t)PARAM1;
+}
+
+void OPPROTO op_mov_T1_im(void)
+{
+ T0 = (uint16_t)PARAM1;
+}
+
+void OPPROTO op_mov_A0_im(void)
+{
+ A0 = (uint16_t)PARAM1;
+}
+
+void OPPROTO op_movb_T0_HLmem(void)
+{
+ A0 = HL;
+ T0 = ldub_kernel(A0);
+}
+
+void OPPROTO op_movb_HLmem_T0(void)
+{
+ A0 = HL;
+ stb_kernel(A0, T0);
+}
+
+void OPPROTO op_movb_T0_IXmem(void)
+{
+ A0 = (uint16_t)(IX + PARAM1);
+ T0 = ldub_kernel(A0);
+}
+
+void OPPROTO op_movb_IXmem_T0(void)
+{
+ A0 = (uint16_t)(IX + PARAM1);
+ stb_kernel(A0, T0);
+}
+
+void OPPROTO op_movb_T0_IYmem(void)
+{
+ A0 = (uint16_t)(IY + PARAM1);
+ T0 = ldub_kernel(A0);
+}
+
+void OPPROTO op_movb_IYmem_T0(void)
+{
+ A0 = (uint16_t)(IY + PARAM1);
+ stb_kernel(A0, T0);
+}
+
+void OPPROTO op_ldb_T0_A0(void)
+{
+ T0 = ldub_kernel(A0);
+}
+
+void OPPROTO op_ldw_T0_A0(void)
+{
+ T0 = lduw_kernel(A0);
+}
+
+void OPPROTO op_stb_T0_A0(void)
+{
+ stb_kernel(A0, T0);
+}
+
+void OPPROTO op_stw_T0_A0(void)
+{
+ stw_kernel(A0, T0);
+}
+
+/* Stack operations */
+
+void OPPROTO op_pushw_T0(void)
+{
+ SP = (uint16_t)(SP - 2);
+ A0 = SP;
+ /* high byte pushed first: i.e. little endian */
+ stw_kernel(A0, T0);
+}
+
+void OPPROTO op_popw_T0(void)
+{
+ A0 = SP;
+ /* low byte popped first: i.e. little endian */
+ T0 = lduw_kernel(A0);
+ SP = (uint16_t)(SP + 2);
+}
+
+void OPPROTO op_popw_T1(void)
+{
+ A0 = SP;
+ /* low byte popped first: i.e. little endian */
+ T1 = lduw_kernel(A0);
+ SP = (uint16_t)(SP + 2);
+}
+
+/* Exchange operations */
+
+void OPPROTO op_ex_de_hl(void)
+{
+ T0 = DE;
+ DE = HL;
+ HL = T0;
+}
+
+void OPPROTO op_ex_af_afx(void)
+{
+ T0 = AFX;
+ AFX = (A << 8) | F;
+ A = (uint8_t)(T0 >> 8);
+ F = (uint8_t)T0;
+}
+
+void OPPROTO op_exx(void)
+{
+ T0 = BCX;
+ BCX = BC;
+ BC = T0;
+
+ T0 = DEX;
+ DEX = DE;
+ DE = T0;
+
+ T0 = HLX;
+ HLX = HL;
+ HL = T0;
+}
+
+/* Misc */
+
+void OPPROTO op_in_T0_im(void)
+{
+ helper_in_debug((A << 8) | PARAM1);
+ T0 = cpu_inb(env, (A << 8) | PARAM1);
+}
+
+void OPPROTO op_in_T0_bc_cc(void)
+{
+ int sf, zf, pf;
+
+ helper_in_debug(BC);
+ 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 OPPROTO op_out_T0_im(void)
+{
+ cpu_outb(env, (A << 8) | PARAM1, T0);
+}
+
+void OPPROTO op_out_T0_bc(void)
+{
+ cpu_outb(env, BC, T0);
+}
+
+void OPPROTO op_bit_T0(void)
+{
+ int sf, zf, pf;
+
+ sf = (T0 & PARAM1 & 0x80) ? CC_S : 0;
+ zf = (T0 & PARAM1) ? 0 : CC_Z;
+ pf = (T0 & PARAM1) ? 0 : CC_P;
+ F = (F & CC_C) | sf | zf | CC_H | pf;
+}
+
+void OPPROTO op_res_T0(void)
+{
+ T0 &= (uint8_t)PARAM1;
+}
+
+void OPPROTO op_set_T0(void)
+{
+ T0 |= (uint8_t)PARAM1;
+}
+
+void OPPROTO op_jmp_T0(void)
+{
+ PC = T0;
+}
+
+void OPPROTO op_djnz(void)
+{
+ BC = (uint16_t)(BC - 0x0100);
+ if (BC & 0xff00)
+ PC = PARAM1;
+ else
+ PC = PARAM2;
+ FORCE_RET();
+}
+
+/* Conditional jumps */
+
+void OPPROTO op_jp_nz(void)
+{
+ if (!(F & CC_Z))
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_z(void)
+{
+ if (F & CC_Z)
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_nc(void)
+{
+ if (!(F & CC_C))
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_c(void)
+{
+ if (F & CC_C)
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_po(void)
+{
+ if (!(F & CC_P))
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_pe(void)
+{
+ if (F & CC_P)
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_p(void)
+{
+ if (!(F & CC_S))
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+void OPPROTO op_jp_m(void)
+{
+ if (F & CC_S)
+ GOTO_LABEL_PARAM(1);
+ FORCE_RET();
+}
+
+/* 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 OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+// CC_DST = (uint8_t)(A - T0);
+}
+
+/* Rotation/shift operations */
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+/* Z80-specific: R800 has tst instruction */
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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 OPPROTO op_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 OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_bli_ld_rep(void)
+{
+ if (BC)
+ PC = PARAM1 - 2;
+ else
+ PC = PARAM1;
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_bli_cp_rep(void)
+{
+ if (BC && T0 != A)
+ PC = PARAM1 - 2;
+ else
+ PC = PARAM1;
+ FORCE_RET();
+}
+
+void OPPROTO op_bli_io_inc(void)
+{
+ HL = (uint16_t)(HL + 1);
+ BC = (uint16_t)BC - 0x0100;
+}
+
+void OPPROTO op_bli_io_dec(void)
+{
+ HL = (uint16_t)(HL - 1);
+ BC = (uint16_t)BC - 0x0100;
+}
+
+void OPPROTO op_bli_io_rep(void)
+{
+ if (BC & 0xff00)
+ PC = PARAM1 - 2;
+ else
+ PC = PARAM1;
+ FORCE_RET();
+}
+
+/* misc */
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+/* TODO */
+void OPPROTO op_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 OPPROTO op_cpl_cc(void)
+{
+ A = (uint8_t)~A;
+ F |= CC_H | CC_N;
+}
+
+void OPPROTO op_scf_cc(void)
+{
+ F = (F & (CC_S | CC_Z | CC_P)) | CC_C;
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+/* misc */
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+/* word operations -- HL only? */
+
+void OPPROTO op_incw_T0(void)
+{
+ T0++;
+ T0 = (uint16_t)T0;
+}
+
+void OPPROTO op_decw_T0(void)
+{
+ T0--;
+ T0 = (uint16_t)T0;
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+/* misc */
+
+void OPPROTO op_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;
+
+ FORCE_RET();
+}
+
+void OPPROTO op_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 */
+
+ FORCE_RET();
+}
+
+/* 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 OPPROTO op_imode(void)
+{
+ /* env->imode = PARAM1; */
+ env->imode = PARAM1;
+}
+
+/* enable interrupts */
+void OPPROTO op_ei(void)
+{
+ env->iff1 = 1;
+ env->iff2 = 1;
+}
+
+/* disable interrupts */
+void OPPROTO op_di(void)
+{
+ env->iff1 = 0;
+ env->iff2 = 0;
+}
+
+/* reenable interrupts if enabled */
+void OPPROTO op_ri(void)
+{
+ env->iff1 = env->iff2;
+}
+
+void OPPROTO op_halt(void)
+{
+ helper_hlt();
+}
+
+void OPPROTO op_ld_R_A(void)
+{
+ R = A;
+}
+
+void OPPROTO op_ld_I_A(void)
+{
+ I = A;
+}
+
+void OPPROTO op_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 OPPROTO op_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 OPPROTO op_dump_registers(void)
+{
+ helper_dump_registers(PARAM1);
+}
+
+/*********** END OF Z80 OPS ***********/
+
+void OPPROTO op_set_cc_op(void)
+{
+ CC_OP = PARAM1;
+}
+
+static int compute_all_eflags(void)
+{
+ return CC_SRC;
+}
+
+static int compute_c_eflags(void)
+{
+ return CC_SRC & CC_C;
+}
+
+CCTable cc_table[CC_OP_NB] = {
+ [CC_OP_DYNAMIC] = { /* should never happen */ },
+
+ [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
+};
+
+/* threading support */
+void OPPROTO op_lock(void)
+{
+ cpu_lock();
+}
+
+void OPPROTO op_unlock(void)
+{
+ cpu_unlock();
+}
diff -urN qemu-0.9.0/target-z80/opreg_template2.h qemu-z80/target-z80/opreg_template2.h
--- qemu-0.9.0/target-z80/opreg_template2.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/opreg_template2.h 2007-03-27 21:42:55.000000000 +0100
@@ -0,0 +1,63 @@
+/*
+ * Z80 micro operations (templates for various register related
+ * operations)
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void OPPROTO glue(op_movw_T0,REGPAIRNAME)(void)
+{
+ T0 = (REGHIGH << 8) | REGLOW;
+}
+
+void OPPROTO glue(op_movb_T0,REGHIGHNAME)(void)
+{
+ T0 = REGHIGH;
+}
+
+void OPPROTO glue(op_movb_T0,REGLOWNAME)(void)
+{
+ T0 = REGLOW;
+}
+
+void OPPROTO glue(op_movw_T1,REGPAIRNAME)(void)
+{
+ T1 = (REGHIGH << 8) | REGLOW;
+}
+
+void OPPROTO glue(glue(op_movw,REGPAIRNAME),_T0)(void)
+{
+ REGHIGH = (uint8_t)(T0 >> 8);
+ REGLOW = (uint8_t)T0;
+}
+
+void OPPROTO glue(glue(op_movb,REGHIGHNAME),_T0)(void)
+{
+ REGHIGH = (uint8_t)T0;
+}
+
+void OPPROTO glue(glue(op_movb,REGLOWNAME),_T0)(void)
+{
+ REGLOW = (uint8_t)T0;
+}
+
+void OPPROTO glue(glue(op_movw,REGPAIRNAME),_T1)(void)
+{
+ REGHIGH = (uint16_t)(T1 >> 8);
+ REGLOW = (uint16_t)T1;
+}
diff -urN qemu-0.9.0/target-z80/opreg_template.h qemu-z80/target-z80/opreg_template.h
--- qemu-0.9.0/target-z80/opreg_template.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/opreg_template.h 2007-03-27 21:43:07.000000000 +0100
@@ -0,0 +1,74 @@
+/*
+ * Z80 micro operations (templates for various register related
+ * operations)
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void OPPROTO glue(op_movw_T0,REGNAME)(void)
+{
+ T0 = REG;
+}
+
+#ifdef REGHIGH
+void OPPROTO glue(op_movb_T0,REGHIGH)(void)
+{
+ T0 = (REG >> 8) & 0xff;
+}
+#endif
+
+#ifdef REGLOW
+void OPPROTO glue(op_movb_T0,REGLOW)(void)
+{
+ T0 = REG & 0xff;
+}
+#endif
+
+void OPPROTO glue(op_movw_T1,REGNAME)(void)
+{
+ T1 = REG;
+}
+
+void OPPROTO glue(op_movw_A0,REGNAME)(void)
+{
+ A0 = REG;
+}
+
+void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
+{
+ REG = (uint16_t)T0;
+}
+
+#ifdef REGHIGH
+void OPPROTO glue(glue(op_movb,REGHIGH),_T0)(void)
+{
+ REG = (REG & 0xff) | ((T0 & 0xff) << 8);
+}
+#endif
+
+#ifdef REGLOW
+void OPPROTO glue(glue(op_movb,REGLOW),_T0)(void)
+{
+ REG = (REG & 0xff00) | (T0 & 0xff);
+}
+#endif
+
+void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
+{
+ REG = (uint16_t)T1;
+}
diff -urN qemu-0.9.0/target-z80/ops_mem.h qemu-z80/target-z80/ops_mem.h
--- qemu-0.9.0/target-z80/ops_mem.h 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/ops_mem.h 2007-04-15 19:39:49.000000000 +0100
@@ -0,0 +1,59 @@
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldub, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldsb, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(lduw, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldsw, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldub, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldsb, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(lduw, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldsw, MEMSUFFIX)(A0);
+}
+
+void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
+{
+ glue(stb, MEMSUFFIX)(A0, T0);
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
+{
+ glue(stw, MEMSUFFIX)(A0, T0);
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void)
+{
+ glue(stw, MEMSUFFIX)(A0, T1);
+ FORCE_RET();
+}
+
+#undef MEMSUFFIX
diff -urN qemu-0.9.0/target-z80/translate.c qemu-z80/target-z80/translate.c
--- qemu-0.9.0/target-z80/translate.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/target-z80/translate.c 2007-04-25 17:54:16.000000000 +0100
@@ -0,0 +1,1600 @@
+/*
+ * Z80 translation
+ *
+ * Copyright (c) 2007 Stuart Brady
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <assert.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+
+/* XXX: move that elsewhere */
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
+
+#define PREFIX_CB 0x01
+#define PREFIX_DD 0x02
+#define PREFIX_ED 0x04
+#define PREFIX_FD 0x08
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
+//#define zprintf(...)
+#define zprintf printf
+
+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) */
+ /* current block context */
+ target_ulong cs_base; /* base of CS segment */
+ int cc_op; /* current CC operation */
+ 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);
+
+/* i386 arith/logic operations */
+enum {
+ OP_ADDL,
+ OP_ORL,
+ OP_ADCL,
+ OP_SBBL,
+ OP_ANDL,
+ OP_SUBL,
+ OP_XORL,
+ OP_CMPL,
+};
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc.h"
+#undef DEF
+ NB_OPS,
+};
+
+#include "gen-op.h"
+
+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,
+};
+
+char *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)",
+};
+
+char *idxnames[] = {
+ [OR_IXmem] = "ix",
+ [OR_IYmem] = "iy",
+};
+
+/* signed hex byte value for printf */
+#define shexb(val) (val < 0 ? '-' : '+'), (abs(val))
+
+static GenOpFunc *gen_op_movb_T0_reg[] = {
+ [OR_B] = gen_op_movb_T0_B,
+ [OR_C] = gen_op_movb_T0_C,
+ [OR_D] = gen_op_movb_T0_D,
+ [OR_E] = gen_op_movb_T0_E,
+ [OR_H] = gen_op_movb_T0_H,
+ [OR_L] = gen_op_movb_T0_L,
+ [OR_HLmem] = gen_op_movb_T0_HLmem,
+ [OR_A] = gen_op_movb_T0_A,
+
+ [OR_IXh] = gen_op_movb_T0_IXh,
+ [OR_IXl] = gen_op_movb_T0_IXl,
+
+ [OR_IYh] = gen_op_movb_T0_IYh,
+ [OR_IYl] = gen_op_movb_T0_IYl,
+};
+
+static GenOpFunc1 *gen_op_movb_T0_idx[] = {
+ [OR_IXmem] = gen_op_movb_T0_IXmem,
+ [OR_IYmem] = gen_op_movb_T0_IYmem,
+};
+
+static GenOpFunc *gen_op_movb_reg_T0[] = {
+ [OR_B] = gen_op_movb_B_T0,
+ [OR_C] = gen_op_movb_C_T0,
+ [OR_D] = gen_op_movb_D_T0,
+ [OR_E] = gen_op_movb_E_T0,
+ [OR_H] = gen_op_movb_H_T0,
+ [OR_L] = gen_op_movb_L_T0,
+ [OR_HLmem] = gen_op_movb_HLmem_T0,
+ [OR_A] = gen_op_movb_A_T0,
+
+ [OR_IXh] = gen_op_movb_IXh_T0,
+ [OR_IXl] = gen_op_movb_IXl_T0,
+
+ [OR_IYh] = gen_op_movb_IYh_T0,
+ [OR_IYl] = gen_op_movb_IYl_T0,
+};
+
+static GenOpFunc1 *gen_op_movb_idx_T0[] = {
+ [OR_IXmem] = gen_op_movb_IXmem_T0,
+ [OR_IYmem] = gen_op_movb_IYmem_T0,
+};
+
+static inline int regmap(int reg, int m) {
+ switch (m) {
+ case 1:
+ switch (reg) {
+ case OR_H:
+ return OR_IXh;
+ case OR_L:
+ return OR_IXl;
+ case OR_HLmem:
+ return OR_IXmem;
+ default:
+ return reg;
+ }
+ case 2:
+ switch (reg) {
+ case OR_H:
+ return OR_IYh;
+ case OR_L:
+ return OR_IYl;
+ case OR_HLmem:
+ return OR_IYmem;
+ default:
+ return reg;
+ }
+ default:
+ return reg;
+ }
+}
+
+static inline int is_indexed(int reg) {
+ if (reg == OR_IXmem || reg == OR_IYmem)
+ return 1;
+ else
+ return 0;
+}
+
+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,
+};
+
+char *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 GenOpFunc *gen_op_movw_T0_reg[] = {
+ [OR2_AF] = gen_op_movw_T0_AF,
+ [OR2_BC] = gen_op_movw_T0_BC,
+ [OR2_DE] = gen_op_movw_T0_DE,
+ [OR2_HL] = gen_op_movw_T0_HL,
+
+ [OR2_IX] = gen_op_movw_T0_IX,
+ [OR2_IY] = gen_op_movw_T0_IY,
+ [OR2_SP] = gen_op_movw_T0_SP,
+
+ [OR2_AFX] = gen_op_movw_T0_AFX,
+ [OR2_BCX] = gen_op_movw_T0_BCX,
+ [OR2_DEX] = gen_op_movw_T0_DEX,
+ [OR2_HLX] = gen_op_movw_T0_HLX,
+};
+
+static GenOpFunc *gen_op_movw_T1_reg[] = {
+ [OR2_AF] = gen_op_movw_T1_AF,
+ [OR2_BC] = gen_op_movw_T1_BC,
+ [OR2_DE] = gen_op_movw_T1_DE,
+ [OR2_HL] = gen_op_movw_T1_HL,
+
+ [OR2_IX] = gen_op_movw_T1_IX,
+ [OR2_IY] = gen_op_movw_T1_IY,
+ [OR2_SP] = gen_op_movw_T1_SP,
+
+ [OR2_AFX] = gen_op_movw_T1_AFX,
+ [OR2_BCX] = gen_op_movw_T1_BCX,
+ [OR2_DEX] = gen_op_movw_T1_DEX,
+ [OR2_HLX] = gen_op_movw_T1_HLX,
+};
+
+static GenOpFunc *gen_op_movw_reg_T0[] = {
+ [OR2_AF] = gen_op_movw_AF_T0,
+ [OR2_BC] = gen_op_movw_BC_T0,
+ [OR2_DE] = gen_op_movw_DE_T0,
+ [OR2_HL] = gen_op_movw_HL_T0,
+
+ [OR2_IX] = gen_op_movw_IX_T0,
+ [OR2_IY] = gen_op_movw_IY_T0,
+ [OR2_SP] = gen_op_movw_SP_T0,
+
+ [OR2_AFX] = gen_op_movw_AFX_T0,
+ [OR2_BCX] = gen_op_movw_BCX_T0,
+ [OR2_DEX] = gen_op_movw_DEX_T0,
+ [OR2_HLX] = gen_op_movw_HLX_T0,
+};
+
+static GenOpFunc *gen_op_movw_reg_T1[] = {
+ [OR2_AF] = gen_op_movw_AF_T1,
+ [OR2_BC] = gen_op_movw_BC_T1,
+ [OR2_DE] = gen_op_movw_DE_T1,
+ [OR2_HL] = gen_op_movw_HL_T1,
+
+ [OR2_IX] = gen_op_movw_IX_T1,
+ [OR2_IY] = gen_op_movw_IY_T1,
+ [OR2_SP] = gen_op_movw_SP_T1,
+
+ [OR2_AFX] = gen_op_movw_AFX_T1,
+ [OR2_BCX] = gen_op_movw_BCX_T1,
+ [OR2_DEX] = gen_op_movw_DEX_T1,
+ [OR2_HLX] = gen_op_movw_HLX_T1,
+};
+
+static inline int regpairmap(int regpair, int m) {
+ switch (regpair) {
+ case OR2_HL:
+ switch (m) {
+ case 1:
+ return OR2_IX;
+ case 2:
+ return OR2_IY;
+ default:
+ return OR2_HL;
+ }
+ default:
+ return regpair;
+ }
+}
+
+int regpair[4] = {
+ OR2_BC,
+ OR2_DE,
+ OR2_HL,
+ OR2_SP,
+};
+
+int regpair2[4] = {
+ OR2_BC,
+ OR2_DE,
+ OR2_HL,
+ OR2_AF,
+};
+
+static inline void gen_jmp_im(target_ulong pc)
+{
+ gen_op_movl_pc_im(pc);
+}
+
+static void gen_debug(DisasContext *s, target_ulong cur_pc)
+{
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_jmp_im(cur_pc);
+ gen_op_debug();
+ s->is_jmp = 3;
+}
+
+static void gen_eob(DisasContext *s)
+{
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
+ gen_op_reset_inhibit_irq();
+ }
+ if (s->singlestep_enabled) {
+ gen_op_debug();
+ } else {
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ }
+ s->is_jmp = 3;
+}
+
+static void gen_exception(DisasContext *s, int trapno, target_ulong cur_pc)
+{
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_jmp_im(cur_pc);
+ gen_op_raise_exception(trapno);
+ s->is_jmp = 3;
+}
+
+/* Conditions */
+
+char *cc[8] = {
+ "nz",
+ "z",
+ "nc",
+ "c",
+ "po",
+ "pe",
+ "p",
+ "m",
+};
+
+static GenOpFunc1 *gen_op_jp_cc[8] = {
+ gen_op_jp_nz,
+ gen_op_jp_z,
+ gen_op_jp_nc,
+ gen_op_jp_c,
+ gen_op_jp_po,
+ gen_op_jp_pe,
+ gen_op_jp_p,
+ gen_op_jp_m,
+};
+
+enum {
+ COND_NZ,
+ COND_Z,
+ COND_NC,
+ COND_C,
+ COND_PO,
+ COND_PE,
+ COND_P,
+ COND_M,
+};
+
+/* Arithmetic/logic operations */
+
+char *alu[8] = {
+ "add a,",
+ "adc a,",
+ "sub ",
+ "sbc a,",
+ "and ",
+ "xor ",
+ "or ",
+ "cp ",
+};
+
+static GenOpFunc *gen_op_alu[8] = {
+ gen_op_add_cc,
+ gen_op_adc_cc,
+ gen_op_sub_cc,
+ gen_op_sbc_cc,
+ gen_op_and_cc,
+ gen_op_xor_cc,
+ gen_op_or_cc,
+ gen_op_cp_cc,
+};
+
+/* Rotation/shift operations */
+
+char *rot[8] = {
+ "rlc",
+ "rrc",
+ "rl",
+ "rr",
+ "sla",
+ "sra",
+ "sll",
+ "srl",
+};
+
+static GenOpFunc *gen_op_rot_T0[8] = {
+ gen_op_rlc_T0_cc,
+ gen_op_rrc_T0_cc,
+ gen_op_rl_T0_cc,
+ gen_op_rr_T0_cc,
+ gen_op_sla_T0_cc,
+ gen_op_sra_T0_cc,
+ gen_op_sll_T0_cc,
+ gen_op_srl_T0_cc,
+};
+
+/* Block instructions */
+
+char *bli[4][4] = {
+ { "ldi", "cpi", "ini", "outi", },
+ { "ldd", "cpd", "ind", "outd", },
+ { "ldir", "cpir", "inir", "otir", },
+ { "lddr", "cpdr", "indr", "otdr", },
+};
+
+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)
+{
+// TranslationBlock *tb;
+//
+// if (tb_num == 0)
+// gen_op_goto_tb0(TBPARAM(tb));
+// else
+// gen_op_goto_tb1(TBPARAM(tb));
+// gen_jmp_im(pc);
+// gen_op_movl_T0_im((long)tb + tb_num);
+// gen_op_exit_tb();
+
+ gen_jmp_im(pc);
+ gen_eob(s);
+}
+
+static inline void gen_jcc(DisasContext *s, int cc,
+ target_ulong val, target_ulong next_pc) {
+ TranslationBlock *tb;
+ GenOpFunc1 *func;
+ int l1;
+
+ func = gen_op_jp_cc[cc];
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+ func(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;
+ GenOpFunc1 *func;
+ int l1;
+
+ func = gen_op_jp_cc[cc];
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+ func(l1);
+
+ gen_goto_tb(s, 0, next_pc);
+
+ gen_set_label(l1);
+ gen_op_mov_T0_im(next_pc);
+ gen_op_pushw_T0();
+ 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;
+ GenOpFunc1 *func;
+ int l1;
+
+ func = gen_op_jp_cc[cc];
+
+ tb = s->tb;
+
+ l1 = gen_new_label();
+ func(l1);
+
+ gen_goto_tb(s, 0, next_pc);
+
+ gen_set_label(l1);
+ gen_op_popw_T0();
+ gen_op_jmp_T0();
+ gen_eob(s);
+
+ s->is_jmp = 3;
+}
+
+/* TODO: do flags properly, using cc_table. */
+/* (search for compute_all in i386 code) */
+/* see also opc_read_flags[], opc_write_flags[] and opc_simpler[] */
+
+/* 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);
+// gen_op_dump_registers(s->pc);
+next_byte:
+ s->prefix = prefixes;
+
+/* START */
+
+ if (prefixes & PREFIX_DD)
+ m = 1;
+ else if (prefixes & PREFIX_FD)
+ m = 2;
+ else
+ m = 0;
+
+ /* 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_op_ex_af_afx();
+ zprintf("ex af,af'\n");
+ break;
+ case 2:
+ n = ldsb_code(s->pc);
+ s->pc++;
+ gen_op_djnz(s->pc + n, 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;
+ gen_op_mov_T0_im(n);
+ r1 = regpairmap(regpair[p], m);
+ gen_op_movw_reg_T0[r1]();
+ zprintf("ld %s,$%04x\n", regpairnames[r1], n);
+ break;
+ case 1:
+ r1 = regpairmap(regpair[p], m);
+ r2 = regpairmap(OR2_HL, m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_movw_T1_reg[r2]();
+ gen_op_addw_T0_T1_cc();
+ gen_op_movw_reg_T0[r2]();
+ zprintf("add %s,%s\n", regpairnames[r2], regpairnames[r1]);
+ break;
+ }
+ break;
+
+ case 2:
+ switch (q) {
+ case 0:
+ switch (p) {
+ case 0:
+ gen_op_movb_T0_reg[OR_A]();
+ gen_op_movw_A0_BC();
+ gen_op_stb_T0_A0();
+ zprintf("ld (bc),a\n");
+ break;
+ case 1:
+ gen_op_movb_T0_reg[OR_A]();
+ gen_op_movw_A0_DE();
+ gen_op_stb_T0_A0();
+ zprintf("ld (de),a\n");
+ break;
+ case 2:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(OR2_HL, m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_mov_A0_im(n);
+ gen_op_stw_T0_A0();
+ zprintf("ld ($%04x),%s\n", n, regpairnames[r1]);
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_op_movb_T0_reg[OR_A]();
+ gen_op_mov_A0_im(n);
+ gen_op_stb_T0_A0();
+ zprintf("ld ($%04x),a\n", n);
+ break;
+ }
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ gen_op_movw_A0_BC();
+ gen_op_ldb_T0_A0();
+ gen_op_movb_reg_T0[OR_A]();
+ zprintf("ld a,(bc)\n");
+ break;
+ case 1:
+ gen_op_movw_A0_DE();
+ gen_op_ldb_T0_A0();
+ gen_op_movb_reg_T0[OR_A]();
+ zprintf("ld a,(de)\n");
+ break;
+ case 2:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(OR2_HL, m);
+ gen_op_mov_A0_im(n);
+ gen_op_ldw_T0_A0();
+ gen_op_movw_reg_T0[r1]();
+ zprintf("ld %s,($%04x)\n", regpairnames[r1], n);
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_op_mov_A0_im(n);
+ gen_op_ldb_T0_A0();
+ gen_op_movb_reg_T0[OR_A]();
+ zprintf("ld a,($%04x)\n", n);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 3:
+ switch (q) {
+ case 0:
+ r1 = regpairmap(regpair[p], m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_incw_T0();
+ gen_op_movw_reg_T0[r1]();
+ zprintf("inc %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ r1 = regpairmap(regpair[p], m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_decw_T0();
+ gen_op_movw_reg_T0[r1]();
+ 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_op_movb_T0_idx[r1](d);
+ } else
+ gen_op_movb_T0_reg[r1]();
+ gen_op_incb_T0_cc();
+ if (is_indexed(r1))
+ gen_op_movb_idx_T0[r1](d);
+ else
+ gen_op_movb_reg_T0[r1]();
+ 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_op_movb_T0_idx[r1](d);
+ } else
+ gen_op_movb_T0_reg[r1]();
+ gen_op_decb_T0_cc();
+ if (is_indexed(r1))
+ gen_op_movb_idx_T0[r1](d);
+ else
+ gen_op_movb_reg_T0[r1]();
+ 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++;
+ gen_op_mov_T0_im(n);
+ if (is_indexed(r1))
+ gen_op_movb_idx_T0[r1](d);
+ else
+ gen_op_movb_reg_T0[r1]();
+ 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_op_rlca_cc();
+ zprintf("rlca\n");
+ break;
+ case 1:
+ gen_op_rrca_cc();
+ zprintf("rrca\n");
+ break;
+ case 2:
+ gen_op_rla_cc();
+ zprintf("rla\n");
+ break;
+ case 3:
+ gen_op_rra_cc();
+ zprintf("rra\n");
+ break;
+ case 4:
+ gen_op_daa_cc();
+ zprintf("daa\n");
+ break;
+ case 5:
+ gen_op_cpl_cc();
+ zprintf("cpl\n");
+ break;
+ case 6:
+ gen_op_scf_cc();
+ zprintf("scf\n");
+ break;
+ case 7:
+ gen_op_ccf_cc();
+ zprintf("ccf\n");
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 1:
+ if (z == 6 && y == 6) {
+//FIXME
+// gen_op_halt();
+// gen_eob(s);
+// s->is_jmp = 3;
+ 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_op_movb_T0_idx[r1](d);
+ else
+ gen_op_movb_T0_reg[r1]();
+ if (is_indexed(r2))
+ gen_op_movb_idx_T0[r2](d);
+ else
+ gen_op_movb_reg_T0[r2]();
+ 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_op_movb_T0_idx[r1](d);
+ } else
+ gen_op_movb_T0_reg[r1]();
+ gen_op_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_op_popw_T0();
+ gen_op_movw_reg_T0[r1]();
+ zprintf("pop %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ gen_op_popw_T0();
+ gen_op_jmp_T0();
+ zprintf("ret\n");
+ gen_eob(s);
+ s->is_jmp = 3;
+// s->is_ei = 1;
+ break;
+ case 1:
+ gen_op_exx();
+ zprintf("exx\n");
+ break;
+ case 2:
+ r1 = regpairmap(OR2_HL, m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_jmp_T0();
+ zprintf("jp %s\n", regpairnames[r1]);
+ gen_eob(s);
+ s->is_jmp = 3;
+ break;
+ case 3:
+ r1 = regpairmap(OR2_HL, m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_movw_reg_T0[OR2_SP]();
+ zprintf("ld sp,%s\n", regpairnames[r1]);
+ gen_op_dump_registers(s->pc);
+ 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_op_movb_T0_reg[OR_A]();
+ gen_op_out_T0_im(n);
+ zprintf("out ($%02x),a\n", n);
+ break;
+ case 3:
+ n = ldub_code(s->pc);
+ s->pc++;
+ gen_op_in_T0_im(n);
+ gen_op_movb_reg_T0[OR_A]();
+ zprintf("in a,($%02x)\n", n);
+ break;
+ case 4:
+ r1 = regpairmap(OR2_HL, m);
+ gen_op_popw_T1();
+ gen_op_movw_T0_reg[r1]();
+ gen_op_pushw_T0();
+ gen_op_movw_reg_T1[r1]();
+ zprintf("ex (sp),%s\n", regpairnames[r1]);
+ break;
+ case 5:
+ gen_op_ex_de_hl();
+ zprintf("ex de,hl\n");
+ break;
+ case 6:
+ gen_op_di();
+ zprintf("di\n");
+ break;
+ case 7:
+ gen_op_ei();
+// gen_op_dump_registers(s->pc);
+ 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_op_movw_T0_reg[r1]();
+ gen_op_pushw_T0();
+ zprintf("push %s\n", regpairnames[r1]);
+ break;
+ case 1:
+ switch (p) {
+ case 0:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ gen_op_mov_T0_im(s->pc);
+ gen_op_pushw_T0();
+ 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++;
+ gen_op_mov_T0_im(n);
+ gen_op_alu[y](); /* places output in A */
+ zprintf("%s$%02x\n", alu[y], n);
+ break;
+
+ case 7:
+ gen_op_mov_T0_im(s->pc);
+ gen_op_pushw_T0();
+ 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) {
+ 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) {
+ r1 = regmap(OR_HLmem, m);
+ gen_op_movb_T0_idx[r1](d);
+ if (z != 6)
+ r2 = regmap(reg[z], 0);
+ } else {
+ r1 = regmap(reg[z], m);
+ gen_op_movb_T0_reg[r1]();
+ }
+
+ switch (x) {
+ case 0:
+ gen_op_rot_T0[y]();
+ if (m) {
+ gen_op_movb_idx_T0[r1](d);
+ if (z != 6)
+ gen_op_movb_reg_T0[r2]();
+ } else {
+ gen_op_movb_reg_T0[r1]();
+ }
+ zprintf("%s %s\n", rot[y], regnames[r1]);
+ break;
+ case 1:
+ gen_op_bit_T0(1 << y);
+ zprintf("bit %i,%s\n", y, regnames[r1]);
+ break;
+ case 2:
+ gen_op_res_T0(~(1 << y));
+ if (m) {
+ gen_op_movb_idx_T0[r1](d);
+ if (z != 6)
+ gen_op_movb_reg_T0[r2]();
+ } else {
+ gen_op_movb_reg_T0[r1]();
+ }
+ zprintf("res %i,%s\n", y, regnames[r1]);
+ break;
+ case 3:
+ gen_op_set_T0(1 << y);
+ if (m) {
+ gen_op_movb_idx_T0[r1](d);
+ if (z != 6)
+ gen_op_movb_reg_T0[r2]();
+ } else {
+ gen_op_movb_reg_T0[r1]();
+ }
+ 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:
+ case 3:
+ zprintf("nop\n");
+ break;
+
+ case 1:
+ switch (z) {
+ case 0:
+ gen_op_in_T0_bc_cc();
+ if (y != 6) {
+ r1 = regmap(reg[y], m);
+ gen_op_movb_reg_T0[r1]();
+ zprintf("in %s,(c)\n", regnames[r1]);
+ } else {
+ zprintf("in (c)\n");
+ }
+ break;
+ case 1:
+ if (y != 6) {
+ r1 = regmap(reg[y], m);
+ gen_op_movb_T0_reg[r1]();
+ zprintf("out (c),%s\n", regnames[r1]);
+ } else {
+ gen_op_mov_T0_im(0);
+ zprintf("out (c),0\n");
+ }
+ gen_op_out_T0_bc();
+ break;
+ case 2:
+ r1 = regpairmap(OR2_HL, m);
+ r2 = regpairmap(regpair[p], m);
+ gen_op_movw_T0_reg[r1]();
+ gen_op_movw_T1_reg[r2]();
+ if (q == 0) {
+ zprintf("sbc %s,%s\n", regpairnames[r1], regpairnames[r2]);
+ gen_op_sbcw_T0_T1_cc();
+ } else {
+ zprintf("adc %s,%s\n", regpairnames[r1], regpairnames[r2]);
+ gen_op_adcw_T0_T1_cc();
+ }
+ gen_op_movw_reg_T0[r1]();
+ break;
+ case 3:
+ n = lduw_code(s->pc);
+ s->pc += 2;
+ r1 = regpairmap(regpair[p], m);
+ if (q == 0) {
+ gen_op_movw_T0_reg[r1]();
+ gen_op_mov_A0_im(n);
+ gen_op_stw_T0_A0();
+ zprintf("ld ($%02x),%s\n", n, regpairnames[r1]);
+ } else {
+ gen_op_mov_A0_im(n);
+ gen_op_ldw_T0_A0();
+ gen_op_movw_reg_T0[r1]();
+ zprintf("ld %s,($%02x)\n", regpairnames[r1], n);
+ }
+ break;
+ case 4:
+ zprintf("neg\n");
+ gen_op_neg_cc();
+ break;
+ case 5:
+ /* FIXME */
+ gen_op_popw_T0();
+ gen_op_jmp_T0();
+ gen_op_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_op_imode(imode[y]);
+ zprintf("im im[%i]\n", imode[y]);
+// gen_eob(s);
+// s->is_ei = 1;
+ break;
+ case 7:
+ switch (y) {
+ case 0:
+ gen_op_ld_I_A();
+ zprintf("ld i,a\n");
+ break;
+ case 1:
+ gen_op_ld_R_A();
+ zprintf("ld r,a\n");
+ break;
+ case 2:
+ gen_op_ld_A_I();
+ zprintf("ld a,i\n");
+ break;
+ case 3:
+ gen_op_ld_A_R();
+ zprintf("ld a,r\n");
+ break;
+ case 4:
+ gen_op_movb_T0_reg[OR_HLmem]();
+ gen_op_rrd_cc();
+ gen_op_movb_reg_T0[OR_HLmem]();
+ zprintf("rrd\n");
+ break;
+ case 5:
+ gen_op_movb_T0_reg[OR_HLmem]();
+ gen_op_rld_cc();
+ gen_op_movb_reg_T0[OR_HLmem]();
+ 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_op_movw_A0_HL();
+ gen_op_ldb_T0_A0();
+ gen_op_movw_A0_DE();
+ gen_op_stb_T0_A0();
+
+ if (!(y & 1))
+ gen_op_bli_ld_inc_cc();
+ else
+ gen_op_bli_ld_dec_cc();
+ if ((y & 2)) {
+ gen_op_bli_ld_rep(s->pc);
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ break;
+
+ case 1: /* cpi/cpd/cpir/cpdr */
+ gen_op_movw_A0_HL();
+ gen_op_ldb_T0_A0();
+ gen_op_bli_cp_cc();
+
+ if (!(y & 1))
+ gen_op_bli_cp_inc_cc();
+ else
+ gen_op_bli_cp_dec_cc();
+ if ((y & 2)) {
+ gen_op_bli_cp_rep(s->pc);
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ break;
+
+ case 2: /* ini/ind/inir/indr */
+ gen_op_in_T0_bc_cc();
+ gen_op_movw_A0_HL();
+ gen_op_stb_T0_A0();
+ if (!(y & 1))
+ gen_op_bli_io_inc();
+ else
+ gen_op_bli_io_dec();
+ if ((y & 2)) {
+ gen_op_bli_io_rep(s->pc);
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ break;
+
+ case 3: /* outi/outd/otir/otdr */
+ gen_op_movw_A0_HL();
+ gen_op_ldb_T0_A0();
+ gen_op_out_T0_bc();
+ if (!(y & 1))
+ gen_op_bli_io_inc();
+ else
+ gen_op_bli_io_dec();
+ if ((y & 2)) {
+ gen_op_bli_io_rep(s->pc);
+ gen_eob(s);
+ s->is_jmp = 3;
+ }
+ 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)
+
+static uint8_t opc_read_flags[NB_OPS] = {
+ [INDEX_op_jp_nz] = CC_SZHPNC,
+ [INDEX_op_jp_z] = CC_SZHPNC,
+ [INDEX_op_jp_nc] = CC_SZHPNC,
+ [INDEX_op_jp_c] = CC_SZHPNC,
+ [INDEX_op_jp_po] = CC_SZHPNC,
+ [INDEX_op_jp_pe] = CC_SZHPNC,
+ [INDEX_op_jp_p] = CC_SZHPNC,
+ [INDEX_op_jp_m] = CC_SZHPNC,
+//...
+};
+
+static uint8_t opc_write_flags[NB_OPS] = {
+ [INDEX_op_add_cc] = CC_SZHPNC,
+ [INDEX_op_adc_cc] = CC_SZHPNC,
+ [INDEX_op_sub_cc] = CC_SZHPNC,
+ [INDEX_op_sbc_cc] = CC_SZHPNC,
+ [INDEX_op_and_cc] = CC_SZHPNC,
+ [INDEX_op_xor_cc] = CC_SZHPNC,
+ [INDEX_op_or_cc] = CC_SZHPNC,
+ [INDEX_op_cp_cc] = CC_SZHPNC,
+//...
+};
+
+static uint16_t opc_simpler[NB_OPS] = {
+#if 0
+ [INDEX_op_add_cc] = INDEX_op_add,
+ [INDEX_op_adc_cc] = INDEX_op_adc,
+ [INDEX_op_sub_cc] = INDEX_op_sub,
+ [INDEX_op_sbc_cc] = INDEX_op_sbc,
+ [INDEX_op_and_cc] = INDEX_op_and,
+ [INDEX_op_xor_cc] = INDEX_op_xor,
+ [INDEX_op_or_cc] = INDEX_op_or,
+ [INDEX_op_cp_cc] = INDEX_op_cp,
+//...
+#endif
+};
+
+void optimize_flags_init(void)
+{
+ int i;
+ /* put default values in arrays */
+ for(i = 0; i < NB_OPS; i++) {
+ if (opc_simpler[i] == 0)
+ opc_simpler[i] = i;
+ }
+}
+
+/* CPU flags computation optimization: we move backward thru the
+ generated code to see which flags are needed. The operation is
+ modified if suitable */
+static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
+{
+}
+
+/* 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;
+ int flags, j, lj, cflags;
+ target_ulong pc_start;
+ target_ulong cs_base;
+
+ /* 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->cc_op = CC_OP_DYNAMIC;
+ 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;
+ nb_gen_labels = 0;
+
+ dc->is_jmp = DISAS_NEXT;
+ pc_ptr = pc_start;
+ lj = -1;
+
+ for(;;) {
+ if (env->nb_breakpoints > 0) {
+ for(j = 0; j < env->nb_breakpoints; j++) {
+ if (env->breakpoints[j] == 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_cc_op[lj] = dc->cc_op;
+ gen_opc_instr_start[lj] = 1;
+ }
+ pc_ptr = disas_insn(dc, pc_ptr);
+ /* 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) ||
+ (cflags & CF_SINGLE_INSN)) {
+ 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)) {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
+ }
+ *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
+ if (loglevel & CPU_LOG_TB_CPU) {
+ cpu_dump_state(env, logfile, fprintf, 0);
+ }
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ int disas_flags;
+ fprintf(logfile, "----------------\n");
+ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+ target_disas(logfile, pc_start, pc_ptr - pc_start, disas_flags);
+ fprintf(logfile, "\n");
+ if (loglevel & CPU_LOG_TB_OP) {
+ fprintf(logfile, "OP:\n");
+ dump_ops(gen_opc_buf, gen_opparam_buf);
+ fprintf(logfile, "\n");
+ }
+ }
+#endif
+
+ /* optimize flag computations */
+ optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
+
+#ifdef DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_OP_OPT) {
+ fprintf(logfile, "AFTER FLAGS OPT:\n");
+ dump_ops(gen_opc_buf, gen_opparam_buf);
+ fprintf(logfile, "\n");
+ }
+#endif
+ if (!search_pc)
+ tb->size = pc_ptr - pc_start;
+ return 0;
+}
+
+int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 0);
+}
+
+int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 1);
+}
+
diff -urN qemu-0.9.0/vl.c qemu-z80/vl.c
--- qemu-0.9.0/vl.c 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/vl.c 2007-04-25 17:58:06.000000000 +0100
@@ -5201,6 +5201,7 @@
qemu_get_be64s(f, &env->fmask);
qemu_get_be64s(f, &env->kernelgsbase);
#endif
+
if (version_id >= 4)
qemu_get_be32s(f, &env->smbase);
@@ -5319,6 +5320,19 @@
return 0;
}
+#elif defined(TARGET_Z80)
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+// CPUState *env = opaque;
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+// CPUState *env = opaque;
+ return 0;
+}
+
#else
#warning No CPU save/restore functions
@@ -6368,6 +6382,8 @@
qemu_register_machine(&realview_machine);
#elif defined(TARGET_SH4)
qemu_register_machine(&shix_machine);
+#elif defined(TARGET_Z80)
+ qemu_register_machine(&z80pc_machine);
#else
#error unsupported CPU
#endif
diff -urN qemu-0.9.0/vl.h qemu-z80/vl.h
--- qemu-0.9.0/vl.h 2007-02-05 23:01:54.000000000 +0000
+++ qemu-z80/vl.h 2007-04-17 20:16:51.000000000 +0100
@@ -901,6 +901,11 @@
void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size);
+/* zx_ula.c */
+void zx_ula_init(DisplayState *ds, uint8_t *zx_screen_base,
+ unsigned long zx_ram_offset);
+void zx_set_flash_dirty(void);
+
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen);
@@ -1065,6 +1070,9 @@
extern QEMUMachine isapc_machine;
extern int fd_bootchk;
+/* z80.c??? */
+extern QEMUMachine z80pc_machine;
+
void ioport_set_a20(int enable);
int ioport_get_a20(void);
diff -urN qemu-0.9.0/z80-dis.c qemu-z80/z80-dis.c
--- qemu-0.9.0/z80-dis.c 1970-01-01 01:00:00.000000000 +0100
+++ qemu-z80/z80-dis.c 2007-02-01 15:20:38.000000000 +0000
@@ -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 "
+} ;
+
+static int
+fetch_data (struct buffer *buf, disassemble_info * info, int n)
+{
+ int r;
+
+ if (buf->n_fetch + n > 4)
+ abort ();
+
+ r = info->read_memory_func (buf->base + buf->n_fetch,
+ (unsigned char*) buf->data + buf->n_fetch,
+ n, info);
+ if (r == 0)
+ buf->n_fetch += n;
+ return !r;
+}
+
+static int
+prt (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s", txt);
+ buf->n_used = buf->n_fetch;
+ return 1;
+}
+
+static int
+prt_e (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char e;
+ int target_addr;
+
+ if (fetch_data (buf, info, 1))
+ {
+ e = buf->data[1];
+ target_addr = (buf->base + 2 + e) & 0xffff;
+ buf->n_used = buf->n_fetch;
+ info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+jr_cc (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]);
+ return prt_e (buf, info, mytxt);
+}
+
+static int
+prt_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int nn;
+ unsigned char *p;
+
+ p = (unsigned char*) buf->data + buf->n_fetch;
+ if (fetch_data (buf, info, 2))
+ {
+ nn = p[0] + (p[1] << 8);
+ info->fprintf_func (info->stream, txt, nn);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+ return buf->n_used;
+}
+
+static int
+prt_rr_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, rr_str[(buf->data[0] >> 4) & 3]);
+ return prt_nn (buf, info, mytxt);
+}
+
+static int
+prt_rr (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s%s", txt,
+ rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+prt_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int n;
+ unsigned char *p;
+
+ p = (unsigned char*) buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ n = p[0];
+ info->fprintf_func (info->stream, txt, n);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+ld_r_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[0] >> 3) & 7]);
+ return prt_n (buf, info, mytxt);
+}
+
+static int
+prt_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+ld_r_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+arit_r (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt,
+ arit_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+prt_cc (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, "%s%s", txt,
+ cc_str[(buf->data[0] >> 3) & 7]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+static int
+pop_rr (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ static char *rr_stack[] = { "bc","de","hl","af"};
+
+ info->fprintf_func (info->stream, "%s %s", txt,
+ rr_stack[(buf->data[0] >> 4) & 3]);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+
+static int
+jp_cc_nn (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt,TXTSIZ,
+ "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]);
+ return prt_nn (buf, info, mytxt);
+}
+
+static int
+arit_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt,TXTSIZ, txt, arit_str[(buf->data[0] >> 3) & 7]);
+ return prt_n (buf, info, mytxt);
+}
+
+static int
+rst (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ info->fprintf_func (info->stream, txt, buf->data[0] & 0x38);
+ buf->n_used = buf->n_fetch;
+ return buf->n_used;
+}
+
+
+static int
+cis (struct buffer *buf, disassemble_info * info, char *txt ATTRIBUTE_UNUSED)
+{
+ static char * opar[] = { "ld", "cp", "in", "out" };
+ char * op;
+ char c;
+
+ c = buf->data[1];
+ op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]);
+ info->fprintf_func (info->stream,
+ "%s%c%s", op,
+ (c & 0x08) ? 'd' : 'i',
+ (c & 0x10) ? "r" : "");
+ buf->n_used = 2;
+ return buf->n_used;
+}
+
+static int
+dump (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int i;
+
+ info->fprintf_func (info->stream, "defb ");
+ for (i = 0; txt[i]; ++i)
+ info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x",
+ (unsigned char) buf->data[i]);
+ buf->n_used = i;
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes with prefix 0xED. */
+struct tab_elt opc_ed[] =
+{
+ { 0x70, 0xFF, prt, "in f,(c)" },
+ { 0x70, 0xFF, dump, "xx" },
+ { 0x40, 0xC7, prt_r, "in %s,(c)" },
+ { 0x71, 0xFF, prt, "out (c),0" },
+ { 0x70, 0xFF, dump, "xx" },
+ { 0x41, 0xC7, prt_r, "out (c),%s" },
+ { 0x42, 0xCF, prt_rr, "sbc hl," },
+ { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s" },
+ { 0x44, 0xFF, prt, "neg" },
+ { 0x45, 0xFF, prt, "retn" },
+ { 0x46, 0xFF, prt, "im 0" },
+ { 0x47, 0xFF, prt, "ld i,a" },
+ { 0x4A, 0xCF, prt_rr, "adc hl," },
+ { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)" },
+ { 0x4D, 0xFF, prt, "reti" },
+ { 0x56, 0xFF, prt, "im 1" },
+ { 0x57, 0xFF, prt, "ld a,i" },
+ { 0x5E, 0xFF, prt, "im 2" },
+ { 0x67, 0xFF, prt, "rrd" },
+ { 0x6F, 0xFF, prt, "rld" },
+ { 0xA0, 0xE4, cis, "" },
+ { 0xC3, 0xFF, prt, "muluw hl,bc" },
+ { 0xC5, 0xE7, prt_r, "mulub a,%s" },
+ { 0xF3, 0xFF, prt, "muluw hl,sp" },
+ { 0x00, 0x00, dump, "xx" }
+};
+
+static int
+pref_ed (struct buffer * buf, disassemble_info * info,
+ char* txt ATTRIBUTE_UNUSED)
+{
+ struct tab_elt *p;
+
+ if (fetch_data(buf, info, 1))
+ {
+ for (p = opc_ed; p->val != (buf->data[1] & p->mask); ++p)
+ ;
+ p->fp (buf, info, p->text);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Instruction names for the instructions addressing single bits. */
+static char *cb1_str[] = { "", "bit", "res", "set"};
+/* Instruction names for shifts and rotates. */
+static char *cb2_str[] =
+{
+ "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl"
+};
+
+static int
+pref_cb (struct buffer * buf, disassemble_info * info,
+ char* txt ATTRIBUTE_UNUSED)
+{
+ if (fetch_data (buf, info, 1))
+ {
+ buf->n_used = 2;
+ if ((buf->data[1] & 0xc0) == 0)
+ info->fprintf_func (info->stream, "%s %s",
+ cb2_str[(buf->data[1] >> 3) & 7],
+ r_str[buf->data[1] & 7]);
+ else
+ info->fprintf_func (info->stream, "%s %d,%s",
+ cb1_str[(buf->data[1] >> 6) & 3],
+ (buf->data[1] >> 3) & 7,
+ r_str[buf->data[1] & 7]);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+addvv (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ info->fprintf_func (info->stream, "add %s,%s", txt, txt);
+
+ return buf->n_used = buf->n_fetch;
+}
+
+static int
+ld_v_v (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ char mytxt[TXTSIZ];
+
+ snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt);
+ return ld_r_r (buf, info, mytxt);
+}
+
+static int
+prt_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ int d;
+ signed char *p;
+
+ p = buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ d = p[0];
+ info->fprintf_func (info->stream, txt, d);
+ buf->n_used = buf->n_fetch;
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+prt_d_n (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ int d;
+ signed char *p;
+
+ p = buf->data + buf->n_fetch;
+
+ if (fetch_data (buf, info, 1))
+ {
+ d = p[0];
+ snprintf (mytxt, TXTSIZ, txt, d);
+ return prt_n (buf, info, mytxt);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+static int
+arit_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, arit_str[(c >> 3) & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+ld_r_d (struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+ld_d_r(struct buffer *buf, disassemble_info * info, char *txt)
+{
+ char mytxt[TXTSIZ];
+ signed char c;
+
+ c = buf->data[buf->n_fetch - 1];
+ snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]);
+ return prt_d (buf, info, mytxt);
+}
+
+static int
+pref_xd_cb (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ if (fetch_data (buf, info, 2))
+ {
+ int d;
+ char arg[TXTSIZ];
+ signed char *p;
+
+ buf->n_used = 4;
+ p = buf->data;
+ d = p[2];
+
+ if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06))
+ snprintf (arg, TXTSIZ, "(%s%+d)", txt, d);
+ else
+ snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]);
+
+ if ((p[3] & 0xc0) == 0)
+ info->fprintf_func (info->stream, "%s %s",
+ cb2_str[(buf->data[3] >> 3) & 7],
+ arg);
+ else
+ info->fprintf_func (info->stream, "%s %d,%s",
+ cb1_str[(buf->data[3] >> 6) & 3],
+ (buf->data[3] >> 3) & 7,
+ arg);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
+static struct tab_elt opc_ind[] =
+{
+ { 0x24, 0xF7, prt_r, "inc %s%%s" },
+ { 0x25, 0xF7, prt_r, "dec %s%%s" },
+ { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x" },
+ { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x" },
+ { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s" },
+ { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)" },
+ { 0x23, 0xFF, prt, "inc %s" },
+ { 0x2B, 0xFF, prt, "dec %s" },
+ { 0x29, 0xFF, addvv, "%s" },
+ { 0x09, 0xCF, prt_rr, "add %s," },
+ { 0x34, 0xFF, prt_d, "inc (%s%%+d)" },
+ { 0x35, 0xFF, prt_d, "dec (%s%%+d)" },
+ { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x" },
+
+ { 0x76, 0xFF, dump, "h" },
+ { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)" },
+ { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s" },
+ { 0x64, 0xF6, ld_v_v, "%s" },
+ { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s" },
+ { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s" },
+
+ { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)" },
+ { 0x84, 0xC6, arit_r, "%%s%s%%s" },
+
+ { 0xE1, 0xFF, prt, "pop %s" },
+ { 0xE5, 0xFF, prt, "push %s" },
+ { 0xCB, 0xFF, pref_xd_cb, "%s" },
+ { 0xE3, 0xFF, prt, "ex (sp),%s" },
+ { 0xE9, 0xFF, prt, "jp (%s)" },
+ { 0xF9, 0xFF, prt, "ld sp,%s" },
+ { 0x00, 0x00, dump, "?" },
+} ;
+
+static int
+pref_ind (struct buffer * buf, disassemble_info * info, char* txt)
+{
+ if (fetch_data (buf, info, 1))
+ {
+ char mytxt[TXTSIZ];
+ struct tab_elt *p;
+
+ for (p = opc_ind; p->val != (buf->data[1] & p->mask); ++p)
+ ;
+ snprintf (mytxt, TXTSIZ, p->text, txt);
+ p->fp (buf, info, mytxt);
+ }
+ else
+ buf->n_used = -1;
+
+ return buf->n_used;
+}
+
+/* Table to disassemble machine codes without prefix. */
+static struct tab_elt opc_main[] =
+{
+ { 0x00, 0xFF, prt, "nop" },
+ { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x" },
+ { 0x02, 0xFF, prt, "ld (bc),a" },
+ { 0x03, 0xCF, prt_rr, "inc " },
+ { 0x04, 0xC7, prt_r, "inc %s" },
+ { 0x05, 0xC7, prt_r, "dec %s" },
+ { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x" },
+ { 0x07, 0xFF, prt, "rlca" },
+ { 0x08, 0xFF, prt, "ex af,af'" },
+ { 0x09, 0xCF, prt_rr, "add hl," },
+ { 0x0A, 0xFF, prt, "ld a,(bc)" },
+ { 0x0B, 0xCF, prt_rr, "dec " },
+ { 0x0F, 0xFF, prt, "rrca" },
+ { 0x10, 0xFF, prt_e, "djnz " },
+ { 0x12, 0xFF, prt, "ld (de),a" },
+ { 0x17, 0xFF, prt, "rla" },
+ { 0x18, 0xFF, prt_e, "jr "},
+ { 0x1A, 0xFF, prt, "ld a,(de)" },
+ { 0x1F, 0xFF, prt, "rra" },
+ { 0x20, 0xE7, jr_cc, "jr %s,"},
+ { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl" },
+ { 0x27, 0xFF, prt, "daa"},
+ { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)" },
+ { 0x2F, 0xFF, prt, "cpl" },
+ { 0x32, 0xFF, prt_nn, "ld (0x%04x),a" },
+ { 0x37, 0xFF, prt, "scf" },
+ { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)" },
+ { 0x3F, 0xFF, prt, "ccf" },
+
+ { 0x76, 0xFF, prt, "halt" },
+ { 0x40, 0xC0, ld_r_r, "ld %s,%s"},
+
+ { 0x80, 0xC0, arit_r, "%s%s" },
+
+ { 0xC0, 0xC7, prt_cc, "ret " },
+ { 0xC1, 0xCF, pop_rr, "pop" },
+ { 0xC2, 0xC7, jp_cc_nn, "jp " },
+ { 0xC3, 0xFF, prt_nn, "jp 0x%04x" },
+ { 0xC4, 0xC7, jp_cc_nn, "call " },
+ { 0xC5, 0xCF, pop_rr, "push" },
+ { 0xC6, 0xC7, arit_n, "%s0x%%02x" },
+ { 0xC7, 0xC7, rst, "rst 0x%02x" },
+ { 0xC9, 0xFF, prt, "ret" },
+ { 0xCB, 0xFF, pref_cb, "" },
+ { 0xCD, 0xFF, prt_nn, "call 0x%04x" },
+ { 0xD3, 0xFF, prt_n, "out (0x%02x),a" },
+ { 0xD9, 0xFF, prt, "exx" },
+ { 0xDB, 0xFF, prt_n, "in a,(0x%02x)" },
+ { 0xDD, 0xFF, pref_ind, "ix" },
+ { 0xE3, 0xFF, prt, "ex (sp),hl" },
+ { 0xE9, 0xFF, prt, "jp (hl)" },
+ { 0xEB, 0xFF, prt, "ex de,hl" },
+ { 0xED, 0xFF, pref_ed, ""},
+ { 0xF3, 0xFF, prt, "di" },
+ { 0xF9, 0xFF, prt, "ld sp,hl" },
+ { 0xFB, 0xFF, prt, "ei" },
+ { 0xFD, 0xFF, pref_ind, "iy" },
+ { 0x00, 0x00, prt, "????" },
+} ;
+
+int
+print_insn_z80 (bfd_vma addr, disassemble_info * info)
+{
+ struct buffer buf;
+ struct tab_elt *p;
+
+ buf.base = addr;
+ buf.n_fetch = 0;
+ buf.n_used = 0;
+
+ if (! fetch_data (& buf, info, 1))
+ return -1;
+
+ for (p = opc_main; p->val != (buf.data[0] & p->mask); ++p)
+ ;
+ p->fp (& buf, info, p->text);
+
+ return buf.n_used;
+}