qemu/qemu-z80.diff

5637 lines
144 KiB
Diff
Raw Normal View History

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;
+}