5637 lines
144 KiB
Diff
5637 lines
144 KiB
Diff
|
diff -urN qemu-0.9.0/configure qemu-z80/configure
|
|||
|
--- qemu-0.9.0/configure 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/configure 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -415,7 +415,7 @@
|
|||
|
if test -z "$target_list" ; then
|
|||
|
# these targets are portable
|
|||
|
if [ "$softmmu" = "yes" ] ; then
|
|||
|
- target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
|
|||
|
+ target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu z80-softmmu"
|
|||
|
fi
|
|||
|
# the following are Linux specific
|
|||
|
if [ "$linux_user" = "yes" ] ; then
|
|||
|
@@ -911,6 +911,11 @@
|
|||
|
echo "#define TARGET_ARCH \"m68k\"" >> $config_h
|
|||
|
echo "#define TARGET_M68K 1" >> $config_h
|
|||
|
bflt="yes"
|
|||
|
+elif test "$target_cpu" = "z80" ; then
|
|||
|
+ echo "TARGET_ARCH=z80" >> $config_mak
|
|||
|
+ echo "#define TARGET_ARCH \"z80\"" >> $config_h
|
|||
|
+ echo "#define TARGET_Z80 1" >> $config_h
|
|||
|
+ bflt="yes"
|
|||
|
else
|
|||
|
echo "Unsupported target CPU"
|
|||
|
exit 1
|
|||
|
diff -urN qemu-0.9.0/cpu-all.h qemu-z80/cpu-all.h
|
|||
|
--- qemu-0.9.0/cpu-all.h 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/cpu-all.h 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -746,6 +746,13 @@
|
|||
|
#define cpu_gen_code cpu_sh4_gen_code
|
|||
|
#define cpu_signal_handler cpu_sh4_signal_handler
|
|||
|
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+#define CPUState CPUZ80State
|
|||
|
+#define cpu_init cpu_z80_init
|
|||
|
+#define cpu_exec cpu_z80_exec
|
|||
|
+#define cpu_gen_code cpu_z80_gen_code
|
|||
|
+#define cpu_signal_handler cpu_z80_signal_handler
|
|||
|
+
|
|||
|
#else
|
|||
|
|
|||
|
#error unsupported target CPU
|
|||
|
diff -urN qemu-0.9.0/cpu-exec.c qemu-z80/cpu-exec.c
|
|||
|
--- qemu-0.9.0/cpu-exec.c 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/cpu-exec.c 2007-04-17 21:14:13.000000000 +0100
|
|||
|
@@ -202,6 +202,10 @@
|
|||
|
flags = env->sr & (SR_MD | SR_RB);
|
|||
|
cs_base = 0; /* XXXXX */
|
|||
|
pc = env->pc;
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ flags = env->hflags;
|
|||
|
+ cs_base = 0;
|
|||
|
+ pc = env->pc;
|
|||
|
#else
|
|||
|
#error unsupported CPU
|
|||
|
#endif
|
|||
|
@@ -325,6 +329,12 @@
|
|||
|
#elif defined(TARGET_MIPS)
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
/* XXXXX */
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ env_to_regs();
|
|||
|
+ /* put eflags in CPU temporary format */
|
|||
|
+ CC_SRC = env->eflags & (CC_S | CC_Z | CC_P | CC_C);
|
|||
|
+ CC_OP = CC_OP_EFLAGS;
|
|||
|
+ env->eflags &= ~(CC_S | CC_Z | CC_P | CC_C);
|
|||
|
#else
|
|||
|
#error unsupported target CPU
|
|||
|
#endif
|
|||
|
@@ -525,6 +535,13 @@
|
|||
|
}
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
/* XXXXX */
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
|
|||
|
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
|||
|
+// Z80 FIXME Z80
|
|||
|
+// env->exception_index = EXCP_IRQ;
|
|||
|
+ do_interrupt(env);
|
|||
|
+ }
|
|||
|
#endif
|
|||
|
/* Don't use the cached interupt_request value,
|
|||
|
do_interrupt may have updated the EXITTB flag. */
|
|||
|
@@ -593,6 +610,8 @@
|
|||
|
cpu_dump_state(env, logfile, fprintf, 0);
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
cpu_dump_state(env, logfile, fprintf, 0);
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ cpu_dump_state(env, logfile, fprintf, 0);
|
|||
|
#else
|
|||
|
#error unsupported target CPU
|
|||
|
#endif
|
|||
|
@@ -785,6 +804,9 @@
|
|||
|
#elif defined(TARGET_MIPS)
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
/* XXXXX */
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ /* restore flags in standard format */
|
|||
|
+// env->eflags = env->eflags | cc_table[CC_OP].compute_all();
|
|||
|
#else
|
|||
|
#error unsupported target CPU
|
|||
|
#endif
|
|||
|
diff -urN qemu-0.9.0/disas.c qemu-z80/disas.c
|
|||
|
--- qemu-0.9.0/disas.c 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/disas.c 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -197,6 +197,8 @@
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
disasm_info.mach = bfd_mach_sh4;
|
|||
|
print_insn = print_insn_sh;
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ print_insn = print_insn_z80;
|
|||
|
#else
|
|||
|
fprintf(out, "0x" TARGET_FMT_lx
|
|||
|
": Asm output not supported on this arch\n", code);
|
|||
|
diff -urN qemu-0.9.0/dis-asm.h qemu-z80/dis-asm.h
|
|||
|
--- qemu-0.9.0/dis-asm.h 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/dis-asm.h 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -377,6 +377,7 @@
|
|||
|
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
|
|||
|
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
|
|||
|
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
|
|||
|
+extern int print_insn_z80 PARAMS ((bfd_vma, disassemble_info*));
|
|||
|
|
|||
|
#if 0
|
|||
|
/* Fetch the disassembler for a given BFD, if that support is available. */
|
|||
|
diff -urN qemu-0.9.0/exec-all.h qemu-z80/exec-all.h
|
|||
|
--- qemu-0.9.0/exec-all.h 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/exec-all.h 2007-04-17 21:26:41.000000000 +0100
|
|||
|
@@ -69,7 +69,7 @@
|
|||
|
typedef void (GenOpFunc2)(long, long);
|
|||
|
typedef void (GenOpFunc3)(long, long, long);
|
|||
|
|
|||
|
-#if defined(TARGET_I386)
|
|||
|
+#if defined(TARGET_I386) | defined(TARGET_Z80)
|
|||
|
|
|||
|
void optimize_flags_init(void);
|
|||
|
|
|||
|
@@ -572,6 +572,8 @@
|
|||
|
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
|
|||
|
#elif defined (TARGET_SH4)
|
|||
|
is_user = ((env->sr & SR_MD) == 0);
|
|||
|
+#elif defined (TARGET_Z80)
|
|||
|
+ is_user = 0; /* no user-mode */
|
|||
|
#else
|
|||
|
#error unimplemented CPU
|
|||
|
#endif
|
|||
|
diff -urN qemu-0.9.0/exec.c qemu-z80/exec.c
|
|||
|
--- qemu-0.9.0/exec.c 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/exec.c 2007-04-15 22:54:52.000000000 +0100
|
|||
|
@@ -679,6 +679,9 @@
|
|||
|
current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
|
|||
|
current_cs_base = (target_ulong)env->segs[R_CS].base;
|
|||
|
current_pc = current_cs_base + env->eip;
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ current_flags = env->hflags;
|
|||
|
+ current_pc = env->pc;
|
|||
|
#else
|
|||
|
#error unsupported CPU
|
|||
|
#endif
|
|||
|
diff -urN qemu-0.9.0/gdbstub.c qemu-z80/gdbstub.c
|
|||
|
--- qemu-0.9.0/gdbstub.c 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/gdbstub.c 2007-04-04 21:35:14.000000000 +0100
|
|||
|
@@ -700,6 +700,34 @@
|
|||
|
LOAD (env->macl);
|
|||
|
LOAD (env->sr);
|
|||
|
}
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+/* Z80 FIXME Z80 TODO Z80 */
|
|||
|
+/* GDB doesn't define this yet */
|
|||
|
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
|||
|
+{
|
|||
|
+ uint32_t *registers = (uint32_t *)mem_buf;
|
|||
|
+ int i, fpus;
|
|||
|
+
|
|||
|
+ for(i = 0; i < 8; i++) {
|
|||
|
+ registers[i] = env->regs[i];
|
|||
|
+ }
|
|||
|
+ registers[8] = env->pc;
|
|||
|
+ registers[9] = env->imode;
|
|||
|
+
|
|||
|
+ return 10 * 4;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
|||
|
+{
|
|||
|
+ uint32_t *registers = (uint32_t *)mem_buf;
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ for(i = 0; i < 8; i++) {
|
|||
|
+ env->regs[i] = tswapl(registers[i]);
|
|||
|
+ }
|
|||
|
+ env->pc = tswapl(registers[8]);
|
|||
|
+ env->imode = tswapl(registers[9]);
|
|||
|
+}
|
|||
|
#else
|
|||
|
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
|||
|
{
|
|||
|
diff -urN qemu-0.9.0/hw/zx_spectrum.c qemu-z80/hw/zx_spectrum.c
|
|||
|
--- qemu-0.9.0/hw/zx_spectrum.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/hw/zx_spectrum.c 2007-04-17 20:27:16.000000000 +0100
|
|||
|
@@ -0,0 +1,236 @@
|
|||
|
+/*
|
|||
|
+ * QEMU ZX Spectrum Emulator
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003-2004 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
|
+ * of this software and associated documentation files (the "Software"), to deal
|
|||
|
+ * in the Software without restriction, including without limitation the rights
|
|||
|
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
|
+ * copies of the Software, and to permit persons to whom the Software is
|
|||
|
+ * furnished to do so, subject to the following conditions:
|
|||
|
+ *
|
|||
|
+ * The above copyright notice and this permission notice shall be included in
|
|||
|
+ * all copies or substantial portions of the Software.
|
|||
|
+ *
|
|||
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|||
|
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
|
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
|
+ * THE SOFTWARE.
|
|||
|
+ */
|
|||
|
+#include "vl.h"
|
|||
|
+
|
|||
|
+/* output Bochs bios info messages */
|
|||
|
+//#define DEBUG_BIOS
|
|||
|
+
|
|||
|
+#define ROM_FILENAME "zx-rom.bin"
|
|||
|
+
|
|||
|
+#define KERNEL_LOAD_ADDR 0x00100000
|
|||
|
+#define INITRD_LOAD_ADDR 0x00600000
|
|||
|
+#define KERNEL_PARAMS_ADDR 0x00090000
|
|||
|
+#define KERNEL_CMDLINE_ADDR 0x00099000
|
|||
|
+
|
|||
|
+int keystate[8];
|
|||
|
+
|
|||
|
+static uint32_t io_keyboard_read(void *opaque, uint32_t addr)
|
|||
|
+{
|
|||
|
+ int r = 0;
|
|||
|
+ uint8_t colbits = 0xff;
|
|||
|
+
|
|||
|
+ uint32_t rowbits = ((addr >> 8) & 0xff);
|
|||
|
+
|
|||
|
+ for (r = 0; r < 8; r++) {
|
|||
|
+ if (!(rowbits & (1 << r))) {
|
|||
|
+ colbits &= keystate[r];
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ return colbits;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static uint32_t io_spectrum_read(void *opaque, uint32_t addr)
|
|||
|
+{
|
|||
|
+ if (addr & 1)
|
|||
|
+ return 0xff;
|
|||
|
+
|
|||
|
+ return io_keyboard_read(opaque, addr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* MSDOS compatibility mode FPU exception support */
|
|||
|
+/* XXX: add IGNNE support */
|
|||
|
+void cpu_set_ferr(CPUZ80State *s)
|
|||
|
+{
|
|||
|
+ pic_set_irq(13, 1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* TSC handling */
|
|||
|
+uint64_t cpu_get_tsc(CPUZ80State *env)
|
|||
|
+{
|
|||
|
+ return cpu_get_ticks();
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void main_cpu_reset(void *opaque)
|
|||
|
+{
|
|||
|
+ CPUState *env = opaque;
|
|||
|
+ cpu_reset(env);
|
|||
|
+}
|
|||
|
+
|
|||
|
+QEMUTimer *zx_ulatimer;
|
|||
|
+int zx_flash = 0;
|
|||
|
+
|
|||
|
+void zx_50hz_timer(void *opaque)
|
|||
|
+{
|
|||
|
+// printf("zx_irq_timer()\n");
|
|||
|
+ int64_t next_time;
|
|||
|
+
|
|||
|
+ CPUState *env = opaque;
|
|||
|
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
|||
|
+
|
|||
|
+ /* FIXME: 50 Hz */
|
|||
|
+ next_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec, 50);
|
|||
|
+ qemu_mod_timer(zx_ulatimer, next_time);
|
|||
|
+
|
|||
|
+ zx_flash++;
|
|||
|
+ zx_flash %= 32;
|
|||
|
+ if ((zx_flash % 16) == 0) {
|
|||
|
+ zx_set_flash_dirty();
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+CPUState *zx_env;
|
|||
|
+
|
|||
|
+void zx_timer_init(DisplayState *ds) {
|
|||
|
+ /* FIXME */
|
|||
|
+
|
|||
|
+ int64_t t = qemu_get_clock(vm_clock);
|
|||
|
+ zx_ulatimer = qemu_new_timer(vm_clock, zx_50hz_timer, zx_env);
|
|||
|
+ qemu_mod_timer(zx_ulatimer, t);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const uint8_t keycodes[128] = {
|
|||
|
+ 0x00, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x45,
|
|||
|
+ 0x44, 0x43, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x55, 0x54, 0x53,
|
|||
|
+ 0x52, 0x51, 0x00, 0x00, 0x61, 0x72, 0x11, 0x12,
|
|||
|
+ 0x13, 0x14, 0x15, 0x65, 0x64, 0x63, 0x62, 0x00,
|
|||
|
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05,
|
|||
|
+ 0x75, 0x74, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|||
|
+ 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static void zx_put_keycode(void *opaque, int keycode) {
|
|||
|
+ int release = keycode & 0x80;
|
|||
|
+ keycode &= 0x7f;
|
|||
|
+
|
|||
|
+ //printf("Keycode %d (%s)\n", keycode, release? "release" : "press");
|
|||
|
+
|
|||
|
+ keycode = keycodes[keycode];
|
|||
|
+
|
|||
|
+ if (keycode) {
|
|||
|
+ int row = keycode >> 4;
|
|||
|
+ int col = 1 << ((keycode & 0xf) - 1);
|
|||
|
+ if (release) {
|
|||
|
+ keystate[row] |= col;
|
|||
|
+ } else {
|
|||
|
+ keystate[row] &= ~col;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_keyboard_init()
|
|||
|
+{
|
|||
|
+ int i;
|
|||
|
+ for (i=0; i<8; i++) {
|
|||
|
+ keystate[i] = 0xff;
|
|||
|
+ }
|
|||
|
+ qemu_add_kbd_event_handler(zx_put_keycode, NULL);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
|
|||
|
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
|
|||
|
+static const int ide_irq[2] = { 14, 15 };
|
|||
|
+
|
|||
|
+/* ZX Spectrum initialisation */
|
|||
|
+static void zx_init1(int ram_size, int vga_ram_size, int boot_device,
|
|||
|
+ DisplayState *ds, const char **fd_filename, int snapshot,
|
|||
|
+ const char *kernel_filename, const char *kernel_cmdline,
|
|||
|
+ const char *initrd_filename,
|
|||
|
+ int pci_enabled)
|
|||
|
+{
|
|||
|
+ char buf[1024];
|
|||
|
+ int ret;
|
|||
|
+ ram_addr_t ram_addr, vga_ram_addr, rom_offset;
|
|||
|
+ int rom_size;
|
|||
|
+ CPUState *env;
|
|||
|
+
|
|||
|
+ /* init CPUs */
|
|||
|
+ env = cpu_init();
|
|||
|
+ zx_env = env; // XXX
|
|||
|
+ register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
|
|||
|
+ qemu_register_reset(main_cpu_reset, env);
|
|||
|
+
|
|||
|
+ cpu_register_physical_memory(0, 0x10000, 0);
|
|||
|
+
|
|||
|
+ /* allocate RAM */
|
|||
|
+// ram_addr = qemu_ram_alloc(0x10000 - 0x5b00);
|
|||
|
+// cpu_register_physical_memory(0x5b00, 0x10000 - 0x5b00, 0);
|
|||
|
+ //ram_addr = qemu_ram_alloc(0x10000 - 0x4000);
|
|||
|
+ //cpu_register_physical_memory(0x4000, 0x10000 - 0x4000, ram_addr);
|
|||
|
+
|
|||
|
+// cpu_register_physical_memory(0x6000, 0x10000 - 0x6000, 0);
|
|||
|
+
|
|||
|
+ /* ROM load */
|
|||
|
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, ROM_FILENAME);
|
|||
|
+ rom_size = get_image_size(buf);
|
|||
|
+ if (rom_size <= 0 ||
|
|||
|
+ (rom_size % 16384) != 0) {
|
|||
|
+ goto rom_error;
|
|||
|
+ }
|
|||
|
+// rom_offset = qemu_ram_alloc(rom_size);
|
|||
|
+ rom_offset = 0x10000;
|
|||
|
+ ret = load_image(buf, phys_ram_base + rom_offset);
|
|||
|
+ if (ret != rom_size) {
|
|||
|
+ rom_error:
|
|||
|
+ fprintf(stderr, "qemu: could not load ZX Spectrum ROM '%s'\n", buf);
|
|||
|
+ exit(1);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ cpu_register_physical_memory(0x0000, 0x4000, rom_offset | IO_MEM_ROM);
|
|||
|
+
|
|||
|
+ /* map entire I/O space */
|
|||
|
+ register_ioport_read(0, 0x10000, 1, io_spectrum_read, NULL);
|
|||
|
+
|
|||
|
+ zx_ula_init(ds, phys_ram_base + ram_size, ram_size);
|
|||
|
+ zx_keyboard_init();
|
|||
|
+ zx_timer_init(ds);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_spectrum_init(int ram_size, int vga_ram_size, int boot_device,
|
|||
|
+ DisplayState *ds, const char **fd_filename,
|
|||
|
+ int snapshot,
|
|||
|
+ const char *kernel_filename,
|
|||
|
+ const char *kernel_cmdline,
|
|||
|
+ const char *initrd_filename)
|
|||
|
+{
|
|||
|
+ zx_init1(ram_size, vga_ram_size, boot_device,
|
|||
|
+ ds, fd_filename, snapshot,
|
|||
|
+ kernel_filename, kernel_cmdline,
|
|||
|
+ initrd_filename, 0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+QEMUMachine z80pc_machine = {
|
|||
|
+ "z80pc",
|
|||
|
+ "Z80 Machine",
|
|||
|
+ zx_spectrum_init,
|
|||
|
+};
|
|||
|
diff -urN qemu-0.9.0/hw/zx_ula.c qemu-z80/hw/zx_ula.c
|
|||
|
--- qemu-0.9.0/hw/zx_ula.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/hw/zx_ula.c 2007-04-17 20:55:28.000000000 +0100
|
|||
|
@@ -0,0 +1,355 @@
|
|||
|
+/*
|
|||
|
+ * QEMU ZX Spectrum Video Emulation.
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
|
+ * of this software and associated documentation files (the "Software"), to deal
|
|||
|
+ * in the Software without restriction, including without limitation the rights
|
|||
|
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
|
+ * copies of the Software, and to permit persons to whom the Software is
|
|||
|
+ * furnished to do so, subject to the following conditions:
|
|||
|
+ *
|
|||
|
+ * The above copyright notice and this permission notice shall be included in
|
|||
|
+ * all copies or substantial portions of the Software.
|
|||
|
+ *
|
|||
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|||
|
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
|
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
|
+ * THE SOFTWARE.
|
|||
|
+ */
|
|||
|
+
|
|||
|
+#include "vl.h"
|
|||
|
+
|
|||
|
+typedef struct {
|
|||
|
+ DisplayState *ds;
|
|||
|
+ uint8_t *vram_ptr;
|
|||
|
+ unsigned long vram_offset;
|
|||
|
+
|
|||
|
+ int bwidth;
|
|||
|
+ int bheight;
|
|||
|
+ int swidth;
|
|||
|
+ int sheight;
|
|||
|
+ int twidth;
|
|||
|
+ int theight;
|
|||
|
+
|
|||
|
+ int border;
|
|||
|
+
|
|||
|
+ int dirty;
|
|||
|
+} ZXVState;
|
|||
|
+
|
|||
|
+char *colnames[8] = {
|
|||
|
+ "black",
|
|||
|
+ "blue",
|
|||
|
+ "red",
|
|||
|
+ "magenta",
|
|||
|
+ "green",
|
|||
|
+ "cyan",
|
|||
|
+ "yellow",
|
|||
|
+ "white"
|
|||
|
+};
|
|||
|
+
|
|||
|
+uint32_t cols[16] = {
|
|||
|
+ 0x00000000,
|
|||
|
+ 0x000000c0,
|
|||
|
+ 0x00c00000,
|
|||
|
+ 0x00c000c0,
|
|||
|
+ 0x0000c000,
|
|||
|
+ 0x0000c0c0,
|
|||
|
+ 0x00c0c000,
|
|||
|
+ 0x00c0c0c0,
|
|||
|
+ 0x00000000,
|
|||
|
+ 0x000000ff,
|
|||
|
+ 0x00ff0000,
|
|||
|
+ 0x00ff00ff,
|
|||
|
+ 0x0000ff00,
|
|||
|
+ 0x0000ffff,
|
|||
|
+ 0x00ffff00,
|
|||
|
+ 0x00ffffff,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* copied from vga_template.h */
|
|||
|
+
|
|||
|
+#define cbswap_32(__x) \
|
|||
|
+((uint32_t)( \
|
|||
|
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
|||
|
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
|||
|
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
|||
|
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
|
|||
|
+
|
|||
|
+#ifdef WORDS_BIGENDIAN
|
|||
|
+#define PAT(x) (x)
|
|||
|
+#else
|
|||
|
+#define PAT(x) cbswap_32(x)
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+static const uint32_t dmask16[16] = {
|
|||
|
+ PAT(0x00000000),
|
|||
|
+ PAT(0x000000ff),
|
|||
|
+ PAT(0x0000ff00),
|
|||
|
+ PAT(0x0000ffff),
|
|||
|
+ PAT(0x00ff0000),
|
|||
|
+ PAT(0x00ff00ff),
|
|||
|
+ PAT(0x00ffff00),
|
|||
|
+ PAT(0x00ffffff),
|
|||
|
+ PAT(0xff000000),
|
|||
|
+ PAT(0xff0000ff),
|
|||
|
+ PAT(0xff00ff00),
|
|||
|
+ PAT(0xff00ffff),
|
|||
|
+ PAT(0xffff0000),
|
|||
|
+ PAT(0xffff00ff),
|
|||
|
+ PAT(0xffffff00),
|
|||
|
+ PAT(0xffffffff),
|
|||
|
+};
|
|||
|
+
|
|||
|
+static const uint32_t dmask4[4] = {
|
|||
|
+ PAT(0x00000000),
|
|||
|
+ PAT(0x0000ffff),
|
|||
|
+ PAT(0xffff0000),
|
|||
|
+ PAT(0xffffffff),
|
|||
|
+};
|
|||
|
+
|
|||
|
+static inline void zx_draw_line_8(uint8_t *d,
|
|||
|
+ uint32_t font_data,
|
|||
|
+ uint32_t xorcol,
|
|||
|
+ uint32_t bgcol)
|
|||
|
+{
|
|||
|
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void zx_draw_line_16(uint8_t *d,
|
|||
|
+ uint32_t font_data,
|
|||
|
+ uint32_t xorcol,
|
|||
|
+ uint32_t bgcol)
|
|||
|
+{
|
|||
|
+ ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void zx_draw_line_32(uint8_t *d,
|
|||
|
+ uint32_t font_data,
|
|||
|
+ uint32_t xorcol,
|
|||
|
+ uint32_t bgcol)
|
|||
|
+{
|
|||
|
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
|
|||
|
+ ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
|
|||
|
+}
|
|||
|
+
|
|||
|
+extern int zx_flash;
|
|||
|
+static ZXVState *zxvstate;
|
|||
|
+
|
|||
|
+void zx_set_flash_dirty(void) {
|
|||
|
+ ZXVState *s = zxvstate;
|
|||
|
+ s->dirty = 1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_draw_line(ZXVState *s1, uint8_t *d,
|
|||
|
+ const uint8_t *s, const uint8_t *as)
|
|||
|
+{
|
|||
|
+ int x;
|
|||
|
+ for (x = 0; x < 32; x++) {
|
|||
|
+ int attrib, fg, bg, bright, flash;
|
|||
|
+
|
|||
|
+ attrib = *as;
|
|||
|
+ bright = (attrib & 0x40) >> 4;
|
|||
|
+ flash = (attrib & 0x80) && (zx_flash >= 16);
|
|||
|
+ if (flash) {
|
|||
|
+ fg = (attrib >> 3) & 0x07;
|
|||
|
+ bg = attrib & 0x07;
|
|||
|
+ } else {
|
|||
|
+ fg = attrib & 0x07;
|
|||
|
+ bg = (attrib >> 3) & 0x07;
|
|||
|
+ }
|
|||
|
+ fg |= bright;
|
|||
|
+ bg |= bright;
|
|||
|
+
|
|||
|
+ zx_draw_line_32(d, *s, cols[fg] ^ cols[bg], cols[bg]);
|
|||
|
+ d += 8 * 4;
|
|||
|
+ s++; as++;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_border_row(ZXVState *s, uint8_t *d)
|
|||
|
+{
|
|||
|
+ int x;
|
|||
|
+ for (x = 0; x < s->twidth; x++) {
|
|||
|
+ *((uint32_t *)d) = cols[s->border];
|
|||
|
+ d += 4;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_border_sides(ZXVState *s, uint8_t *d)
|
|||
|
+{
|
|||
|
+ int x;
|
|||
|
+ for (x = 0; x < s->bwidth; x++) {
|
|||
|
+ *((uint32_t *)d) = cols[s->border];
|
|||
|
+ d += 4;
|
|||
|
+ }
|
|||
|
+ d += s->swidth * 4;
|
|||
|
+ for (x = 0; x < s->bwidth; x++) {
|
|||
|
+ *((uint32_t *)d) = cols[s->border];
|
|||
|
+ d += 4;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_update_display(void *opaque)
|
|||
|
+{
|
|||
|
+ int y;
|
|||
|
+ uint8_t *d;
|
|||
|
+ ZXVState *s = (ZXVState *)opaque;
|
|||
|
+ uint32_t addr, attrib;
|
|||
|
+
|
|||
|
+ if (!s->dirty)
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ d = s->ds->data;
|
|||
|
+ d += s->bheight * s->ds->linesize;
|
|||
|
+ d += s->bwidth * 4;
|
|||
|
+
|
|||
|
+ for (y = 0; y < 192; y++) {
|
|||
|
+ addr = ((y & 0x07) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5);
|
|||
|
+ attrib = 0x1800 | ((y & 0xf8) << 2);
|
|||
|
+ zx_draw_line(s, d, s->vram_ptr + addr, s->vram_ptr + attrib);
|
|||
|
+ d += s->ds->linesize;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ d = s->ds->data;
|
|||
|
+ for (y = 0; y < s->bheight; y++) {
|
|||
|
+ zx_border_row(s, d + y * s->ds->linesize);
|
|||
|
+ }
|
|||
|
+ for (y = s->bheight; y < s->theight - s->bheight; y++) {
|
|||
|
+ zx_border_sides(s, d + y * s->ds->linesize);
|
|||
|
+ }
|
|||
|
+ for (y = s->theight - s->bheight; y < s->theight; y++) {
|
|||
|
+ zx_border_row(s, d + y * s->ds->linesize);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ dpy_update(s->ds, 0, 0, s->twidth, s->theight);
|
|||
|
+ s->dirty = 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_invalidate_display(void *opaque)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void zx_screen_dump(void *opaque, const char *filename)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+uint32_t zx_mem_readb(void *opaque, target_phys_addr_t addr)
|
|||
|
+{
|
|||
|
+ ZXVState *s = opaque;
|
|||
|
+
|
|||
|
+ addr -= 0x4000;
|
|||
|
+ return s->vram_ptr[addr];
|
|||
|
+}
|
|||
|
+
|
|||
|
+uint32_t zx_mem_readw(void *opaque, target_phys_addr_t addr)
|
|||
|
+{
|
|||
|
+ return (zx_mem_readb(opaque, addr + 1) << 8) | zx_mem_readb(opaque, addr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+uint32_t zx_mem_readl(void *opaque, target_phys_addr_t addr)
|
|||
|
+{
|
|||
|
+ return (zx_mem_readb(opaque, addr + 3) << 24) |
|
|||
|
+ (zx_mem_readb(opaque, addr + 2) << 16) |
|
|||
|
+ (zx_mem_readb(opaque, addr + 1) << 8) |
|
|||
|
+ zx_mem_readb(opaque, addr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void zx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|||
|
+{
|
|||
|
+ ZXVState *s = opaque;
|
|||
|
+
|
|||
|
+ if (addr < 0x5b00) // XXX
|
|||
|
+ s->dirty = 1;
|
|||
|
+ addr -= 0x4000;
|
|||
|
+ s->vram_ptr[addr] = val;
|
|||
|
+
|
|||
|
+ cpu_physical_memory_set_dirty(s->vram_offset + addr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void zx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|||
|
+{
|
|||
|
+ zx_mem_writeb(opaque, addr, val & 0xff);
|
|||
|
+ zx_mem_writeb(opaque, addr + 1, val >> 8);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void zx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|||
|
+{
|
|||
|
+ zx_mem_writeb(opaque, addr, val & 0xff);
|
|||
|
+ zx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
|||
|
+ zx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
|||
|
+ zx_mem_writeb(opaque, addr + 3, val >> 24);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static CPUReadMemoryFunc *zx_mem_read[3] = {
|
|||
|
+ zx_mem_readb,
|
|||
|
+ zx_mem_readw,
|
|||
|
+ zx_mem_readl,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static CPUWriteMemoryFunc *zx_mem_write[3] = {
|
|||
|
+ zx_mem_writeb,
|
|||
|
+ zx_mem_writew,
|
|||
|
+ zx_mem_writel,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static void io_spectrum_write(void *opaque, uint32_t addr, uint32_t data)
|
|||
|
+{
|
|||
|
+ ZXVState *s = (ZXVState *)opaque;
|
|||
|
+
|
|||
|
+/* port xxfe */
|
|||
|
+ s->border = data & 0x07;
|
|||
|
+ s->dirty = 1;
|
|||
|
+};
|
|||
|
+
|
|||
|
+void zx_ula_init(DisplayState *ds, uint8_t *zx_screen_base,
|
|||
|
+ unsigned long ula_ram_offset)
|
|||
|
+{
|
|||
|
+ int zx_io_memory;
|
|||
|
+
|
|||
|
+ ZXVState *s = qemu_mallocz(sizeof(ZXVState));
|
|||
|
+ if (!s)
|
|||
|
+ return;
|
|||
|
+ zxvstate = s;
|
|||
|
+ s->ds = ds;
|
|||
|
+ s->dirty = 1;
|
|||
|
+// s->vram_ptr = zx_screen_base;
|
|||
|
+// s->vram_offset = ula_ram_offset;
|
|||
|
+
|
|||
|
+ graphic_console_init(ds, zx_update_display, zx_invalidate_display,
|
|||
|
+ zx_screen_dump, s);
|
|||
|
+
|
|||
|
+ s->bwidth = 32;
|
|||
|
+ s->bheight = 24;
|
|||
|
+ s->swidth = 256;
|
|||
|
+ s->sheight = 192;
|
|||
|
+ s->twidth = s->swidth + s->bwidth * 2;
|
|||
|
+ s->theight = s->sheight + s->bheight * 2;
|
|||
|
+ s->border = 0;
|
|||
|
+ dpy_resize(s->ds, s->twidth, s->theight);
|
|||
|
+
|
|||
|
+ zx_io_memory = cpu_register_io_memory(0, zx_mem_read, zx_mem_write, s);
|
|||
|
+ cpu_register_physical_memory(0x4000, 0x1b00, zx_io_memory);
|
|||
|
+// cpu_register_physical_memory(0x4000, 0x2000, zx_io_memory);
|
|||
|
+// cpu_register_physical_memory(0x4000, 0xc000, zx_io_memory);
|
|||
|
+ s->vram_ptr = phys_ram_base + zx_io_memory;
|
|||
|
+ s->vram_offset = zx_io_memory;
|
|||
|
+
|
|||
|
+ /* ZX Spectrum ULA */
|
|||
|
+ register_ioport_write(0, 0x10000, 1, io_spectrum_write, s);
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/Makefile qemu-z80/Makefile
|
|||
|
--- qemu-0.9.0/Makefile 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/Makefile 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -79,7 +79,7 @@
|
|||
|
mkdir -p "$(DESTDIR)$(datadir)"
|
|||
|
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
|||
|
video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
|
|||
|
- pxe-rtl8139.bin pxe-pcnet.bin; do \
|
|||
|
+ pxe-rtl8139.bin pxe-pcnet.bin zx-rom.bin ; do \
|
|||
|
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
|
|||
|
done
|
|||
|
ifndef CONFIG_WIN32
|
|||
|
diff -urN qemu-0.9.0/Makefile.target qemu-z80/Makefile.target
|
|||
|
--- qemu-0.9.0/Makefile.target 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/Makefile.target 2007-04-15 19:35:13.000000000 +0100
|
|||
|
@@ -271,6 +271,10 @@
|
|||
|
LIBOBJS+= helper.o
|
|||
|
endif
|
|||
|
|
|||
|
+ifeq ($(TARGET_BASE_ARCH), z80)
|
|||
|
+LIBOBJS+=helper.o helper2.o
|
|||
|
+endif
|
|||
|
+
|
|||
|
# NOTE: the disassembler code is only needed for debugging
|
|||
|
LIBOBJS+=disas.o
|
|||
|
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
|
|||
|
@@ -303,6 +307,9 @@
|
|||
|
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
|
|||
|
LIBOBJS+=sh4-dis.o
|
|||
|
endif
|
|||
|
+ifeq ($(findstring z80, $(TARGET_ARCH) $(ARCH)),z80)
|
|||
|
+LIBOBJS+=z80-dis.o
|
|||
|
+endif
|
|||
|
|
|||
|
ifdef CONFIG_GDBSTUB
|
|||
|
OBJS+=gdbstub.o
|
|||
|
@@ -407,6 +414,10 @@
|
|||
|
ifeq ($(TARGET_BASE_ARCH), sh4)
|
|||
|
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
|
|||
|
endif
|
|||
|
+ifeq ($(TARGET_BASE_ARCH), z80)
|
|||
|
+VL_OBJS+= zx_spectrum.o zx_ula.o dma.o $(AUDIODRV)
|
|||
|
+VL_OBJS+= serial.o i8259.o mixeng.o
|
|||
|
+endif
|
|||
|
ifdef CONFIG_GDBSTUB
|
|||
|
VL_OBJS+=gdbstub.o
|
|||
|
endif
|
|||
|
@@ -514,9 +525,15 @@
|
|||
|
helper.o: helper.c
|
|||
|
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
|||
|
else
|
|||
|
+ifeq ($(TARGET_BASE_ARCH), z80)
|
|||
|
+# XXX: rename helper.c to op_helper.c
|
|||
|
+helper.o: helper.c
|
|||
|
+ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
|||
|
+else
|
|||
|
op_helper.o: op_helper.c
|
|||
|
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
|||
|
endif
|
|||
|
+endif
|
|||
|
|
|||
|
cpu-exec.o: cpu-exec.c
|
|||
|
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
|
|||
|
@@ -529,6 +546,9 @@
|
|||
|
ifeq ($(TARGET_BASE_ARCH), i386)
|
|||
|
op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
|
|||
|
endif
|
|||
|
+ifeq ($(TARGET_BASE_ARCH), z80)
|
|||
|
+op.o: op.c opreg_template.h ops_mem.h
|
|||
|
+endif
|
|||
|
|
|||
|
ifeq ($(TARGET_ARCH), arm)
|
|||
|
op.o: op.c op_template.h
|
|||
|
Binary files qemu-0.9.0/pc-bios/zx-rom.bin and qemu-z80/pc-bios/zx-rom.bin differ
|
|||
|
diff -urN qemu-0.9.0/softmmu_header.h qemu-z80/softmmu_header.h
|
|||
|
--- qemu-0.9.0/softmmu_header.h 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/softmmu_header.h 2007-03-27 21:07:11.000000000 +0100
|
|||
|
@@ -63,6 +63,8 @@
|
|||
|
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
|
|||
|
#elif defined (TARGET_SH4)
|
|||
|
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
|
|||
|
+#elif defined (TARGET_Z80)
|
|||
|
+#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
|||
|
#else
|
|||
|
#error unsupported CPU
|
|||
|
#endif
|
|||
|
@@ -82,6 +84,8 @@
|
|||
|
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
|
|||
|
#elif defined (TARGET_SH4)
|
|||
|
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
|
|||
|
+#elif defined (TARGET_Z80)
|
|||
|
+#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
|
|||
|
#else
|
|||
|
#error unsupported CPU
|
|||
|
#endif
|
|||
|
diff -urN qemu-0.9.0/target-z80/cpu.h qemu-z80/target-z80/cpu.h
|
|||
|
--- qemu-0.9.0/target-z80/cpu.h 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/cpu.h 2007-04-17 21:05:57.000000000 +0100
|
|||
|
@@ -0,0 +1,235 @@
|
|||
|
+/*
|
|||
|
+ * Z80 virtual CPU header
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+#ifndef CPU_Z80_H
|
|||
|
+#define CPU_Z80_H
|
|||
|
+
|
|||
|
+#include "config.h"
|
|||
|
+
|
|||
|
+#define TARGET_LONG_BITS 32
|
|||
|
+
|
|||
|
+/* target supports implicit self modifying code */
|
|||
|
+#define TARGET_HAS_SMC
|
|||
|
+/* support for self modifying code even if the modified instruction is
|
|||
|
+ close to the modifying instruction */
|
|||
|
+#define TARGET_HAS_PRECISE_SMC
|
|||
|
+
|
|||
|
+#define TARGET_HAS_ICE 1
|
|||
|
+
|
|||
|
+#define ELF_MACHINE EM_NONE
|
|||
|
+
|
|||
|
+#include "cpu-defs.h"
|
|||
|
+
|
|||
|
+#include "softfloat.h"
|
|||
|
+
|
|||
|
+/* Z80 registers */
|
|||
|
+
|
|||
|
+#define R_A 0
|
|||
|
+#define R_F 1
|
|||
|
+
|
|||
|
+#define R_BC 2
|
|||
|
+#define R_DE 3
|
|||
|
+#define R_HL 4
|
|||
|
+#define R_IX 5
|
|||
|
+#define R_IY 6
|
|||
|
+#define R_SP 7
|
|||
|
+
|
|||
|
+#define R_I 8
|
|||
|
+#define R_R 9
|
|||
|
+
|
|||
|
+#define R_AFX 10
|
|||
|
+#define R_BCX 11
|
|||
|
+#define R_DEX 12
|
|||
|
+#define R_HLX 13
|
|||
|
+
|
|||
|
+/* flags masks */
|
|||
|
+#define CC_C 0x0001
|
|||
|
+#define CC_N 0x0002
|
|||
|
+#define CC_P 0x0004
|
|||
|
+#define CC_X 0x0008
|
|||
|
+#define CC_H 0x0010
|
|||
|
+#define CC_Y 0x0020
|
|||
|
+#define CC_Z 0x0040
|
|||
|
+#define CC_S 0x0080
|
|||
|
+
|
|||
|
+/* hidden flags - used internally by qemu to represent additionnal cpu
|
|||
|
+ states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid
|
|||
|
+ using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
|
|||
|
+ with eflags. */
|
|||
|
+/* current cpl */
|
|||
|
+#define HF_CPL_SHIFT 0
|
|||
|
+/* true if soft mmu is being used */
|
|||
|
+#define HF_SOFTMMU_SHIFT 2
|
|||
|
+/* true if hardware interrupts must be disabled for next instruction */
|
|||
|
+#define HF_INHIBIT_IRQ_SHIFT 3
|
|||
|
+/* 16 or 32 segments */
|
|||
|
+#define HF_CS32_SHIFT 4
|
|||
|
+#define HF_SS32_SHIFT 5
|
|||
|
+/* zero base for DS, ES and SS : can be '0' only in 32 bit CS segment */
|
|||
|
+#define HF_ADDSEG_SHIFT 6
|
|||
|
+/* copy of CR0.PE (protected mode) */
|
|||
|
+#define HF_PE_SHIFT 7
|
|||
|
+#define HF_TF_SHIFT 8 /* must be same as eflags */
|
|||
|
+#define HF_MP_SHIFT 9 /* the order must be MP, EM, TS */
|
|||
|
+#define HF_EM_SHIFT 10
|
|||
|
+#define HF_TS_SHIFT 11
|
|||
|
+#define HF_IOPL_SHIFT 12 /* must be same as eflags */
|
|||
|
+#define HF_LMA_SHIFT 14 /* only used on x86_64: long mode active */
|
|||
|
+#define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */
|
|||
|
+#define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */
|
|||
|
+#define HF_VM_SHIFT 17 /* must be same as eflags */
|
|||
|
+#define HF_HALTED_SHIFT 18 /* CPU halted */
|
|||
|
+#define HF_SMM_SHIFT 19 /* CPU in SMM mode */
|
|||
|
+
|
|||
|
+#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
|
|||
|
+#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
|
|||
|
+#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
|
|||
|
+#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
|
|||
|
+#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
|
|||
|
+#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
|
|||
|
+#define HF_PE_MASK (1 << HF_PE_SHIFT)
|
|||
|
+#define HF_TF_MASK (1 << HF_TF_SHIFT)
|
|||
|
+#define HF_MP_MASK (1 << HF_MP_SHIFT)
|
|||
|
+#define HF_EM_MASK (1 << HF_EM_SHIFT)
|
|||
|
+#define HF_TS_MASK (1 << HF_TS_SHIFT)
|
|||
|
+#define HF_LMA_MASK (1 << HF_LMA_SHIFT)
|
|||
|
+#define HF_CS64_MASK (1 << HF_CS64_SHIFT)
|
|||
|
+#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
|
|||
|
+#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)
|
|||
|
+#define HF_SMM_MASK (1 << HF_SMM_SHIFT)
|
|||
|
+
|
|||
|
+#define EXCP00_DIVZ 0
|
|||
|
+#define EXCP01_SSTP 1
|
|||
|
+#define EXCP02_NMI 2
|
|||
|
+#define EXCP03_INT3 3
|
|||
|
+#define EXCP04_INTO 4
|
|||
|
+#define EXCP05_BOUND 5
|
|||
|
+#define EXCP06_ILLOP 6
|
|||
|
+#define EXCP07_PREX 7
|
|||
|
+#define EXCP08_DBLE 8
|
|||
|
+#define EXCP09_XERR 9
|
|||
|
+#define EXCP0A_TSS 10
|
|||
|
+#define EXCP0B_NOSEG 11
|
|||
|
+#define EXCP0C_STACK 12
|
|||
|
+#define EXCP0D_GPF 13
|
|||
|
+#define EXCP0E_PAGE 14
|
|||
|
+#define EXCP10_COPR 16
|
|||
|
+#define EXCP11_ALGN 17
|
|||
|
+#define EXCP12_MCHK 18
|
|||
|
+
|
|||
|
+enum {
|
|||
|
+ CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
|||
|
+ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
|
|||
|
+
|
|||
|
+ CC_OP_NB,
|
|||
|
+};
|
|||
|
+
|
|||
|
+#define CPU_NB_REGS 14
|
|||
|
+
|
|||
|
+typedef struct CPUZ80State {
|
|||
|
+#if TARGET_LONG_BITS > HOST_LONG_BITS
|
|||
|
+ /* temporaries if we cannot store them in host registers */
|
|||
|
+ target_ulong t0, t1, t2;
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+ /* Z80 registers */
|
|||
|
+ uint16_t pc;
|
|||
|
+ /* not sure if this is messy: */
|
|||
|
+ target_ulong regs[CPU_NB_REGS];
|
|||
|
+
|
|||
|
+ int iff1;
|
|||
|
+ int iff2;
|
|||
|
+ int imode;
|
|||
|
+
|
|||
|
+ int ir;
|
|||
|
+
|
|||
|
+ /* standard registers */
|
|||
|
+ target_ulong eflags; /* eflags register. During CPU emulation, CC
|
|||
|
+ flags are set to zero because they are
|
|||
|
+ stored elsewhere */
|
|||
|
+
|
|||
|
+ /* emulator internal eflags handling */
|
|||
|
+ target_ulong cc_src;
|
|||
|
+ target_ulong cc_dst;
|
|||
|
+ uint32_t cc_op;
|
|||
|
+ uint32_t hflags; /* hidden flags, see HF_xxx constants */
|
|||
|
+
|
|||
|
+ target_ulong cr[5]; /* NOTE: cr1 is unused */
|
|||
|
+
|
|||
|
+ /* sysenter registers */
|
|||
|
+ uint64_t efer;
|
|||
|
+ uint64_t star;
|
|||
|
+
|
|||
|
+ uint64_t pat;
|
|||
|
+
|
|||
|
+ /* exception/interrupt handling */
|
|||
|
+ jmp_buf jmp_env;
|
|||
|
+ int exception_index;
|
|||
|
+ int error_code;
|
|||
|
+ int exception_is_int;
|
|||
|
+ target_ulong exception_next_pc;
|
|||
|
+ target_ulong dr[8]; /* debug registers */
|
|||
|
+ uint32_t smbase;
|
|||
|
+ int interrupt_request;
|
|||
|
+ int user_mode_only; /* user mode only simulation */
|
|||
|
+
|
|||
|
+ CPU_COMMON
|
|||
|
+
|
|||
|
+ /* in order to simplify APIC support, we leave this pointer to the
|
|||
|
+ user */
|
|||
|
+ struct APICState *apic_state;
|
|||
|
+} CPUZ80State;
|
|||
|
+
|
|||
|
+CPUZ80State *cpu_z80_init(void);
|
|||
|
+int cpu_z80_exec(CPUZ80State *s);
|
|||
|
+void cpu_z80_close(CPUZ80State *s);
|
|||
|
+int cpu_get_pic_interrupt(CPUZ80State *s);
|
|||
|
+
|
|||
|
+/* wrapper, just in case memory mappings must be changed */
|
|||
|
+static inline void cpu_z80_set_cpl(CPUZ80State *s, int cpl)
|
|||
|
+{
|
|||
|
+#if HF_CPL_MASK == 3
|
|||
|
+ s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
|
|||
|
+#else
|
|||
|
+#error HF_CPL_MASK is hardcoded
|
|||
|
+#endif
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* you can call this signal handler from your SIGBUS and SIGSEGV
|
|||
|
+ signal handlers to inform the virtual CPU of exceptions. non zero
|
|||
|
+ is returned if the signal was handled by the virtual CPU. */
|
|||
|
+struct siginfo;
|
|||
|
+int cpu_z80_signal_handler(int host_signum, struct siginfo *info,
|
|||
|
+ void *puc);
|
|||
|
+
|
|||
|
+uint64_t cpu_get_tsc(CPUZ80State *env);
|
|||
|
+
|
|||
|
+void cpu_set_apic_base(CPUZ80State *env, uint64_t val);
|
|||
|
+uint64_t cpu_get_apic_base(CPUZ80State *env);
|
|||
|
+void cpu_set_apic_tpr(CPUZ80State *env, uint8_t val);
|
|||
|
+#ifndef NO_CPU_IO_DEFS
|
|||
|
+uint8_t cpu_get_apic_tpr(CPUZ80State *env);
|
|||
|
+#endif
|
|||
|
+void cpu_smm_update(CPUZ80State *env);
|
|||
|
+
|
|||
|
+#define TARGET_PAGE_BITS 12
|
|||
|
+#include "cpu-all.h"
|
|||
|
+
|
|||
|
+#endif /* CPU_Z80_H */
|
|||
|
diff -urN qemu-0.9.0/target-z80/exec.h qemu-z80/target-z80/exec.h
|
|||
|
--- qemu-0.9.0/target-z80/exec.h 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/exec.h 2007-04-17 21:02:26.000000000 +0100
|
|||
|
@@ -0,0 +1,361 @@
|
|||
|
+/*
|
|||
|
+ * Z80 execution defines
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+#include "config.h"
|
|||
|
+#include "dyngen-exec.h"
|
|||
|
+
|
|||
|
+#define TARGET_LONG_BITS 32
|
|||
|
+
|
|||
|
+#include "cpu-defs.h"
|
|||
|
+
|
|||
|
+/* at least 4 register variables are defined */
|
|||
|
+register struct CPUZ80State *env asm(AREG0);
|
|||
|
+
|
|||
|
+#if TARGET_LONG_BITS > HOST_LONG_BITS
|
|||
|
+
|
|||
|
+/* no registers can be used */
|
|||
|
+#define T0 (env->t0)
|
|||
|
+#define T1 (env->t1)
|
|||
|
+#define T2 (env->t2)
|
|||
|
+
|
|||
|
+#else
|
|||
|
+
|
|||
|
+/* XXX: use unsigned long instead of target_ulong - better code will
|
|||
|
+ be generated for 64 bit CPUs */
|
|||
|
+register target_ulong T0 asm(AREG1);
|
|||
|
+register target_ulong T1 asm(AREG2);
|
|||
|
+register target_ulong T2 asm(AREG3);
|
|||
|
+
|
|||
|
+/* if more registers are available, we define some registers too */
|
|||
|
+#ifdef AREG4
|
|||
|
+register target_ulong A asm(AREG4);
|
|||
|
+#define reg_A
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG5
|
|||
|
+register target_ulong F asm(AREG5);
|
|||
|
+#define reg_F
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG6
|
|||
|
+register target_ulong BC asm(AREG6);
|
|||
|
+#define reg_BC
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG7
|
|||
|
+register target_ulong DE asm(AREG7);
|
|||
|
+#define reg_DE
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG8
|
|||
|
+register target_ulong HL asm(AREG8);
|
|||
|
+#define reg_HL
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG9
|
|||
|
+register target_ulong IX asm(AREG9);
|
|||
|
+#define reg_IX
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG10
|
|||
|
+register target_ulong IY asm(AREG10);
|
|||
|
+#define reg_IY
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef AREG11
|
|||
|
+register target_ulong R asm(AREG11);
|
|||
|
+#define reg_R
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */
|
|||
|
+
|
|||
|
+#define A0 T2
|
|||
|
+
|
|||
|
+extern FILE *logfile;
|
|||
|
+extern int loglevel;
|
|||
|
+
|
|||
|
+#ifndef reg_A
|
|||
|
+#define A (env->regs[R_A])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_F
|
|||
|
+#define F (env->regs[R_F])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_BC
|
|||
|
+#define BC (env->regs[R_BC])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_DE
|
|||
|
+#define DE (env->regs[R_DE])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_HL
|
|||
|
+#define HL (env->regs[R_HL])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_IX
|
|||
|
+#define IX (env->regs[R_IX])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_IY
|
|||
|
+#define IY (env->regs[R_IY])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_SP
|
|||
|
+#define SP (env->regs[R_SP])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_I
|
|||
|
+#define I (env->regs[R_I])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_R
|
|||
|
+#define R (env->regs[R_R])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_AFX
|
|||
|
+#define AFX (env->regs[R_AFX])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_BCX
|
|||
|
+#define BCX (env->regs[R_BCX])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_DEX
|
|||
|
+#define DEX (env->regs[R_DEX])
|
|||
|
+#endif
|
|||
|
+#ifndef reg_HLX
|
|||
|
+#define HLX (env->regs[R_HLX])
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#define PC (env->pc)
|
|||
|
+
|
|||
|
+#define CC_SRC (env->cc_src)
|
|||
|
+#define CC_DST (env->cc_dst)
|
|||
|
+#define CC_OP (env->cc_op)
|
|||
|
+
|
|||
|
+/* float macros */
|
|||
|
+#if 0
|
|||
|
+#define FT0 (env->ft0)
|
|||
|
+#define ST0 (env->fpregs[env->fpstt].d)
|
|||
|
+#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d)
|
|||
|
+#define ST1 ST(1)
|
|||
|
+
|
|||
|
+#ifdef USE_FP_CONVERT
|
|||
|
+#define FP_CONVERT (env->fp_convert)
|
|||
|
+#endif
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#include "cpu.h"
|
|||
|
+#include "exec-all.h"
|
|||
|
+
|
|||
|
+typedef struct CCTable {
|
|||
|
+ int (*compute_all)(void); /* return all the flags */
|
|||
|
+ int (*compute_c)(void); /* return the C flag */
|
|||
|
+} CCTable;
|
|||
|
+
|
|||
|
+extern CCTable cc_table[];
|
|||
|
+
|
|||
|
+void load_seg(int seg_reg, int selector);
|
|||
|
+void helper_ljmp_protected_T0_T1(int next_eip);
|
|||
|
+void helper_lcall_real_T0_T1(int shift, int next_eip);
|
|||
|
+void helper_lcall_protected_T0_T1(int shift, int next_eip);
|
|||
|
+void helper_iret_real(int shift);
|
|||
|
+void helper_iret_protected(int shift, int next_eip);
|
|||
|
+void helper_lret_protected(int shift, int addend);
|
|||
|
+void helper_lldt_T0(void);
|
|||
|
+void helper_ltr_T0(void);
|
|||
|
+void helper_movl_crN_T0(int reg);
|
|||
|
+void helper_movl_drN_T0(int reg);
|
|||
|
+void helper_invlpg(target_ulong addr);
|
|||
|
+
|
|||
|
+int cpu_z80_handle_mmu_fault(CPUZ80State *env, target_ulong addr,
|
|||
|
+ int is_write, int is_user, int is_softmmu);
|
|||
|
+void tlb_fill(target_ulong addr, int is_write, int is_user,
|
|||
|
+ void *retaddr);
|
|||
|
+void __hidden cpu_lock(void);
|
|||
|
+void __hidden cpu_unlock(void);
|
|||
|
+void do_interrupt(CPUZ80State *env);
|
|||
|
+void raise_interrupt(int intno, int is_int, int error_code,
|
|||
|
+ int next_eip_addend);
|
|||
|
+void raise_exception_err(int exception_index, int error_code);
|
|||
|
+void raise_exception(int exception_index);
|
|||
|
+void do_smm_enter(void);
|
|||
|
+void __hidden cpu_loop_exit(void);
|
|||
|
+
|
|||
|
+void OPPROTO op_movl_eflags_T0(void);
|
|||
|
+void OPPROTO op_movl_T0_eflags(void);
|
|||
|
+
|
|||
|
+void helper_dump_registers(int pc);
|
|||
|
+void helper_in_debug(int port);
|
|||
|
+
|
|||
|
+#if !defined(CONFIG_USER_ONLY)
|
|||
|
+
|
|||
|
+#include "softmmu_exec.h"
|
|||
|
+
|
|||
|
+static inline double ldfq(target_ulong ptr)
|
|||
|
+{
|
|||
|
+ union {
|
|||
|
+ double d;
|
|||
|
+ uint64_t i;
|
|||
|
+ } u;
|
|||
|
+ u.i = ldq(ptr);
|
|||
|
+ return u.d;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void stfq(target_ulong ptr, double v)
|
|||
|
+{
|
|||
|
+ union {
|
|||
|
+ double d;
|
|||
|
+ uint64_t i;
|
|||
|
+ } u;
|
|||
|
+ u.d = v;
|
|||
|
+ stq(ptr, u.i);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline float ldfl(target_ulong ptr)
|
|||
|
+{
|
|||
|
+ union {
|
|||
|
+ float f;
|
|||
|
+ uint32_t i;
|
|||
|
+ } u;
|
|||
|
+ u.i = ldl(ptr);
|
|||
|
+ return u.f;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void stfl(target_ulong ptr, float v)
|
|||
|
+{
|
|||
|
+ union {
|
|||
|
+ float f;
|
|||
|
+ uint32_t i;
|
|||
|
+ } u;
|
|||
|
+ u.f = v;
|
|||
|
+ stl(ptr, u.i);
|
|||
|
+}
|
|||
|
+
|
|||
|
+#endif /* !defined(CONFIG_USER_ONLY) */
|
|||
|
+
|
|||
|
+#define RC_MASK 0xc00
|
|||
|
+#define RC_NEAR 0x000
|
|||
|
+#define RC_DOWN 0x400
|
|||
|
+#define RC_UP 0x800
|
|||
|
+#define RC_CHOP 0xc00
|
|||
|
+
|
|||
|
+void helper_hlt(void);
|
|||
|
+void helper_monitor(void);
|
|||
|
+void helper_mwait(void);
|
|||
|
+
|
|||
|
+extern const uint8_t parity_table[256];
|
|||
|
+extern const uint8_t rclw_table[32];
|
|||
|
+extern const uint8_t rclb_table[32];
|
|||
|
+
|
|||
|
+static inline uint32_t compute_eflags(void)
|
|||
|
+{
|
|||
|
+ return env->eflags | cc_table[CC_OP].compute_all();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
|
|||
|
+static inline void load_eflags(int eflags, int update_mask)
|
|||
|
+{
|
|||
|
+ CC_SRC = eflags & (CC_S | CC_Z | CC_P | CC_C);
|
|||
|
+ env->eflags = (env->eflags & ~update_mask) |
|
|||
|
+ (eflags & update_mask);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void env_to_regs(void)
|
|||
|
+{
|
|||
|
+#ifdef reg_A
|
|||
|
+ A = env->regs[R_A];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_F
|
|||
|
+ F = env->regs[R_F];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_BC
|
|||
|
+ BC = env->regs[R_BC];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_DE
|
|||
|
+ DE = env->regs[R_DE];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_HL
|
|||
|
+ HL = env->regs[R_HL];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_IX
|
|||
|
+ IX = env->regs[R_IX];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_IY
|
|||
|
+ IY = env->regs[R_IY];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_SP
|
|||
|
+ SP = env->regs[R_SP];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_I
|
|||
|
+ I = env->regs[R_I];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_R
|
|||
|
+ R = env->regs[R_R];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_AFX
|
|||
|
+ AFX = env->regs[R_AFX];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_BCX
|
|||
|
+ BCX = env->regs[R_BCX];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_DEX
|
|||
|
+ DEX = env->regs[R_DEX];
|
|||
|
+#endif
|
|||
|
+#ifdef reg_HLX
|
|||
|
+ HLX = env->regs[R_HLX];
|
|||
|
+#endif
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void regs_to_env(void)
|
|||
|
+{
|
|||
|
+#ifdef reg_A
|
|||
|
+ env->regs[R_A] = A;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_F
|
|||
|
+ env->regs[R_F] = F;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_BC
|
|||
|
+ env->regs[R_BC] = BC;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_DE
|
|||
|
+ env->regs[R_DE] = DE;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_HL
|
|||
|
+ env->regs[R_HL] = HL;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_IX
|
|||
|
+ env->regs[R_IX] = IX;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_IY
|
|||
|
+ env->regs[R_IY] = IY;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_SP
|
|||
|
+ env->regs[R_SP] = SP;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_I
|
|||
|
+ env->regs[R_I] = I;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_R
|
|||
|
+ env->regs[R_R] = R;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_AFX
|
|||
|
+ env->regs[R_AFX] = AFX;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_BCX
|
|||
|
+ env->regs[R_BCX] = BCX;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_DEX
|
|||
|
+ env->regs[R_DEX] = DEX;
|
|||
|
+#endif
|
|||
|
+#ifdef reg_HLX
|
|||
|
+ env->regs[R_HLX] = HLX;
|
|||
|
+#endif
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/helper2.c qemu-z80/target-z80/helper2.c
|
|||
|
--- qemu-0.9.0/target-z80/helper2.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/helper2.c 2007-04-17 21:29:49.000000000 +0100
|
|||
|
@@ -0,0 +1,170 @@
|
|||
|
+/*
|
|||
|
+ * Z80 helpers (without register variable usage)
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+#include <stdarg.h>
|
|||
|
+#include <stdlib.h>
|
|||
|
+#include <stdio.h>
|
|||
|
+#include <string.h>
|
|||
|
+#include <inttypes.h>
|
|||
|
+#include <signal.h>
|
|||
|
+#include <assert.h>
|
|||
|
+
|
|||
|
+#include "cpu.h"
|
|||
|
+#include "exec-all.h"
|
|||
|
+
|
|||
|
+//#define DEBUG_MMU
|
|||
|
+
|
|||
|
+CPUZ80State *cpu_z80_init(void)
|
|||
|
+{
|
|||
|
+ CPUZ80State *env;
|
|||
|
+ static int inited;
|
|||
|
+
|
|||
|
+ env = qemu_mallocz(sizeof(CPUZ80State));
|
|||
|
+ if (!env)
|
|||
|
+ return NULL;
|
|||
|
+ cpu_exec_init(env);
|
|||
|
+
|
|||
|
+ /* init various static tables */
|
|||
|
+ if (!inited) {
|
|||
|
+ inited = 1;
|
|||
|
+ optimize_flags_init();
|
|||
|
+ }
|
|||
|
+ cpu_reset(env);
|
|||
|
+ return env;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* NOTE: must be called outside the CPU execute loop */
|
|||
|
+void cpu_reset(CPUZ80State *env)
|
|||
|
+{
|
|||
|
+ memset(env, 0, offsetof(CPUZ80State, breakpoints));
|
|||
|
+
|
|||
|
+ tlb_flush(env, 1);
|
|||
|
+
|
|||
|
+ /* init to reset state */
|
|||
|
+
|
|||
|
+#ifdef CONFIG_SOFTMMU
|
|||
|
+ env->hflags |= HF_SOFTMMU_MASK;
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+ env->pc = 0x0000;
|
|||
|
+ env->iff1 = 0;
|
|||
|
+ env->iff2 = 0;
|
|||
|
+ env->imode = 0;
|
|||
|
+ env->regs[R_A] = 0xff;
|
|||
|
+ env->regs[R_F] = 0xff;
|
|||
|
+ env->regs[R_SP] = 0xffff;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void cpu_z80_close(CPUZ80State *env)
|
|||
|
+{
|
|||
|
+ free(env);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/***********************************************************/
|
|||
|
+/* x86 debug */
|
|||
|
+
|
|||
|
+static const char *cc_op_str[] = {
|
|||
|
+ "DYNAMIC",
|
|||
|
+ "EFLAGS",
|
|||
|
+};
|
|||
|
+
|
|||
|
+void cpu_dump_state(CPUState *env, FILE *f,
|
|||
|
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
|||
|
+ int flags)
|
|||
|
+{
|
|||
|
+ int fl = env->regs[R_F];
|
|||
|
+
|
|||
|
+ cpu_fprintf(f, "AF =%04x BC =%04x DE =%04x HL =%04x IX=%04x\n"
|
|||
|
+ "AF'=%04x BC'=%04x DE'=%04x HL'=%04x IY=%04x\n"
|
|||
|
+ "PC =%04x SP =%04x F=[%c%c%c%c%c%c%c%c]\n"
|
|||
|
+ "IM=%i IFF1=%i IFF2=%i I=%02x R=%02x\n",
|
|||
|
+ (env->regs[R_A] << 8) | env->regs[R_F],
|
|||
|
+ env->regs[R_BC],
|
|||
|
+ env->regs[R_DE],
|
|||
|
+ env->regs[R_HL],
|
|||
|
+ env->regs[R_IX],
|
|||
|
+ env->regs[R_AFX],
|
|||
|
+ env->regs[R_BCX],
|
|||
|
+ env->regs[R_DEX],
|
|||
|
+ env->regs[R_HLX],
|
|||
|
+ env->regs[R_IY],
|
|||
|
+ env->pc,
|
|||
|
+ env->regs[R_SP],
|
|||
|
+ fl & 0x80 ? 'S' : '-',
|
|||
|
+ fl & 0x40 ? 'Z' : '-',
|
|||
|
+ fl & 0x20 ? 'Y' : '-',
|
|||
|
+ fl & 0x10 ? 'H' : '-',
|
|||
|
+ fl & 0x08 ? 'X' : '-',
|
|||
|
+ fl & 0x04 ? 'P' : '-',
|
|||
|
+ fl & 0x02 ? 'N' : '-',
|
|||
|
+ fl & 0x01 ? 'C' : '-',
|
|||
|
+ env->imode, env->iff1, env->iff2, env->regs[R_I], env->regs[R_R]);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/***********************************************************/
|
|||
|
+void cpu_z80_flush_tlb(CPUZ80State *env, target_ulong addr)
|
|||
|
+{
|
|||
|
+ tlb_flush_page(env, addr);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* return value:
|
|||
|
+ -1 = cannot handle fault
|
|||
|
+ 0 = nothing more to do
|
|||
|
+ 1 = generate PF fault
|
|||
|
+ 2 = soft MMU activation required for this block
|
|||
|
+*/
|
|||
|
+int cpu_z80_handle_mmu_fault(CPUZ80State *env, target_ulong addr,
|
|||
|
+ int is_write1, int is_user, int is_softmmu)
|
|||
|
+{
|
|||
|
+ int prot, page_size, ret, is_write;
|
|||
|
+ unsigned long paddr, page_offset;
|
|||
|
+ target_ulong vaddr, virt_addr;
|
|||
|
+
|
|||
|
+#if defined(DEBUG_MMU)
|
|||
|
+ printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d pc=" TARGET_FMT_lx "\n",
|
|||
|
+ addr, is_write1, is_user, env->pc);
|
|||
|
+#endif
|
|||
|
+ is_write = is_write1 & 1;
|
|||
|
+
|
|||
|
+ virt_addr = addr & TARGET_PAGE_MASK;
|
|||
|
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
|||
|
+ page_size = 4096;
|
|||
|
+
|
|||
|
+ /* Even if 4MB pages, we map only one 4KB page in the cache to
|
|||
|
+ avoid filling it too fast */
|
|||
|
+ page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
|
|||
|
+ paddr = (addr & TARGET_PAGE_MASK) + page_offset;
|
|||
|
+ vaddr = virt_addr + page_offset;
|
|||
|
+
|
|||
|
+ ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
|
|||
|
+ return ret;
|
|||
|
+}
|
|||
|
+
|
|||
|
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
|||
|
+{
|
|||
|
+ uint32_t pte, paddr, page_offset, page_size;
|
|||
|
+
|
|||
|
+ pte = addr;
|
|||
|
+ page_size = 4096;
|
|||
|
+
|
|||
|
+ page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
|
|||
|
+ paddr = (pte & TARGET_PAGE_MASK) + page_offset;
|
|||
|
+ return paddr;
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/helper.c qemu-z80/target-z80/helper.c
|
|||
|
--- qemu-0.9.0/target-z80/helper.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/helper.c 2007-04-25 17:54:06.000000000 +0100
|
|||
|
@@ -0,0 +1,283 @@
|
|||
|
+/*
|
|||
|
+ * Z80 helpers
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+#include "exec.h"
|
|||
|
+
|
|||
|
+//#define DEBUG_PCALL
|
|||
|
+
|
|||
|
+const uint8_t parity_table[256] = {
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
|
|||
|
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* modulo 17 table */
|
|||
|
+const uint8_t rclw_table[32] = {
|
|||
|
+ 0, 1, 2, 3, 4, 5, 6, 7,
|
|||
|
+ 8, 9,10,11,12,13,14,15,
|
|||
|
+ 16, 0, 1, 2, 3, 4, 5, 6,
|
|||
|
+ 7, 8, 9,10,11,12,13,14,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* modulo 9 table */
|
|||
|
+const uint8_t rclb_table[32] = {
|
|||
|
+ 0, 1, 2, 3, 4, 5, 6, 7,
|
|||
|
+ 8, 0, 1, 2, 3, 4, 5, 6,
|
|||
|
+ 7, 8, 0, 1, 2, 3, 4, 5,
|
|||
|
+ 6, 7, 8, 0, 1, 2, 3, 4,
|
|||
|
+};
|
|||
|
+
|
|||
|
+
|
|||
|
+/* thread support */
|
|||
|
+
|
|||
|
+spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
|
|||
|
+
|
|||
|
+void cpu_lock(void)
|
|||
|
+{
|
|||
|
+ spin_lock(&global_cpu_lock);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void cpu_unlock(void)
|
|||
|
+{
|
|||
|
+ spin_unlock(&global_cpu_lock);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void cpu_loop_exit(void)
|
|||
|
+{
|
|||
|
+ /* NOTE: the register at this point must be saved by hand because
|
|||
|
+ longjmp restore them */
|
|||
|
+ regs_to_env();
|
|||
|
+ longjmp(env->jmp_env, 1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void do_interrupt(CPUZ80State *env)
|
|||
|
+{
|
|||
|
+// printf("z80: do_interrupt()\n");
|
|||
|
+
|
|||
|
+ if (!env->iff1)
|
|||
|
+ return;
|
|||
|
+
|
|||
|
+ env->iff1 = 0;
|
|||
|
+ env->iff2 = 0; /* XXX: Unchanged for NMI */
|
|||
|
+
|
|||
|
+ {
|
|||
|
+ target_ulong sp;
|
|||
|
+ sp = (uint16_t)(env->regs[R_SP] - 2);
|
|||
|
+ env->regs[R_SP] = sp;
|
|||
|
+ stw_kernel(sp, env->pc);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* IM0 = execute data on bus (0xff == rst $38) */
|
|||
|
+ /* IM1 = execute rst $38 (ROM uses this)*/
|
|||
|
+ /* IM2 = indirect jump -- address is held at (I << 8) | DATA */
|
|||
|
+
|
|||
|
+ /* value on data bus is 0xff for the zx spectrum */
|
|||
|
+
|
|||
|
+ /* when an interrupt occurs, iff1 and iff2 are reset, disabling interrupts */
|
|||
|
+ /* when an NMI occurs, iff1 is reset. iff2 is left unchanged */
|
|||
|
+
|
|||
|
+ uint8_t d;
|
|||
|
+ switch (env->imode) {
|
|||
|
+ case 0:
|
|||
|
+ /* XXX: assuming 0xff on data bus */
|
|||
|
+ case 1:
|
|||
|
+ env->pc = 0x0038;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ /* XXX: assuming 0xff on data bus */
|
|||
|
+ d = 0xff;
|
|||
|
+ env->pc = lduw_kernel((env->regs[R_I] << 8) | d);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+/*
|
|||
|
+ * Signal an interruption. It is executed in the main CPU loop.
|
|||
|
+ * is_int is TRUE if coming from the int instruction. next_eip is the
|
|||
|
+ * EIP value AFTER the interrupt instruction. It is only relevant if
|
|||
|
+ * is_int is TRUE.
|
|||
|
+ */
|
|||
|
+void raise_interrupt(int intno, int is_int, int error_code,
|
|||
|
+ int next_eip_addend)
|
|||
|
+{
|
|||
|
+ env->exception_index = intno;
|
|||
|
+ env->error_code = error_code;
|
|||
|
+ env->exception_is_int = is_int;
|
|||
|
+ env->exception_next_pc = env->pc + next_eip_addend;
|
|||
|
+ cpu_loop_exit();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* same as raise_exception_err, but do not restore global registers */
|
|||
|
+static void raise_exception_err_norestore(int exception_index, int error_code)
|
|||
|
+{
|
|||
|
+ env->exception_index = exception_index;
|
|||
|
+ env->error_code = error_code;
|
|||
|
+ env->exception_is_int = 0;
|
|||
|
+ env->exception_next_pc = 0;
|
|||
|
+ longjmp(env->jmp_env, 1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* shortcuts to generate exceptions */
|
|||
|
+
|
|||
|
+void (raise_exception_err)(int exception_index, int error_code)
|
|||
|
+{
|
|||
|
+ raise_interrupt(exception_index, 0, error_code, 0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void raise_exception(int exception_index)
|
|||
|
+{
|
|||
|
+ raise_interrupt(exception_index, 0, 0, 0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void helper_hlt(void)
|
|||
|
+{
|
|||
|
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
|
|||
|
+ env->hflags |= HF_HALTED_MASK;
|
|||
|
+ env->exception_index = EXCP_HLT;
|
|||
|
+ cpu_loop_exit();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void helper_monitor(void)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+void helper_mwait(void)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+#if !defined(CONFIG_USER_ONLY)
|
|||
|
+
|
|||
|
+#define MMUSUFFIX _mmu
|
|||
|
+#define GETPC() (__builtin_return_address(0))
|
|||
|
+
|
|||
|
+#define SHIFT 0
|
|||
|
+#include "softmmu_template.h"
|
|||
|
+
|
|||
|
+#define SHIFT 1
|
|||
|
+#include "softmmu_template.h"
|
|||
|
+
|
|||
|
+#define SHIFT 2
|
|||
|
+#include "softmmu_template.h"
|
|||
|
+
|
|||
|
+#define SHIFT 3
|
|||
|
+#include "softmmu_template.h"
|
|||
|
+
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+/* try to fill the TLB and return an exception if error. If retaddr is
|
|||
|
+ NULL, it means that the function was called in C code (i.e. not
|
|||
|
+ from generated code or from helper.c) */
|
|||
|
+/* XXX: fix it to restore all registers */
|
|||
|
+void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
|
|||
|
+{
|
|||
|
+ TranslationBlock *tb;
|
|||
|
+ int ret;
|
|||
|
+ unsigned long pc;
|
|||
|
+ CPUZ80State *saved_env;
|
|||
|
+
|
|||
|
+ /* XXX: hack to restore env in all cases, even if not called from
|
|||
|
+ generated code */
|
|||
|
+ saved_env = env;
|
|||
|
+ env = cpu_single_env;
|
|||
|
+
|
|||
|
+ ret = cpu_z80_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
|||
|
+ if (ret) {
|
|||
|
+ if (retaddr) {
|
|||
|
+ /* now we have a real cpu fault */
|
|||
|
+ pc = (unsigned long)retaddr;
|
|||
|
+ tb = tb_find_pc(pc);
|
|||
|
+ if (tb) {
|
|||
|
+ /* the PC is inside the translated code. It means that we have
|
|||
|
+ a virtual CPU fault */
|
|||
|
+ cpu_restore_state(tb, env, pc, NULL);
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ if (retaddr)
|
|||
|
+ raise_exception_err(env->exception_index, env->error_code);
|
|||
|
+ else
|
|||
|
+ raise_exception_err_norestore(env->exception_index, env->error_code);
|
|||
|
+ }
|
|||
|
+ env = saved_env;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void helper_in_debug(int port)
|
|||
|
+{
|
|||
|
+// printf("IN with port %02x\n", port);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void helper_dump_registers(int pc)
|
|||
|
+{
|
|||
|
+ int fl = env->regs[R_F];
|
|||
|
+ printf("--------------\n"
|
|||
|
+ "AF =%04x BC =%04x DE =%04x HL =%04x IX=%04x\n"
|
|||
|
+ "AF'=%04x BC'=%04x DE'=%04x HL'=%04x IY=%04x\n"
|
|||
|
+ "PC =%04x SP =%04x F=[%c%c%c%c%c%c%c%c]\n"
|
|||
|
+ "IM=%i IFF1=%i IFF2=%i I=%02x R=%02x\n",
|
|||
|
+ (env->regs[R_A] << 8) | env->regs[R_F],
|
|||
|
+ env->regs[R_BC],
|
|||
|
+ env->regs[R_DE],
|
|||
|
+ env->regs[R_HL],
|
|||
|
+ env->regs[R_IX],
|
|||
|
+ env->regs[R_AFX],
|
|||
|
+ env->regs[R_BCX],
|
|||
|
+ env->regs[R_DEX],
|
|||
|
+ env->regs[R_HLX],
|
|||
|
+ env->regs[R_IY],
|
|||
|
+ pc == -1 ? env->pc : pc,
|
|||
|
+ env->regs[R_SP],
|
|||
|
+ fl & 0x80 ? 'S' : '-',
|
|||
|
+ fl & 0x40 ? 'Z' : '-',
|
|||
|
+ fl & 0x20 ? '5' : '-',
|
|||
|
+ fl & 0x10 ? 'H' : '-',
|
|||
|
+ fl & 0x08 ? '3' : '-',
|
|||
|
+ fl & 0x04 ? 'P' : '-',
|
|||
|
+ fl & 0x02 ? 'N' : '-',
|
|||
|
+ fl & 0x01 ? 'C' : '-',
|
|||
|
+ env->imode, env->iff1, env->iff2, env->regs[R_I], env->regs[R_R]);
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/op.c qemu-z80/target-z80/op.c
|
|||
|
--- qemu-0.9.0/target-z80/op.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/op.c 2007-04-25 17:41:33.000000000 +0100
|
|||
|
@@ -0,0 +1,1175 @@
|
|||
|
+/*
|
|||
|
+ * Z80 micro operations
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+
|
|||
|
+#define ASM_SOFTMMU
|
|||
|
+#include "exec.h"
|
|||
|
+
|
|||
|
+#define REGHIGH A
|
|||
|
+#define REGLOW F
|
|||
|
+#define REGPAIRNAME _AF
|
|||
|
+#define REGHIGHNAME _A
|
|||
|
+#define REGLOWNAME _F
|
|||
|
+#include "opreg_template2.h"
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+#undef REGPAIRNAME
|
|||
|
+#undef REGHIGHNAME
|
|||
|
+#undef REGLOWNAME
|
|||
|
+
|
|||
|
+#define REG BC
|
|||
|
+#define REGNAME _BC
|
|||
|
+#define REGHIGH _B
|
|||
|
+#define REGLOW _C
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+
|
|||
|
+#define REG DE
|
|||
|
+#define REGNAME _DE
|
|||
|
+#define REGHIGH _D
|
|||
|
+#define REGLOW _E
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+
|
|||
|
+#define REG HL
|
|||
|
+#define REGNAME _HL
|
|||
|
+#define REGHIGH _H
|
|||
|
+#define REGLOW _L
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+
|
|||
|
+#define REG IX
|
|||
|
+#define REGNAME _IX
|
|||
|
+#define REGHIGH _IXh
|
|||
|
+#define REGLOW _IXl
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+
|
|||
|
+#define REG IY
|
|||
|
+#define REGNAME _IY
|
|||
|
+#define REGHIGH _IYh
|
|||
|
+#define REGLOW _IYl
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+#undef REGHIGH
|
|||
|
+#undef REGLOW
|
|||
|
+
|
|||
|
+#define REG SP
|
|||
|
+#define REGNAME _SP
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+
|
|||
|
+#define REG AFX
|
|||
|
+#define REGNAME _AFX
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+
|
|||
|
+#define REG BCX
|
|||
|
+#define REGNAME _BCX
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+
|
|||
|
+#define REG DEX
|
|||
|
+#define REGNAME _DEX
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+
|
|||
|
+#define REG HLX
|
|||
|
+#define REGNAME _HLX
|
|||
|
+#include "opreg_template.h"
|
|||
|
+#undef REG
|
|||
|
+#undef REGNAME
|
|||
|
+
|
|||
|
+void OPPROTO op_movl_pc_im(void)
|
|||
|
+{
|
|||
|
+ PC = (uint16_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_debug(void)
|
|||
|
+{
|
|||
|
+ env->exception_index = EXCP_DEBUG;
|
|||
|
+ cpu_loop_exit();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_raise_exception(void)
|
|||
|
+{
|
|||
|
+ int exception_index;
|
|||
|
+ exception_index = PARAM1;
|
|||
|
+ raise_exception(exception_index);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_set_inhibit_irq(void)
|
|||
|
+{
|
|||
|
+ env->hflags |= HF_INHIBIT_IRQ_MASK;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_reset_inhibit_irq(void)
|
|||
|
+{
|
|||
|
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movl_T0_0(void)
|
|||
|
+{
|
|||
|
+ T0 = 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_exit_tb(void)
|
|||
|
+{
|
|||
|
+ EXIT_TB();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/************ Z80 MICRO-OPS ***********/
|
|||
|
+
|
|||
|
+/* Loads/stores */
|
|||
|
+
|
|||
|
+void OPPROTO op_mov_T0_im(void)
|
|||
|
+{
|
|||
|
+ T0 = (uint16_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_mov_T1_im(void)
|
|||
|
+{
|
|||
|
+ T0 = (uint16_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_mov_A0_im(void)
|
|||
|
+{
|
|||
|
+ A0 = (uint16_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_T0_HLmem(void)
|
|||
|
+{
|
|||
|
+ A0 = HL;
|
|||
|
+ T0 = ldub_kernel(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_HLmem_T0(void)
|
|||
|
+{
|
|||
|
+ A0 = HL;
|
|||
|
+ stb_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_T0_IXmem(void)
|
|||
|
+{
|
|||
|
+ A0 = (uint16_t)(IX + PARAM1);
|
|||
|
+ T0 = ldub_kernel(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_IXmem_T0(void)
|
|||
|
+{
|
|||
|
+ A0 = (uint16_t)(IX + PARAM1);
|
|||
|
+ stb_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_T0_IYmem(void)
|
|||
|
+{
|
|||
|
+ A0 = (uint16_t)(IY + PARAM1);
|
|||
|
+ T0 = ldub_kernel(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_movb_IYmem_T0(void)
|
|||
|
+{
|
|||
|
+ A0 = (uint16_t)(IY + PARAM1);
|
|||
|
+ stb_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ldb_T0_A0(void)
|
|||
|
+{
|
|||
|
+ T0 = ldub_kernel(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ldw_T0_A0(void)
|
|||
|
+{
|
|||
|
+ T0 = lduw_kernel(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_stb_T0_A0(void)
|
|||
|
+{
|
|||
|
+ stb_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_stw_T0_A0(void)
|
|||
|
+{
|
|||
|
+ stw_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Stack operations */
|
|||
|
+
|
|||
|
+void OPPROTO op_pushw_T0(void)
|
|||
|
+{
|
|||
|
+ SP = (uint16_t)(SP - 2);
|
|||
|
+ A0 = SP;
|
|||
|
+ /* high byte pushed first: i.e. little endian */
|
|||
|
+ stw_kernel(A0, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_popw_T0(void)
|
|||
|
+{
|
|||
|
+ A0 = SP;
|
|||
|
+ /* low byte popped first: i.e. little endian */
|
|||
|
+ T0 = lduw_kernel(A0);
|
|||
|
+ SP = (uint16_t)(SP + 2);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_popw_T1(void)
|
|||
|
+{
|
|||
|
+ A0 = SP;
|
|||
|
+ /* low byte popped first: i.e. little endian */
|
|||
|
+ T1 = lduw_kernel(A0);
|
|||
|
+ SP = (uint16_t)(SP + 2);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Exchange operations */
|
|||
|
+
|
|||
|
+void OPPROTO op_ex_de_hl(void)
|
|||
|
+{
|
|||
|
+ T0 = DE;
|
|||
|
+ DE = HL;
|
|||
|
+ HL = T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ex_af_afx(void)
|
|||
|
+{
|
|||
|
+ T0 = AFX;
|
|||
|
+ AFX = (A << 8) | F;
|
|||
|
+ A = (uint8_t)(T0 >> 8);
|
|||
|
+ F = (uint8_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_exx(void)
|
|||
|
+{
|
|||
|
+ T0 = BCX;
|
|||
|
+ BCX = BC;
|
|||
|
+ BC = T0;
|
|||
|
+
|
|||
|
+ T0 = DEX;
|
|||
|
+ DEX = DE;
|
|||
|
+ DE = T0;
|
|||
|
+
|
|||
|
+ T0 = HLX;
|
|||
|
+ HLX = HL;
|
|||
|
+ HL = T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Misc */
|
|||
|
+
|
|||
|
+void OPPROTO op_in_T0_im(void)
|
|||
|
+{
|
|||
|
+ helper_in_debug((A << 8) | PARAM1);
|
|||
|
+ T0 = cpu_inb(env, (A << 8) | PARAM1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_in_T0_bc_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+
|
|||
|
+ helper_in_debug(BC);
|
|||
|
+ T0 = cpu_inb(env, BC);
|
|||
|
+
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[(uint8_t)T0];
|
|||
|
+ F = (F & CC_C) | sf | zf | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_out_T0_im(void)
|
|||
|
+{
|
|||
|
+ cpu_outb(env, (A << 8) | PARAM1, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_out_T0_bc(void)
|
|||
|
+{
|
|||
|
+ cpu_outb(env, BC, T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bit_T0(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+
|
|||
|
+ sf = (T0 & PARAM1 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = (T0 & PARAM1) ? 0 : CC_Z;
|
|||
|
+ pf = (T0 & PARAM1) ? 0 : CC_P;
|
|||
|
+ F = (F & CC_C) | sf | zf | CC_H | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_res_T0(void)
|
|||
|
+{
|
|||
|
+ T0 &= (uint8_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_set_T0(void)
|
|||
|
+{
|
|||
|
+ T0 |= (uint8_t)PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jmp_T0(void)
|
|||
|
+{
|
|||
|
+ PC = T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_djnz(void)
|
|||
|
+{
|
|||
|
+ BC = (uint16_t)(BC - 0x0100);
|
|||
|
+ if (BC & 0xff00)
|
|||
|
+ PC = PARAM1;
|
|||
|
+ else
|
|||
|
+ PC = PARAM2;
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Conditional jumps */
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_nz(void)
|
|||
|
+{
|
|||
|
+ if (!(F & CC_Z))
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_z(void)
|
|||
|
+{
|
|||
|
+ if (F & CC_Z)
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_nc(void)
|
|||
|
+{
|
|||
|
+ if (!(F & CC_C))
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_c(void)
|
|||
|
+{
|
|||
|
+ if (F & CC_C)
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_po(void)
|
|||
|
+{
|
|||
|
+ if (!(F & CC_P))
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_pe(void)
|
|||
|
+{
|
|||
|
+ if (F & CC_P)
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_p(void)
|
|||
|
+{
|
|||
|
+ if (!(F & CC_S))
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_jp_m(void)
|
|||
|
+{
|
|||
|
+ if (F & CC_S)
|
|||
|
+ GOTO_LABEL_PARAM(1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Arithmetic/logic operations */
|
|||
|
+
|
|||
|
+#define signed_overflow_add(op1, op2, res, size) \
|
|||
|
+ (!!((~(op1 ^ op2) & (op1 ^ res)) >> (size - 1)))
|
|||
|
+
|
|||
|
+#define signed_overflow_sub(op1, op2, res, size) \
|
|||
|
+ (!!(((op1 ^ op2) & (op1 ^ res)) >> (size - 1)))
|
|||
|
+
|
|||
|
+void OPPROTO op_add_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = A;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ A = (uint8_t)(A + T0);
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_add(tmp, T0, A, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_adc_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = A;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ A = (uint8_t)(A + T0 + !!(F & CC_C));
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_add(tmp, T0, A, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_sub_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = A;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ A = (uint8_t)(A - T0);
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ carry = (~tmp & T0) | (~(tmp ^ T0) & A);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | CC_N | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_sbc_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = A;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ A = (uint8_t)(A - T0 - !!(F & CC_C));
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ carry = (~tmp & T0) | (~(tmp ^ T0) & A);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | CC_N | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_and_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+ A = (uint8_t)(A & T0);
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[(uint8_t)A];
|
|||
|
+ F = sf | zf | CC_H | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_xor_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+ A = (uint8_t)(A ^ T0);
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[(uint8_t)A];
|
|||
|
+ F = sf | zf | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_or_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+ A = (uint8_t)(A | T0);
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[(uint8_t)A];
|
|||
|
+ F = sf | zf | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_cp_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int res, carry;
|
|||
|
+
|
|||
|
+ res = (uint8_t)(A - T0);
|
|||
|
+ sf = (res & 0x80) ? CC_S : 0;
|
|||
|
+ zf = res ? 0 : CC_Z;
|
|||
|
+ carry = (~A & T0) | (~(A ^ T0) & res);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(A, T0, res, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | CC_N | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+// CC_DST = (uint8_t)(A - T0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Rotation/shift operations */
|
|||
|
+
|
|||
|
+void OPPROTO op_rlc_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 << 1) | !!(T0 & 0x80));
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rrc_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 >> 1) | ((tmp & 0x01) ? 0x80 : 0));
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rl_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 << 1) | !!(F & CC_C));
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rr_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 >> 1) | ((F & CC_C) ? 0x80 : 0));
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_sla_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)(T0 << 1);
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_sra_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 >> 1) | (T0 & 0x80));
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Z80-specific: R800 has tst instruction */
|
|||
|
+void OPPROTO op_sll_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)((T0 << 1) | 1); /* Yes -- bit 0 is *set* */
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_srl_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf, cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)(T0 >> 1);
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[T0];
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = sf | zf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rld_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+ int tmp = A & 0x0f;
|
|||
|
+ A = (A & 0xf0) | ((T0 >> 4) & 0x0f);
|
|||
|
+ T0 = ((T0 << 4) & 0xf0) | tmp;
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[A];
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rrd_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+ int tmp = A & 0x0f;
|
|||
|
+ A = (A & 0xf0) | (T0 & 0x0f);
|
|||
|
+ T0 = (T0 >> 4) | (tmp << 4);
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = parity_table[A];
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Block instructions */
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_ld_inc_cc(void)
|
|||
|
+{
|
|||
|
+ int pf;
|
|||
|
+
|
|||
|
+ BC = (uint16_t)(BC - 1);
|
|||
|
+ DE = (uint16_t)(DE + 1);
|
|||
|
+ HL = (uint16_t)(HL + 1);
|
|||
|
+
|
|||
|
+ pf = BC ? CC_P : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_C)) | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_ld_dec_cc(void)
|
|||
|
+{
|
|||
|
+ int pf;
|
|||
|
+
|
|||
|
+ BC = (uint16_t)(BC - 1);
|
|||
|
+ DE = (uint16_t)(DE - 1);
|
|||
|
+ HL = (uint16_t)(HL - 1);
|
|||
|
+
|
|||
|
+ pf = BC ? CC_P : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_C)) | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_ld_rep(void)
|
|||
|
+{
|
|||
|
+ if (BC)
|
|||
|
+ PC = PARAM1 - 2;
|
|||
|
+ else
|
|||
|
+ PC = PARAM1;
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_cp_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf;
|
|||
|
+ int res, carry;
|
|||
|
+
|
|||
|
+ res = (uint8_t)(A - T0);
|
|||
|
+ sf = (res & 0x80) ? CC_S : 0;
|
|||
|
+ zf = res ? 0 : CC_Z;
|
|||
|
+ carry = (~A & T0) | (~(A ^ T0) & res);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = BC ? CC_P : 0;
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | hf | pf | CC_N;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_cp_inc_cc(void)
|
|||
|
+{
|
|||
|
+ int pf;
|
|||
|
+
|
|||
|
+ BC = (uint16_t)(BC - 1);
|
|||
|
+ HL = (uint16_t)(HL + 1);
|
|||
|
+
|
|||
|
+ pf = BC ? CC_P : 0;
|
|||
|
+ F = (F & ~CC_P) | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_cp_dec_cc(void)
|
|||
|
+{
|
|||
|
+ int pf;
|
|||
|
+
|
|||
|
+ BC = (uint16_t)(BC - 1);
|
|||
|
+ HL = (uint16_t)(HL - 1);
|
|||
|
+
|
|||
|
+ pf = BC ? CC_P : 0;
|
|||
|
+ F = (F & ~CC_P) | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_cp_rep(void)
|
|||
|
+{
|
|||
|
+ if (BC && T0 != A)
|
|||
|
+ PC = PARAM1 - 2;
|
|||
|
+ else
|
|||
|
+ PC = PARAM1;
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_io_inc(void)
|
|||
|
+{
|
|||
|
+ HL = (uint16_t)(HL + 1);
|
|||
|
+ BC = (uint16_t)BC - 0x0100;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_io_dec(void)
|
|||
|
+{
|
|||
|
+ HL = (uint16_t)(HL - 1);
|
|||
|
+ BC = (uint16_t)BC - 0x0100;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_bli_io_rep(void)
|
|||
|
+{
|
|||
|
+ if (BC & 0xff00)
|
|||
|
+ PC = PARAM1 - 2;
|
|||
|
+ else
|
|||
|
+ PC = PARAM1;
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* misc */
|
|||
|
+
|
|||
|
+void OPPROTO op_rlca_cc(void)
|
|||
|
+{
|
|||
|
+ int cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = A;
|
|||
|
+ A = (uint8_t)((A << 1) | !!(tmp & 0x80));
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rrca_cc(void)
|
|||
|
+{
|
|||
|
+ int cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = A;
|
|||
|
+ A = (A >> 1) | ((tmp & 0x01) ? 0x80 : 0);
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rla_cc(void)
|
|||
|
+{
|
|||
|
+ int cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = A;
|
|||
|
+ A = (uint8_t)((A << 1) | !!(F & CC_C));
|
|||
|
+ cf = (tmp & 0x80) ? CC_C : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_rra_cc(void)
|
|||
|
+{
|
|||
|
+ int cf;
|
|||
|
+ int tmp;
|
|||
|
+
|
|||
|
+ tmp = A;
|
|||
|
+ A = (A >> 1) | ((F & CC_C) ? 0x80 : 0);
|
|||
|
+ cf = (tmp & 0x01) ? CC_C : 0;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* TODO */
|
|||
|
+void OPPROTO op_daa_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int cor = 0;
|
|||
|
+ int tmp = A;
|
|||
|
+
|
|||
|
+ if (A > 0x99 || (F & CC_C)) {
|
|||
|
+ cor |= 0x60;
|
|||
|
+ cf = CC_C;
|
|||
|
+ } else {
|
|||
|
+ cf = 0;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if ((A & 0x0f) > 0x09 || (F & CC_H)) {
|
|||
|
+ cor |= 0x06;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (!(F & CC_N)) {
|
|||
|
+ A = (uint8_t)(A + cor);
|
|||
|
+ } else {
|
|||
|
+ A = (uint8_t)(A - cor);
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ hf = ((tmp ^ A) & 0x10) ? CC_H : 0;
|
|||
|
+ pf = parity_table[(uint8_t)A];
|
|||
|
+
|
|||
|
+ F = (F & CC_N) | sf | zf | hf | pf | cf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_cpl_cc(void)
|
|||
|
+{
|
|||
|
+ A = (uint8_t)~A;
|
|||
|
+ F |= CC_H | CC_N;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_scf_cc(void)
|
|||
|
+{
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | CC_C;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ccf_cc(void)
|
|||
|
+{
|
|||
|
+ int hf, cf;
|
|||
|
+
|
|||
|
+ hf = (F & CC_C) ? CC_H : 0;
|
|||
|
+ cf = (F & CC_C) ^ CC_C;
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | hf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* misc */
|
|||
|
+
|
|||
|
+void OPPROTO op_neg_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = A;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ A = (uint8_t)-A;
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ carry = (tmp & T0) | ((tmp | T0) & ~A);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(tmp, T0, A, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x80) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | CC_N | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* word operations -- HL only? */
|
|||
|
+
|
|||
|
+void OPPROTO op_incw_T0(void)
|
|||
|
+{
|
|||
|
+ T0++;
|
|||
|
+ T0 = (uint16_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_decw_T0(void)
|
|||
|
+{
|
|||
|
+ T0--;
|
|||
|
+ T0 = (uint16_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_sbcw_T0_T1_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = T0;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ T0 = (uint16_t)(T0 - T1 - !!(F & CC_C));
|
|||
|
+ sf = (T0 & 0x8000) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ carry = (~tmp & T1) | (~(tmp ^ T1) & T0);
|
|||
|
+ hf = (carry & 0x0800) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(tmp, T1, T0, 16) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x8000) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | CC_N | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_addw_T0_T1_cc(void)
|
|||
|
+{
|
|||
|
+ int hf, cf;
|
|||
|
+ int tmp = T0;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ T0 = (uint16_t)(T0 + T1);
|
|||
|
+ carry = (tmp & T1) | ((tmp | T1) & ~T0);
|
|||
|
+ hf = (carry & 0x0800) ? CC_H : 0;
|
|||
|
+ cf = (carry & 0x8000) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = (F & (CC_S | CC_Z | CC_P)) | hf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_adcw_T0_T1_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf, cf;
|
|||
|
+ int tmp = T0;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ T0 = (uint16_t)(T0 + T1 + !!(F & CC_C));
|
|||
|
+ sf = (T0 & 0x8000) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+ carry = (tmp & T1) | ((tmp | T1) & ~T0);
|
|||
|
+ hf = (carry & 0x0800) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_add(tmp, T1, T0, 8) ? CC_P : 0;
|
|||
|
+ cf = (carry & 0x8000) ? CC_C : 0;
|
|||
|
+
|
|||
|
+ F = sf | zf | hf | pf | cf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* misc */
|
|||
|
+
|
|||
|
+void OPPROTO op_incb_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf;
|
|||
|
+ int tmp;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)(T0 + 1);
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+
|
|||
|
+ carry = (tmp & 1) | ((tmp | 1) & ~T0);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_add(tmp, 1, T0, 8) ? CC_P : 0;
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | hf | pf;
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_decb_T0_cc(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, hf, pf;
|
|||
|
+ int tmp;
|
|||
|
+ int carry;
|
|||
|
+
|
|||
|
+ tmp = T0;
|
|||
|
+ T0 = (uint8_t)(T0 - 1);
|
|||
|
+ sf = (T0 & 0x80) ? CC_S : 0;
|
|||
|
+ zf = T0 ? 0 : CC_Z;
|
|||
|
+
|
|||
|
+ carry = (~tmp & 1) | (~(tmp ^ 1) & T0);
|
|||
|
+ hf = (carry & 0x08) ? CC_H : 0;
|
|||
|
+ pf = signed_overflow_sub(tmp, 1, T0, 8) ? CC_P : 0;
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | hf | CC_N | pf;
|
|||
|
+ /* TODO: check CC_N is set */
|
|||
|
+
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* value on data bus is 0xff for speccy */
|
|||
|
+/* IM0 = execute data on bus (rst $38 on speccy) */
|
|||
|
+/* IM1 = execute rst $38 (ROM uses this)*/
|
|||
|
+/* IM2 = indirect jump -- address is held at (I << 8) | DATA */
|
|||
|
+
|
|||
|
+/* when an interrupt occurs, iff1 and iff2 are reset, disabling interrupts */
|
|||
|
+/* when an NMI occurs, iff1 is reset. iff2 is left unchanged */
|
|||
|
+
|
|||
|
+void OPPROTO op_imode(void)
|
|||
|
+{
|
|||
|
+ /* env->imode = PARAM1; */
|
|||
|
+ env->imode = PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* enable interrupts */
|
|||
|
+void OPPROTO op_ei(void)
|
|||
|
+{
|
|||
|
+ env->iff1 = 1;
|
|||
|
+ env->iff2 = 1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* disable interrupts */
|
|||
|
+void OPPROTO op_di(void)
|
|||
|
+{
|
|||
|
+ env->iff1 = 0;
|
|||
|
+ env->iff2 = 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* reenable interrupts if enabled */
|
|||
|
+void OPPROTO op_ri(void)
|
|||
|
+{
|
|||
|
+ env->iff1 = env->iff2;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_halt(void)
|
|||
|
+{
|
|||
|
+ helper_hlt();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ld_R_A(void)
|
|||
|
+{
|
|||
|
+ R = A;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ld_I_A(void)
|
|||
|
+{
|
|||
|
+ I = A;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ld_A_R(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+
|
|||
|
+ A = R;
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = env->iff2 ? CC_P : 0;
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_ld_A_I(void)
|
|||
|
+{
|
|||
|
+ int sf, zf, pf;
|
|||
|
+
|
|||
|
+ A = I;
|
|||
|
+ sf = (A & 0x80) ? CC_S : 0;
|
|||
|
+ zf = A ? 0 : CC_Z;
|
|||
|
+ pf = env->iff2 ? CC_P : 0;
|
|||
|
+
|
|||
|
+ F = (F & CC_C) | sf | zf | pf;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_dump_registers(void)
|
|||
|
+{
|
|||
|
+ helper_dump_registers(PARAM1);
|
|||
|
+}
|
|||
|
+
|
|||
|
+/*********** END OF Z80 OPS ***********/
|
|||
|
+
|
|||
|
+void OPPROTO op_set_cc_op(void)
|
|||
|
+{
|
|||
|
+ CC_OP = PARAM1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int compute_all_eflags(void)
|
|||
|
+{
|
|||
|
+ return CC_SRC;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int compute_c_eflags(void)
|
|||
|
+{
|
|||
|
+ return CC_SRC & CC_C;
|
|||
|
+}
|
|||
|
+
|
|||
|
+CCTable cc_table[CC_OP_NB] = {
|
|||
|
+ [CC_OP_DYNAMIC] = { /* should never happen */ },
|
|||
|
+
|
|||
|
+ [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* threading support */
|
|||
|
+void OPPROTO op_lock(void)
|
|||
|
+{
|
|||
|
+ cpu_lock();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO op_unlock(void)
|
|||
|
+{
|
|||
|
+ cpu_unlock();
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/opreg_template2.h qemu-z80/target-z80/opreg_template2.h
|
|||
|
--- qemu-0.9.0/target-z80/opreg_template2.h 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/opreg_template2.h 2007-03-27 21:42:55.000000000 +0100
|
|||
|
@@ -0,0 +1,63 @@
|
|||
|
+/*
|
|||
|
+ * Z80 micro operations (templates for various register related
|
|||
|
+ * operations)
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movw_T0,REGPAIRNAME)(void)
|
|||
|
+{
|
|||
|
+ T0 = (REGHIGH << 8) | REGLOW;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movb_T0,REGHIGHNAME)(void)
|
|||
|
+{
|
|||
|
+ T0 = REGHIGH;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movb_T0,REGLOWNAME)(void)
|
|||
|
+{
|
|||
|
+ T0 = REGLOW;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movw_T1,REGPAIRNAME)(void)
|
|||
|
+{
|
|||
|
+ T1 = (REGHIGH << 8) | REGLOW;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movw,REGPAIRNAME),_T0)(void)
|
|||
|
+{
|
|||
|
+ REGHIGH = (uint8_t)(T0 >> 8);
|
|||
|
+ REGLOW = (uint8_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movb,REGHIGHNAME),_T0)(void)
|
|||
|
+{
|
|||
|
+ REGHIGH = (uint8_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movb,REGLOWNAME),_T0)(void)
|
|||
|
+{
|
|||
|
+ REGLOW = (uint8_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movw,REGPAIRNAME),_T1)(void)
|
|||
|
+{
|
|||
|
+ REGHIGH = (uint16_t)(T1 >> 8);
|
|||
|
+ REGLOW = (uint16_t)T1;
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/opreg_template.h qemu-z80/target-z80/opreg_template.h
|
|||
|
--- qemu-0.9.0/target-z80/opreg_template.h 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/opreg_template.h 2007-03-27 21:43:07.000000000 +0100
|
|||
|
@@ -0,0 +1,74 @@
|
|||
|
+/*
|
|||
|
+ * Z80 micro operations (templates for various register related
|
|||
|
+ * operations)
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movw_T0,REGNAME)(void)
|
|||
|
+{
|
|||
|
+ T0 = REG;
|
|||
|
+}
|
|||
|
+
|
|||
|
+#ifdef REGHIGH
|
|||
|
+void OPPROTO glue(op_movb_T0,REGHIGH)(void)
|
|||
|
+{
|
|||
|
+ T0 = (REG >> 8) & 0xff;
|
|||
|
+}
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef REGLOW
|
|||
|
+void OPPROTO glue(op_movb_T0,REGLOW)(void)
|
|||
|
+{
|
|||
|
+ T0 = REG & 0xff;
|
|||
|
+}
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movw_T1,REGNAME)(void)
|
|||
|
+{
|
|||
|
+ T1 = REG;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(op_movw_A0,REGNAME)(void)
|
|||
|
+{
|
|||
|
+ A0 = REG;
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
|
|||
|
+{
|
|||
|
+ REG = (uint16_t)T0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+#ifdef REGHIGH
|
|||
|
+void OPPROTO glue(glue(op_movb,REGHIGH),_T0)(void)
|
|||
|
+{
|
|||
|
+ REG = (REG & 0xff) | ((T0 & 0xff) << 8);
|
|||
|
+}
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+#ifdef REGLOW
|
|||
|
+void OPPROTO glue(glue(op_movb,REGLOW),_T0)(void)
|
|||
|
+{
|
|||
|
+ REG = (REG & 0xff00) | (T0 & 0xff);
|
|||
|
+}
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
|
|||
|
+{
|
|||
|
+ REG = (uint16_t)T1;
|
|||
|
+}
|
|||
|
diff -urN qemu-0.9.0/target-z80/ops_mem.h qemu-z80/target-z80/ops_mem.h
|
|||
|
--- qemu-0.9.0/target-z80/ops_mem.h 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/ops_mem.h 2007-04-15 19:39:49.000000000 +0100
|
|||
|
@@ -0,0 +1,59 @@
|
|||
|
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ T0 = glue(ldub, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ T0 = glue(ldsb, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ T0 = glue(lduw, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ T0 = glue(ldsw, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
|
|||
|
+{
|
|||
|
+ T1 = glue(ldub, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
|
|||
|
+{
|
|||
|
+ T1 = glue(ldsb, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
|
|||
|
+{
|
|||
|
+ T1 = glue(lduw, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
|
|||
|
+{
|
|||
|
+ T1 = glue(ldsw, MEMSUFFIX)(A0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ glue(stb, MEMSUFFIX)(A0, T0);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
|
|||
|
+{
|
|||
|
+ glue(stw, MEMSUFFIX)(A0, T0);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void)
|
|||
|
+{
|
|||
|
+ glue(stw, MEMSUFFIX)(A0, T1);
|
|||
|
+ FORCE_RET();
|
|||
|
+}
|
|||
|
+
|
|||
|
+#undef MEMSUFFIX
|
|||
|
diff -urN qemu-0.9.0/target-z80/translate.c qemu-z80/target-z80/translate.c
|
|||
|
--- qemu-0.9.0/target-z80/translate.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/target-z80/translate.c 2007-04-25 17:54:16.000000000 +0100
|
|||
|
@@ -0,0 +1,1600 @@
|
|||
|
+/*
|
|||
|
+ * Z80 translation
|
|||
|
+ *
|
|||
|
+ * Copyright (c) 2007 Stuart Brady
|
|||
|
+ * Copyright (c) 2003 Fabrice Bellard
|
|||
|
+ *
|
|||
|
+ * This library is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library; if not, write to the Free Software
|
|||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
+ */
|
|||
|
+#include <stdarg.h>
|
|||
|
+#include <stdlib.h>
|
|||
|
+#include <stdio.h>
|
|||
|
+#include <string.h>
|
|||
|
+#include <inttypes.h>
|
|||
|
+#include <signal.h>
|
|||
|
+#include <assert.h>
|
|||
|
+
|
|||
|
+#include "cpu.h"
|
|||
|
+#include "exec-all.h"
|
|||
|
+#include "disas.h"
|
|||
|
+
|
|||
|
+/* XXX: move that elsewhere */
|
|||
|
+static uint16_t *gen_opc_ptr;
|
|||
|
+static uint32_t *gen_opparam_ptr;
|
|||
|
+
|
|||
|
+#define PREFIX_CB 0x01
|
|||
|
+#define PREFIX_DD 0x02
|
|||
|
+#define PREFIX_ED 0x04
|
|||
|
+#define PREFIX_FD 0x08
|
|||
|
+
|
|||
|
+#ifdef USE_DIRECT_JUMP
|
|||
|
+#define TBPARAM(x)
|
|||
|
+#else
|
|||
|
+#define TBPARAM(x) (long)(x)
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+//#define zprintf(...)
|
|||
|
+#define zprintf printf
|
|||
|
+
|
|||
|
+typedef struct DisasContext {
|
|||
|
+ /* current insn context */
|
|||
|
+ int override; /* -1 if no override */
|
|||
|
+ int prefix;
|
|||
|
+ uint16_t pc; /* pc = pc + cs_base */
|
|||
|
+ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
|
|||
|
+ static state change (stop translation) */
|
|||
|
+ /* current block context */
|
|||
|
+ target_ulong cs_base; /* base of CS segment */
|
|||
|
+ int cc_op; /* current CC operation */
|
|||
|
+ int singlestep_enabled; /* "hardware" single step enabled */
|
|||
|
+ int jmp_opt; /* use direct block chaining for direct jumps */
|
|||
|
+ int flags; /* all execution flags */
|
|||
|
+ struct TranslationBlock *tb;
|
|||
|
+} DisasContext;
|
|||
|
+
|
|||
|
+static void gen_eob(DisasContext *s);
|
|||
|
+static void gen_jmp(DisasContext *s, target_ulong pc);
|
|||
|
+static void gen_jmp_tb(DisasContext *s, target_ulong pc, int tb_num);
|
|||
|
+
|
|||
|
+/* i386 arith/logic operations */
|
|||
|
+enum {
|
|||
|
+ OP_ADDL,
|
|||
|
+ OP_ORL,
|
|||
|
+ OP_ADCL,
|
|||
|
+ OP_SBBL,
|
|||
|
+ OP_ANDL,
|
|||
|
+ OP_SUBL,
|
|||
|
+ OP_XORL,
|
|||
|
+ OP_CMPL,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum {
|
|||
|
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
|||
|
+#include "opc.h"
|
|||
|
+#undef DEF
|
|||
|
+ NB_OPS,
|
|||
|
+};
|
|||
|
+
|
|||
|
+#include "gen-op.h"
|
|||
|
+
|
|||
|
+enum {
|
|||
|
+ /* 8-bit registers */
|
|||
|
+ OR_B,
|
|||
|
+ OR_C,
|
|||
|
+ OR_D,
|
|||
|
+ OR_E,
|
|||
|
+ OR_H,
|
|||
|
+ OR_L,
|
|||
|
+ OR_HLmem,
|
|||
|
+ OR_A,
|
|||
|
+
|
|||
|
+ OR_IXh,
|
|||
|
+ OR_IXl,
|
|||
|
+
|
|||
|
+ OR_IYh,
|
|||
|
+ OR_IYl,
|
|||
|
+
|
|||
|
+ OR_IXmem,
|
|||
|
+ OR_IYmem,
|
|||
|
+};
|
|||
|
+
|
|||
|
+char *regnames[] = {
|
|||
|
+ [OR_B] = "b",
|
|||
|
+ [OR_C] = "c",
|
|||
|
+ [OR_D] = "d",
|
|||
|
+ [OR_E] = "e",
|
|||
|
+ [OR_H] = "h",
|
|||
|
+ [OR_L] = "l",
|
|||
|
+ [OR_HLmem] = "(hl)",
|
|||
|
+ [OR_A] = "a",
|
|||
|
+
|
|||
|
+ [OR_IXh] = "ixh",
|
|||
|
+ [OR_IXl] = "ixl",
|
|||
|
+
|
|||
|
+ [OR_IYh] = "iyh",
|
|||
|
+ [OR_IYl] = "iyl",
|
|||
|
+
|
|||
|
+ [OR_IXmem] = "(ix+d)",
|
|||
|
+ [OR_IYmem] = "(iy+d)",
|
|||
|
+};
|
|||
|
+
|
|||
|
+char *idxnames[] = {
|
|||
|
+ [OR_IXmem] = "ix",
|
|||
|
+ [OR_IYmem] = "iy",
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* signed hex byte value for printf */
|
|||
|
+#define shexb(val) (val < 0 ? '-' : '+'), (abs(val))
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movb_T0_reg[] = {
|
|||
|
+ [OR_B] = gen_op_movb_T0_B,
|
|||
|
+ [OR_C] = gen_op_movb_T0_C,
|
|||
|
+ [OR_D] = gen_op_movb_T0_D,
|
|||
|
+ [OR_E] = gen_op_movb_T0_E,
|
|||
|
+ [OR_H] = gen_op_movb_T0_H,
|
|||
|
+ [OR_L] = gen_op_movb_T0_L,
|
|||
|
+ [OR_HLmem] = gen_op_movb_T0_HLmem,
|
|||
|
+ [OR_A] = gen_op_movb_T0_A,
|
|||
|
+
|
|||
|
+ [OR_IXh] = gen_op_movb_T0_IXh,
|
|||
|
+ [OR_IXl] = gen_op_movb_T0_IXl,
|
|||
|
+
|
|||
|
+ [OR_IYh] = gen_op_movb_T0_IYh,
|
|||
|
+ [OR_IYl] = gen_op_movb_T0_IYl,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc1 *gen_op_movb_T0_idx[] = {
|
|||
|
+ [OR_IXmem] = gen_op_movb_T0_IXmem,
|
|||
|
+ [OR_IYmem] = gen_op_movb_T0_IYmem,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movb_reg_T0[] = {
|
|||
|
+ [OR_B] = gen_op_movb_B_T0,
|
|||
|
+ [OR_C] = gen_op_movb_C_T0,
|
|||
|
+ [OR_D] = gen_op_movb_D_T0,
|
|||
|
+ [OR_E] = gen_op_movb_E_T0,
|
|||
|
+ [OR_H] = gen_op_movb_H_T0,
|
|||
|
+ [OR_L] = gen_op_movb_L_T0,
|
|||
|
+ [OR_HLmem] = gen_op_movb_HLmem_T0,
|
|||
|
+ [OR_A] = gen_op_movb_A_T0,
|
|||
|
+
|
|||
|
+ [OR_IXh] = gen_op_movb_IXh_T0,
|
|||
|
+ [OR_IXl] = gen_op_movb_IXl_T0,
|
|||
|
+
|
|||
|
+ [OR_IYh] = gen_op_movb_IYh_T0,
|
|||
|
+ [OR_IYl] = gen_op_movb_IYl_T0,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc1 *gen_op_movb_idx_T0[] = {
|
|||
|
+ [OR_IXmem] = gen_op_movb_IXmem_T0,
|
|||
|
+ [OR_IYmem] = gen_op_movb_IYmem_T0,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static inline int regmap(int reg, int m) {
|
|||
|
+ switch (m) {
|
|||
|
+ case 1:
|
|||
|
+ switch (reg) {
|
|||
|
+ case OR_H:
|
|||
|
+ return OR_IXh;
|
|||
|
+ case OR_L:
|
|||
|
+ return OR_IXl;
|
|||
|
+ case OR_HLmem:
|
|||
|
+ return OR_IXmem;
|
|||
|
+ default:
|
|||
|
+ return reg;
|
|||
|
+ }
|
|||
|
+ case 2:
|
|||
|
+ switch (reg) {
|
|||
|
+ case OR_H:
|
|||
|
+ return OR_IYh;
|
|||
|
+ case OR_L:
|
|||
|
+ return OR_IYl;
|
|||
|
+ case OR_HLmem:
|
|||
|
+ return OR_IYmem;
|
|||
|
+ default:
|
|||
|
+ return reg;
|
|||
|
+ }
|
|||
|
+ default:
|
|||
|
+ return reg;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline int is_indexed(int reg) {
|
|||
|
+ if (reg == OR_IXmem || reg == OR_IYmem)
|
|||
|
+ return 1;
|
|||
|
+ else
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int reg[8] = {
|
|||
|
+ OR_B,
|
|||
|
+ OR_C,
|
|||
|
+ OR_D,
|
|||
|
+ OR_E,
|
|||
|
+ OR_H,
|
|||
|
+ OR_L,
|
|||
|
+ OR_HLmem,
|
|||
|
+ OR_A,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum {
|
|||
|
+ /* 16-bit registers and register pairs */
|
|||
|
+ OR2_AF,
|
|||
|
+ OR2_BC,
|
|||
|
+ OR2_DE,
|
|||
|
+ OR2_HL,
|
|||
|
+
|
|||
|
+ OR2_IX,
|
|||
|
+ OR2_IY,
|
|||
|
+ OR2_SP,
|
|||
|
+
|
|||
|
+ OR2_AFX,
|
|||
|
+ OR2_BCX,
|
|||
|
+ OR2_DEX,
|
|||
|
+ OR2_HLX,
|
|||
|
+};
|
|||
|
+
|
|||
|
+char *regpairnames[] = {
|
|||
|
+ [OR2_AF] = "af",
|
|||
|
+ [OR2_BC] = "bc",
|
|||
|
+ [OR2_DE] = "de",
|
|||
|
+ [OR2_HL] = "hl",
|
|||
|
+
|
|||
|
+ [OR2_IX] = "ix",
|
|||
|
+ [OR2_IY] = "iy",
|
|||
|
+ [OR2_SP] = "sp",
|
|||
|
+
|
|||
|
+ [OR2_AFX] = "afx",
|
|||
|
+ [OR2_BCX] = "bcx",
|
|||
|
+ [OR2_DEX] = "dex",
|
|||
|
+ [OR2_HLX] = "hlx",
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movw_T0_reg[] = {
|
|||
|
+ [OR2_AF] = gen_op_movw_T0_AF,
|
|||
|
+ [OR2_BC] = gen_op_movw_T0_BC,
|
|||
|
+ [OR2_DE] = gen_op_movw_T0_DE,
|
|||
|
+ [OR2_HL] = gen_op_movw_T0_HL,
|
|||
|
+
|
|||
|
+ [OR2_IX] = gen_op_movw_T0_IX,
|
|||
|
+ [OR2_IY] = gen_op_movw_T0_IY,
|
|||
|
+ [OR2_SP] = gen_op_movw_T0_SP,
|
|||
|
+
|
|||
|
+ [OR2_AFX] = gen_op_movw_T0_AFX,
|
|||
|
+ [OR2_BCX] = gen_op_movw_T0_BCX,
|
|||
|
+ [OR2_DEX] = gen_op_movw_T0_DEX,
|
|||
|
+ [OR2_HLX] = gen_op_movw_T0_HLX,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movw_T1_reg[] = {
|
|||
|
+ [OR2_AF] = gen_op_movw_T1_AF,
|
|||
|
+ [OR2_BC] = gen_op_movw_T1_BC,
|
|||
|
+ [OR2_DE] = gen_op_movw_T1_DE,
|
|||
|
+ [OR2_HL] = gen_op_movw_T1_HL,
|
|||
|
+
|
|||
|
+ [OR2_IX] = gen_op_movw_T1_IX,
|
|||
|
+ [OR2_IY] = gen_op_movw_T1_IY,
|
|||
|
+ [OR2_SP] = gen_op_movw_T1_SP,
|
|||
|
+
|
|||
|
+ [OR2_AFX] = gen_op_movw_T1_AFX,
|
|||
|
+ [OR2_BCX] = gen_op_movw_T1_BCX,
|
|||
|
+ [OR2_DEX] = gen_op_movw_T1_DEX,
|
|||
|
+ [OR2_HLX] = gen_op_movw_T1_HLX,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movw_reg_T0[] = {
|
|||
|
+ [OR2_AF] = gen_op_movw_AF_T0,
|
|||
|
+ [OR2_BC] = gen_op_movw_BC_T0,
|
|||
|
+ [OR2_DE] = gen_op_movw_DE_T0,
|
|||
|
+ [OR2_HL] = gen_op_movw_HL_T0,
|
|||
|
+
|
|||
|
+ [OR2_IX] = gen_op_movw_IX_T0,
|
|||
|
+ [OR2_IY] = gen_op_movw_IY_T0,
|
|||
|
+ [OR2_SP] = gen_op_movw_SP_T0,
|
|||
|
+
|
|||
|
+ [OR2_AFX] = gen_op_movw_AFX_T0,
|
|||
|
+ [OR2_BCX] = gen_op_movw_BCX_T0,
|
|||
|
+ [OR2_DEX] = gen_op_movw_DEX_T0,
|
|||
|
+ [OR2_HLX] = gen_op_movw_HLX_T0,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_movw_reg_T1[] = {
|
|||
|
+ [OR2_AF] = gen_op_movw_AF_T1,
|
|||
|
+ [OR2_BC] = gen_op_movw_BC_T1,
|
|||
|
+ [OR2_DE] = gen_op_movw_DE_T1,
|
|||
|
+ [OR2_HL] = gen_op_movw_HL_T1,
|
|||
|
+
|
|||
|
+ [OR2_IX] = gen_op_movw_IX_T1,
|
|||
|
+ [OR2_IY] = gen_op_movw_IY_T1,
|
|||
|
+ [OR2_SP] = gen_op_movw_SP_T1,
|
|||
|
+
|
|||
|
+ [OR2_AFX] = gen_op_movw_AFX_T1,
|
|||
|
+ [OR2_BCX] = gen_op_movw_BCX_T1,
|
|||
|
+ [OR2_DEX] = gen_op_movw_DEX_T1,
|
|||
|
+ [OR2_HLX] = gen_op_movw_HLX_T1,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static inline int regpairmap(int regpair, int m) {
|
|||
|
+ switch (regpair) {
|
|||
|
+ case OR2_HL:
|
|||
|
+ switch (m) {
|
|||
|
+ case 1:
|
|||
|
+ return OR2_IX;
|
|||
|
+ case 2:
|
|||
|
+ return OR2_IY;
|
|||
|
+ default:
|
|||
|
+ return OR2_HL;
|
|||
|
+ }
|
|||
|
+ default:
|
|||
|
+ return regpair;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+int regpair[4] = {
|
|||
|
+ OR2_BC,
|
|||
|
+ OR2_DE,
|
|||
|
+ OR2_HL,
|
|||
|
+ OR2_SP,
|
|||
|
+};
|
|||
|
+
|
|||
|
+int regpair2[4] = {
|
|||
|
+ OR2_BC,
|
|||
|
+ OR2_DE,
|
|||
|
+ OR2_HL,
|
|||
|
+ OR2_AF,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static inline void gen_jmp_im(target_ulong pc)
|
|||
|
+{
|
|||
|
+ gen_op_movl_pc_im(pc);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void gen_debug(DisasContext *s, target_ulong cur_pc)
|
|||
|
+{
|
|||
|
+ if (s->cc_op != CC_OP_DYNAMIC)
|
|||
|
+ gen_op_set_cc_op(s->cc_op);
|
|||
|
+ gen_jmp_im(cur_pc);
|
|||
|
+ gen_op_debug();
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void gen_eob(DisasContext *s)
|
|||
|
+{
|
|||
|
+ if (s->cc_op != CC_OP_DYNAMIC)
|
|||
|
+ gen_op_set_cc_op(s->cc_op);
|
|||
|
+ if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
|
|||
|
+ gen_op_reset_inhibit_irq();
|
|||
|
+ }
|
|||
|
+ if (s->singlestep_enabled) {
|
|||
|
+ gen_op_debug();
|
|||
|
+ } else {
|
|||
|
+ gen_op_movl_T0_0();
|
|||
|
+ gen_op_exit_tb();
|
|||
|
+ }
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static void gen_exception(DisasContext *s, int trapno, target_ulong cur_pc)
|
|||
|
+{
|
|||
|
+ if (s->cc_op != CC_OP_DYNAMIC)
|
|||
|
+ gen_op_set_cc_op(s->cc_op);
|
|||
|
+ gen_jmp_im(cur_pc);
|
|||
|
+ gen_op_raise_exception(trapno);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Conditions */
|
|||
|
+
|
|||
|
+char *cc[8] = {
|
|||
|
+ "nz",
|
|||
|
+ "z",
|
|||
|
+ "nc",
|
|||
|
+ "c",
|
|||
|
+ "po",
|
|||
|
+ "pe",
|
|||
|
+ "p",
|
|||
|
+ "m",
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc1 *gen_op_jp_cc[8] = {
|
|||
|
+ gen_op_jp_nz,
|
|||
|
+ gen_op_jp_z,
|
|||
|
+ gen_op_jp_nc,
|
|||
|
+ gen_op_jp_c,
|
|||
|
+ gen_op_jp_po,
|
|||
|
+ gen_op_jp_pe,
|
|||
|
+ gen_op_jp_p,
|
|||
|
+ gen_op_jp_m,
|
|||
|
+};
|
|||
|
+
|
|||
|
+enum {
|
|||
|
+ COND_NZ,
|
|||
|
+ COND_Z,
|
|||
|
+ COND_NC,
|
|||
|
+ COND_C,
|
|||
|
+ COND_PO,
|
|||
|
+ COND_PE,
|
|||
|
+ COND_P,
|
|||
|
+ COND_M,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* Arithmetic/logic operations */
|
|||
|
+
|
|||
|
+char *alu[8] = {
|
|||
|
+ "add a,",
|
|||
|
+ "adc a,",
|
|||
|
+ "sub ",
|
|||
|
+ "sbc a,",
|
|||
|
+ "and ",
|
|||
|
+ "xor ",
|
|||
|
+ "or ",
|
|||
|
+ "cp ",
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_alu[8] = {
|
|||
|
+ gen_op_add_cc,
|
|||
|
+ gen_op_adc_cc,
|
|||
|
+ gen_op_sub_cc,
|
|||
|
+ gen_op_sbc_cc,
|
|||
|
+ gen_op_and_cc,
|
|||
|
+ gen_op_xor_cc,
|
|||
|
+ gen_op_or_cc,
|
|||
|
+ gen_op_cp_cc,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* Rotation/shift operations */
|
|||
|
+
|
|||
|
+char *rot[8] = {
|
|||
|
+ "rlc",
|
|||
|
+ "rrc",
|
|||
|
+ "rl",
|
|||
|
+ "rr",
|
|||
|
+ "sla",
|
|||
|
+ "sra",
|
|||
|
+ "sll",
|
|||
|
+ "srl",
|
|||
|
+};
|
|||
|
+
|
|||
|
+static GenOpFunc *gen_op_rot_T0[8] = {
|
|||
|
+ gen_op_rlc_T0_cc,
|
|||
|
+ gen_op_rrc_T0_cc,
|
|||
|
+ gen_op_rl_T0_cc,
|
|||
|
+ gen_op_rr_T0_cc,
|
|||
|
+ gen_op_sla_T0_cc,
|
|||
|
+ gen_op_sra_T0_cc,
|
|||
|
+ gen_op_sll_T0_cc,
|
|||
|
+ gen_op_srl_T0_cc,
|
|||
|
+};
|
|||
|
+
|
|||
|
+/* Block instructions */
|
|||
|
+
|
|||
|
+char *bli[4][4] = {
|
|||
|
+ { "ldi", "cpi", "ini", "outi", },
|
|||
|
+ { "ldd", "cpd", "ind", "outd", },
|
|||
|
+ { "ldir", "cpir", "inir", "otir", },
|
|||
|
+ { "lddr", "cpdr", "indr", "otdr", },
|
|||
|
+};
|
|||
|
+
|
|||
|
+int imode[8] = {
|
|||
|
+ 0, 0, 1, 2, 0, 0, 1, 2,
|
|||
|
+};
|
|||
|
+
|
|||
|
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc)
|
|||
|
+{
|
|||
|
+// TranslationBlock *tb;
|
|||
|
+//
|
|||
|
+// if (tb_num == 0)
|
|||
|
+// gen_op_goto_tb0(TBPARAM(tb));
|
|||
|
+// else
|
|||
|
+// gen_op_goto_tb1(TBPARAM(tb));
|
|||
|
+// gen_jmp_im(pc);
|
|||
|
+// gen_op_movl_T0_im((long)tb + tb_num);
|
|||
|
+// gen_op_exit_tb();
|
|||
|
+
|
|||
|
+ gen_jmp_im(pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void gen_jcc(DisasContext *s, int cc,
|
|||
|
+ target_ulong val, target_ulong next_pc) {
|
|||
|
+ TranslationBlock *tb;
|
|||
|
+ GenOpFunc1 *func;
|
|||
|
+ int l1;
|
|||
|
+
|
|||
|
+ func = gen_op_jp_cc[cc];
|
|||
|
+
|
|||
|
+ tb = s->tb;
|
|||
|
+
|
|||
|
+ l1 = gen_new_label();
|
|||
|
+ func(l1);
|
|||
|
+
|
|||
|
+ gen_goto_tb(s, 0, next_pc);
|
|||
|
+
|
|||
|
+ gen_set_label(l1);
|
|||
|
+ gen_goto_tb(s, 1, val);
|
|||
|
+
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void gen_callcc(DisasContext *s, int cc,
|
|||
|
+ target_ulong val, target_ulong next_pc) {
|
|||
|
+ TranslationBlock *tb;
|
|||
|
+ GenOpFunc1 *func;
|
|||
|
+ int l1;
|
|||
|
+
|
|||
|
+ func = gen_op_jp_cc[cc];
|
|||
|
+
|
|||
|
+ tb = s->tb;
|
|||
|
+
|
|||
|
+ l1 = gen_new_label();
|
|||
|
+ func(l1);
|
|||
|
+
|
|||
|
+ gen_goto_tb(s, 0, next_pc);
|
|||
|
+
|
|||
|
+ gen_set_label(l1);
|
|||
|
+ gen_op_mov_T0_im(next_pc);
|
|||
|
+ gen_op_pushw_T0();
|
|||
|
+ gen_goto_tb(s, 1, val);
|
|||
|
+
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static inline void gen_retcc(DisasContext *s, int cc,
|
|||
|
+ target_ulong next_pc) {
|
|||
|
+ TranslationBlock *tb;
|
|||
|
+ GenOpFunc1 *func;
|
|||
|
+ int l1;
|
|||
|
+
|
|||
|
+ func = gen_op_jp_cc[cc];
|
|||
|
+
|
|||
|
+ tb = s->tb;
|
|||
|
+
|
|||
|
+ l1 = gen_new_label();
|
|||
|
+ func(l1);
|
|||
|
+
|
|||
|
+ gen_goto_tb(s, 0, next_pc);
|
|||
|
+
|
|||
|
+ gen_set_label(l1);
|
|||
|
+ gen_op_popw_T0();
|
|||
|
+ gen_op_jmp_T0();
|
|||
|
+ gen_eob(s);
|
|||
|
+
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* TODO: do flags properly, using cc_table. */
|
|||
|
+/* (search for compute_all in i386 code) */
|
|||
|
+/* see also opc_read_flags[], opc_write_flags[] and opc_simpler[] */
|
|||
|
+
|
|||
|
+/* micro-ops that modify condition codes should end in _cc */
|
|||
|
+
|
|||
|
+/* convert one instruction. s->is_jmp is set if the translation must
|
|||
|
+ be stopped. Return the next pc value */
|
|||
|
+static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
|||
|
+{
|
|||
|
+ int b, prefixes;
|
|||
|
+ int rex_w, rex_r;
|
|||
|
+ int m;
|
|||
|
+
|
|||
|
+ s->pc = pc_start;
|
|||
|
+ prefixes = 0;
|
|||
|
+ s->override = -1;
|
|||
|
+ rex_w = -1;
|
|||
|
+ rex_r = 0;
|
|||
|
+
|
|||
|
+ printf("PC = %04x: ", s->pc);
|
|||
|
+// gen_op_dump_registers(s->pc);
|
|||
|
+next_byte:
|
|||
|
+ s->prefix = prefixes;
|
|||
|
+
|
|||
|
+/* START */
|
|||
|
+
|
|||
|
+ if (prefixes & PREFIX_DD)
|
|||
|
+ m = 1;
|
|||
|
+ else if (prefixes & PREFIX_FD)
|
|||
|
+ m = 2;
|
|||
|
+ else
|
|||
|
+ m = 0;
|
|||
|
+
|
|||
|
+ /* unprefixed opcodes */
|
|||
|
+
|
|||
|
+ if ((prefixes & (PREFIX_CB | PREFIX_ED)) == 0) {
|
|||
|
+ b = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+
|
|||
|
+ int x, y, z, p, q;
|
|||
|
+ int n, d;
|
|||
|
+ int r1, r2;
|
|||
|
+
|
|||
|
+ x = (b >> 6) & 0x03;
|
|||
|
+ y = (b >> 3) & 0x07;
|
|||
|
+ z = b & 0x07;
|
|||
|
+ p = y >> 1;
|
|||
|
+ q = y & 0x01;
|
|||
|
+
|
|||
|
+ switch (x) {
|
|||
|
+ case 0:
|
|||
|
+ switch (z) {
|
|||
|
+
|
|||
|
+ case 0:
|
|||
|
+ switch (y) {
|
|||
|
+ case 0:
|
|||
|
+ zprintf("nop\n");
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_ex_af_afx();
|
|||
|
+ zprintf("ex af,af'\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ n = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_djnz(s->pc + n, s->pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ zprintf("djnz $%02x\n", n);
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ n = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_jmp_im(s->pc + n);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ zprintf("jr $%02x\n", n);
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ case 5:
|
|||
|
+ case 6:
|
|||
|
+ case 7:
|
|||
|
+ n = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ zprintf("jr %s,$%04x\n", cc[y-4], (s->pc + n) & 0xffff);
|
|||
|
+ gen_jcc(s, y-4, s->pc + n, s->pc);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 1:
|
|||
|
+ switch (q) {
|
|||
|
+ case 0:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_op_mov_T0_im(n);
|
|||
|
+ r1 = regpairmap(regpair[p], m);
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("ld %s,$%04x\n", regpairnames[r1], n);
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ r1 = regpairmap(regpair[p], m);
|
|||
|
+ r2 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_movw_T1_reg[r2]();
|
|||
|
+ gen_op_addw_T0_T1_cc();
|
|||
|
+ gen_op_movw_reg_T0[r2]();
|
|||
|
+ zprintf("add %s,%s\n", regpairnames[r2], regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 2:
|
|||
|
+ switch (q) {
|
|||
|
+ case 0:
|
|||
|
+ switch (p) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_movb_T0_reg[OR_A]();
|
|||
|
+ gen_op_movw_A0_BC();
|
|||
|
+ gen_op_stb_T0_A0();
|
|||
|
+ zprintf("ld (bc),a\n");
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_movb_T0_reg[OR_A]();
|
|||
|
+ gen_op_movw_A0_DE();
|
|||
|
+ gen_op_stb_T0_A0();
|
|||
|
+ zprintf("ld (de),a\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_stw_T0_A0();
|
|||
|
+ zprintf("ld ($%04x),%s\n", n, regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_op_movb_T0_reg[OR_A]();
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_stb_T0_A0();
|
|||
|
+ zprintf("ld ($%04x),a\n", n);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ switch (p) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_movw_A0_BC();
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_movb_reg_T0[OR_A]();
|
|||
|
+ zprintf("ld a,(bc)\n");
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_movw_A0_DE();
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_movb_reg_T0[OR_A]();
|
|||
|
+ zprintf("ld a,(de)\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_ldw_T0_A0();
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("ld %s,($%04x)\n", regpairnames[r1], n);
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_movb_reg_T0[OR_A]();
|
|||
|
+ zprintf("ld a,($%04x)\n", n);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 3:
|
|||
|
+ switch (q) {
|
|||
|
+ case 0:
|
|||
|
+ r1 = regpairmap(regpair[p], m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_incw_T0();
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("inc %s\n", regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ r1 = regpairmap(regpair[p], m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_decw_T0();
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("dec %s\n", regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 4:
|
|||
|
+ r1 = regmap(reg[y], m);
|
|||
|
+ if (is_indexed(r1)) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_movb_T0_idx[r1](d);
|
|||
|
+ } else
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ gen_op_incb_T0_cc();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ else
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ zprintf("inc (%s%c$%02x)\n", idxnames[r1], shexb(d));
|
|||
|
+ else
|
|||
|
+ zprintf("inc %s\n", regnames[r1]);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 5:
|
|||
|
+ r1 = regmap(reg[y], m);
|
|||
|
+ if (is_indexed(r1)) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_movb_T0_idx[r1](d);
|
|||
|
+ } else
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ gen_op_decb_T0_cc();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ else
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ zprintf("dec (%s%c$%02x)\n", idxnames[r1], shexb(d));
|
|||
|
+ else
|
|||
|
+ zprintf("dec %s\n", regnames[r1]);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 6:
|
|||
|
+ r1 = regmap(reg[y], m);
|
|||
|
+ if (is_indexed(r1)) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ }
|
|||
|
+ n = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_mov_T0_im(n);
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ else
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ zprintf("ld (%s%c$%02x),$%02x\n", idxnames[r1], shexb(d), n);
|
|||
|
+ else
|
|||
|
+ zprintf("ld %s,$%02x\n", regnames[r1], n);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 7:
|
|||
|
+ switch (y) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_rlca_cc();
|
|||
|
+ zprintf("rlca\n");
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_rrca_cc();
|
|||
|
+ zprintf("rrca\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ gen_op_rla_cc();
|
|||
|
+ zprintf("rla\n");
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ gen_op_rra_cc();
|
|||
|
+ zprintf("rra\n");
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ gen_op_daa_cc();
|
|||
|
+ zprintf("daa\n");
|
|||
|
+ break;
|
|||
|
+ case 5:
|
|||
|
+ gen_op_cpl_cc();
|
|||
|
+ zprintf("cpl\n");
|
|||
|
+ break;
|
|||
|
+ case 6:
|
|||
|
+ gen_op_scf_cc();
|
|||
|
+ zprintf("scf\n");
|
|||
|
+ break;
|
|||
|
+ case 7:
|
|||
|
+ gen_op_ccf_cc();
|
|||
|
+ zprintf("ccf\n");
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 1:
|
|||
|
+ if (z == 6 && y == 6) {
|
|||
|
+//FIXME
|
|||
|
+// gen_op_halt();
|
|||
|
+// gen_eob(s);
|
|||
|
+// s->is_jmp = 3;
|
|||
|
+ zprintf("halt\n");
|
|||
|
+ } else {
|
|||
|
+ if (z == 6) {
|
|||
|
+ r1 = regmap(reg[z], m);
|
|||
|
+ r2 = regmap(reg[y], 0);
|
|||
|
+ } else if (y == 6) {
|
|||
|
+ r1 = regmap(reg[z], 0);
|
|||
|
+ r2 = regmap(reg[y], m);
|
|||
|
+ } else {
|
|||
|
+ r1 = regmap(reg[z], m);
|
|||
|
+ r2 = regmap(reg[y], m);
|
|||
|
+ }
|
|||
|
+ if (is_indexed(r1) || is_indexed(r2)) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ }
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ gen_op_movb_T0_idx[r1](d);
|
|||
|
+ else
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ if (is_indexed(r2))
|
|||
|
+ gen_op_movb_idx_T0[r2](d);
|
|||
|
+ else
|
|||
|
+ gen_op_movb_reg_T0[r2]();
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ zprintf("ld %s,(%s%c$%02x)\n", regnames[r2], idxnames[r1], shexb(d));
|
|||
|
+ else if (is_indexed(r2))
|
|||
|
+ zprintf("ld (%s%c$%02x),%s\n", idxnames[r2], shexb(d), regnames[r1]);
|
|||
|
+ else
|
|||
|
+ zprintf("ld %s,%s\n", regnames[r2], regnames[r1]);
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 2:
|
|||
|
+ r1 = regmap(reg[z], m);
|
|||
|
+ if (is_indexed(r1)) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_movb_T0_idx[r1](d);
|
|||
|
+ } else
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ gen_op_alu[y](); /* places output in A */
|
|||
|
+ if (is_indexed(r1))
|
|||
|
+ zprintf("%s(%s%c$%02x)\n", alu[y], idxnames[r1], shexb(d));
|
|||
|
+ else
|
|||
|
+ zprintf("%s%s\n", alu[y], regnames[r1]);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 3:
|
|||
|
+ switch (z) {
|
|||
|
+ case 0:
|
|||
|
+ gen_retcc(s, y, s->pc);
|
|||
|
+ zprintf("ret %s\n", cc[y]);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 1:
|
|||
|
+ switch (q) {
|
|||
|
+ case 0:
|
|||
|
+ r1 = regpairmap(regpair2[p], m);
|
|||
|
+ gen_op_popw_T0();
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("pop %s\n", regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ switch (p) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_popw_T0();
|
|||
|
+ gen_op_jmp_T0();
|
|||
|
+ zprintf("ret\n");
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+// s->is_ei = 1;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_exx();
|
|||
|
+ zprintf("exx\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_jmp_T0();
|
|||
|
+ zprintf("jp %s\n", regpairnames[r1]);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_movw_reg_T0[OR2_SP]();
|
|||
|
+ zprintf("ld sp,%s\n", regpairnames[r1]);
|
|||
|
+ gen_op_dump_registers(s->pc);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 2:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_jcc(s, y, n, s->pc);
|
|||
|
+ zprintf("jp %s,$%04x\n", cc[y], n);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 3:
|
|||
|
+ switch (y) {
|
|||
|
+ case 0:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_jmp_im(n);
|
|||
|
+ zprintf("jp $%04x\n", n);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ zprintf("cb prefix\n");
|
|||
|
+ prefixes |= PREFIX_CB;
|
|||
|
+ goto next_byte;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ n = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_movb_T0_reg[OR_A]();
|
|||
|
+ gen_op_out_T0_im(n);
|
|||
|
+ zprintf("out ($%02x),a\n", n);
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ n = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_in_T0_im(n);
|
|||
|
+ gen_op_movb_reg_T0[OR_A]();
|
|||
|
+ zprintf("in a,($%02x)\n", n);
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ gen_op_popw_T1();
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_pushw_T0();
|
|||
|
+ gen_op_movw_reg_T1[r1]();
|
|||
|
+ zprintf("ex (sp),%s\n", regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 5:
|
|||
|
+ gen_op_ex_de_hl();
|
|||
|
+ zprintf("ex de,hl\n");
|
|||
|
+ break;
|
|||
|
+ case 6:
|
|||
|
+ gen_op_di();
|
|||
|
+ zprintf("di\n");
|
|||
|
+ break;
|
|||
|
+ case 7:
|
|||
|
+ gen_op_ei();
|
|||
|
+// gen_op_dump_registers(s->pc);
|
|||
|
+ zprintf("ei\n");
|
|||
|
+// gen_eob(s);
|
|||
|
+// s->is_ei = 1;
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 4:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_callcc(s, y, n, s->pc);
|
|||
|
+ zprintf("call %s,$%04x\n", cc[y], n);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 5:
|
|||
|
+ switch (q) {
|
|||
|
+ case 0:
|
|||
|
+ r1 = regpairmap(regpair2[p], m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_pushw_T0();
|
|||
|
+ zprintf("push %s\n", regpairnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ switch (p) {
|
|||
|
+ case 0:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ gen_op_mov_T0_im(s->pc);
|
|||
|
+ gen_op_pushw_T0();
|
|||
|
+ gen_jmp_im(n);
|
|||
|
+ zprintf("call $%04x\n", n);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ zprintf("dd prefix\n");
|
|||
|
+ prefixes |= PREFIX_DD;
|
|||
|
+ goto next_byte;
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ zprintf("ed prefix\n");
|
|||
|
+ prefixes |= PREFIX_ED;
|
|||
|
+ goto next_byte;
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ zprintf("fd prefix\n");
|
|||
|
+ prefixes |= PREFIX_FD;
|
|||
|
+ goto next_byte;
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 6:
|
|||
|
+ n = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ gen_op_mov_T0_im(n);
|
|||
|
+ gen_op_alu[y](); /* places output in A */
|
|||
|
+ zprintf("%s$%02x\n", alu[y], n);
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 7:
|
|||
|
+ gen_op_mov_T0_im(s->pc);
|
|||
|
+ gen_op_pushw_T0();
|
|||
|
+ gen_jmp_im(y*8);
|
|||
|
+ zprintf("rst $%02x\n", y*8);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ } else if (prefixes & PREFIX_CB) {
|
|||
|
+ /* cb mode: */
|
|||
|
+
|
|||
|
+ int x, y, z, p, q;
|
|||
|
+ int d;
|
|||
|
+ int r1, r2;
|
|||
|
+
|
|||
|
+ if (m) {
|
|||
|
+ d = ldsb_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ b = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+
|
|||
|
+ x = (b >> 6) & 0x03;
|
|||
|
+ y = (b >> 3) & 0x07;
|
|||
|
+ z = b & 0x07;
|
|||
|
+ p = y >> 1;
|
|||
|
+ q = y & 0x01;
|
|||
|
+
|
|||
|
+ if (m) {
|
|||
|
+ r1 = regmap(OR_HLmem, m);
|
|||
|
+ gen_op_movb_T0_idx[r1](d);
|
|||
|
+ if (z != 6)
|
|||
|
+ r2 = regmap(reg[z], 0);
|
|||
|
+ } else {
|
|||
|
+ r1 = regmap(reg[z], m);
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ switch (x) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_rot_T0[y]();
|
|||
|
+ if (m) {
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ if (z != 6)
|
|||
|
+ gen_op_movb_reg_T0[r2]();
|
|||
|
+ } else {
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ }
|
|||
|
+ zprintf("%s %s\n", rot[y], regnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_bit_T0(1 << y);
|
|||
|
+ zprintf("bit %i,%s\n", y, regnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ gen_op_res_T0(~(1 << y));
|
|||
|
+ if (m) {
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ if (z != 6)
|
|||
|
+ gen_op_movb_reg_T0[r2]();
|
|||
|
+ } else {
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ }
|
|||
|
+ zprintf("res %i,%s\n", y, regnames[r1]);
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ gen_op_set_T0(1 << y);
|
|||
|
+ if (m) {
|
|||
|
+ gen_op_movb_idx_T0[r1](d);
|
|||
|
+ if (z != 6)
|
|||
|
+ gen_op_movb_reg_T0[r2]();
|
|||
|
+ } else {
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ }
|
|||
|
+ zprintf("set %i,%s\n", y, regnames[r1]);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ } else if (prefixes & PREFIX_ED) {
|
|||
|
+ /* ed mode: */
|
|||
|
+
|
|||
|
+ b = ldub_code(s->pc);
|
|||
|
+ s->pc++;
|
|||
|
+
|
|||
|
+ int x, y, z, p, q;
|
|||
|
+ int n;
|
|||
|
+ int r1, r2;
|
|||
|
+
|
|||
|
+ x = (b >> 6) & 0x03;
|
|||
|
+ y = (b >> 3) & 0x07;
|
|||
|
+ z = b & 0x07;
|
|||
|
+ p = y >> 1;
|
|||
|
+ q = y & 0x01;
|
|||
|
+
|
|||
|
+ switch (x) {
|
|||
|
+ case 0:
|
|||
|
+ case 3:
|
|||
|
+ zprintf("nop\n");
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 1:
|
|||
|
+ switch (z) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_in_T0_bc_cc();
|
|||
|
+ if (y != 6) {
|
|||
|
+ r1 = regmap(reg[y], m);
|
|||
|
+ gen_op_movb_reg_T0[r1]();
|
|||
|
+ zprintf("in %s,(c)\n", regnames[r1]);
|
|||
|
+ } else {
|
|||
|
+ zprintf("in (c)\n");
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ if (y != 6) {
|
|||
|
+ r1 = regmap(reg[y], m);
|
|||
|
+ gen_op_movb_T0_reg[r1]();
|
|||
|
+ zprintf("out (c),%s\n", regnames[r1]);
|
|||
|
+ } else {
|
|||
|
+ gen_op_mov_T0_im(0);
|
|||
|
+ zprintf("out (c),0\n");
|
|||
|
+ }
|
|||
|
+ gen_op_out_T0_bc();
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ r1 = regpairmap(OR2_HL, m);
|
|||
|
+ r2 = regpairmap(regpair[p], m);
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_movw_T1_reg[r2]();
|
|||
|
+ if (q == 0) {
|
|||
|
+ zprintf("sbc %s,%s\n", regpairnames[r1], regpairnames[r2]);
|
|||
|
+ gen_op_sbcw_T0_T1_cc();
|
|||
|
+ } else {
|
|||
|
+ zprintf("adc %s,%s\n", regpairnames[r1], regpairnames[r2]);
|
|||
|
+ gen_op_adcw_T0_T1_cc();
|
|||
|
+ }
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ n = lduw_code(s->pc);
|
|||
|
+ s->pc += 2;
|
|||
|
+ r1 = regpairmap(regpair[p], m);
|
|||
|
+ if (q == 0) {
|
|||
|
+ gen_op_movw_T0_reg[r1]();
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_stw_T0_A0();
|
|||
|
+ zprintf("ld ($%02x),%s\n", n, regpairnames[r1]);
|
|||
|
+ } else {
|
|||
|
+ gen_op_mov_A0_im(n);
|
|||
|
+ gen_op_ldw_T0_A0();
|
|||
|
+ gen_op_movw_reg_T0[r1]();
|
|||
|
+ zprintf("ld %s,($%02x)\n", regpairnames[r1], n);
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ zprintf("neg\n");
|
|||
|
+ gen_op_neg_cc();
|
|||
|
+ break;
|
|||
|
+ case 5:
|
|||
|
+ /* FIXME */
|
|||
|
+ gen_op_popw_T0();
|
|||
|
+ gen_op_jmp_T0();
|
|||
|
+ gen_op_ri();
|
|||
|
+ if (q == 0) {
|
|||
|
+ zprintf("retn\n");
|
|||
|
+ } else {
|
|||
|
+ zprintf("reti\n");
|
|||
|
+ }
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+// s->is_ei = 1;
|
|||
|
+ break;
|
|||
|
+ case 6:
|
|||
|
+ gen_op_imode(imode[y]);
|
|||
|
+ zprintf("im im[%i]\n", imode[y]);
|
|||
|
+// gen_eob(s);
|
|||
|
+// s->is_ei = 1;
|
|||
|
+ break;
|
|||
|
+ case 7:
|
|||
|
+ switch (y) {
|
|||
|
+ case 0:
|
|||
|
+ gen_op_ld_I_A();
|
|||
|
+ zprintf("ld i,a\n");
|
|||
|
+ break;
|
|||
|
+ case 1:
|
|||
|
+ gen_op_ld_R_A();
|
|||
|
+ zprintf("ld r,a\n");
|
|||
|
+ break;
|
|||
|
+ case 2:
|
|||
|
+ gen_op_ld_A_I();
|
|||
|
+ zprintf("ld a,i\n");
|
|||
|
+ break;
|
|||
|
+ case 3:
|
|||
|
+ gen_op_ld_A_R();
|
|||
|
+ zprintf("ld a,r\n");
|
|||
|
+ break;
|
|||
|
+ case 4:
|
|||
|
+ gen_op_movb_T0_reg[OR_HLmem]();
|
|||
|
+ gen_op_rrd_cc();
|
|||
|
+ gen_op_movb_reg_T0[OR_HLmem]();
|
|||
|
+ zprintf("rrd\n");
|
|||
|
+ break;
|
|||
|
+ case 5:
|
|||
|
+ gen_op_movb_T0_reg[OR_HLmem]();
|
|||
|
+ gen_op_rld_cc();
|
|||
|
+ gen_op_movb_reg_T0[OR_HLmem]();
|
|||
|
+ zprintf("rld\n");
|
|||
|
+ break;
|
|||
|
+ case 6:
|
|||
|
+ case 7:
|
|||
|
+ zprintf("nop2\n");
|
|||
|
+ /* nop */
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 2:
|
|||
|
+ /* FIXME */
|
|||
|
+ if (y >= 4) {
|
|||
|
+ switch (z) {
|
|||
|
+ case 0: /* ldi/ldd/ldir/lddr */
|
|||
|
+ gen_op_movw_A0_HL();
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_movw_A0_DE();
|
|||
|
+ gen_op_stb_T0_A0();
|
|||
|
+
|
|||
|
+ if (!(y & 1))
|
|||
|
+ gen_op_bli_ld_inc_cc();
|
|||
|
+ else
|
|||
|
+ gen_op_bli_ld_dec_cc();
|
|||
|
+ if ((y & 2)) {
|
|||
|
+ gen_op_bli_ld_rep(s->pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 1: /* cpi/cpd/cpir/cpdr */
|
|||
|
+ gen_op_movw_A0_HL();
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_bli_cp_cc();
|
|||
|
+
|
|||
|
+ if (!(y & 1))
|
|||
|
+ gen_op_bli_cp_inc_cc();
|
|||
|
+ else
|
|||
|
+ gen_op_bli_cp_dec_cc();
|
|||
|
+ if ((y & 2)) {
|
|||
|
+ gen_op_bli_cp_rep(s->pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 2: /* ini/ind/inir/indr */
|
|||
|
+ gen_op_in_T0_bc_cc();
|
|||
|
+ gen_op_movw_A0_HL();
|
|||
|
+ gen_op_stb_T0_A0();
|
|||
|
+ if (!(y & 1))
|
|||
|
+ gen_op_bli_io_inc();
|
|||
|
+ else
|
|||
|
+ gen_op_bli_io_dec();
|
|||
|
+ if ((y & 2)) {
|
|||
|
+ gen_op_bli_io_rep(s->pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ case 3: /* outi/outd/otir/otdr */
|
|||
|
+ gen_op_movw_A0_HL();
|
|||
|
+ gen_op_ldb_T0_A0();
|
|||
|
+ gen_op_out_T0_bc();
|
|||
|
+ if (!(y & 1))
|
|||
|
+ gen_op_bli_io_inc();
|
|||
|
+ else
|
|||
|
+ gen_op_bli_io_dec();
|
|||
|
+ if ((y & 2)) {
|
|||
|
+ gen_op_bli_io_rep(s->pc);
|
|||
|
+ gen_eob(s);
|
|||
|
+ s->is_jmp = 3;
|
|||
|
+ }
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ zprintf("%s\n", bli[y-4][z]);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ prefixes = 0;
|
|||
|
+
|
|||
|
+ /* now check op code */
|
|||
|
+// switch (b) {
|
|||
|
+// default:
|
|||
|
+// goto illegal_op;
|
|||
|
+// }
|
|||
|
+ /* lock generation */
|
|||
|
+ return s->pc;
|
|||
|
+ illegal_op:
|
|||
|
+ /* XXX: ensure that no lock was generated */
|
|||
|
+ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
|
|||
|
+ return s->pc;
|
|||
|
+}
|
|||
|
+
|
|||
|
+#define CC_SZHPNC (CC_S | CC_Z | CC_H | CC_P | CC_N | CC_C)
|
|||
|
+#define CC_SZHPN (CC_S | CC_Z | CC_H | CC_P | CC_N)
|
|||
|
+
|
|||
|
+static uint8_t opc_read_flags[NB_OPS] = {
|
|||
|
+ [INDEX_op_jp_nz] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_z] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_nc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_c] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_po] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_pe] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_p] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_jp_m] = CC_SZHPNC,
|
|||
|
+//...
|
|||
|
+};
|
|||
|
+
|
|||
|
+static uint8_t opc_write_flags[NB_OPS] = {
|
|||
|
+ [INDEX_op_add_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_adc_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_sub_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_sbc_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_and_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_xor_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_or_cc] = CC_SZHPNC,
|
|||
|
+ [INDEX_op_cp_cc] = CC_SZHPNC,
|
|||
|
+//...
|
|||
|
+};
|
|||
|
+
|
|||
|
+static uint16_t opc_simpler[NB_OPS] = {
|
|||
|
+#if 0
|
|||
|
+ [INDEX_op_add_cc] = INDEX_op_add,
|
|||
|
+ [INDEX_op_adc_cc] = INDEX_op_adc,
|
|||
|
+ [INDEX_op_sub_cc] = INDEX_op_sub,
|
|||
|
+ [INDEX_op_sbc_cc] = INDEX_op_sbc,
|
|||
|
+ [INDEX_op_and_cc] = INDEX_op_and,
|
|||
|
+ [INDEX_op_xor_cc] = INDEX_op_xor,
|
|||
|
+ [INDEX_op_or_cc] = INDEX_op_or,
|
|||
|
+ [INDEX_op_cp_cc] = INDEX_op_cp,
|
|||
|
+//...
|
|||
|
+#endif
|
|||
|
+};
|
|||
|
+
|
|||
|
+void optimize_flags_init(void)
|
|||
|
+{
|
|||
|
+ int i;
|
|||
|
+ /* put default values in arrays */
|
|||
|
+ for(i = 0; i < NB_OPS; i++) {
|
|||
|
+ if (opc_simpler[i] == 0)
|
|||
|
+ opc_simpler[i] = i;
|
|||
|
+ }
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* CPU flags computation optimization: we move backward thru the
|
|||
|
+ generated code to see which flags are needed. The operation is
|
|||
|
+ modified if suitable */
|
|||
|
+static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
|
|||
|
+{
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
|
|||
|
+ basic block 'tb'. If search_pc is TRUE, also generate PC
|
|||
|
+ information for each intermediate instruction. */
|
|||
|
+static inline int gen_intermediate_code_internal(CPUState *env,
|
|||
|
+ TranslationBlock *tb,
|
|||
|
+ int search_pc)
|
|||
|
+{
|
|||
|
+ DisasContext dc1, *dc = &dc1;
|
|||
|
+ target_ulong pc_ptr;
|
|||
|
+ uint16_t *gen_opc_end;
|
|||
|
+ int flags, j, lj, cflags;
|
|||
|
+ target_ulong pc_start;
|
|||
|
+ target_ulong cs_base;
|
|||
|
+
|
|||
|
+ /* generate intermediate code */
|
|||
|
+ pc_start = tb->pc;
|
|||
|
+ cs_base = tb->cs_base;
|
|||
|
+ flags = tb->flags;
|
|||
|
+ cflags = tb->cflags;
|
|||
|
+
|
|||
|
+ dc->singlestep_enabled = env->singlestep_enabled;
|
|||
|
+ dc->cc_op = CC_OP_DYNAMIC;
|
|||
|
+ dc->cs_base = cs_base;
|
|||
|
+ dc->tb = tb;
|
|||
|
+ dc->flags = flags;
|
|||
|
+ dc->jmp_opt = !(env->singlestep_enabled ||
|
|||
|
+ (flags & HF_INHIBIT_IRQ_MASK)
|
|||
|
+#ifndef CONFIG_SOFTMMU
|
|||
|
+ || (flags & HF_SOFTMMU_MASK)
|
|||
|
+#endif
|
|||
|
+ );
|
|||
|
+
|
|||
|
+ gen_opc_ptr = gen_opc_buf;
|
|||
|
+ gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
|||
|
+ gen_opparam_ptr = gen_opparam_buf;
|
|||
|
+ nb_gen_labels = 0;
|
|||
|
+
|
|||
|
+ dc->is_jmp = DISAS_NEXT;
|
|||
|
+ pc_ptr = pc_start;
|
|||
|
+ lj = -1;
|
|||
|
+
|
|||
|
+ for(;;) {
|
|||
|
+ if (env->nb_breakpoints > 0) {
|
|||
|
+ for(j = 0; j < env->nb_breakpoints; j++) {
|
|||
|
+ if (env->breakpoints[j] == pc_ptr) {
|
|||
|
+ gen_debug(dc, pc_ptr - dc->cs_base);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ if (search_pc) {
|
|||
|
+ j = gen_opc_ptr - gen_opc_buf;
|
|||
|
+ if (lj < j) {
|
|||
|
+ lj++;
|
|||
|
+ while (lj < j)
|
|||
|
+ gen_opc_instr_start[lj++] = 0;
|
|||
|
+ }
|
|||
|
+ gen_opc_pc[lj] = pc_ptr;
|
|||
|
+// gen_opc_cc_op[lj] = dc->cc_op;
|
|||
|
+ gen_opc_instr_start[lj] = 1;
|
|||
|
+ }
|
|||
|
+ pc_ptr = disas_insn(dc, pc_ptr);
|
|||
|
+ /* stop translation if indicated */
|
|||
|
+ if (dc->is_jmp)
|
|||
|
+ break;
|
|||
|
+ /* if single step mode, we generate only one instruction and
|
|||
|
+ generate an exception */
|
|||
|
+ /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
|
|||
|
+ the flag and abort the translation to give the irqs a
|
|||
|
+ change to be happen */
|
|||
|
+ if (dc->singlestep_enabled ||
|
|||
|
+ (flags & HF_INHIBIT_IRQ_MASK) ||
|
|||
|
+ (cflags & CF_SINGLE_INSN)) {
|
|||
|
+ gen_jmp_im(pc_ptr - dc->cs_base);
|
|||
|
+ gen_eob(dc);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ /* if too long translation, stop generation too */
|
|||
|
+ if (gen_opc_ptr >= gen_opc_end ||
|
|||
|
+ (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
|
|||
|
+ gen_jmp_im(pc_ptr - dc->cs_base);
|
|||
|
+ gen_eob(dc);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ *gen_opc_ptr = INDEX_op_end;
|
|||
|
+ /* we don't forget to fill the last values */
|
|||
|
+ if (search_pc) {
|
|||
|
+ j = gen_opc_ptr - gen_opc_buf;
|
|||
|
+ lj++;
|
|||
|
+ while (lj <= j)
|
|||
|
+ gen_opc_instr_start[lj++] = 0;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+#ifdef DEBUG_DISAS
|
|||
|
+ if (loglevel & CPU_LOG_TB_CPU) {
|
|||
|
+ cpu_dump_state(env, logfile, fprintf, 0);
|
|||
|
+ }
|
|||
|
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
|
|||
|
+ int disas_flags;
|
|||
|
+ fprintf(logfile, "----------------\n");
|
|||
|
+ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
|||
|
+ target_disas(logfile, pc_start, pc_ptr - pc_start, disas_flags);
|
|||
|
+ fprintf(logfile, "\n");
|
|||
|
+ if (loglevel & CPU_LOG_TB_OP) {
|
|||
|
+ fprintf(logfile, "OP:\n");
|
|||
|
+ dump_ops(gen_opc_buf, gen_opparam_buf);
|
|||
|
+ fprintf(logfile, "\n");
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+#endif
|
|||
|
+
|
|||
|
+ /* optimize flag computations */
|
|||
|
+ optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
|
|||
|
+
|
|||
|
+#ifdef DEBUG_DISAS
|
|||
|
+ if (loglevel & CPU_LOG_TB_OP_OPT) {
|
|||
|
+ fprintf(logfile, "AFTER FLAGS OPT:\n");
|
|||
|
+ dump_ops(gen_opc_buf, gen_opparam_buf);
|
|||
|
+ fprintf(logfile, "\n");
|
|||
|
+ }
|
|||
|
+#endif
|
|||
|
+ if (!search_pc)
|
|||
|
+ tb->size = pc_ptr - pc_start;
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
|
|||
|
+{
|
|||
|
+ return gen_intermediate_code_internal(env, tb, 0);
|
|||
|
+}
|
|||
|
+
|
|||
|
+int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
|
|||
|
+{
|
|||
|
+ return gen_intermediate_code_internal(env, tb, 1);
|
|||
|
+}
|
|||
|
+
|
|||
|
diff -urN qemu-0.9.0/vl.c qemu-z80/vl.c
|
|||
|
--- qemu-0.9.0/vl.c 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/vl.c 2007-04-25 17:58:06.000000000 +0100
|
|||
|
@@ -5201,6 +5201,7 @@
|
|||
|
qemu_get_be64s(f, &env->fmask);
|
|||
|
qemu_get_be64s(f, &env->kernelgsbase);
|
|||
|
#endif
|
|||
|
+
|
|||
|
if (version_id >= 4)
|
|||
|
qemu_get_be32s(f, &env->smbase);
|
|||
|
|
|||
|
@@ -5319,6 +5320,19 @@
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+
|
|||
|
+void cpu_save(QEMUFile *f, void *opaque)
|
|||
|
+{
|
|||
|
+// CPUState *env = opaque;
|
|||
|
+}
|
|||
|
+
|
|||
|
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||
|
+{
|
|||
|
+// CPUState *env = opaque;
|
|||
|
+ return 0;
|
|||
|
+}
|
|||
|
+
|
|||
|
#else
|
|||
|
|
|||
|
#warning No CPU save/restore functions
|
|||
|
@@ -6368,6 +6382,8 @@
|
|||
|
qemu_register_machine(&realview_machine);
|
|||
|
#elif defined(TARGET_SH4)
|
|||
|
qemu_register_machine(&shix_machine);
|
|||
|
+#elif defined(TARGET_Z80)
|
|||
|
+ qemu_register_machine(&z80pc_machine);
|
|||
|
#else
|
|||
|
#error unsupported CPU
|
|||
|
#endif
|
|||
|
diff -urN qemu-0.9.0/vl.h qemu-z80/vl.h
|
|||
|
--- qemu-0.9.0/vl.h 2007-02-05 23:01:54.000000000 +0000
|
|||
|
+++ qemu-z80/vl.h 2007-04-17 20:16:51.000000000 +0100
|
|||
|
@@ -901,6 +901,11 @@
|
|||
|
void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
|
|||
|
unsigned long vga_ram_offset, int vga_ram_size);
|
|||
|
|
|||
|
+/* zx_ula.c */
|
|||
|
+void zx_ula_init(DisplayState *ds, uint8_t *zx_screen_base,
|
|||
|
+ unsigned long zx_ram_offset);
|
|||
|
+void zx_set_flash_dirty(void);
|
|||
|
+
|
|||
|
/* sdl.c */
|
|||
|
void sdl_display_init(DisplayState *ds, int full_screen);
|
|||
|
|
|||
|
@@ -1065,6 +1070,9 @@
|
|||
|
extern QEMUMachine isapc_machine;
|
|||
|
extern int fd_bootchk;
|
|||
|
|
|||
|
+/* z80.c??? */
|
|||
|
+extern QEMUMachine z80pc_machine;
|
|||
|
+
|
|||
|
void ioport_set_a20(int enable);
|
|||
|
int ioport_get_a20(void);
|
|||
|
|
|||
|
diff -urN qemu-0.9.0/z80-dis.c qemu-z80/z80-dis.c
|
|||
|
--- qemu-0.9.0/z80-dis.c 1970-01-01 01:00:00.000000000 +0100
|
|||
|
+++ qemu-z80/z80-dis.c 2007-02-01 15:20:38.000000000 +0000
|
|||
|
@@ -0,0 +1,621 @@
|
|||
|
+/* Print Z80 and R800 instructions
|
|||
|
+ Copyright 2005 Free Software Foundation, Inc.
|
|||
|
+ Contributed by Arnold Metselaar <arnold_m@operamail.com>
|
|||
|
+
|
|||
|
+ Taken from GDB
|
|||
|
+
|
|||
|
+ This file is free software; you can redistribute it and/or modify
|
|||
|
+ it under the terms of the GNU General Public License as published by
|
|||
|
+ the Free Software Foundation; either version 2 of the License, or
|
|||
|
+ (at your option) any later version.
|
|||
|
+
|
|||
|
+ This program is distributed in the hope that it will be useful,
|
|||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
+ GNU General Public License for more details.
|
|||
|
+
|
|||
|
+ You should have received a copy of the GNU General Public License
|
|||
|
+ along with this program; if not, write to the Free Software
|
|||
|
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|||
|
+ MA 02110-1301, USA. */
|
|||
|
+
|
|||
|
+#include "dis-asm.h"
|
|||
|
+#include <stdio.h>
|
|||
|
+
|
|||
|
+struct buffer
|
|||
|
+{
|
|||
|
+ bfd_vma base;
|
|||
|
+ int n_fetch;
|
|||
|
+ int n_used;
|
|||
|
+ signed char data[4];
|
|||
|
+} ;
|
|||
|
+
|
|||
|
+typedef int (*func)(struct buffer *, disassemble_info *, char *);
|
|||
|
+
|
|||
|
+struct tab_elt
|
|||
|
+{
|
|||
|
+ unsigned char val;
|
|||
|
+ unsigned char mask;
|
|||
|
+ func fp;
|
|||
|
+ char * text;
|
|||
|
+} ;
|
|||
|
+
|
|||
|
+#define TXTSIZ 24
|
|||
|
+/* Names of 16-bit registers. */
|
|||
|
+static char * rr_str[] = { "bc", "de", "hl", "sp" };
|
|||
|
+/* Names of 8-bit registers. */
|
|||
|
+static char * r_str[] = { "b", "c", "d", "e", "h", "l", "(hl)", "a" };
|
|||
|
+/* Texts for condition codes. */
|
|||
|
+static char * cc_str[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m" };
|
|||
|
+/* Instruction names for 8-bit arithmetic, operand "a" is often implicit */
|
|||
|
+static char * arit_str[] =
|
|||
|
+{
|
|||
|
+ "add a,", "adc a,", "sub ", "sbc a,", "and ", "xor ", "or ", "cp "
|
|||
|
+} ;
|
|||
|
+
|
|||
|
+static int
|
|||
|
+fetch_data (struct buffer *buf, disassemble_info * info, int n)
|
|||
|
+{
|
|||
|
+ int r;
|
|||
|
+
|
|||
|
+ if (buf->n_fetch + n > 4)
|
|||
|
+ abort ();
|
|||
|
+
|
|||
|
+ r = info->read_memory_func (buf->base + buf->n_fetch,
|
|||
|
+ (unsigned char*) buf->data + buf->n_fetch,
|
|||
|
+ n, info);
|
|||
|
+ if (r == 0)
|
|||
|
+ buf->n_fetch += n;
|
|||
|
+ return !r;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, "%s", txt);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return 1;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_e (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char e;
|
|||
|
+ int target_addr;
|
|||
|
+
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ e = buf->data[1];
|
|||
|
+ target_addr = (buf->base + 2 + e) & 0xffff;
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ info->fprintf_func (info->stream, "%s0x%04x", txt, target_addr);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+jr_cc (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, cc_str[(buf->data[0] >> 3) & 3]);
|
|||
|
+ return prt_e (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_nn (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ int nn;
|
|||
|
+ unsigned char *p;
|
|||
|
+
|
|||
|
+ p = (unsigned char*) buf->data + buf->n_fetch;
|
|||
|
+ if (fetch_data (buf, info, 2))
|
|||
|
+ {
|
|||
|
+ nn = p[0] + (p[1] << 8);
|
|||
|
+ info->fprintf_func (info->stream, txt, nn);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_rr_nn (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, rr_str[(buf->data[0] >> 4) & 3]);
|
|||
|
+ return prt_nn (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_rr (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, "%s%s", txt,
|
|||
|
+ rr_str[(buf->data[buf->n_fetch - 1] >> 4) & 3]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_n (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ int n;
|
|||
|
+ unsigned char *p;
|
|||
|
+
|
|||
|
+ p = (unsigned char*) buf->data + buf->n_fetch;
|
|||
|
+
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ n = p[0];
|
|||
|
+ info->fprintf_func (info->stream, txt, n);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+ld_r_n (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, r_str[(buf->data[0] >> 3) & 7]);
|
|||
|
+ return prt_n (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_r (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, txt,
|
|||
|
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+ld_r_r (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, txt,
|
|||
|
+ r_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
|
|||
|
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+arit_r (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, txt,
|
|||
|
+ arit_str[(buf->data[buf->n_fetch - 1] >> 3) & 7],
|
|||
|
+ r_str[buf->data[buf->n_fetch - 1] & 7]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_cc (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, "%s%s", txt,
|
|||
|
+ cc_str[(buf->data[0] >> 3) & 7]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+pop_rr (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ static char *rr_stack[] = { "bc","de","hl","af"};
|
|||
|
+
|
|||
|
+ info->fprintf_func (info->stream, "%s %s", txt,
|
|||
|
+ rr_stack[(buf->data[0] >> 4) & 3]);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+
|
|||
|
+static int
|
|||
|
+jp_cc_nn (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt,TXTSIZ,
|
|||
|
+ "%s%s,0x%%04x", txt, cc_str[(buf->data[0] >> 3) & 7]);
|
|||
|
+ return prt_nn (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+arit_n (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt,TXTSIZ, txt, arit_str[(buf->data[0] >> 3) & 7]);
|
|||
|
+ return prt_n (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+rst (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, txt, buf->data[0] & 0x38);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+
|
|||
|
+static int
|
|||
|
+cis (struct buffer *buf, disassemble_info * info, char *txt ATTRIBUTE_UNUSED)
|
|||
|
+{
|
|||
|
+ static char * opar[] = { "ld", "cp", "in", "out" };
|
|||
|
+ char * op;
|
|||
|
+ char c;
|
|||
|
+
|
|||
|
+ c = buf->data[1];
|
|||
|
+ op = ((0x13 & c) == 0x13) ? "ot" : (opar[c & 3]);
|
|||
|
+ info->fprintf_func (info->stream,
|
|||
|
+ "%s%c%s", op,
|
|||
|
+ (c & 0x08) ? 'd' : 'i',
|
|||
|
+ (c & 0x10) ? "r" : "");
|
|||
|
+ buf->n_used = 2;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+dump (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ int i;
|
|||
|
+
|
|||
|
+ info->fprintf_func (info->stream, "defb ");
|
|||
|
+ for (i = 0; txt[i]; ++i)
|
|||
|
+ info->fprintf_func (info->stream, i ? ", 0x%02x" : "0x%02x",
|
|||
|
+ (unsigned char) buf->data[i]);
|
|||
|
+ buf->n_used = i;
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Table to disassemble machine codes with prefix 0xED. */
|
|||
|
+struct tab_elt opc_ed[] =
|
|||
|
+{
|
|||
|
+ { 0x70, 0xFF, prt, "in f,(c)" },
|
|||
|
+ { 0x70, 0xFF, dump, "xx" },
|
|||
|
+ { 0x40, 0xC7, prt_r, "in %s,(c)" },
|
|||
|
+ { 0x71, 0xFF, prt, "out (c),0" },
|
|||
|
+ { 0x70, 0xFF, dump, "xx" },
|
|||
|
+ { 0x41, 0xC7, prt_r, "out (c),%s" },
|
|||
|
+ { 0x42, 0xCF, prt_rr, "sbc hl," },
|
|||
|
+ { 0x43, 0xCF, prt_rr_nn, "ld (0x%%04x),%s" },
|
|||
|
+ { 0x44, 0xFF, prt, "neg" },
|
|||
|
+ { 0x45, 0xFF, prt, "retn" },
|
|||
|
+ { 0x46, 0xFF, prt, "im 0" },
|
|||
|
+ { 0x47, 0xFF, prt, "ld i,a" },
|
|||
|
+ { 0x4A, 0xCF, prt_rr, "adc hl," },
|
|||
|
+ { 0x4B, 0xCF, prt_rr_nn, "ld %s,(0x%%04x)" },
|
|||
|
+ { 0x4D, 0xFF, prt, "reti" },
|
|||
|
+ { 0x56, 0xFF, prt, "im 1" },
|
|||
|
+ { 0x57, 0xFF, prt, "ld a,i" },
|
|||
|
+ { 0x5E, 0xFF, prt, "im 2" },
|
|||
|
+ { 0x67, 0xFF, prt, "rrd" },
|
|||
|
+ { 0x6F, 0xFF, prt, "rld" },
|
|||
|
+ { 0xA0, 0xE4, cis, "" },
|
|||
|
+ { 0xC3, 0xFF, prt, "muluw hl,bc" },
|
|||
|
+ { 0xC5, 0xE7, prt_r, "mulub a,%s" },
|
|||
|
+ { 0xF3, 0xFF, prt, "muluw hl,sp" },
|
|||
|
+ { 0x00, 0x00, dump, "xx" }
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int
|
|||
|
+pref_ed (struct buffer * buf, disassemble_info * info,
|
|||
|
+ char* txt ATTRIBUTE_UNUSED)
|
|||
|
+{
|
|||
|
+ struct tab_elt *p;
|
|||
|
+
|
|||
|
+ if (fetch_data(buf, info, 1))
|
|||
|
+ {
|
|||
|
+ for (p = opc_ed; p->val != (buf->data[1] & p->mask); ++p)
|
|||
|
+ ;
|
|||
|
+ p->fp (buf, info, p->text);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Instruction names for the instructions addressing single bits. */
|
|||
|
+static char *cb1_str[] = { "", "bit", "res", "set"};
|
|||
|
+/* Instruction names for shifts and rotates. */
|
|||
|
+static char *cb2_str[] =
|
|||
|
+{
|
|||
|
+ "rlc", "rrc", "rl", "rr", "sla", "sra", "sli", "srl"
|
|||
|
+};
|
|||
|
+
|
|||
|
+static int
|
|||
|
+pref_cb (struct buffer * buf, disassemble_info * info,
|
|||
|
+ char* txt ATTRIBUTE_UNUSED)
|
|||
|
+{
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ buf->n_used = 2;
|
|||
|
+ if ((buf->data[1] & 0xc0) == 0)
|
|||
|
+ info->fprintf_func (info->stream, "%s %s",
|
|||
|
+ cb2_str[(buf->data[1] >> 3) & 7],
|
|||
|
+ r_str[buf->data[1] & 7]);
|
|||
|
+ else
|
|||
|
+ info->fprintf_func (info->stream, "%s %d,%s",
|
|||
|
+ cb1_str[(buf->data[1] >> 6) & 3],
|
|||
|
+ (buf->data[1] >> 3) & 7,
|
|||
|
+ r_str[buf->data[1] & 7]);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+addvv (struct buffer * buf, disassemble_info * info, char* txt)
|
|||
|
+{
|
|||
|
+ info->fprintf_func (info->stream, "add %s,%s", txt, txt);
|
|||
|
+
|
|||
|
+ return buf->n_used = buf->n_fetch;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+ld_v_v (struct buffer * buf, disassemble_info * info, char* txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+
|
|||
|
+ snprintf (mytxt, TXTSIZ, "ld %s%%s,%s%%s", txt, txt);
|
|||
|
+ return ld_r_r (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_d (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ int d;
|
|||
|
+ signed char *p;
|
|||
|
+
|
|||
|
+ p = buf->data + buf->n_fetch;
|
|||
|
+
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ d = p[0];
|
|||
|
+ info->fprintf_func (info->stream, txt, d);
|
|||
|
+ buf->n_used = buf->n_fetch;
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+prt_d_n (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+ int d;
|
|||
|
+ signed char *p;
|
|||
|
+
|
|||
|
+ p = buf->data + buf->n_fetch;
|
|||
|
+
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ d = p[0];
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, d);
|
|||
|
+ return prt_n (buf, info, mytxt);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+arit_d (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+ signed char c;
|
|||
|
+
|
|||
|
+ c = buf->data[buf->n_fetch - 1];
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, arit_str[(c >> 3) & 7]);
|
|||
|
+ return prt_d (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+ld_r_d (struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+ signed char c;
|
|||
|
+
|
|||
|
+ c = buf->data[buf->n_fetch - 1];
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, r_str[(c >> 3) & 7]);
|
|||
|
+ return prt_d (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+ld_d_r(struct buffer *buf, disassemble_info * info, char *txt)
|
|||
|
+{
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+ signed char c;
|
|||
|
+
|
|||
|
+ c = buf->data[buf->n_fetch - 1];
|
|||
|
+ snprintf (mytxt, TXTSIZ, txt, r_str[c & 7]);
|
|||
|
+ return prt_d (buf, info, mytxt);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static int
|
|||
|
+pref_xd_cb (struct buffer * buf, disassemble_info * info, char* txt)
|
|||
|
+{
|
|||
|
+ if (fetch_data (buf, info, 2))
|
|||
|
+ {
|
|||
|
+ int d;
|
|||
|
+ char arg[TXTSIZ];
|
|||
|
+ signed char *p;
|
|||
|
+
|
|||
|
+ buf->n_used = 4;
|
|||
|
+ p = buf->data;
|
|||
|
+ d = p[2];
|
|||
|
+
|
|||
|
+ if (((p[3] & 0xC0) == 0x40) || ((p[3] & 7) == 0x06))
|
|||
|
+ snprintf (arg, TXTSIZ, "(%s%+d)", txt, d);
|
|||
|
+ else
|
|||
|
+ snprintf (arg, TXTSIZ, "(%s%+d),%s", txt, d, r_str[p[3] & 7]);
|
|||
|
+
|
|||
|
+ if ((p[3] & 0xc0) == 0)
|
|||
|
+ info->fprintf_func (info->stream, "%s %s",
|
|||
|
+ cb2_str[(buf->data[3] >> 3) & 7],
|
|||
|
+ arg);
|
|||
|
+ else
|
|||
|
+ info->fprintf_func (info->stream, "%s %d,%s",
|
|||
|
+ cb1_str[(buf->data[3] >> 6) & 3],
|
|||
|
+ (buf->data[3] >> 3) & 7,
|
|||
|
+ arg);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Table to disassemble machine codes with prefix 0xDD or 0xFD. */
|
|||
|
+static struct tab_elt opc_ind[] =
|
|||
|
+{
|
|||
|
+ { 0x24, 0xF7, prt_r, "inc %s%%s" },
|
|||
|
+ { 0x25, 0xF7, prt_r, "dec %s%%s" },
|
|||
|
+ { 0x26, 0xF7, ld_r_n, "ld %s%%s,0x%%%%02x" },
|
|||
|
+ { 0x21, 0xFF, prt_nn, "ld %s,0x%%04x" },
|
|||
|
+ { 0x22, 0xFF, prt_nn, "ld (0x%%04x),%s" },
|
|||
|
+ { 0x2A, 0xFF, prt_nn, "ld %s,(0x%%04x)" },
|
|||
|
+ { 0x23, 0xFF, prt, "inc %s" },
|
|||
|
+ { 0x2B, 0xFF, prt, "dec %s" },
|
|||
|
+ { 0x29, 0xFF, addvv, "%s" },
|
|||
|
+ { 0x09, 0xCF, prt_rr, "add %s," },
|
|||
|
+ { 0x34, 0xFF, prt_d, "inc (%s%%+d)" },
|
|||
|
+ { 0x35, 0xFF, prt_d, "dec (%s%%+d)" },
|
|||
|
+ { 0x36, 0xFF, prt_d_n, "ld (%s%%+d),0x%%%%02x" },
|
|||
|
+
|
|||
|
+ { 0x76, 0xFF, dump, "h" },
|
|||
|
+ { 0x46, 0xC7, ld_r_d, "ld %%s,(%s%%%%+d)" },
|
|||
|
+ { 0x70, 0xF8, ld_d_r, "ld (%s%%%%+d),%%s" },
|
|||
|
+ { 0x64, 0xF6, ld_v_v, "%s" },
|
|||
|
+ { 0x60, 0xF0, ld_r_r, "ld %s%%s,%%s" },
|
|||
|
+ { 0x44, 0xC6, ld_r_r, "ld %%s,%s%%s" },
|
|||
|
+
|
|||
|
+ { 0x86, 0xC7, arit_d, "%%s(%s%%%%+d)" },
|
|||
|
+ { 0x84, 0xC6, arit_r, "%%s%s%%s" },
|
|||
|
+
|
|||
|
+ { 0xE1, 0xFF, prt, "pop %s" },
|
|||
|
+ { 0xE5, 0xFF, prt, "push %s" },
|
|||
|
+ { 0xCB, 0xFF, pref_xd_cb, "%s" },
|
|||
|
+ { 0xE3, 0xFF, prt, "ex (sp),%s" },
|
|||
|
+ { 0xE9, 0xFF, prt, "jp (%s)" },
|
|||
|
+ { 0xF9, 0xFF, prt, "ld sp,%s" },
|
|||
|
+ { 0x00, 0x00, dump, "?" },
|
|||
|
+} ;
|
|||
|
+
|
|||
|
+static int
|
|||
|
+pref_ind (struct buffer * buf, disassemble_info * info, char* txt)
|
|||
|
+{
|
|||
|
+ if (fetch_data (buf, info, 1))
|
|||
|
+ {
|
|||
|
+ char mytxt[TXTSIZ];
|
|||
|
+ struct tab_elt *p;
|
|||
|
+
|
|||
|
+ for (p = opc_ind; p->val != (buf->data[1] & p->mask); ++p)
|
|||
|
+ ;
|
|||
|
+ snprintf (mytxt, TXTSIZ, p->text, txt);
|
|||
|
+ p->fp (buf, info, mytxt);
|
|||
|
+ }
|
|||
|
+ else
|
|||
|
+ buf->n_used = -1;
|
|||
|
+
|
|||
|
+ return buf->n_used;
|
|||
|
+}
|
|||
|
+
|
|||
|
+/* Table to disassemble machine codes without prefix. */
|
|||
|
+static struct tab_elt opc_main[] =
|
|||
|
+{
|
|||
|
+ { 0x00, 0xFF, prt, "nop" },
|
|||
|
+ { 0x01, 0xCF, prt_rr_nn, "ld %s,0x%%04x" },
|
|||
|
+ { 0x02, 0xFF, prt, "ld (bc),a" },
|
|||
|
+ { 0x03, 0xCF, prt_rr, "inc " },
|
|||
|
+ { 0x04, 0xC7, prt_r, "inc %s" },
|
|||
|
+ { 0x05, 0xC7, prt_r, "dec %s" },
|
|||
|
+ { 0x06, 0xC7, ld_r_n, "ld %s,0x%%02x" },
|
|||
|
+ { 0x07, 0xFF, prt, "rlca" },
|
|||
|
+ { 0x08, 0xFF, prt, "ex af,af'" },
|
|||
|
+ { 0x09, 0xCF, prt_rr, "add hl," },
|
|||
|
+ { 0x0A, 0xFF, prt, "ld a,(bc)" },
|
|||
|
+ { 0x0B, 0xCF, prt_rr, "dec " },
|
|||
|
+ { 0x0F, 0xFF, prt, "rrca" },
|
|||
|
+ { 0x10, 0xFF, prt_e, "djnz " },
|
|||
|
+ { 0x12, 0xFF, prt, "ld (de),a" },
|
|||
|
+ { 0x17, 0xFF, prt, "rla" },
|
|||
|
+ { 0x18, 0xFF, prt_e, "jr "},
|
|||
|
+ { 0x1A, 0xFF, prt, "ld a,(de)" },
|
|||
|
+ { 0x1F, 0xFF, prt, "rra" },
|
|||
|
+ { 0x20, 0xE7, jr_cc, "jr %s,"},
|
|||
|
+ { 0x22, 0xFF, prt_nn, "ld (0x%04x),hl" },
|
|||
|
+ { 0x27, 0xFF, prt, "daa"},
|
|||
|
+ { 0x2A, 0xFF, prt_nn, "ld hl,(0x%04x)" },
|
|||
|
+ { 0x2F, 0xFF, prt, "cpl" },
|
|||
|
+ { 0x32, 0xFF, prt_nn, "ld (0x%04x),a" },
|
|||
|
+ { 0x37, 0xFF, prt, "scf" },
|
|||
|
+ { 0x3A, 0xFF, prt_nn, "ld a,(0x%04x)" },
|
|||
|
+ { 0x3F, 0xFF, prt, "ccf" },
|
|||
|
+
|
|||
|
+ { 0x76, 0xFF, prt, "halt" },
|
|||
|
+ { 0x40, 0xC0, ld_r_r, "ld %s,%s"},
|
|||
|
+
|
|||
|
+ { 0x80, 0xC0, arit_r, "%s%s" },
|
|||
|
+
|
|||
|
+ { 0xC0, 0xC7, prt_cc, "ret " },
|
|||
|
+ { 0xC1, 0xCF, pop_rr, "pop" },
|
|||
|
+ { 0xC2, 0xC7, jp_cc_nn, "jp " },
|
|||
|
+ { 0xC3, 0xFF, prt_nn, "jp 0x%04x" },
|
|||
|
+ { 0xC4, 0xC7, jp_cc_nn, "call " },
|
|||
|
+ { 0xC5, 0xCF, pop_rr, "push" },
|
|||
|
+ { 0xC6, 0xC7, arit_n, "%s0x%%02x" },
|
|||
|
+ { 0xC7, 0xC7, rst, "rst 0x%02x" },
|
|||
|
+ { 0xC9, 0xFF, prt, "ret" },
|
|||
|
+ { 0xCB, 0xFF, pref_cb, "" },
|
|||
|
+ { 0xCD, 0xFF, prt_nn, "call 0x%04x" },
|
|||
|
+ { 0xD3, 0xFF, prt_n, "out (0x%02x),a" },
|
|||
|
+ { 0xD9, 0xFF, prt, "exx" },
|
|||
|
+ { 0xDB, 0xFF, prt_n, "in a,(0x%02x)" },
|
|||
|
+ { 0xDD, 0xFF, pref_ind, "ix" },
|
|||
|
+ { 0xE3, 0xFF, prt, "ex (sp),hl" },
|
|||
|
+ { 0xE9, 0xFF, prt, "jp (hl)" },
|
|||
|
+ { 0xEB, 0xFF, prt, "ex de,hl" },
|
|||
|
+ { 0xED, 0xFF, pref_ed, ""},
|
|||
|
+ { 0xF3, 0xFF, prt, "di" },
|
|||
|
+ { 0xF9, 0xFF, prt, "ld sp,hl" },
|
|||
|
+ { 0xFB, 0xFF, prt, "ei" },
|
|||
|
+ { 0xFD, 0xFF, pref_ind, "iy" },
|
|||
|
+ { 0x00, 0x00, prt, "????" },
|
|||
|
+} ;
|
|||
|
+
|
|||
|
+int
|
|||
|
+print_insn_z80 (bfd_vma addr, disassemble_info * info)
|
|||
|
+{
|
|||
|
+ struct buffer buf;
|
|||
|
+ struct tab_elt *p;
|
|||
|
+
|
|||
|
+ buf.base = addr;
|
|||
|
+ buf.n_fetch = 0;
|
|||
|
+ buf.n_used = 0;
|
|||
|
+
|
|||
|
+ if (! fetch_data (& buf, info, 1))
|
|||
|
+ return -1;
|
|||
|
+
|
|||
|
+ for (p = opc_main; p->val != (buf.data[0] & p->mask); ++p)
|
|||
|
+ ;
|
|||
|
+ p->fp (& buf, info, p->text);
|
|||
|
+
|
|||
|
+ return buf.n_used;
|
|||
|
+}
|