diff --exclude='*.orig' --exclude=CVS -ruN qemu/configure qemu-z80/configure --- qemu/configure 2007-06-23 18:03:35.000000000 +0200 +++ qemu-z80/configure 2007-07-06 13:07:47.000000000 +0200 @@ -86,6 +86,7 @@ dsound="no" coreaudio="no" alsa="no" +libspectrum="no" fmod="no" fmod_lib="" fmod_inc="" @@ -245,6 +246,8 @@ ;; --fmod-inc=*) fmod_inc="$optarg" ;; + --enable-libspectrum) libspectrum="yes" + ;; --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no" ;; --disable-slirp) slirp="no" @@ -355,6 +358,7 @@ echo " --enable-alsa enable ALSA audio driver" echo " --enable-fmod enable FMOD audio driver" echo " --enable-dsound enable DirectSound audio driver" +echo " --enable-libspectrum enable ZX Spectrum snapshot loading" echo " --enable-system enable all system emulation targets" echo " --disable-system disable all system emulation targets" echo " --enable-linux-user enable all linux usermode emulation targets" @@ -473,7 +477,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 mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu" + target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu z80-softmmu" fi # the following are Linux specific if [ "$linux_user" = "yes" ] ; then @@ -680,6 +684,7 @@ if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" fi +echo "libspec. support $libspectrum" echo "kqemu support $kqemu" echo "Documentation $build_docs" [ ! -z "$uname_release" ] && \ @@ -841,6 +846,10 @@ echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak echo "#define CONFIG_FMOD 1" >> $config_h fi +if test "$libspectrum" = "yes" ; then + echo "CONFIG_LIBSPECTRUM=yes" >> $config_mak + echo "#define CONFIG_LIBSPECTRUM 1" >> $config_h +fi qemu_version=`head $source_path/VERSION` echo "VERSION=$qemu_version" >>$config_mak echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h @@ -1008,6 +1017,11 @@ echo "TARGET_ARCH=alpha" >> $config_mak echo "#define TARGET_ARCH \"alpha\"" >> $config_h echo "#define TARGET_ALPHA 1" >> $config_h +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 --exclude='*.orig' --exclude=CVS -ruN qemu/cpu-exec.c qemu-z80/cpu-exec.c --- qemu/cpu-exec.c 2007-06-03 20:52:15.000000000 +0200 +++ qemu-z80/cpu-exec.c 2007-07-05 18:36:50.000000000 +0200 @@ -209,6 +209,10 @@ flags = env->ps; cs_base = 0; pc = env->pc; +#elif defined(TARGET_Z80) + flags = env->hflags; + cs_base = 0; + pc = env->pc; #else #error unsupported CPU #endif @@ -284,6 +288,15 @@ #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); +#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 @@ -500,6 +513,13 @@ env->exception_index = env->pending_vector; do_interrupt(1); } +#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. */ @@ -547,6 +567,8 @@ cpu_dump_state(env, logfile, fprintf, 0); #elif defined(TARGET_ALPHA) cpu_dump_state(env, logfile, fprintf, 0); +#elif defined(TARGET_Z80) + cpu_dump_state(env, logfile, fprintf, 0); #else #error unsupported target CPU #endif @@ -741,6 +763,9 @@ #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) /* 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 --exclude='*.orig' --exclude=CVS -ruN qemu/disas.c qemu-z80/disas.c --- qemu/disas.c 2007-06-03 21:16:42.000000000 +0200 +++ qemu-z80/disas.c 2007-07-05 18:03:59.000000000 +0200 @@ -200,6 +200,8 @@ #elif defined(TARGET_ALPHA) disasm_info.mach = bfd_mach_alpha; print_insn = print_insn_alpha; +#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 --exclude='*.orig' --exclude=CVS -ruN qemu/dis-asm.h qemu-z80/dis-asm.h --- qemu/dis-asm.h 2007-04-05 09:22:49.000000000 +0200 +++ qemu-z80/dis-asm.h 2007-07-05 18:05:17.000000000 +0200 @@ -379,6 +379,7 @@ extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_alpha 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 --exclude='*.orig' --exclude=CVS -ruN qemu/exec-all.h qemu-z80/exec-all.h --- qemu/exec-all.h 2007-07-02 16:06:26.000000000 +0200 +++ qemu-z80/exec-all.h 2007-07-05 18:04:44.000000000 +0200 @@ -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); @@ -586,6 +586,8 @@ is_user = ((env->ps >> 3) & 3); #elif defined (TARGET_M68K) is_user = ((env->sr & SR_S) == 0); +#elif defined (TARGET_Z80) + is_user = 0; /* no user-mode */ #else #error unimplemented CPU #endif diff --exclude='*.orig' --exclude=CVS -ruN qemu/exec.c qemu-z80/exec.c --- qemu/exec.c 2007-07-01 20:21:11.000000000 +0200 +++ qemu-z80/exec.c 2007-07-06 12:04:38.000000000 +0200 @@ -709,6 +709,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 --exclude='*.orig' --exclude=CVS -ruN qemu/gdbstub.c qemu-z80/gdbstub.c --- qemu/gdbstub.c 2007-06-03 19:08:32.000000000 +0200 +++ qemu-z80/gdbstub.c 2007-07-05 18:03:12.000000000 +0200 @@ -718,6 +718,34 @@ for (i = 0; i < 8; i++) LOAD(env->gregs[i]); for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]); } +#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 --exclude='*.orig' --exclude=CVS -ruN qemu/hw/zx_spectrum.c qemu-z80/hw/zx_spectrum.c --- qemu/hw/zx_spectrum.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/hw/zx_spectrum.c 2007-07-06 13:17:46.000000000 +0200 @@ -0,0 +1,303 @@ +/* + * 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" +#ifdef CONFIG_LIBSPECTRUM +#include +#endif + +/* 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); +} + +#if 0 +/* MSDOS compatibility mode FPU exception support */ +/* XXX: add IGNNE support */ +void cpu_set_ferr(CPUZ80State *s) +{ + pic_set_irq(13, 1); +} +#endif + +/* 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(0x4000, 0x10000 - 0x4000, 0 | IO_MEM_RAM); + + /* 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); + +#ifdef CONFIG_LIBSPECTRUM + if(kernel_filename) { + libspectrum_id_t type; + libspectrum_class_t cls; + libspectrum_snap* snap; + uint8_t* snapmem; + libspectrum_byte* page; + int length; + int i; + if(libspectrum_init() != LIBSPECTRUM_ERROR_NONE || + libspectrum_identify_file(&type, kernel_filename, NULL, 0) != LIBSPECTRUM_ERROR_NONE || + libspectrum_identify_class(&cls, type) != LIBSPECTRUM_ERROR_NONE || + libspectrum_snap_alloc(&snap) != LIBSPECTRUM_ERROR_NONE) { + fprintf(stderr, "%s: libspectrum error\n", __FUNCTION__); + exit(1); + } + if(cls != LIBSPECTRUM_CLASS_SNAPSHOT) { + fprintf(stderr, "%s: %s is not a snapshot\n", __FUNCTION__, kernel_filename); + exit(1); + } + snapmem = malloc(65536); + length = load_image(kernel_filename, snapmem); + //printf("loaded %d bytes from %s\n",length, kernel_filename); + if(libspectrum_snap_read(snap, snapmem, length, type, NULL) != LIBSPECTRUM_ERROR_NONE) { + fprintf(stderr, "%s: failed to load snapshot %s\n", __FUNCTION__, kernel_filename); + exit(1); + } + //printf("snap pc = %d\n",libspectrum_snap_pc(snap)); + page = libspectrum_snap_pages(snap, 5); + for(i = 0x4000; i < 0x8000; i++) { + //printf("storing 0x%x in 0x%x\n",page[i-0x4000],i); + stb_phys(i, page[i - 0x4000]); + } + page = libspectrum_snap_pages(snap, 2); + for(i = 0x8000; i < 0xc000; i++) + stb_phys(i, page[i - 0x8000]); + page = libspectrum_snap_pages(snap, 0); + for(i = 0xc000; i < 0x10000; i++) + stb_phys(i, page[i - 0xc000]); + env->regs[R_A] = libspectrum_snap_a(snap); + env->regs[R_F] = libspectrum_snap_f(snap); + env->regs[R_BC] = libspectrum_snap_bc(snap); + env->regs[R_DE] = libspectrum_snap_de(snap); + env->regs[R_HL] = libspectrum_snap_hl(snap); + env->regs[R_AFX] = libspectrum_snap_a_(snap) << 8 | libspectrum_snap_f_(snap); + env->regs[R_BCX] = libspectrum_snap_bc_(snap); + env->regs[R_DEX] = libspectrum_snap_de_(snap); + env->regs[R_HLX] = libspectrum_snap_hl_(snap); + env->regs[R_IX] = libspectrum_snap_ix(snap); + env->regs[R_IY] = libspectrum_snap_iy(snap); + env->regs[R_I] = libspectrum_snap_i(snap); + env->regs[R_R] = libspectrum_snap_r(snap); + env->regs[R_SP] = libspectrum_snap_sp(snap); + env->pc = libspectrum_snap_pc(snap); + env->iff1 = libspectrum_snap_iff1(snap); + env->iff2 = libspectrum_snap_iff2(snap); + env->imode = libspectrum_snap_im(snap); + + } +#endif +} + +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 --exclude='*.orig' --exclude=CVS -ruN qemu/hw/zx_ula.c qemu-z80/hw/zx_ula.c --- qemu/hw/zx_ula.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/hw/zx_ula.c 2007-07-06 13:01:14.000000000 +0200 @@ -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, 0x2000, 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 + 0;//x4000;//zx_io_memory; + s->vram_offset = 0;//x4000;//zx_io_memory; + + /* ZX Spectrum ULA */ + register_ioport_write(0, 0x10000, 1, io_spectrum_write, s); +} diff --exclude='*.orig' --exclude=CVS -ruN qemu/Makefile qemu-z80/Makefile --- qemu/Makefile 2007-06-17 18:41:04.000000000 +0200 +++ qemu-z80/Makefile 2007-07-05 18:07:36.000000000 +0200 @@ -72,7 +72,7 @@ mkdir -p "$(DESTDIR)$(datadir)" for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ video.x openbios-sparc32 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 --exclude='*.orig' --exclude=CVS -ruN qemu/Makefile.target qemu-z80/Makefile.target --- qemu/Makefile.target 2007-06-30 19:32:17.000000000 +0200 +++ qemu-z80/Makefile.target 2007-07-06 14:59:02.000000000 +0200 @@ -315,6 +315,13 @@ LIBOBJS+= op_helper.o helper.o alpha_palcode.o endif +ifeq ($(TARGET_BASE_ARCH), z80) +LIBOBJS+=helper.o helper2.o +ifdef CONFIG_LIBSPECTRUM +LIBS+=-lspectrum +endif +endif + # NOTE: the disassembler code is only needed for debugging LIBOBJS+=disas.o ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386) @@ -347,6 +354,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 @@ -472,6 +482,10 @@ VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o VL_OBJS+= m68k-semi.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 @@ -582,9 +596,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 $@ $< @@ -601,6 +621,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 Files qemu/school.z80 and qemu-z80/school.z80 differ diff --exclude='*.orig' --exclude=CVS -ruN qemu/softmmu_header.h qemu-z80/softmmu_header.h --- qemu/softmmu_header.h 2007-05-23 21:58:10.000000000 +0200 +++ qemu-z80/softmmu_header.h 2007-07-05 18:11:08.000000000 +0200 @@ -67,6 +67,8 @@ #define CPU_MEM_INDEX ((env->ps >> 3) & 3) #elif defined (TARGET_M68K) #define CPU_MEM_INDEX ((env->sr & SR_S) == 0) +#elif defined (TARGET_Z80) +#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #else #error unsupported CPU #endif @@ -90,6 +92,8 @@ #define CPU_MEM_INDEX ((env->ps >> 3) & 3) #elif defined (TARGET_M68K) #define CPU_MEM_INDEX ((env->sr & SR_S) == 0) +#elif defined (TARGET_Z80) +#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3) #else #error unsupported CPU #endif diff --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/cpu.h qemu-z80/target-z80/cpu.h --- qemu/target-z80/cpu.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/cpu.h 2007-07-06 11:59:06.000000000 +0200 @@ -0,0 +1,243 @@ +/* + * 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 */ + int halted; + + 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 + +#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 + +#include "cpu-all.h" + +#endif /* CPU_Z80_H */ diff --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/exec.h qemu-z80/target-z80/exec.h --- qemu/target-z80/exec.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/exec.h 2007-07-05 18:30:59.000000000 +0200 @@ -0,0 +1,372 @@ +/* + * 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 +} + +static inline int cpu_halted(CPUState* env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + env->hflags &= ~HF_HALTED_MASK; + return 0; + } + return EXCP_HALTED; +} diff --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/helper2.c qemu-z80/target-z80/helper2.c --- qemu/target-z80/helper2.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/helper2.c 2007-07-05 18:37:36.000000000 +0200 @@ -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 +#include +#include +#include +#include +#include +#include + +#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_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint32_t pte, paddr, page_offset, page_size; + + pte = addr; + page_size = 4096; + + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + return paddr; +} diff --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/helper.c qemu-z80/target-z80/helper.c --- qemu/target-z80/helper.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/helper.c 2007-07-05 18:38:49.000000000 +0200 @@ -0,0 +1,276 @@ +/* + * 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 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->halted = 1; + 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 --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/op.c qemu-z80/target-z80/op.c --- qemu/target-z80/op.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/op.c 2007-07-05 18:03:12.000000000 +0200 @@ -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 --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/opreg_template2.h qemu-z80/target-z80/opreg_template2.h --- qemu/target-z80/opreg_template2.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/opreg_template2.h 2007-07-05 18:03:12.000000000 +0200 @@ -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 --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/opreg_template.h qemu-z80/target-z80/opreg_template.h --- qemu/target-z80/opreg_template.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/opreg_template.h 2007-07-05 18:03:12.000000000 +0200 @@ -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 --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/ops_mem.h qemu-z80/target-z80/ops_mem.h --- qemu/target-z80/ops_mem.h 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/ops_mem.h 2007-07-05 18:03:12.000000000 +0200 @@ -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 --exclude='*.orig' --exclude=CVS -ruN qemu/target-z80/translate.c qemu-z80/target-z80/translate.c --- qemu/target-z80/translate.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/target-z80/translate.c 2007-07-05 18:03:12.000000000 +0200 @@ -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 +#include +#include +#include +#include +#include +#include + +#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 --exclude='*.orig' --exclude=CVS -ruN qemu/vl.c qemu-z80/vl.c --- qemu/vl.c 2007-07-02 17:03:13.000000000 +0200 +++ qemu-z80/vl.c 2007-07-05 18:09:48.000000000 +0200 @@ -5595,6 +5595,7 @@ qemu_get_be64s(f, &env->fmask); qemu_get_be64s(f, &env->kernelgsbase); #endif + if (version_id >= 4) qemu_get_be32s(f, &env->smbase); @@ -5846,6 +5847,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 @@ -6997,6 +7011,8 @@ #elif defined(TARGET_M68K) qemu_register_machine(&mcf5208evb_machine); qemu_register_machine(&an5206_machine); +#elif defined(TARGET_Z80) + qemu_register_machine(&z80pc_machine); #else #error unsupported CPU #endif diff --exclude='*.orig' --exclude=CVS -ruN qemu/vl.h qemu-z80/vl.h --- qemu/vl.h 2007-06-30 19:32:17.000000000 +0200 +++ qemu-z80/vl.h 2007-07-05 18:03:12.000000000 +0200 @@ -959,6 +959,11 @@ void pci_vmsvga_init(PCIBus *bus, 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, int no_frame); @@ -1150,6 +1155,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 --exclude='*.orig' --exclude=CVS -ruN qemu/z80-dis.c qemu-z80/z80-dis.c --- qemu/z80-dis.c 1970-01-01 01:00:00.000000000 +0100 +++ qemu-z80/z80-dis.c 2007-07-05 18:03:12.000000000 +0200 @@ -0,0 +1,621 @@ +/* Print Z80 and R800 instructions + Copyright 2005 Free Software Foundation, Inc. + Contributed by Arnold Metselaar + + Taken from GDB + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "dis-asm.h" +#include + +struct buffer +{ + bfd_vma base; + int n_fetch; + int n_used; + signed char data[4]; +} ; + +typedef int (*func)(struct buffer *, disassemble_info *, char *); + +struct tab_elt +{ + unsigned char val; + unsigned char mask; + func fp; + char * text; +} ; + +#define TXTSIZ 24 +/* Names of 16-bit registers. */ +static char * rr_str[] = { "bc", "de", "hl", "sp" }; +/* Names of 8-bit registers. */ +static char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" }; +/* Texts for condition codes. */ +static char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" }; +/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */ +static char * arit_str[] = +{ + "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp " +} ; + +static int +fetch_data (struct buffer *buf, disassemble_info * info, int n) +{ + int r; + + if (buf->n_fetch + n > 4) + abort (); + + r = info->read_memory_func (buf->base + buf->n_fetch, + (unsigned char*) buf->data + buf->n_fetch, + n, info); + if (r == 0) + buf->n_fetch += n; + return !r; +} + +static int +prt (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, "%s", txt); + buf->n_used = buf->n_fetch; + return 1; +} + +static int +prt_e (struct buffer *buf, disassemble_info * info, char *txt) +{ + char e; + int target_addr; + + if (fetch_data (buf, info, 1)) + { + e = buf->data[1]; + target_addr = (buf->base + 2 + e) & 0xffff; + buf->n_used = buf->n_fetch; + info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +static int +jr_cc (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]); + return prt_e (buf, info, mytxt); +} + +static int +prt_nn (struct buffer *buf, disassemble_info * info, char *txt) +{ + int nn; + unsigned char *p; + + p = (unsigned char*) buf->data + buf->n_fetch; + if (fetch_data (buf, info, 2)) + { + nn = p[0] + (p[1] << 8); + info->fprintf_func (info->stream, txt, nn); + buf->n_used = buf->n_fetch; + } + else + buf->n_used = -1; + return buf->n_used; +} + +static int +prt_rr_nn (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt, TXTSIZ, txt, rr_str[(buf->data[0] >> 4) & 3]); + return prt_nn (buf, info, mytxt); +} + +static int +prt_rr (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, "%s%s", txt, + rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + +static int +prt_n (struct buffer *buf, disassemble_info * info, char *txt) +{ + int n; + unsigned char *p; + + p = (unsigned char*) buf->data + buf->n_fetch; + + if (fetch_data (buf, info, 1)) + { + n = p[0]; + info->fprintf_func (info->stream, txt, n); + buf->n_used = buf->n_fetch; + } + else + buf->n_used = -1; + + return buf->n_used; +} + +static int +ld_r_n (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[0] >> 3) & 7]); + return prt_n (buf, info, mytxt); +} + +static int +prt_r (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, txt, + r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + +static int +ld_r_r (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, txt, + r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7], + r_str[buf->data[buf->n_fetch - 1] & 7]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + +static int +arit_r (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, txt, + arit_str[(buf->data[buf->n_fetch - 1] >> 3) & 7], + r_str[buf->data[buf->n_fetch - 1] & 7]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + +static int +prt_cc (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, "%s%s", txt, + cc_str[(buf->data[0] >> 3) & 7]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + +static int +pop_rr (struct buffer *buf, disassemble_info * info, char *txt) +{ + static char *rr_stack[] = { "bc","de","hl","af"}; + + info->fprintf_func (info->stream, "%s %s", txt, + rr_stack[(buf->data[0] >> 4) & 3]); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + + +static int +jp_cc_nn (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt,TXTSIZ, + "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]); + return prt_nn (buf, info, mytxt); +} + +static int +arit_n (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt,TXTSIZ, txt, arit_str[(buf->data[0] >> 3) & 7]); + return prt_n (buf, info, mytxt); +} + +static int +rst (struct buffer *buf, disassemble_info * info, char *txt) +{ + info->fprintf_func (info->stream, txt, buf->data[0] & 0x38); + buf->n_used = buf->n_fetch; + return buf->n_used; +} + + +static int +cis (struct buffer *buf, disassemble_info * info, char *txt ATTRIBUTE_UNUSED) +{ + static char * opar[] = { "ld", "cp", "in", "out" }; + char * op; + char c; + + c = buf->data[1]; + op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]); + info->fprintf_func (info->stream, + "%s%c%s", op, + (c & 0x08) ? 'd' : 'i', + (c & 0x10) ? "r" : ""); + buf->n_used = 2; + return buf->n_used; +} + +static int +dump (struct buffer *buf, disassemble_info * info, char *txt) +{ + int i; + + info->fprintf_func (info->stream, "defb "); + for (i = 0; txt[i]; ++i) + info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x", + (unsigned char) buf->data[i]); + buf->n_used = i; + return buf->n_used; +} + +/* Table to disassemble machine codes with prefix 0xED. */ +struct tab_elt opc_ed[] = +{ + { 0x70, 0xFF, prt, "in f,(c)" }, + { 0x70, 0xFF, dump, "xx" }, + { 0x40, 0xC7, prt_r, "in %s,(c)" }, + { 0x71, 0xFF, prt, "out (c),0" }, + { 0x70, 0xFF, dump, "xx" }, + { 0x41, 0xC7, prt_r, "out (c),%s" }, + { 0x42, 0xCF, prt_rr, "sbc hl," }, + { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s" }, + { 0x44, 0xFF, prt, "neg" }, + { 0x45, 0xFF, prt, "retn" }, + { 0x46, 0xFF, prt, "im 0" }, + { 0x47, 0xFF, prt, "ld i,a" }, + { 0x4A, 0xCF, prt_rr, "adc hl," }, + { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)" }, + { 0x4D, 0xFF, prt, "reti" }, + { 0x56, 0xFF, prt, "im 1" }, + { 0x57, 0xFF, prt, "ld a,i" }, + { 0x5E, 0xFF, prt, "im 2" }, + { 0x67, 0xFF, prt, "rrd" }, + { 0x6F, 0xFF, prt, "rld" }, + { 0xA0, 0xE4, cis, "" }, + { 0xC3, 0xFF, prt, "muluw hl,bc" }, + { 0xC5, 0xE7, prt_r, "mulub a,%s" }, + { 0xF3, 0xFF, prt, "muluw hl,sp" }, + { 0x00, 0x00, dump, "xx" } +}; + +static int +pref_ed (struct buffer * buf, disassemble_info * info, + char* txt ATTRIBUTE_UNUSED) +{ + struct tab_elt *p; + + if (fetch_data(buf, info, 1)) + { + for (p = opc_ed; p->val != (buf->data[1] & p->mask); ++p) + ; + p->fp (buf, info, p->text); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +/* Instruction names for the instructions addressing single bits. */ +static char *cb1_str[] = { "", "bit", "res", "set"}; +/* Instruction names for shifts and rotates. */ +static char *cb2_str[] = +{ + "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl" +}; + +static int +pref_cb (struct buffer * buf, disassemble_info * info, + char* txt ATTRIBUTE_UNUSED) +{ + if (fetch_data (buf, info, 1)) + { + buf->n_used = 2; + if ((buf->data[1] & 0xc0) == 0) + info->fprintf_func (info->stream, "%s %s", + cb2_str[(buf->data[1] >> 3) & 7], + r_str[buf->data[1] & 7]); + else + info->fprintf_func (info->stream, "%s %d,%s", + cb1_str[(buf->data[1] >> 6) & 3], + (buf->data[1] >> 3) & 7, + r_str[buf->data[1] & 7]); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +static int +addvv (struct buffer * buf, disassemble_info * info, char* txt) +{ + info->fprintf_func (info->stream, "add %s,%s", txt, txt); + + return buf->n_used = buf->n_fetch; +} + +static int +ld_v_v (struct buffer * buf, disassemble_info * info, char* txt) +{ + char mytxt[TXTSIZ]; + + snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt); + return ld_r_r (buf, info, mytxt); +} + +static int +prt_d (struct buffer *buf, disassemble_info * info, char *txt) +{ + int d; + signed char *p; + + p = buf->data + buf->n_fetch; + + if (fetch_data (buf, info, 1)) + { + d = p[0]; + info->fprintf_func (info->stream, txt, d); + buf->n_used = buf->n_fetch; + } + else + buf->n_used = -1; + + return buf->n_used; +} + +static int +prt_d_n (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + int d; + signed char *p; + + p = buf->data + buf->n_fetch; + + if (fetch_data (buf, info, 1)) + { + d = p[0]; + snprintf (mytxt, TXTSIZ, txt, d); + return prt_n (buf, info, mytxt); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +static int +arit_d (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + signed char c; + + c = buf->data[buf->n_fetch - 1]; + snprintf (mytxt, TXTSIZ, txt, arit_str[(c >> 3) & 7]); + return prt_d (buf, info, mytxt); +} + +static int +ld_r_d (struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + signed char c; + + c = buf->data[buf->n_fetch - 1]; + snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]); + return prt_d (buf, info, mytxt); +} + +static int +ld_d_r(struct buffer *buf, disassemble_info * info, char *txt) +{ + char mytxt[TXTSIZ]; + signed char c; + + c = buf->data[buf->n_fetch - 1]; + snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]); + return prt_d (buf, info, mytxt); +} + +static int +pref_xd_cb (struct buffer * buf, disassemble_info * info, char* txt) +{ + if (fetch_data (buf, info, 2)) + { + int d; + char arg[TXTSIZ]; + signed char *p; + + buf->n_used = 4; + p = buf->data; + d = p[2]; + + if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06)) + snprintf (arg, TXTSIZ, "(%s%+d)", txt, d); + else + snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]); + + if ((p[3] & 0xc0) == 0) + info->fprintf_func (info->stream, "%s %s", + cb2_str[(buf->data[3] >> 3) & 7], + arg); + else + info->fprintf_func (info->stream, "%s %d,%s", + cb1_str[(buf->data[3] >> 6) & 3], + (buf->data[3] >> 3) & 7, + arg); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */ +static struct tab_elt opc_ind[] = +{ + { 0x24, 0xF7, prt_r, "inc %s%%s" }, + { 0x25, 0xF7, prt_r, "dec %s%%s" }, + { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x" }, + { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x" }, + { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s" }, + { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)" }, + { 0x23, 0xFF, prt, "inc %s" }, + { 0x2B, 0xFF, prt, "dec %s" }, + { 0x29, 0xFF, addvv, "%s" }, + { 0x09, 0xCF, prt_rr, "add %s," }, + { 0x34, 0xFF, prt_d, "inc (%s%%+d)" }, + { 0x35, 0xFF, prt_d, "dec (%s%%+d)" }, + { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x" }, + + { 0x76, 0xFF, dump, "h" }, + { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)" }, + { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s" }, + { 0x64, 0xF6, ld_v_v, "%s" }, + { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s" }, + { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s" }, + + { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)" }, + { 0x84, 0xC6, arit_r, "%%s%s%%s" }, + + { 0xE1, 0xFF, prt, "pop %s" }, + { 0xE5, 0xFF, prt, "push %s" }, + { 0xCB, 0xFF, pref_xd_cb, "%s" }, + { 0xE3, 0xFF, prt, "ex (sp),%s" }, + { 0xE9, 0xFF, prt, "jp (%s)" }, + { 0xF9, 0xFF, prt, "ld sp,%s" }, + { 0x00, 0x00, dump, "?" }, +} ; + +static int +pref_ind (struct buffer * buf, disassemble_info * info, char* txt) +{ + if (fetch_data (buf, info, 1)) + { + char mytxt[TXTSIZ]; + struct tab_elt *p; + + for (p = opc_ind; p->val != (buf->data[1] & p->mask); ++p) + ; + snprintf (mytxt, TXTSIZ, p->text, txt); + p->fp (buf, info, mytxt); + } + else + buf->n_used = -1; + + return buf->n_used; +} + +/* Table to disassemble machine codes without prefix. */ +static struct tab_elt opc_main[] = +{ + { 0x00, 0xFF, prt, "nop" }, + { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x" }, + { 0x02, 0xFF, prt, "ld (bc),a" }, + { 0x03, 0xCF, prt_rr, "inc " }, + { 0x04, 0xC7, prt_r, "inc %s" }, + { 0x05, 0xC7, prt_r, "dec %s" }, + { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x" }, + { 0x07, 0xFF, prt, "rlca" }, + { 0x08, 0xFF, prt, "ex af,af'" }, + { 0x09, 0xCF, prt_rr, "add hl," }, + { 0x0A, 0xFF, prt, "ld a,(bc)" }, + { 0x0B, 0xCF, prt_rr, "dec " }, + { 0x0F, 0xFF, prt, "rrca" }, + { 0x10, 0xFF, prt_e, "djnz " }, + { 0x12, 0xFF, prt, "ld (de),a" }, + { 0x17, 0xFF, prt, "rla" }, + { 0x18, 0xFF, prt_e, "jr "}, + { 0x1A, 0xFF, prt, "ld a,(de)" }, + { 0x1F, 0xFF, prt, "rra" }, + { 0x20, 0xE7, jr_cc, "jr %s,"}, + { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl" }, + { 0x27, 0xFF, prt, "daa"}, + { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)" }, + { 0x2F, 0xFF, prt, "cpl" }, + { 0x32, 0xFF, prt_nn, "ld (0x%04x),a" }, + { 0x37, 0xFF, prt, "scf" }, + { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)" }, + { 0x3F, 0xFF, prt, "ccf" }, + + { 0x76, 0xFF, prt, "halt" }, + { 0x40, 0xC0, ld_r_r, "ld %s,%s"}, + + { 0x80, 0xC0, arit_r, "%s%s" }, + + { 0xC0, 0xC7, prt_cc, "ret " }, + { 0xC1, 0xCF, pop_rr, "pop" }, + { 0xC2, 0xC7, jp_cc_nn, "jp " }, + { 0xC3, 0xFF, prt_nn, "jp 0x%04x" }, + { 0xC4, 0xC7, jp_cc_nn, "call " }, + { 0xC5, 0xCF, pop_rr, "push" }, + { 0xC6, 0xC7, arit_n, "%s0x%%02x" }, + { 0xC7, 0xC7, rst, "rst 0x%02x" }, + { 0xC9, 0xFF, prt, "ret" }, + { 0xCB, 0xFF, pref_cb, "" }, + { 0xCD, 0xFF, prt_nn, "call 0x%04x" }, + { 0xD3, 0xFF, prt_n, "out (0x%02x),a" }, + { 0xD9, 0xFF, prt, "exx" }, + { 0xDB, 0xFF, prt_n, "in a,(0x%02x)" }, + { 0xDD, 0xFF, pref_ind, "ix" }, + { 0xE3, 0xFF, prt, "ex (sp),hl" }, + { 0xE9, 0xFF, prt, "jp (hl)" }, + { 0xEB, 0xFF, prt, "ex de,hl" }, + { 0xED, 0xFF, pref_ed, ""}, + { 0xF3, 0xFF, prt, "di" }, + { 0xF9, 0xFF, prt, "ld sp,hl" }, + { 0xFB, 0xFF, prt, "ei" }, + { 0xFD, 0xFF, pref_ind, "iy" }, + { 0x00, 0x00, prt, "????" }, +} ; + +int +print_insn_z80 (bfd_vma addr, disassemble_info * info) +{ + struct buffer buf; + struct tab_elt *p; + + buf.base = addr; + buf.n_fetch = 0; + buf.n_used = 0; + + if (! fetch_data (& buf, info, 1)) + return -1; + + for (p = opc_main; p->val != (buf.data[0] & p->mask); ++p) + ; + p->fp (& buf, info, p->text); + + return buf.n_used; +}