# HG changeset patch # User Michael Pavone # Date 1419995494 28800 # Node ID f822d92169685bbcb6566585adf1e18151352da3 # Parent 9d6fed6501baf2592e6cf65752a21568d9caf6bf# Parent 103d5cabbe144d61820ed6a37f40be500180725c Merge diff -r 103d5cabbe14 -r f822d9216968 .hgignore --- a/.hgignore Tue Dec 16 01:10:54 2014 -0800 +++ b/.hgignore Tue Dec 30 19:11:34 2014 -0800 @@ -6,15 +6,22 @@ *.jpg *.pdf *.tar.gz +*.list *~ starscream/* +gxz80/* +musashi/* vdpreverse/* nemesis/* html/* +generated_tests/* +ztests/* *.o *.list blastem dis stateview trans - +zdis +ztestrun +address.log diff -r 103d5cabbe14 -r f822d9216968 .hgtags --- a/.hgtags Tue Dec 16 01:10:54 2014 -0800 +++ b/.hgtags Tue Dec 30 19:11:34 2014 -0800 @@ -1,1 +1,2 @@ 949c7d8756931ca19d93d6de5cc507405a007937 v0.1.0 +6b7a96d0eda8ed9f1a1436c3ac590a1c4db94f27 v0.2.0 diff -r 103d5cabbe14 -r f822d9216968 68kinst.c --- a/68kinst.c Tue Dec 16 01:10:54 2014 -0800 +++ b/68kinst.c Tue Dec 30 19:11:34 2014 -0800 @@ -1097,6 +1097,7 @@ break; case 4: decoded->op = M68K_SBCD; + decoded->extra.size = OPSIZE_BYTE; decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG; decoded->src.params.regs.pri = *istream & 0x7; decoded->dst.params.regs.pri = (*istream >> 9) & 0x7; diff -r 103d5cabbe14 -r f822d9216968 Makefile --- a/Makefile Tue Dec 16 01:10:54 2014 -0800 +++ b/Makefile Tue Dec 30 19:11:34 2014 -0800 @@ -3,11 +3,12 @@ else LIBS=sdl glew gl endif -LDFLAGS=-lm `pkg-config --libs $(LIBS)` ifdef DEBUG -CFLAGS=-ggdb -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type +CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration +LDFLAGS:=-ggdb -lm $(shell pkg-config --libs $(LIBS)) else -CFLAGS=-O2 -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type +CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration +LDFLAGS:=-O2 -flto -lm $(shell pkg-config --libs $(LIBS)) endif ifdef PROFILE @@ -28,16 +29,50 @@ CFLAGS+= -DM68010 endif -TRANSOBJS=gen_x86.o x86_backend.o mem.o -M68KOBJS=68kinst.o m68k_to_x86.o runtime.o -Z80OBJS=z80inst.o z80_to_x86.o zruntime.o +ifndef CPU +CPU:=$(shell uname -m) +endif + + + +TRANSOBJS=gen.o backend.o mem.o +M68KOBJS=68kinst.o m68k_core.o +ifeq ($(CPU),x86_64) +M68KOBJS+= runtime.o m68k_core_x86.o +TRANSOBJS+= gen_x86.o backend_x86.o +else +ifeq ($(CPU),i686) +M68KOBJS+= runtime_32.o m68k_core_x86.o +TRANSOBJS+= gen_x86.o backend_x86.o +NOZ80:=1 +endif +endif + +Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o +MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) + +ifeq ($(CPU),x86_64) +CFLAGS+=-DX86_64 +else +ifeq ($(CPU),i686) +CFLAGS+=-DX86_32 +endif +endif + +ifdef NOZ80 +CFLAGS+=-DNO_Z80 +else +MAINOBJS+= $(Z80OBJS) +endif + + all : dis zdis stateview vgmplay blastem -blastem : blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) - $(CC) -ggdb -o blastem blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS) +blastem : $(MAINOBJS) + $(CC) -o blastem $(MAINOBJS) $(LDFLAGS) dis : dis.o 68kinst.o tern.o vos_program_module.o $(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o @@ -69,13 +104,16 @@ testgst : testgst.o gst.o $(CC) -o testgst testgst.o gst.o -test_x86 : test_x86.o gen_x86.o - $(CC) -o test_x86 test_x86.o gen_x86.o +test_x86 : test_x86.o gen_x86.o gen.o + $(CC) -o test_x86 test_x86.o gen_x86.o gen.o + +test_arm : test_arm.o gen_arm.o mem.o gen.o + $(CC) -o test_arm test_arm.o gen_arm.o mem.o gen.o gen_fib : gen_fib.o gen_x86.o mem.o $(CC) -o gen_fib gen_fib.o gen_x86.o mem.o -offsets : offsets.c z80_to_x86.h m68k_to_x86.h +offsets : offsets.c z80_to_x86.h m68k_core.h $(CC) -o offsets offsets.c vos_prog_info : vos_prog_info.o vos_program_module.o diff -r 103d5cabbe14 -r f822d9216968 backend.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/backend.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,53 @@ +/* + Copyright 2013 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#include "backend.h" +#include + +deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest) +{ + deferred_addr * new_head = malloc(sizeof(deferred_addr)); + new_head->next = old_head; + new_head->address = address & 0xFFFFFF; + new_head->dest = dest; + return new_head; +} + +void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to) +{ + for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr) + { + *head_ptr = cur->next; + free(cur); + } +} + +void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native) +{ + deferred_addr * cur = *head_ptr; + deferred_addr **last_next = head_ptr; + while(cur) + { + code_ptr native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address); + if (native) { + int32_t disp = native - (cur->dest + 4); + code_ptr out = cur->dest; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *out = disp; + *last_next = cur->next; + free(cur); + cur = *last_next; + } else { + last_next = &(cur->next); + cur = cur->next; + } + } +} + diff -r 103d5cabbe14 -r f822d9216968 backend.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/backend.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,117 @@ +/* + Copyright 2013 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#ifndef BACKEND_H_ +#define BACKEND_H_ + +#include +#include +#include "gen.h" + +#define INVALID_OFFSET 0xFFFFFFFF +#define EXTENSION_WORD 0xFFFFFFFE + +#if defined(X86_32) || defined(X86_64) +typedef struct { + int32_t disp; + uint8_t mode; + uint8_t base; + uint8_t index; +} host_ea; +#else +typedef struct { + int32_t disp; + uint8_t mode; + uint8_t base; +} host_ea; +#endif + +typedef struct { + uint8_t *base; + int32_t *offsets; +} native_map_slot; + +typedef struct deferred_addr { + struct deferred_addr *next; + code_ptr dest; + uint32_t address; +} deferred_addr; + +typedef enum { + READ_16, + READ_8, + WRITE_16, + WRITE_8 +} ftype; + +typedef struct { + uint32_t flags; + native_map_slot *native_code_map; + deferred_addr *deferred; + code_info code; + uint8_t **ram_inst_sizes; + code_ptr save_context; + code_ptr load_context; + code_ptr handle_cycle_limit; + code_ptr handle_cycle_limit_int; + code_ptr handle_code_write; + uint32_t address_mask; + uint32_t max_address; + uint32_t bus_cycles; + int32_t mem_ptr_off; + int32_t ram_flags_off; + uint8_t ram_flags_shift; + uint8_t address_size; + uint8_t byte_swap; + uint8_t context_reg; + uint8_t cycles; + uint8_t limit; + uint8_t scratch1; + uint8_t scratch2; +} cpu_options; + + +#define MMAP_READ 0x01 +#define MMAP_WRITE 0x02 +#define MMAP_CODE 0x04 +#define MMAP_PTR_IDX 0x08 +#define MMAP_ONLY_ODD 0x10 +#define MMAP_ONLY_EVEN 0x20 +#define MMAP_FUNC_NULL 0x40 +#define MMAP_BYTESWAP 0x80 + +typedef uint16_t (*read_16_fun)(uint32_t address, void * context); +typedef uint8_t (*read_8_fun)(uint32_t address, void * context); +typedef void * (*write_16_fun)(uint32_t address, void * context, uint16_t value); +typedef void * (*write_8_fun)(uint32_t address, void * context, uint8_t value); + +typedef struct { + uint32_t start; + uint32_t end; + uint32_t mask; + uint16_t ptr_index; + uint16_t flags; + void * buffer; + read_16_fun read_16; + write_16_fun write_16; + read_8_fun read_8; + write_8_fun write_8; +} memmap_chunk; + +typedef uint8_t * (*native_addr_func)(void * context, uint32_t address); + +deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest); +void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to); +void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native); + +void cycles(cpu_options *opts, uint32_t num); +void check_cycles_int(cpu_options *opts, uint32_t address); +void check_cycles(cpu_options * opts); +void check_code_prologue(code_info *code); + +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); + +#endif //BACKEND_H_ + diff -r 103d5cabbe14 -r f822d9216968 backend_x86.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/backend_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,288 @@ +#include "backend.h" +#include "gen_x86.h" + +void cycles(cpu_options *opts, uint32_t num) +{ + add_ir(&opts->code, num, opts->cycles, SZ_D); +} + +void check_cycles_int(cpu_options *opts, uint32_t address) +{ + code_info *code = &opts->code; + cmp_rr(code, opts->cycles, opts->limit, SZ_D); + code_ptr jmp_off = code->cur+1; + jcc(code, CC_NC, jmp_off+1); + mov_ir(code, address, opts->scratch1, SZ_D); + call(code, opts->handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); +} + +void check_cycles(cpu_options * opts) +{ + code_info *code = &opts->code; + cmp_rr(code, opts->cycles, opts->limit, SZ_D); + check_alloc_code(code, MAX_INST_LEN*2); + code_ptr jmp_off = code->cur+1; + jcc(code, CC_NC, jmp_off+1); + call(code, opts->handle_cycle_limit); + *jmp_off = code->cur - (jmp_off+1); +} + +void check_code_prologue(code_info *code) +{ + check_alloc_code(code, MAX_INST_LEN*4); +} + +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc) +{ + code_info *code = &opts->code; + code_ptr start = code->cur; + check_cycles(opts); + cycles(opts, opts->bus_cycles); + if (after_inc) { + *after_inc = code->cur; + } + if (opts->address_size == SZ_D && opts->address_mask < 0xFFFFFFFF) { + and_ir(code, opts->address_mask, opts->scratch1, SZ_D); + } + code_ptr lb_jcc = NULL, ub_jcc = NULL; + uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8; + uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1; + uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ; + uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B; + for (uint32_t chunk = 0; chunk < num_chunks; chunk++) + { + if (memmap[chunk].start > 0) { + cmp_ir(code, memmap[chunk].start, adr_reg, opts->address_size); + lb_jcc = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + } + if (memmap[chunk].end < opts->max_address) { + cmp_ir(code, memmap[chunk].end, adr_reg, opts->address_size); + ub_jcc = code->cur + 1; + jcc(code, CC_NC, code->cur + 2); + } + + if (memmap[chunk].mask != opts->address_mask) { + and_ir(code, memmap[chunk].mask, adr_reg, opts->address_size); + } + void * cfun; + switch (fun_type) + { + case READ_16: + cfun = memmap[chunk].read_16; + break; + case READ_8: + cfun = memmap[chunk].read_8; + break; + case WRITE_16: + cfun = memmap[chunk].write_16; + break; + case WRITE_8: + cfun = memmap[chunk].write_8; + break; + default: + cfun = NULL; + } + if(memmap[chunk].flags & access_flag) { + if (memmap[chunk].flags & MMAP_PTR_IDX) { + if (memmap[chunk].flags & MMAP_FUNC_NULL) { + cmp_irdisp(code, 0, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, SZ_PTR); + code_ptr not_null = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, opts->save_context); +#ifdef X86_64 + if (is_write) { + if (opts->scratch2 != RDI) { + mov_rr(code, opts->scratch2, RDI, opts->address_size); + } + mov_rr(code, opts->scratch1, RDX, size); + } else { + push_r(code, opts->context_reg); + mov_rr(code, opts->scratch1, RDI, opts->address_size); + } + test_ir(code, 8, RSP, opts->address_size); + code_ptr adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, cfun); + code_ptr no_adjust = code->cur + 1; + jmp(code, code->cur + 2); + *adjust_rsp = code->cur - (adjust_rsp + 1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, cfun); + add_ir(code, 8, RSP, SZ_PTR); + *no_adjust = code->cur - (no_adjust + 1); +#else + if (is_write) { + push_r(code, opts->scratch1); + } else { + push_r(code, opts->context_reg);//save opts->context_reg for later + } + push_r(code, opts->context_reg); + push_r(code, is_write ? opts->scratch2 : opts->scratch1); + call(code, cfun); + add_ir(code, is_write ? 12 : 8, RSP, opts->address_size); +#endif + if (is_write) { + mov_rr(code, RAX, opts->context_reg, SZ_PTR); + } else { + pop_r(code, opts->context_reg); + mov_rr(code, RAX, opts->scratch1, size); + } + jmp(code, opts->load_context); + + *not_null = code->cur - (not_null + 1); + } + if ((opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) && size == SZ_B) { + xor_ir(code, 1, adr_reg, opts->address_size); + } + if (opts->address_size != SZ_D) { + movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D); + } + add_rdispr(code, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_PTR); + if (is_write) { + mov_rrind(code, opts->scratch1, opts->scratch2, size); + + } else { + mov_rindr(code, opts->scratch1, opts->scratch1, size); + } + } else { + uint8_t tmp_size = size; + if (size == SZ_B) { + if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { + bt_ir(code, 0, adr_reg, opts->address_size); + code_ptr good_addr = code->cur + 1; + jcc(code, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, code->cur + 2); + if (!is_write) { + mov_ir(code, 0xFF, opts->scratch1, SZ_B); + } + retn(code); + *good_addr = code->cur - (good_addr + 1); + shr_ir(code, 1, adr_reg, opts->address_size); + } else if (opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) { + xor_ir(code, 1, adr_reg, opts->address_size); + } + } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { + tmp_size = SZ_B; + shr_ir(code, 1, adr_reg, opts->address_size); + if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) { + shr_ir(code, 8, opts->scratch1, SZ_W); + } + } + if (opts->address_size != SZ_D) { + movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D); + } + if ((intptr_t)memmap[chunk].buffer <= 0x7FFFFFFF && (intptr_t)memmap[chunk].buffer >= -2147483648) { + if (is_write) { + mov_rrdisp(code, opts->scratch1, opts->scratch2, (intptr_t)memmap[chunk].buffer, tmp_size); + } else { + mov_rdispr(code, opts->scratch1, (intptr_t)memmap[chunk].buffer, opts->scratch1, tmp_size); + } + } else { + if (is_write) { + push_r(code, opts->scratch1); + mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch1, SZ_PTR); + add_rr(code, opts->scratch1, opts->scratch2, SZ_PTR); + pop_r(code, opts->scratch1); + mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size); + } else { + mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR); + mov_rindexr(code, opts->scratch2, opts->scratch1, 1, opts->scratch1, tmp_size); + } + } + if (size != tmp_size && !is_write) { + if (memmap[chunk].flags & MMAP_ONLY_EVEN) { + shl_ir(code, 8, opts->scratch1, SZ_W); + mov_ir(code, 0xFF, opts->scratch1, SZ_B); + } else { + or_ir(code, 0xFF00, opts->scratch1, SZ_W); + } + } + } + if (is_write && (memmap[chunk].flags & MMAP_CODE)) { + mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size); + shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size); + bt_rrdisp(code, opts->scratch1, opts->context_reg, opts->ram_flags_off, opts->address_size); + code_ptr not_code = code->cur + 1; + jcc(code, CC_NC, code->cur + 2); + call(code, opts->save_context); +#ifdef X86_32 + push_r(code, opts->context_reg); + push_r(code, opts->scratch2); +#else + if (opts->scratch2 != RDI) { + mov_rr(code, opts->scratch2, RDI, opts->address_size); + } +#endif + call(code, opts->handle_code_write); +#ifdef X86_32 + add_ir(code, 8, RSP, SZ_D); +#endif + mov_rr(code, RAX, opts->context_reg, SZ_PTR); + call(code, opts->load_context); + *not_code = code->cur - (not_code+1); + } + retn(code); + } else if (cfun) { + call(code, opts->save_context); +#ifdef X86_64 + if (is_write) { + if (opts->scratch2 != RDI) { + mov_rr(code, opts->scratch2, RDI, opts->address_size); + } + mov_rr(code, opts->scratch1, RDX, size); + } else { + push_r(code, opts->context_reg); + mov_rr(code, opts->scratch1, RDI, opts->address_size); + } + test_ir(code, 8, RSP, SZ_D); + code_ptr adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, cfun); + code_ptr no_adjust = code->cur + 1; + jmp(code, code->cur + 2); + *adjust_rsp = code->cur - (adjust_rsp + 1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, cfun); + add_ir(code, 8, RSP, SZ_PTR); + *no_adjust = code->cur - (no_adjust+1); +#else + if (is_write) { + push_r(code, opts->scratch1); + } else { + push_r(code, opts->context_reg);//save opts->context_reg for later + } + push_r(code, opts->context_reg); + push_r(code, is_write ? opts->scratch2 : opts->scratch1); + call(code, cfun); + add_ir(code, is_write ? 12 : 8, RSP, SZ_D); +#endif + if (is_write) { + mov_rr(code, RAX, opts->context_reg, SZ_PTR); + } else { + pop_r(code, opts->context_reg); + mov_rr(code, RAX, opts->scratch1, size); + } + jmp(code, opts->load_context); + } else { + //Not sure the best course of action here + if (!is_write) { + mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size); + } + retn(code); + } + if (lb_jcc) { + *lb_jcc = code->cur - (lb_jcc+1); + lb_jcc = NULL; + } + if (ub_jcc) { + *ub_jcc = code->cur - (ub_jcc+1); + ub_jcc = NULL; + } + } + if (!is_write) { + mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size); + } + retn(code); + return start; +} diff -r 103d5cabbe14 -r f822d9216968 blastem.c --- a/blastem.c Tue Dec 16 01:10:54 2014 -0800 +++ b/blastem.c Tue Dec 30 19:11:34 2014 -0800 @@ -4,7 +4,7 @@ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "68kinst.h" -#include "m68k_to_x86.h" +#include "m68k_core.h" #include "z80_to_x86.h" #include "mem.h" #include "vdp.h" @@ -182,6 +182,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks) { +#ifndef NO_Z80 if (z80_enabled && !reset && !busreq) { genesis_context * gen = z_context->system; z_context->sync_cycle = mclks / MCLKS_PER_Z80; @@ -198,14 +199,18 @@ } if (z_context->iff1) { z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; + } else { + z_context->int_cycle = CYCLE_NEVER; } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); - z80_run(z_context); + z_context->run(z_context); dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); } } - } else { + } else +#endif + { z_context->current_cycle = mclks / MCLKS_PER_Z80; } } @@ -410,8 +415,9 @@ return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0)); } -z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value) +void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) { + z80_context * context = vcontext; genesis_context * gen = context->system; if (vdp_port & 0xE0) { printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); @@ -480,6 +486,34 @@ } } +uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) +{ + z80_context * context = vcontext; + if (vdp_port & 0xE0) { + printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); + exit(1); + } + genesis_context * gen = context->system; + vdp_port &= 0x1F; + uint16_t ret; + if (vdp_port < 0x10) { + //These probably won't currently interact well with the 68K accessing the VDP + vdp_run_context(gen->vdp, context->current_cycle * MCLKS_PER_Z80); + if (vdp_port < 4) { + ret = vdp_data_port_read(gen->vdp); + } else if (vdp_port < 8) { + ret = vdp_control_port_read(gen->vdp); + } else { + printf("Illegal write to HV Counter port %X\n", vdp_port); + exit(1); + } + } else { + //TODO: Figure out the correct value today + ret = 0xFFFF; + } + return vdp_port & 1 ? ret : ret >> 8; +} + uint32_t zram_counter = 0; #define Z80_ACK_DELAY 3 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this @@ -499,7 +533,9 @@ location &= 0x7FFF; if (location < 0x4000) { z80_ram[location & 0x1FFF] = value; +#ifndef NO_Z80 z80_handle_code_write(location & 0x1FFF, gen->z80); +#endif } else if (location < 0x6000) { sync_sound(gen, context->current_cycle * MCLKS_PER_68K); if (location & 1) { @@ -699,8 +735,9 @@ return value; } -z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) +void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) { + z80_context * context = vcontext; genesis_context * gen = context->system; sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); if (location & 1) { @@ -713,13 +750,55 @@ return context; } -uint8_t z80_read_ym(uint16_t location, z80_context * context) +uint8_t z80_read_ym(uint32_t location, void * vcontext) { + z80_context * context = vcontext; genesis_context * gen = context->system; sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); return ym_read_status(gen->ym); } +uint8_t z80_read_bank(uint32_t location, void * vcontext) +{ + z80_context * context = vcontext; + uint32_t address = context->bank_reg << 15 | location; + if (address >= 0xC00000 && address < 0xE00000) { + return z80_vdp_port_read(location & 0xFF, context); + } else { + fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area\n", address); + } + return 0; +} + +void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) +{ + z80_context * context = vcontext; + uint32_t address = context->bank_reg << 15 | location; + if (address >= 0xE00000) { + address &= 0xFFFF; + ((uint8_t *)ram)[address ^ 1] = value; + } else if (address >= 0xC00000) { + z80_vdp_port_write(location & 0xFF, context, value); + } else { + fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address); + } + return context; +} + +void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) +{ + z80_context * context = vcontext; + + context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; + if (context->bank_reg < 0x80) { + context->mem_pointers[1] = context->mem_pointers[2] + (context->bank_reg << 15); + } else { + context->mem_pointers[1] = NULL; + } + + return context; +} + uint16_t read_sram_w(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; @@ -894,7 +973,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger) { m68k_context context; - x86_68k_options opts; + m68k_options opts; gen->m68k = &context; memmap_chunk memmap[MAX_MAP_CHUNKS]; uint32_t num_chunks; @@ -988,9 +1067,9 @@ } atexit(save_sram); } - init_x86_68k_opts(&opts, memmap, num_chunks); + init_m68k_opts(&opts, memmap, num_chunks); opts.address_log = address_log; - init_68k_context(&context, opts.native_code_map, &opts); + init_68k_context(&context, opts.gen.native_code_map, &opts); context.video_context = gen->vdp; context.system = gen; @@ -1016,7 +1095,9 @@ insert_breakpoint(&context, pc, debugger); } adjust_int_cycle(gen->m68k, gen->vdp); +#ifndef NO_Z80 gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); +#endif start_68k_context(&context, pc); } else { if (debugger) { @@ -1095,6 +1176,15 @@ } } } +#ifndef NO_Z80 +const memmap_chunk z80_map[] = { + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x8000, 0x10000, 0x7FFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, + { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, + { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, + { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} +}; +#endif int main(int argc, char ** argv) { @@ -1260,9 +1350,11 @@ psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); z80_context z_context; - x86_z80_options z_opts; - init_x86_z80_opts(&z_opts); +#ifndef NO_Z80 + z80_options z_opts; + init_x86_z80_opts(&z_opts, z80_map, 5); init_z80_context(&z_context, &z_opts); +#endif z_context.system = &gen; z_context.mem_pointers[0] = z80_ram; diff -r 103d5cabbe14 -r f822d9216968 blastem.h --- a/blastem.h Tue Dec 16 01:10:54 2014 -0800 +++ b/blastem.h Tue Dec 30 19:11:34 2014 -0800 @@ -7,7 +7,7 @@ #define BLASTEM_H_ #include -#include "m68k_to_x86.h" +#include "m68k_core.h" #include "z80_to_x86.h" #include "ym2612.h" #include "vdp.h" diff -r 103d5cabbe14 -r f822d9216968 comparetests.py --- a/comparetests.py Tue Dec 16 01:10:54 2014 -0800 +++ b/comparetests.py Tue Dec 30 19:11:34 2014 -0800 @@ -18,6 +18,49 @@ else: prefixes.append(argv[i]) +def print_mismatch(path, b, m): + blines = b.split('\n') + mlines = m.split('\n') + if len(blines) != len(mlines): + print '-----------------------------' + print 'Unknown mismatch in', path + print 'blastem output:' + print b + print 'musashi output:' + print m + print '-----------------------------' + return + prevline = '' + differences = [] + flagmismatch = False + regmismatch = False + for i in xrange(0, len(blines)): + if blines[i] != mlines[i]: + if prevline == 'XNZVC': + differences.append((prevline, prevline)) + flagmismatch = True + else: + regmismatch = True + differences.append((blines[i], mlines[i])) + prevline = blines[i] + if flagmismatch and regmismatch: + mtype = 'General' + elif flagmismatch: + mtype = 'Flag' + elif regmismatch: + mtype = 'Register' + else: + mtype = 'Unknown' + print '-----------------------------' + print mtype, 'mismatch in', path + for i in xrange(0, 2): + print 'musashi' if i else 'blastem', 'output:' + for diff in differences: + print diff[i] + print '-----------------------------' + + + for path in glob('generated_tests/*/*.bin'): if path in skip: continue @@ -36,13 +79,8 @@ m = subprocess.check_output(['musashi/mustrans', path]) #_,_,b = b.partition('\n') if b != m: - print '-----------------------------' - print 'Mismatch in ' + path - print 'blastem output:' - print b - print 'musashi output:' - print m - print '-----------------------------' + print_mismatch(path, b, m) + else: print path, 'passed' except subprocess.CalledProcessError as e: diff -r 103d5cabbe14 -r f822d9216968 debug.c --- a/debug.c Tue Dec 16 01:10:54 2014 -0800 +++ b/debug.c Tue Dec 30 19:11:34 2014 -0800 @@ -82,6 +82,8 @@ } } +#ifndef NO_Z80 + void zdebugger_print(z80_context * context, char format_char, char * param) { uint32_t value; @@ -460,6 +462,8 @@ return context; } +#endif + m68k_context * debugger(m68k_context * context, uint32_t address) { static char last_cmd[1024]; @@ -527,19 +531,49 @@ debugging = 0; break; case 'b': - param = find_param(input_buf); - if (!param) { - fputs("b command requires a parameter\n", stderr); - break; + if (input_buf[1] == 't') { + uint32_t stack = context->aregs[7]; + if (stack >= 0xE00000) { + stack &= 0xFFFF; + uint8_t non_adr_count = 0; + do { + uint32_t bt_address = ram[stack/2] << 16 | ram[stack/2+1]; + bt_address = get_instruction_start(context->native_code_map, bt_address - 2); + if (bt_address) { + stack += 4; + non_adr_count = 0; + uint16_t *bt_pc = NULL; + if (bt_address < 0x400000) { + bt_pc = cart + bt_address/2; + } else if(bt_address > 0xE00000) { + bt_pc = ram + (bt_address & 0xFFFF)/2; + } + m68k_decode(bt_pc, &inst, bt_address); + m68k_disasm(&inst, input_buf); + printf("%X: %s\n", bt_address, input_buf); + } else { + //non-return address value on stack can be word wide + stack += 2; + non_adr_count++; + } + stack &= 0xFFFF; + } while (stack && non_adr_count < 6); + } + } else { + param = find_param(input_buf); + if (!param) { + fputs("b command requires a parameter\n", stderr); + break; + } + value = strtol(param, NULL, 16); + insert_breakpoint(context, value, (uint8_t *)debugger); + new_bp = malloc(sizeof(bp_def)); + new_bp->next = breakpoints; + new_bp->address = value; + new_bp->index = bp_index++; + breakpoints = new_bp; + printf("68K Breakpoint %d set at %X\n", new_bp->index, value); } - value = strtol(param, NULL, 16); - insert_breakpoint(context, value, (uint8_t *)debugger); - new_bp = malloc(sizeof(bp_def)); - new_bp->next = breakpoints; - new_bp->address = value; - new_bp->index = bp_index++; - breakpoints = new_bp; - printf("68K Breakpoint %d set at %X\n", new_bp->index, value); break; case 'a': param = find_param(input_buf); @@ -706,6 +740,7 @@ } break; } +#ifndef NO_Z80 case 'z': { genesis_context * gen = context->system; //Z80 debug commands @@ -736,6 +771,7 @@ } break; } +#endif case 'q': puts("Quitting"); exit(0); diff -r 103d5cabbe14 -r f822d9216968 debug.h --- a/debug.h Tue Dec 16 01:10:54 2014 -0800 +++ b/debug.h Tue Dec 30 19:11:34 2014 -0800 @@ -2,7 +2,7 @@ #define DEBUG_H_ #include -#include "m68k_to_x86.h" +#include "m68k_core.h" typedef struct disp_def { struct disp_def * next; diff -r 103d5cabbe14 -r f822d9216968 dis.c --- a/dis.c Tue Dec 16 01:10:54 2014 -0800 +++ b/dis.c Tue Dec 30 19:11:34 2014 -0800 @@ -292,7 +292,7 @@ if (is_visited(address)) { break; } - } else if (instbuf.src.addr_mode = MODE_PC_DISPLACE) { + } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) { address = instbuf.src.params.regs.displacement + instbuf.address + 2; encoded = filebuf + (address - address_off)/2; if (is_visited(address)) { diff -r 103d5cabbe14 -r f822d9216968 gdb_remote.c --- a/gdb_remote.c Tue Dec 16 01:10:54 2014 -0800 +++ b/gdb_remote.c Tue Dec 30 19:11:34 2014 -0800 @@ -145,7 +145,9 @@ } else if (address >= 0xA00000 && address < 0xA04000) { z80_ram[address & 0x1FFF] = value; genesis_context * gen = context->system; +#ifndef NO_Z80 z80_handle_code_write(address & 0x1FFF, gen->z80); +#endif return; } else { return; diff -r 103d5cabbe14 -r f822d9216968 gen.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,15 @@ +#include +#include +#include "gen.h" +#include "mem.h" + +void init_code_info(code_info *code) +{ + size_t size = CODE_ALLOC_SIZE; + code->cur = alloc_code(&size); + if (!code->cur) { + fputs("Failed to allocate memory for generated code\n", stderr); + exit(1); + } + code->last = code->cur + size/sizeof(code_word) - RESERVE_WORDS; +} diff -r 103d5cabbe14 -r f822d9216968 gen.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,25 @@ +#ifndef GEN_H_ +#define GEN_H_ +#include + +#if defined(X86_64) || defined(X86_32) +typedef uint8_t code_word; +#define RESERVE_WORDS 5 //opcode + 4-byte displacement +#else +typedef uint32_t code_word; +#define RESERVE_WORDS 4 //1 push + 1 ldr + 1bx + 1 constant +#endif +typedef code_word * code_ptr; +#define CODE_ALLOC_SIZE (1024*1024) + +typedef struct { + code_ptr cur; + code_ptr last; +} code_info; + +void init_code_info(code_info *code); +void call(code_info *code, code_ptr fun); +void jmp(code_info *code, code_ptr dest); +void jmp_r(code_info *code, uint8_t dst); + +#endif //GEN_H_ diff -r 103d5cabbe14 -r f822d9216968 gen_arm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen_arm.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,550 @@ +/* + Copyright 2014 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#include "gen_arm.h" +#include "mem.h" +#include +#include + +#define OP_FIELD_SHIFT 21u + +//Data processing format instructions +#define OP_AND 0x0u +#define OP_EOR (0x1u << OP_FIELD_SHIFT) +#define OP_SUB (0x2u << OP_FIELD_SHIFT) +#define OP_RSB (0x3u << OP_FIELD_SHIFT) +#define OP_ADD (0x4u << OP_FIELD_SHIFT) +#define OP_ADC (0x5u << OP_FIELD_SHIFT) +#define OP_SBC (0x6u << OP_FIELD_SHIFT) +#define OP_RSC (0x7u << OP_FIELD_SHIFT) +#define OP_TST (0x8u << OP_FIELD_SHIFT) +#define OP_TEQ (0x9u << OP_FIELD_SHIFT) +#define OP_CMP (0xAu << OP_FIELD_SHIFT) +#define OP_CMN (0xBu << OP_FIELD_SHIFT) +#define OP_ORR (0xCu << OP_FIELD_SHIFT) +#define OP_MOV (0xDu << OP_FIELD_SHIFT) +#define OP_BIC (0xEu << OP_FIELD_SHIFT) +#define OP_MVN (0xFu << OP_FIELD_SHIFT) + +//branch instructions +#define OP_B 0xA000000u +#define OP_BL 0xB000000u +#define OP_BX 0x12FFF10u + +//load/store +#define OP_STR 0x4000000u +#define OP_LDR 0x4100000u +#define OP_STM 0x8000000u +#define OP_LDM 0x8100000u +#define POST_IND 0u +#define PRE_IND 0x1000000u +#define DIR_DOWN 0u +#define DIR_UP 0x0800000u +#define SZ_W 0u +#define SZ_B 0x0400000u +#define WRITE_B 0x0200000u +#define OFF_IMM 0u +#define OFF_REG 0x2000000u + +#define PUSH (OP_STR | PRE_IND | OFF_IMM | SZ_W | WRITE_B | DIR_DOWN | sizeof(uint32_t) | (sp << 16)) +#define POP (OP_LDR | POST_IND | OFF_IMM | SZ_W | DIR_UP | sizeof(uint32_t) | (sp << 16)) +#define PUSHM (OP_STM | PRE_IND | SZ_W | WRITE_B | DIR_DOWN | (sp << 16)) +#define POPM (OP_LDM | POST_IND | SZ_W | WRITE_B | DIR_UP | (sp << 16)) + +#define IMMED 0x2000000u +#define REG 0u + + +uint32_t make_immed(uint32_t val) +{ + uint32_t rot_amount = 0; + for (; rot_amount < 0x20; rot_amount += 2) + { + uint32_t test_mask = ~(0xFF << rot_amount | 0xFF >> (32-rot_amount)); + if (!(test_mask & val)) { + return val << rot_amount | val >> (32-rot_amount) | rot_amount << 7; + } + } + return INVALID_IMMED; +} + +void check_alloc_code(code_info *code) +{ + if (code->cur == code->last) { + size_t size = CODE_ALLOC_SIZE; + uint32_t *next_code = alloc_code(&size); + if (!next_code) { + fputs("Failed to allocate memory for generated code\n", stderr); + exit(1); + } + if (next_code = code->last + RESERVE_WORDS) { + //new chunk is contiguous with the current one + code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS; + } else { + uint32_t * from = code->cur + 2; + if (next_code - from < 0x400000 || from - next_code <= 0x400000) { + *from = CC_AL | OP_B | ((next_code - from) & 0xFFFFFF); + } else { + //push r0 onto the stack + *(from++) = CC_AL | PUSH; + uint32_t immed = make_immed((uint32_t)next_code); + if (immed == INVALID_IMMED) { + //Load target into r0 from word after next instruction into register 0 + *(from++) = CC_AL | OP_LDR | OFF_IMM | DIR_DOWN | PRE_IND | SZ_W | (pc << 16) | 4; + from[1] = (uint32_t)next_code; + } else { + //Load target into r0 + *(from++) = CC_AL | OP_MOV | IMMED | NO_COND | immed; + } + //branch to address in r0 + *from = CC_AL | OP_BX; + code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS; + //pop r0 + *(next_code++) = CC_AL | POP; + code->cur = next_code; + } + } + } +} + +uint32_t data_proc(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t src2) +{ + check_alloc_code(code); + *(code->cur++) = cond | op | set_cond | (src1 << 16) | (dst << 12) | src2; + + return CODE_OK; +} + +uint32_t data_proci(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t immed) +{ + immed = make_immed(immed); + if (immed == INVALID_IMMED) { + return immed; + } + return data_proc(code, cond, op | IMMED, set_cond, dst, src1, immed); +} + +//TODO: support shifted register for op2 + +uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_AND, set_cond, dst, src1, src2); +} + +uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_AND, set_cond, dst, src1, immed); +} + +uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_AND, set_cond, dst, src1, src2); +} + +uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_AND, set_cond, dst, src1, immed); +} + +uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_EOR, set_cond, dst, src1, src2); +} + +uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_EOR, set_cond, dst, src1, immed); +} + +uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_EOR, set_cond, dst, src1, src2); +} + +uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_EOR, set_cond, dst, src1, immed); +} + +uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_SUB, set_cond, dst, src1, src2); +} + +uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_SUB, set_cond, dst, src1, immed); +} + +uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_SUB, set_cond, dst, src1, src2); +} + +uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_SUB, set_cond, dst, src1, immed); +} + +uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_RSB, set_cond, dst, src1, src2); +} + +uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_RSB, set_cond, dst, src1, immed); +} + +uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_RSB, set_cond, dst, src1, src2); +} + +uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_RSB, set_cond, dst, src1, immed); +} + +uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_ADD, set_cond, dst, src1, src2); +} + +uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_ADD, set_cond, dst, src1, immed); +} + +uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_ADD, set_cond, dst, src1, src2); +} + +uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_ADD, set_cond, dst, src1, immed); +} + +uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_ADC, set_cond, dst, src1, src2); +} + +uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_ADC, set_cond, dst, src1, immed); +} + +uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_ADC, set_cond, dst, src1, src2); +} + +uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_ADC, set_cond, dst, src1, immed); +} + +uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_SBC, set_cond, dst, src1, src2); +} + +uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_SBC, set_cond, dst, src1, immed); +} + +uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_SBC, set_cond, dst, src1, src2); +} + +uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_SBC, set_cond, dst, src1, immed); +} + +uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_RSC, set_cond, dst, src1, src2); +} + +uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_RSC, set_cond, dst, src1, immed); +} + +uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_RSC, set_cond, dst, src1, src2); +} + +uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_RSC, set_cond, dst, src1, immed); +} + +uint32_t tst(code_info *code, uint32_t src1, uint32_t src2) +{ + return data_proc(code, CC_AL, OP_TST, SET_COND, r0, src1, src2); +} + +uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed) +{ + return data_proci(code, CC_AL, OP_TST, SET_COND, r0, src1, immed); +} + +uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc) +{ + return data_proc(code, cc, OP_TST, SET_COND, r0, src1, src2); +} + +uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc) +{ + return data_proci(code, cc, OP_TST, SET_COND, r0, src1, immed); +} + +uint32_t teq(code_info *code, uint32_t src1, uint32_t src2) +{ + return data_proc(code, CC_AL, OP_TEQ, SET_COND, r0, src1, src2); +} + +uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed) +{ + return data_proci(code, CC_AL, OP_TEQ, SET_COND, r0, src1, immed); +} + +uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc) +{ + return data_proc(code, cc, OP_TEQ, SET_COND, r0, src1, src2); +} + +uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc) +{ + return data_proci(code, cc, OP_TEQ, SET_COND, r0, src1, immed); +} + +uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2) +{ + return data_proc(code, CC_AL, OP_CMP, SET_COND, r0, src1, src2); +} + +uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed) +{ + return data_proci(code, CC_AL, OP_CMP, SET_COND, r0, src1, immed); +} + +uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc) +{ + return data_proc(code, cc, OP_CMP, SET_COND, r0, src1, src2); +} + +uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc) +{ + return data_proci(code, cc, OP_CMP, SET_COND, r0, src1, immed); +} + +uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2) +{ + return data_proc(code, CC_AL, OP_CMN, SET_COND, r0, src1, src2); +} + +uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed) +{ + return data_proci(code, CC_AL, OP_CMN, SET_COND, r0, src1, immed); +} + +uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc) +{ + return data_proc(code, cc, OP_CMN, SET_COND, r0, src1, src2); +} + +uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc) +{ + return data_proci(code, cc, OP_CMN, SET_COND, r0, src1, immed); +} + +uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_ORR, set_cond, dst, src1, src2); +} + +uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_ORR, set_cond, dst, src1, immed); +} + +uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_ORR, set_cond, dst, src1, src2); +} + +uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_ORR, set_cond, dst, src1, immed); +} + +uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_MOV, set_cond, dst, 0, src2); +} + +uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_MOV, set_cond, dst, 0, immed); +} + +uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_MOV, set_cond, dst, 0, src2); +} + +uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_MOV, set_cond, dst, 0, immed); +} + +uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_BIC, set_cond, dst, src1, src2); +} + +uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_BIC, set_cond, dst, src1, immed); +} + +uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_BIC, set_cond, dst, src1, src2); +} + +uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_BIC, set_cond, dst, src1, immed); +} + +uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond) +{ + return data_proc(code, CC_AL, OP_MVN, set_cond, dst, 0, src2); +} + +uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond) +{ + return data_proci(code, CC_AL, OP_MVN, set_cond, dst, 0, immed); +} + +uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond) +{ + return data_proc(code, cc, OP_MVN, set_cond, dst, 0, src2); +} + +uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond) +{ + return data_proci(code, cc, OP_MVN, set_cond, dst, 0, immed); +} + +uint32_t branchi(code_info *code, uint32_t cc, uint32_t op, uint32_t *dst) +{ + uint32_t * from = code->cur + 2; + if (dst - from >= 0x400000 && from - dst > 0x400000) { + return INVALID_IMMED; + } + check_alloc_code(code); + *(code->cur++) = cc | op | ((dst - from) & 0xFFFFFF); + return CODE_OK; +} + +uint32_t b(code_info *code, uint32_t *dst) +{ + return branchi(code, CC_AL, OP_B, dst); +} + +uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc) +{ + return branchi(code, cc, OP_B, dst); +} + +uint32_t bl(code_info *code, uint32_t *dst) +{ + return branchi(code, CC_AL, OP_BL, dst); +} + +uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc) +{ + return branchi(code, cc, OP_BL, dst); +} + +uint32_t bx(code_info *code, uint32_t dst) +{ + check_alloc_code(code); + *(code->cur++) = CC_AL | OP_BX | dst; + return CODE_OK; +} + +uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc) +{ + check_alloc_code(code); + *(code->cur++) = cc | OP_BX | dst; + return CODE_OK; +} + +uint32_t push(code_info *code, uint32_t reg) +{ + check_alloc_code(code); + *(code->cur++) = CC_AL | PUSH | reg << 12; + return CODE_OK; +} + +uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc) +{ + check_alloc_code(code); + *(code->cur++) = cc | PUSH | reg << 12; + return CODE_OK; +} + +uint32_t pushm(code_info *code, uint32_t reglist) +{ + check_alloc_code(code); + *(code->cur++) = CC_AL | PUSHM | reglist; + return CODE_OK; +} + +uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc) +{ + check_alloc_code(code); + *(code->cur++) = cc | PUSHM | reglist; + return CODE_OK; +} + +uint32_t pop(code_info *code, uint32_t reg) +{ + check_alloc_code(code); + *(code->cur++) = CC_AL | POP | reg << 12; + return CODE_OK; +} + +uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc) +{ + check_alloc_code(code); + *(code->cur++) = cc | POP | reg << 12; + return CODE_OK; +} + +uint32_t popm(code_info *code, uint32_t reglist) +{ + check_alloc_code(code); + *(code->cur++) = CC_AL | POPM | reglist; + return CODE_OK; +} + +uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc) +{ + check_alloc_code(code); + *(code->cur++) = cc | POPM | reglist; + return CODE_OK; +} diff -r 103d5cabbe14 -r f822d9216968 gen_arm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen_arm.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,153 @@ +/* + Copyright 2014 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#ifndef GEN_ARM_H_ +#define GEN_ARM_H_ + +#include +#include "gen.h" + +#define SET_COND 0x100000u +#define NO_COND 0u + +#define CC_FIELD_SHIFT 28 + +#define CC_EQ 0x0u +#define CC_NE (0x1u << CC_FIELD_SHIFT) +#define CC_CS (0x2u << CC_FIELD_SHIFT) +#define CC_CC (0x3u << CC_FIELD_SHIFT) +#define CC_MI (0x4u << CC_FIELD_SHIFT) +#define CC_PL (0x5u << CC_FIELD_SHIFT) +#define CC_VS (0x6u << CC_FIELD_SHIFT) +#define CC_VC (0x7u << CC_FIELD_SHIFT) +#define CC_HI (0x8u << CC_FIELD_SHIFT) +#define CC_LS (0x9u << CC_FIELD_SHIFT) +#define CC_GE (0xAu << CC_FIELD_SHIFT) +#define CC_LT (0xBu << CC_FIELD_SHIFT) +#define CC_GT (0xCu << CC_FIELD_SHIFT) +#define CC_LE (0xDu << CC_FIELD_SHIFT) +#define CC_AL (0xEu << CC_FIELD_SHIFT) + +#define INVALID_IMMED 0xFFFFFFFFu +#define CODE_OK 0u + +enum { + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + sp, + lr, + pc +}; + +#define R0 0x1 +#define R1 0x2 +#define R2 0x4 +#define R3 0x8 +#define R4 0x10 +#define R5 0x20 +#define R6 0x40 +#define R7 0x80 +#define R8 0x100 +#define R9 0x200 +#define R10 0x400 +#define R11 0x800 +#define R12 0x1000 +#define SP 0x2000 +#define LR 0x4000 +#define PC 0x8000 + +uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t tst(code_info *code, uint32_t src1, uint32_t src2); +uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed); +uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc); +uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc); +uint32_t teq(code_info *code, uint32_t src1, uint32_t src2); +uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed); +uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc); +uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc); +uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2); +uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed); +uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc); +uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc); +uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2); +uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed); +uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc); +uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc); +uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond); +uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond); +uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond); +uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond); +uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond); +uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond); +uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond); +uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond); +uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond); + +uint32_t b(code_info *code, uint32_t *dst); +uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc); +uint32_t bl(code_info *code, uint32_t *dst); +uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc); +uint32_t bx(code_info *code, uint32_t dst); +uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc); + +uint32_t push(code_info *code, uint32_t reg); +uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc); +uint32_t pushm(code_info *code, uint32_t reglist); +uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc); +uint32_t pop(code_info *code, uint32_t reg); +uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc); +uint32_t popm(code_info *code, uint32_t reglist); +uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc); + +#endif //GEN_ARM_H_ diff -r 103d5cabbe14 -r f822d9216968 gen_x86.c --- a/gen_x86.c Tue Dec 16 01:10:54 2014 -0800 +++ b/gen_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -4,7 +4,7 @@ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "gen_x86.h" -#include "68kinst.h" +#include "mem.h" #include #include #include @@ -33,6 +33,7 @@ #define OP_TEST 0x84 #define OP_XCHG 0x86 #define OP_MOV 0x88 +#define PRE_XOP 0x8F #define OP_XCHG_AX 0x90 #define OP_CDQ 0x99 #define OP_PUSHF 0x9C @@ -127,8 +128,55 @@ X86_R15 } x86_regs_enc; -uint8_t * x86_rr_sizedir(uint8_t * out, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size) +void jmp_nocheck(code_info *code, code_ptr dest) { + code_ptr out = code->cur; + ptrdiff_t disp = dest-(out+2); + if (disp <= 0x7F && disp >= -0x80) { + *(out++) = OP_JMP_BYTE; + *(out++) = disp; + } else { + disp = dest-(out+5); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = OP_JMP; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp); + exit(1); + } + } + code->cur = out; +} + +void check_alloc_code(code_info *code, uint32_t inst_size) +{ + if (code->cur + inst_size > code->last) { + size_t size = CODE_ALLOC_SIZE; + code_ptr next_code = alloc_code(&size); + if (!next_code) { + fputs("Failed to allocate memory for generated code\n", stderr); + exit(1); + } + if (next_code != code->last + RESERVE_WORDS) { + //new chunk is not contiguous with the current one + jmp_nocheck(code, next_code); + code->cur = next_code; + code->last = next_code + size/sizeof(RESERVE_WORDS); + } + code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS; + } +} + +void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size) +{ + check_alloc_code(code, 5); + code_ptr out = code->cur; uint8_t tmp; if (size == SZ_W) { *(out++) = PRE_SIZE; @@ -175,60 +223,13 @@ *(out++) = opcode; } *(out++) = MODE_REG_DIRECT | dst | (src << 3); - return out; + code->cur = out; } -uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int8_t disp, uint8_t size, uint8_t dir) +void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir) { - //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix - uint8_t tmp; - if (size == SZ_W) { - *(out++) = PRE_SIZE; - } - if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { - *out = PRE_REX; - if (reg >= AH && reg <= BH) { - fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); - exit(1); - } - if (size == SZ_Q) { - *out |= REX_QUAD; - } - if (reg >= R8) { - *out |= REX_REG_FIELD; - reg -= (R8 - X86_R8); - } - if (base >= R8) { - *out |= REX_RM_FIELD; - base -= (R8 - X86_R8); - } - out++; - } - if (size == SZ_B) { - if (reg >= AH && reg <= BH) { - reg -= (AH-X86_AH); - } - } else { - opcode |= BIT_SIZE; - } - opcode |= dir; - if (opcode >= 0x100) { - *(out++) = opcode >> 8; - *(out++) = opcode; - } else { - *(out++) = opcode; - } - *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); - if (base == RSP) { - //add SIB byte, with no index and RSP as base - *(out++) = (RSP << 3) | RSP; - } - *(out++) = disp; - return out; -} - -uint8_t * x86_rrdisp32_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir) -{ + check_alloc_code(code, 10); + code_ptr out = code->cur; //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix uint8_t tmp; if (size == SZ_W) { @@ -267,20 +268,28 @@ } else { *(out++) = opcode; } - *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3); + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); + } else { + *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3); + } if (base == RSP) { //add SIB byte, with no index and RSP as base *(out++) = (RSP << 3) | RSP; } *(out++) = disp; - *(out++) = disp >> 8; - *(out++) = disp >> 16; - *(out++) = disp >> 24; - return out; + if (disp >= 128 || disp < -128) { + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir) +void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir) { + check_alloc_code(code, 5); + code_ptr out = code->cur; //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix uint8_t tmp; if (size == SZ_W) { @@ -313,16 +322,25 @@ opcode |= BIT_SIZE; } *(out++) = opcode | dir; - *(out++) = MODE_REG_INDIRECT | base | (reg << 3); - if (base == RSP) { - //add SIB byte, with no index and RSP as base - *(out++) = (RSP << 3) | RSP; + if (base == RBP) { + //add a dummy 8-bit displacement since MODE_REG_INDIRECT with + //an R/M field of RBP selects RIP, relative addressing + *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); + *(out++) = 0; + } else { + *(out++) = MODE_REG_INDIRECT | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } } - return out; + code->cur = out; } -uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir) +void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir) { + check_alloc_code(code, 5); + code_ptr out = code->cur; //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix uint8_t tmp; if (size == SZ_W) { @@ -359,18 +377,22 @@ opcode |= BIT_SIZE; } *(out++) = opcode | dir; - *(out++) = MODE_REG_INDIRECT | base | (RSP << 3); - if (base == RSP) { - if (scale == 4) { - scale = 3; - } - *(out++) = scale << 6 | (index << 3) | base; + *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3); + if (scale == 4) { + scale = 2; + } else if(scale == 8) { + scale = 3; + } else { + scale--; } - return out; + *(out++) = scale << 6 | (index << 3) | base; + code->cur = out; } -uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size) +void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size) { + check_alloc_code(code, 4); + code_ptr out = code->cur; uint8_t tmp; if (size == SZ_W) { *(out++) = PRE_SIZE; @@ -399,11 +421,13 @@ } *(out++) = opcode; *(out++) = MODE_REG_DIRECT | dst | (opex << 3); - return out; + code->cur = out; } -uint8_t * x86_rdisp8_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, int8_t disp, uint8_t size) +void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, int32_t disp, uint8_t size) { + check_alloc_code(code, 7); + code_ptr out = code->cur; uint8_t tmp; if (size == SZ_W) { *(out++) = PRE_SIZE; @@ -423,13 +447,23 @@ opcode |= BIT_SIZE; } *(out++) = opcode; - *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3); - *(out++) = disp; - return out; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3); + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size) +void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size) { + check_alloc_code(code, 8); + code_ptr out = code->cur; uint8_t sign_extend = 0; if (opcode != OP_NOT_NEG && (size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { sign_extend = 1; @@ -478,53 +512,13 @@ *(out++) = val; } } - return out; + code->cur = out; } -uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int8_t disp, uint8_t size) +void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_t disp, uint8_t size) { - uint8_t sign_extend = 0; - if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { - sign_extend = 1; - opcode |= BIT_DIR; - } - if (size == SZ_W) { - *(out++) = PRE_SIZE; - } - - if (size == SZ_Q || dst >= R8) { - *out = PRE_REX; - if (size == SZ_Q) { - *out |= REX_QUAD; - } - if (dst >= R8) { - *out |= REX_RM_FIELD; - dst -= (R8 - X86_R8); - } - out++; - } - if (size != SZ_B) { - opcode |= BIT_SIZE; - } - *(out++) = opcode; - *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); - *(out++) = disp; - *(out++) = val; - if (size != SZ_B && !sign_extend) { - val >>= 8; - *(out++) = val; - if (size != SZ_W) { - val >>= 8; - *(out++) = val; - val >>= 8; - *(out++) = val; - } - } - return out; -} - -uint8_t * x86_irdisp32(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_t disp, uint8_t size) -{ + check_alloc_code(code, 12); + code_ptr out = code->cur; uint8_t sign_extend = 0; if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { sign_extend = 1; @@ -549,14 +543,19 @@ opcode |= BIT_SIZE; } *(out++) = opcode; - *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); - *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } *(out++) = val; if (size != SZ_B && !sign_extend) { val >>= 8; @@ -568,12 +567,13 @@ *(out++) = val; } } - return out; + code->cur = out; } - -uint8_t * x86_shiftrot_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) +void x86_shiftrot_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) { + check_alloc_code(code, 5); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -597,11 +597,13 @@ if (val != 1) { *(out++) = val; } - return out; + code->cur = out; } -uint8_t * x86_shiftrot_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, int8_t disp, uint8_t size) +void x86_shiftrot_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, int32_t disp, uint8_t size) { + check_alloc_code(code, 9); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -621,16 +623,26 @@ } *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE); - *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); - *(out++) = disp; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } if (val != 1) { *(out++) = val; } - return out; + code->cur = out; } -uint8_t * x86_shiftrot_clr(uint8_t * out, uint8_t op_ex, uint8_t dst, uint8_t size) +void x86_shiftrot_clr(code_info *code, uint8_t op_ex, uint8_t dst, uint8_t size) { + check_alloc_code(code, 4); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -651,11 +663,13 @@ *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE); *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3); - return out; + code->cur = out; } -uint8_t * x86_shiftrot_clrdisp8(uint8_t * out, uint8_t op_ex, uint8_t dst, int8_t disp, uint8_t size) +void x86_shiftrot_clrdisp(code_info *code, uint8_t op_ex, uint8_t dst, int32_t disp, uint8_t size) { + check_alloc_code(code, 8); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -675,497 +689,492 @@ } *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE); - *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); - *(out++) = disp; - return out; -} - -uint8_t * rol_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) -{ - return x86_shiftrot_ir(out, OP_EX_ROL, val, dst, size); + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * ror_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_ROR, val, dst, size); + x86_shiftrot_ir(code, OP_EX_ROL, val, dst, size); } -uint8_t * rcl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_RCL, val, dst, size); + x86_shiftrot_ir(code, OP_EX_ROR, val, dst, size); } -uint8_t * rcr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_RCR, val, dst, size); + x86_shiftrot_ir(code, OP_EX_RCL, val, dst, size); } -uint8_t * shl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_SHL, val, dst, size); + x86_shiftrot_ir(code, OP_EX_RCR, val, dst, size); } -uint8_t * shr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_SHR, val, dst, size); + x86_shiftrot_ir(code, OP_EX_SHL, val, dst, size); } -uint8_t * sar_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_ir(out, OP_EX_SAR, val, dst, size); + x86_shiftrot_ir(code, OP_EX_SHR, val, dst, size); } -uint8_t * rol_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_ROL, val, dst_base, disp, size); + x86_shiftrot_ir(code, OP_EX_SAR, val, dst, size); } -uint8_t * ror_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_ROR, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_ROL, val, dst_base, disp, size); } -uint8_t * rcl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_RCL, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_ROR, val, dst_base, disp, size); } -uint8_t * rcr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_RCR, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_RCL, val, dst_base, disp, size); } -uint8_t * shl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_SHL, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_RCR, val, dst_base, disp, size); } -uint8_t * shr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_SHR, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_SHL, val, dst_base, disp, size); } -uint8_t * sar_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_irdisp8(out, OP_EX_SAR, val, dst_base, disp, size); + x86_shiftrot_irdisp(code, OP_EX_SHR, val, dst_base, disp, size); } -uint8_t * rol_clr(uint8_t * out, uint8_t dst, uint8_t size) +void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_ROL, dst, size); -} - -uint8_t * ror_clr(uint8_t * out, uint8_t dst, uint8_t size) -{ - return x86_shiftrot_clr(out, OP_EX_ROR, dst, size); + x86_shiftrot_irdisp(code, OP_EX_SAR, val, dst_base, disp, size); } -uint8_t * rcl_clr(uint8_t * out, uint8_t dst, uint8_t size) +void rol_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_RCL, dst, size); + x86_shiftrot_clr(code, OP_EX_ROL, dst, size); } -uint8_t * rcr_clr(uint8_t * out, uint8_t dst, uint8_t size) +void ror_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_RCR, dst, size); + x86_shiftrot_clr(code, OP_EX_ROR, dst, size); } -uint8_t * shl_clr(uint8_t * out, uint8_t dst, uint8_t size) +void rcl_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_SHL, dst, size); + x86_shiftrot_clr(code, OP_EX_RCL, dst, size); } -uint8_t * shr_clr(uint8_t * out, uint8_t dst, uint8_t size) +void rcr_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_SHR, dst, size); + x86_shiftrot_clr(code, OP_EX_RCR, dst, size); } -uint8_t * sar_clr(uint8_t * out, uint8_t dst, uint8_t size) +void shl_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clr(out, OP_EX_SAR, dst, size); + x86_shiftrot_clr(code, OP_EX_SHL, dst, size); } -uint8_t * rol_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void shr_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_ROL, dst_base, disp, size); + x86_shiftrot_clr(code, OP_EX_SHR, dst, size); } -uint8_t * ror_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void sar_clr(code_info *code, uint8_t dst, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_ROR, dst_base, disp, size); + x86_shiftrot_clr(code, OP_EX_SAR, dst, size); } -uint8_t * rcl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_RCL, dst_base, disp, size); + x86_shiftrot_clrdisp(code, OP_EX_ROL, dst_base, disp, size); } -uint8_t * rcr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_RCR, dst_base, disp, size); + x86_shiftrot_clrdisp(code, OP_EX_ROR, dst_base, disp, size); } -uint8_t * shl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_SHL, dst_base, disp, size); + x86_shiftrot_clrdisp(code, OP_EX_RCL, dst_base, disp, size); } -uint8_t * shr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_SHR, dst_base, disp, size); + x86_shiftrot_clrdisp(code, OP_EX_RCR, dst_base, disp, size); } -uint8_t * sar_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_shiftrot_clrdisp8(out, OP_EX_SAR, dst_base, disp, size); + x86_shiftrot_clrdisp(code, OP_EX_SHL, dst_base, disp, size); } -uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rr_sizedir(out, OP_ADD, src, dst, size); + x86_shiftrot_clrdisp(code, OP_EX_SHR, dst_base, disp, size); } -uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); + x86_shiftrot_clrdisp(code, OP_EX_SAR, dst_base, disp, size); } -uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size); + x86_rr_sizedir(code, OP_ADD, src, dst, size); } -uint8_t * add_irdisp32(uint8_t * out, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) +void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp32(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); } -uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size); } -uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_ADD, src, dst_base, disp, size, 0); } -uint8_t * adc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_ADC, src, dst, size); + x86_rrdisp_sizedir(code, OP_ADD, dst, src_base, disp, size, BIT_DIR); } -uint8_t * adc_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size); + x86_rr_sizedir(code, OP_ADC, src, dst, size); } -uint8_t * adc_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size); } -uint8_t * adc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_ADC, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size); } -uint8_t * adc_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_ADC, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_ADC, src, dst_base, disp, size, 0); } -uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_OR, src, dst, size); -} -uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) -{ - return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); + x86_rrdisp_sizedir(code, OP_ADC, dst, src_base, disp, size, BIT_DIR); } -uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size); + x86_rr_sizedir(code, OP_OR, src, dst, size); +} +void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) +{ + x86_ir(code, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); } -uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size); } -uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_OR, src, dst_base, disp, size, 0); } -uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_AND, src, dst, size); + x86_rrdisp_sizedir(code, OP_OR, dst, src_base, disp, size, BIT_DIR); } -uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); + x86_rr_sizedir(code, OP_AND, src, dst, size); } -uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); } -uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size); } -uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_AND, src, dst_base, disp, size, 0); } -uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_XOR, src, dst, size); + x86_rrdisp_sizedir(code, OP_AND, dst, src_base, disp, size, BIT_DIR); } -uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); + x86_rr_sizedir(code, OP_XOR, src, dst, size); } -uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); } -uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size); } -uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_XOR, src, dst_base, disp, size, 0); } -uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_SUB, src, dst, size); + x86_rrdisp_sizedir(code, OP_XOR, dst, src_base, disp, size, BIT_DIR); } -uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); + x86_rr_sizedir(code, OP_SUB, src, dst, size); } -uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); } -uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size); } -uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_SUB, src, dst_base, disp, size, 0); } -uint8_t * sbb_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_SBB, src, dst, size); + x86_rrdisp_sizedir(code, OP_SUB, dst, src_base, disp, size, BIT_DIR); } -uint8_t * sbb_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size); + x86_rr_sizedir(code, OP_SBB, src, dst, size); } -uint8_t * sbb_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size); } -uint8_t * sbb_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_SBB, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size); } -uint8_t * sbb_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_SBB, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_SBB, src, dst_base, disp, size, 0); } -uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_CMP, src, dst, size); + x86_rrdisp_sizedir(code, OP_SBB, dst, src_base, disp, size, BIT_DIR); } -uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); + x86_rr_sizedir(code, OP_CMP, src, dst, size); } -uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size); + x86_ir(code, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); } -uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size); } -uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_CMP, src, dst_base, disp, size, 0); } -uint8_t * test_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP_TEST, src, dst, size); + x86_rrdisp_sizedir(code, OP_CMP, dst, src_base, disp, size, BIT_DIR); } -uint8_t * test_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_ir(out, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size); + x86_rr_sizedir(code, OP_TEST, src, dst, size); } -uint8_t * test_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size) { - return x86_irdisp8(out, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size); + x86_ir(code, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size); } -uint8_t * test_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_TEST, src, dst_base, disp, size, 0); + x86_irdisp(code, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size); } -uint8_t * test_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_TEST, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_TEST, src, dst_base, disp, size, 0); } -uint8_t * imul_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rr_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size); + x86_rrdisp_sizedir(code, OP_TEST, dst, src_base, disp, size, BIT_DIR); } -uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0); + x86_rr_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size); } -uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size) +void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_NOT, dst, size); + x86_rrdisp_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0); } -uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size) +void not_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_NEG, dst, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_NOT, dst, size); } -uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void neg_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_NEG, dst, size); } -uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size); } -uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size) +void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_MUL, dst, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size); } -uint8_t * imul_r(uint8_t * out, uint8_t dst, uint8_t size) +void mul_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_IMUL, dst, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_MUL, dst, size); } -uint8_t * div_r(uint8_t * out, uint8_t dst, uint8_t size) +void imul_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_DIV, dst, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_IMUL, dst, size); } -uint8_t * idiv_r(uint8_t * out, uint8_t dst, uint8_t size) +void div_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_r_size(out, OP_NOT_NEG, OP_EX_IDIV, dst, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_DIV, dst, size); } -uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void idiv_r(code_info *code, uint8_t dst, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size); + x86_r_size(code, OP_NOT_NEG, OP_EX_IDIV, dst, size); } -uint8_t * imul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size); } -uint8_t * div_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size); } -uint8_t * idiv_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size); } -uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rr_sizedir(out, OP_MOV, src, dst, size); + x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size); } -uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0); + x86_rr_sizedir(code, OP_MOV, src, dst, size); } -uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) { - return x86_rrdisp8_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR); + x86_rrdisp_sizedir(code, OP_MOV, src, dst_base, disp, size, 0); } -uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size) +void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) { - return x86_rrdisp32_sizedir(out, OP_MOV, src, dst_base, disp, size, 0); + x86_rrdisp_sizedir(code, OP_MOV, dst, src_base, disp, size, BIT_DIR); } -uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size) +void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_rrdisp32_sizedir(out, OP_MOV, dst, src_base, disp, size, BIT_DIR); + x86_rrind_sizedir(code, OP_MOV, src, dst, size, 0); } -uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return x86_rrind_sizedir(out, OP_MOV, src, dst, size, 0); + x86_rrind_sizedir(code, OP_MOV, dst, src, size, BIT_DIR); } -uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size) { - return x86_rrind_sizedir(out, OP_MOV, dst, src, size, BIT_DIR); + x86_rrindex_sizedir(code, OP_MOV, src, dst_base, dst_index, scale, size, 0); } -uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size) +void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size) { - return x86_rrindex_sizedir(out, OP_MOV, src, dst_base, dst_index, scale, size, 0); + x86_rrindex_sizedir(code, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR); } -uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size) +void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size) { - return x86_rrindex_sizedir(out, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR); -} - -uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size) -{ + check_alloc_code(code, 14); + code_ptr out = code->cur; uint8_t sign_extend = 0; if (size == SZ_Q && val <= 0x7FFFFFFF && val >= -2147483648) { sign_extend = 1; @@ -1216,11 +1225,13 @@ } } } - return out; + code->cur = out; } -uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size) +void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size) { + check_alloc_code(code, 12); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1239,8 +1250,16 @@ dst -= (AH-X86_AH); } *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE); - *(out++) = MODE_REG_DISPLACE8 | dst; - *(out++) = disp; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst; + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst; + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } *(out++) = val; if (size != SZ_B) { @@ -1253,11 +1272,13 @@ *(out++) = val; } } - return out; + code->cur = out; } -uint8_t * mov_irind(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) +void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size) { + check_alloc_code(code, 8); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1289,11 +1310,13 @@ *(out++) = val; } } - return out; + code->cur = out; } -uint8_t * movsx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size) +void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size) { + check_alloc_code(code, 5); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1319,11 +1342,13 @@ *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE); } *(out++) = MODE_REG_DIRECT | src | (dst << 3); - return out; + code->cur = out; } -uint8_t * movsx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size) +void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size) { + check_alloc_code(code, 12); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1348,13 +1373,23 @@ *(out++) = PRE_2BYTE; *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE); } - *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); - *(out++) = disp; - return out; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3); + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size) +void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size) { + check_alloc_code(code, 5); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1376,11 +1411,13 @@ *(out++) = PRE_2BYTE; *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE); *(out++) = MODE_REG_DIRECT | src | (dst << 3); - return out; + code->cur = out; } -uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size) +void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size) { + check_alloc_code(code, 9); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1401,13 +1438,23 @@ } *(out++) = PRE_2BYTE; *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE); - *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); - *(out++) = disp; - return out; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3); + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { + check_alloc_code(code, 4); + code_ptr out = code->cur; //TODO: Use OP_XCHG_AX when one of the registers is AX, EAX or RAX uint8_t tmp; if (size == SZ_W) { @@ -1446,43 +1493,73 @@ } *(out++) = opcode; *(out++) = MODE_REG_DIRECT | dst | (src << 3); - return out; + code->cur = out; } -uint8_t * pushf(uint8_t * out) +void pushf(code_info *code) { + check_alloc_code(code, 1); + code_ptr out = code->cur; *(out++) = OP_PUSHF; - return out; + code->cur = out; } -uint8_t * popf(uint8_t * out) +void popf(code_info *code) { + check_alloc_code(code, 1); + code_ptr out = code->cur; *(out++) = OP_POPF; - return out; + code->cur = out; } -uint8_t * push_r(uint8_t * out, uint8_t reg) +void push_r(code_info *code, uint8_t reg) { + check_alloc_code(code, 2); + code_ptr out = code->cur; if (reg >= R8) { *(out++) = PRE_REX | REX_RM_FIELD; reg -= R8 - X86_R8; } *(out++) = OP_PUSH | reg; - return out; + code->cur = out; } -uint8_t * pop_r(uint8_t * out, uint8_t reg) +void push_rdisp(code_info *code, uint8_t base, int32_t disp) { + //This instruction has no explicit size, so we pass SZ_B + //to avoid any prefixes or bits being set + x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B); +} + +void pop_r(code_info *code, uint8_t reg) +{ + check_alloc_code(code, 2); + code_ptr out = code->cur; if (reg >= R8) { *(out++) = PRE_REX | REX_RM_FIELD; reg -= R8 - X86_R8; } *(out++) = OP_POP | reg; - return out; + code->cur = out; } -uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst) +void pop_rind(code_info *code, uint8_t reg) { + check_alloc_code(code, 3); + code_ptr out = code->cur; + if (reg >= R8) { + *(out++) = PRE_REX | REX_RM_FIELD; + reg -= R8 - X86_R8; + } + *(out++) = PRE_XOP; + *(out++) = MODE_REG_INDIRECT | reg; + code->cur = out; +} + +void setcc_r(code_info *code, uint8_t cc, uint8_t dst) +{ + check_alloc_code(code, 4); + code_ptr out = code->cur; if (dst >= R8) { *(out++) = PRE_REX | REX_RM_FIELD; dst -= R8 - X86_R8; @@ -1494,11 +1571,13 @@ *(out++) = PRE_2BYTE; *(out++) = OP2_SETCC | cc; *(out++) = MODE_REG_DIRECT | dst; - return out; + code->cur = out; } -uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst) +void setcc_rind(code_info *code, uint8_t cc, uint8_t dst) { + check_alloc_code(code, 4); + code_ptr out = code->cur; if (dst >= R8) { *(out++) = PRE_REX | REX_RM_FIELD; dst -= R8 - X86_R8; @@ -1506,24 +1585,36 @@ *(out++) = PRE_2BYTE; *(out++) = OP2_SETCC | cc; *(out++) = MODE_REG_INDIRECT | dst; - return out; + code->cur = out; } -uint8_t * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp) +void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp) { + check_alloc_code(code, 8); + code_ptr out = code->cur; if (dst >= R8) { *(out++) = PRE_REX | REX_RM_FIELD; dst -= R8 - X86_R8; } *(out++) = PRE_2BYTE; *(out++) = OP2_SETCC | cc; - *(out++) = MODE_REG_DISPLACE8 | dst; - *(out++) = disp; - return out; + if (disp < 128 && disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst; + *(out++) = disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst; + *(out++) = disp; + *(out++) = disp >> 8; + *(out++) = disp >> 16; + *(out++) = disp >> 24; + } + code->cur = out; } -uint8_t * bit_rr(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size) +void bit_rr(code_info *code, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size) { + check_alloc_code(code, 5); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1545,38 +1636,13 @@ *(out++) = PRE_2BYTE; *(out++) = op2; *(out++) = MODE_REG_DIRECT | dst | (src << 3); - return out; + code->cur = out; } -uint8_t * bit_rrdisp8(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bit_rrdisp(code_info *code, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - if (size == SZ_W) { - *(out++) = PRE_SIZE; - } - if (size == SZ_Q || src >= R8 || dst_base >= R8) { - *out = PRE_REX; - if (size == SZ_Q) { - *out |= REX_QUAD; - } - if (src >= R8) { - *out |= REX_REG_FIELD; - src -= (R8 - X86_R8); - } - if (dst_base >= R8) { - *out |= REX_RM_FIELD; - dst_base -= (R8 - X86_R8); - } - out++; - } - *(out++) = PRE_2BYTE; - *(out++) = op2; - *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3); - *(out++) = dst_disp; - return out; -} - -uint8_t * bit_rrdisp32(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) -{ + check_alloc_code(code, 9); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1597,16 +1663,23 @@ } *(out++) = PRE_2BYTE; *(out++) = op2; - *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3); - *(out++) = dst_disp; - *(out++) = dst_disp >> 8; - *(out++) = dst_disp >> 16; - *(out++) = dst_disp >> 24; - return out; + if (dst_disp < 128 && dst_disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3); + *(out++) = dst_disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3); + *(out++) = dst_disp; + *(out++) = dst_disp >> 8; + *(out++) = dst_disp >> 16; + *(out++) = dst_disp >> 24; + } + code->cur = out; } -uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) +void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) { + check_alloc_code(code, 6); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1625,11 +1698,13 @@ *(out++) = OP2_BTX_I; *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3); *(out++) = val; - return out; + code->cur = out; } -uint8_t * bit_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bit_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size) { + check_alloc_code(code, 10); + code_ptr out = code->cur; if (size == SZ_W) { *(out++) = PRE_SIZE; } @@ -1646,99 +1721,104 @@ } *(out++) = PRE_2BYTE; *(out++) = OP2_BTX_I; - *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3); - *(out++) = dst_disp; + if (dst_disp < 128 && dst_disp >= -128) { + *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3); + *(out++) = dst_disp; + } else { + *(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3); + *(out++) = dst_disp; + *(out++) = dst_disp >> 8; + *(out++) = dst_disp >> 16; + *(out++) = dst_disp >> 24; + } *(out++) = val; - return out; + code->cur = out; } -uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return bit_rr(out, OP2_BT, src, dst, size); + return bit_rr(code, OP2_BT, src, dst, size); } -uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size); -} - -uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) -{ - return bit_rrdisp32(out, OP2_BT, src, dst_base, dst_disp, size); + return bit_rrdisp(code, OP2_BT, src, dst_base, dst_disp, size); } -uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return bit_ir(out, OP_EX_BT, val, dst, size); + return bit_ir(code, OP_EX_BT, val, dst, size); } -uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_irdisp8(out, OP_EX_BT, val, dst_base, dst_disp, size); + return bit_irdisp(code, OP_EX_BT, val, dst_base, dst_disp, size); } -uint8_t * bts_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return bit_rr(out, OP2_BTS, src, dst, size); + return bit_rr(code, OP2_BTS, src, dst, size); } -uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_rrdisp8(out, OP2_BTS, src, dst_base, dst_disp, size); + return bit_rrdisp(code, OP2_BTS, src, dst_base, dst_disp, size); } -uint8_t * bts_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return bit_ir(out, OP_EX_BTS, val, dst, size); + return bit_ir(code, OP_EX_BTS, val, dst, size); } -uint8_t * bts_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_irdisp8(out, OP_EX_BTS, val, dst_base, dst_disp, size); + return bit_irdisp(code, OP_EX_BTS, val, dst_base, dst_disp, size); +} + +void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) +{ + return bit_rr(code, OP2_BTR, src, dst, size); } -uint8_t * btr_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_rr(out, OP2_BTR, src, dst, size); + return bit_rrdisp(code, OP2_BTR, src, dst_base, dst_disp, size); } -uint8_t * btr_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return bit_rrdisp8(out, OP2_BTR, src, dst_base, dst_disp, size); + return bit_ir(code, OP_EX_BTR, val, dst, size); } -uint8_t * btr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_ir(out, OP_EX_BTR, val, dst, size); + return bit_irdisp(code, OP_EX_BTR, val, dst_base, dst_disp, size); } -uint8_t * btr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size) { - return bit_irdisp8(out, OP_EX_BTR, val, dst_base, dst_disp, size); + return bit_rr(code, OP2_BTC, src, dst, size); } -uint8_t * btc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_rr(out, OP2_BTC, src, dst, size); + return bit_rrdisp(code, OP2_BTC, src, dst_base, dst_disp, size); } -uint8_t * btc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) { - return bit_rrdisp8(out, OP2_BTC, src, dst_base, dst_disp, size); + return bit_ir(code, OP_EX_BTC, val, dst, size); } -uint8_t * btc_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size) +void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size) { - return bit_ir(out, OP_EX_BTC, val, dst, size); + return bit_irdisp(code, OP_EX_BTC, val, dst_base, dst_disp, size); } -uint8_t * btc_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size) +void jcc(code_info *code, uint8_t cc, code_ptr dest) { - return bit_irdisp8(out, OP_EX_BTC, val, dst_base, dst_disp, size); -} - -uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest) -{ + check_alloc_code(code, 6); + code_ptr out = code->cur; ptrdiff_t disp = dest-(out+2); if (disp <= 0x7F && disp >= -0x80) { *(out++) = OP_JCC | cc; @@ -1756,15 +1836,17 @@ disp >>= 8; *(out++) = disp; } else { - printf("%p - %p = %lX\n", dest, out + 6, disp); - return NULL; + fprintf(stderr, "jcc: %p - %p = %lX\n", dest, out + 6, (long)disp); + exit(1); } } - return out; + code->cur = out; } -uint8_t * jmp(uint8_t * out, uint8_t * dest) +void jmp(code_info *code, code_ptr dest) { + check_alloc_code(code, 5); + code_ptr out = code->cur; ptrdiff_t disp = dest-(out+2); if (disp <= 0x7F && disp >= -0x80) { *(out++) = OP_JMP_BYTE; @@ -1781,26 +1863,43 @@ disp >>= 8; *(out++) = disp; } else { - printf("%p - %p = %lX\n", dest, out + 6, disp); - return NULL; + fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp); + exit(1); } } - return out; + code->cur = out; } -uint8_t * jmp_r(uint8_t * out, uint8_t dst) +void jmp_r(code_info *code, uint8_t dst) { + check_alloc_code(code, 3); + code_ptr out = code->cur; if (dst >= R8) { dst -= R8 - X86_R8; *(out++) = PRE_REX | REX_RM_FIELD; } *(out++) = OP_SINGLE_EA; *(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3); - return out; + code->cur = out; } -uint8_t * call(uint8_t * out, uint8_t * fun) +void jmp_rind(code_info *code, uint8_t dst) { + check_alloc_code(code, 3); + code_ptr out = code->cur; + if (dst >= R8) { + dst -= R8 - X86_R8; + *(out++) = PRE_REX | REX_RM_FIELD; + } + *(out++) = OP_SINGLE_EA; + *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3); + code->cur = out; +} + +void call(code_info *code, code_ptr fun) +{ + check_alloc_code(code, 5); + code_ptr out = code->cur; ptrdiff_t disp = fun-(out+5); if (disp <= 0x7FFFFFFF && disp >= -2147483648) { *(out++) = OP_CALL; @@ -1813,35 +1912,44 @@ *(out++) = disp; } else { //TODO: Implement far call??? - printf("%p - %p = %lX\n", fun, out + 5, disp); - return NULL; + fprintf(stderr, "%p - %p = %lX\n", fun, out + 5, (long)disp); + exit(1); } - return out; + code->cur = out; } -uint8_t * call_r(uint8_t * out, uint8_t dst) +void call_r(code_info *code, uint8_t dst) { + check_alloc_code(code, 2); + code_ptr out = code->cur; *(out++) = OP_SINGLE_EA; *(out++) = MODE_REG_DIRECT | dst | (OP_EX_CALL_EA << 3); - return out; + code->cur = out; } -uint8_t * retn(uint8_t * out) +void retn(code_info *code) { + check_alloc_code(code, 1); + code_ptr out = code->cur; *(out++) = OP_RETN; - return out; + code->cur = out; } -uint8_t * cdq(uint8_t * out) +void cdq(code_info *code) { + check_alloc_code(code, 1); + code_ptr out = code->cur; *(out++) = OP_CDQ; - return out; + code->cur = out; } -uint8_t * loop(uint8_t * out, uint8_t * dst) +void loop(code_info *code, code_ptr dst) { + check_alloc_code(code, 2); + code_ptr out = code->cur; ptrdiff_t disp = dst-(out+2); *(out++) = OP_LOOP; *(out++) = disp; - return out; + code->cur = out; } + diff -r 103d5cabbe14 -r f822d9216968 gen_x86.h --- a/gen_x86.h Tue Dec 16 01:10:54 2014 -0800 +++ b/gen_x86.h Tue Dec 30 19:11:34 2014 -0800 @@ -7,6 +7,7 @@ #define GEN_X86_H_ #include +#include "gen.h" enum { RAX = 0, @@ -35,7 +36,9 @@ CC_O = 0, CC_NO, CC_C, + CC_B = CC_C, CC_NC, + CC_NB = CC_NC, CC_Z, CC_NZ, CC_BE, @@ -57,6 +60,14 @@ SZ_Q } x86_size; +#ifdef X86_64 +#define SZ_PTR SZ_Q +#define MAX_INST_LEN 14 +#else +#define SZ_PTR SZ_D +#define MAX_INST_LEN 11 +#endif + enum { MODE_REG_INDIRECT = 0, MODE_REG_INDEXED = 4, @@ -69,145 +80,142 @@ MODE_IMMED = 0xFF } x86_modes; +void check_alloc_code(code_info *code, uint32_t inst_size); -uint8_t * rol_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * ror_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * rcl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * rcr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * shl_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * shr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * sar_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * rol_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * ror_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * rcl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * rcr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * shl_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * shr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sar_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * rol_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * ror_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * rcl_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * rcr_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * shl_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * shr_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * sar_clr(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * rol_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * ror_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * rcl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * rcr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * shl_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * shr_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sar_clrdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * adc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * sbb_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * adc_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * sbb_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * add_irdisp32(uint8_t * out, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); -uint8_t * adc_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sbb_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * adc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * adc_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * sbb_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * sbb_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * imul_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * imul_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * neg_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * neg_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * imul_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * div_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * idiv_r(uint8_t * out, uint8_t dst, uint8_t size); -uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * imul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * div_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * idiv_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * test_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * test_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * test_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * test_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * test_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * mov_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size); -uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size); -uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); -uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); -uint8_t * mov_rrindex(uint8_t * out, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size); -uint8_t * mov_rindexr(uint8_t * out, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size); -uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * mov_rindr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size); -uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size); -uint8_t * mov_irind(uint8_t * out, int32_t val, uint8_t dst, uint8_t size); -uint8_t * movsx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size); -uint8_t * movsx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size); -uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size); -uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size); -uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * pushf(uint8_t * out); -uint8_t * popf(uint8_t * out); -uint8_t * push_r(uint8_t * out, uint8_t reg); -uint8_t * pop_r(uint8_t * out, uint8_t reg); -uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst); -uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst); -uint8_t * setcc_rdisp8(uint8_t * out, uint8_t cc, uint8_t dst, int8_t disp); -uint8_t * bt_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * bt_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * bt_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size); -uint8_t * bt_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * bts_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * bts_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * bts_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * btr_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * btr_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * btr_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * btr_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * btc_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size); -uint8_t * btc_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * btc_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -uint8_t * btc_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size); -uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t *dest); -uint8_t * jmp(uint8_t * out, uint8_t *dest); -uint8_t * jmp_r(uint8_t * out, uint8_t dst); -uint8_t * call(uint8_t * out, uint8_t * fun); -uint8_t * call_r(uint8_t * out, uint8_t dst); -uint8_t * retn(uint8_t * out); -uint8_t * cdq(uint8_t * out); -uint8_t * loop(uint8_t * out, uint8_t * dst); +void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void rol_clr(code_info *code, uint8_t dst, uint8_t size); +void ror_clr(code_info *code, uint8_t dst, uint8_t size); +void rcl_clr(code_info *code, uint8_t dst, uint8_t size); +void rcr_clr(code_info *code, uint8_t dst, uint8_t size); +void shl_clr(code_info *code, uint8_t dst, uint8_t size); +void shr_clr(code_info *code, uint8_t dst, uint8_t size); +void sar_clr(code_info *code, uint8_t dst, uint8_t size); +void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void imul_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void not_r(code_info *code, uint8_t dst, uint8_t size); +void neg_r(code_info *code, uint8_t dst, uint8_t size); +void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void mul_r(code_info *code, uint8_t dst, uint8_t size); +void imul_r(code_info *code, uint8_t dst, uint8_t size); +void div_r(code_info *code, uint8_t dst, uint8_t size); +void idiv_r(code_info *code, uint8_t dst, uint8_t size); +void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); +void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size); +void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size); +void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size); +void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size); +void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size); +void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size); +void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size); +void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size); +void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size); +void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size); +void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size); +void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size); +void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void pushf(code_info *code); +void popf(code_info *code); +void push_r(code_info *code, uint8_t reg); +void push_rdisp(code_info *code, uint8_t base, int32_t disp); +void pop_r(code_info *code, uint8_t reg); +void pop_rind(code_info *code, uint8_t reg); +void setcc_r(code_info *code, uint8_t cc, uint8_t dst); +void setcc_rind(code_info *code, uint8_t cc, uint8_t dst); +void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp); +void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); +void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); +void jcc(code_info *code, uint8_t cc, code_ptr dest); +void jmp_rind(code_info *code, uint8_t dst); +void call_r(code_info *code, uint8_t dst); +void retn(code_info *code); +void cdq(code_info *code); +void loop(code_info *code, code_ptr dst); #endif //GEN_X86_H_ diff -r 103d5cabbe14 -r f822d9216968 gentests.py --- a/gentests.py Tue Dec 16 01:10:54 2014 -0800 +++ b/gentests.py Tue Dec 30 19:11:34 2014 -0800 @@ -178,9 +178,17 @@ self.disp -= (address & 0xFFFFFF) else: self.disp += 0xE00000-(address & 0xFFFFFF) + if self.disp > 127: + self.disp = 127 + elif self.disp < -128: + self.disp = -128 address = base + index + self.disp elif (address & 0xFFFFFF) > 0xFFFFFC: self.disp -= (address & 0xFFFFFF) - 0xFFFFFC + if self.disp > 127: + self.disp = 127 + elif self.disp < -128: + self.disp = -128 address = base + index + self.disp if size != 'b' and address & 1: self.disp = self.disp ^ 1 diff -r 103d5cabbe14 -r f822d9216968 m68k_core.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m68k_core.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,939 @@ +/* + Copyright 2014 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#include "m68k_core.h" +#include "m68k_internal.h" +#include "68kinst.h" +#include "backend.h" +#include "gen.h" +#include +#include +#include +#include + +char disasm_buf[1024]; + +int8_t native_reg(m68k_op_info * op, m68k_options * opts) +{ + if (op->addr_mode == MODE_REG) { + return opts->dregs[op->params.regs.pri]; + } + if (op->addr_mode == MODE_AREG) { + return opts->aregs[op->params.regs.pri]; + } + return -1; +} + +size_t dreg_offset(uint8_t reg) +{ + return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg; +} + +size_t areg_offset(uint8_t reg) +{ + return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg; +} + +//must be called with an m68k_op_info that uses a register +size_t reg_offset(m68k_op_info *op) +{ + return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri); +} + +void print_regs_exit(m68k_context * context) +{ + printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]); + for (int i = 0; i < 8; i++) { + printf("d%d: %X\n", i, context->dregs[i]); + } + for (int i = 0; i < 8; i++) { + printf("a%d: %X\n", i, context->aregs[i]); + } + exit(0); +} + +void m68k_read_size(m68k_options *opts, uint8_t size) +{ + switch (size) + { + case OPSIZE_BYTE: + call(&opts->gen.code, opts->read_8); + break; + case OPSIZE_WORD: + call(&opts->gen.code, opts->read_16); + break; + case OPSIZE_LONG: + call(&opts->gen.code, opts->read_32); + break; + } +} + +void m68k_write_size(m68k_options *opts, uint8_t size) +{ + switch (size) + { + case OPSIZE_BYTE: + call(&opts->gen.code, opts->write_8); + break; + case OPSIZE_WORD: + call(&opts->gen.code, opts->write_16); + break; + case OPSIZE_LONG: + call(&opts->gen.code, opts->write_32_highfirst); + break; + } +} + +void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int8_t dst_reg = inst->op == M68K_PEA ? opts->gen.scratch1 : native_reg(&(inst->dst), opts); + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + cycles(&opts->gen, BUS); + if (dst_reg >= 0) { + areg_to_native(opts, inst->src.params.regs.pri, dst_reg); + } else { + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri); + } else { + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + } + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, 8); + calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1); + if (dst_reg < 0) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, 12); + if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) { + dst_reg = opts->gen.scratch1; + } + calc_areg_index_disp8(opts, &inst->src, dst_reg); + if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_PC_DISPLACE: + cycles(&opts->gen, 8); + if (inst->op == M68K_PEA) { + ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, dst_reg); + } else { + ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri); + } + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, BUS*3); + if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) { + dst_reg = opts->gen.scratch1; + } + ldi_native(opts, inst->address+2, dst_reg); + calc_index_disp8(opts, &inst->src, dst_reg); + if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2); + if (inst->op == M68K_PEA) { + ldi_native(opts, inst->src.params.immed, dst_reg); + } else { + ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri); + } + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); + exit(1); + } + if (inst->op == M68K_PEA) { + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + } +} + +void push_const(m68k_options *opts, int32_t value) +{ + ldi_native(opts, value, opts->gen.scratch1); + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(&opts->gen.code, opts->write_32_highfirst); +} + +void jump_m68k_abs(m68k_options * opts, uint32_t address) +{ + code_info *code = &opts->gen.code; + code_ptr dest_addr = get_native_address(opts->gen.native_code_map, address); + if (!dest_addr) { + opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = code->cur + 256; + } + jmp(code, dest_addr); + //this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed + //since instruction retranslation patches the original native instruction location +} + +void translate_m68k_bsr(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4); + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, 10); + push_const(opts, after); + jump_m68k_abs(opts, inst->address + 2 + disp); +} + +void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst) +{ + uint8_t is_jsr = inst->op == M68K_JSR; + code_info *code = &opts->gen.code; + code_ptr dest_addr; + uint8_t sec_reg; + uint32_t after; + uint32_t m68k_addr; + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + cycles(&opts->gen, BUS*2); + if (is_jsr) { + push_const(opts, inst->address+2); + } + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, BUS*2); + if (is_jsr) { + push_const(opts, inst->address+4); + } + calc_areg_displace(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct + if (is_jsr) { + push_const(opts, inst->address+4); + } + calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_PC_DISPLACE: + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, 10); + if (is_jsr) { + push_const(opts, inst->address+4); + } + jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2); + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct + if (is_jsr) { + push_const(opts, inst->address+4); + } + ldi_native(opts, inst->address+2, opts->gen.scratch1); + calc_index_disp8(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10); + if (is_jsr) { + push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4)); + } + jump_m68k_abs(opts, inst->src.params.immed); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp"); + exit(1); + } +} + +void translate_m68k_unlk(m68k_options * opts, m68kinst * inst) +{ + cycles(&opts->gen, BUS); + areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]); + areg_to_native(opts, 7, opts->gen.scratch1); + call(&opts->gen.code, opts->read_32); + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + addi_areg(opts, 4, 7); +} + +void translate_m68k_link(m68k_options * opts, m68kinst * inst) +{ + //compensate for displacement word + cycles(&opts->gen, BUS); + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + call(&opts->gen.code, opts->write_32_highfirst); + native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri); + addi_areg(opts, inst->dst.params.immed, 7); + //prefetch + cycles(&opts->gen, BUS); +} + +void translate_m68k_rts(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + //TODO: Add cycles + areg_to_native(opts, 7, opts->gen.scratch1); + addi_areg(opts, 4, 7); + call(code, opts->read_32); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); +} + +void translate_m68k_rtr(m68k_options *opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + //Read saved CCR + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_16); + addi_areg(opts, 2, 7); + call(code, opts->set_ccr); + //Read saved PC + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_32); + addi_areg(opts, 4, 7); + //Get native address and jump to it + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); +} + +void translate_m68k_trap(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + ldi_native(opts, inst->src.params.immed + VECTOR_TRAP_0, opts->gen.scratch2); + ldi_native(opts, inst->address+2, opts->gen.scratch1); + jmp(code, opts->trap); +} + +void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst) +{ + cycles(&opts->gen, BUS); + int8_t reg; + if (inst->src.addr_mode == MODE_UNUSED) { + reg = native_reg(&inst->dst, opts); + if (reg < 0) { + reg = opts->gen.scratch1; + } + areg_to_native(opts, 8, reg); + if (reg == opts->gen.scratch1) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + } else { + reg = native_reg(&inst->src, opts); + if (reg < 0) { + reg = opts->gen.scratch1; + areg_to_native(opts, inst->src.params.regs.pri, reg); + } + native_to_areg(opts, reg, 8); + } +} + +void translate_m68k_movem(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int8_t bit,reg,sec_reg; + uint8_t early_cycles; + if(inst->src.addr_mode == MODE_REG) { + //reg to mem + early_cycles = 8; + int8_t dir; + switch (inst->dst.addr_mode) + { + case MODE_AREG_INDIRECT: + case MODE_AREG_PREDEC: + areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); + break; + case MODE_AREG_DISPLACE: + early_cycles += BUS; + calc_areg_displace(opts, &inst->dst, opts->gen.scratch2); + break; + case MODE_AREG_INDEX_DISP8: + early_cycles += 6; + calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2); + break; + case MODE_PC_DISPLACE: + early_cycles += BUS; + ldi_native(opts, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2); + break; + case MODE_PC_INDEX_DISP8: + early_cycles += 6; + ldi_native(opts, inst->address+2, opts->gen.scratch2); + calc_index_disp8(opts, &inst->dst, opts->gen.scratch2); + case MODE_ABSOLUTE: + early_cycles += 4; + case MODE_ABSOLUTE_SHORT: + early_cycles += 4; + ldi_native(opts, inst->dst.params.immed, opts->gen.scratch2); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); + exit(1); + } + if (inst->dst.addr_mode == MODE_AREG_PREDEC) { + reg = 15; + dir = -1; + } else { + reg = 0; + dir = 1; + } + cycles(&opts->gen, early_cycles); + for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) { + if (inst->src.params.immed & (1 << bit)) { + if (inst->dst.addr_mode == MODE_AREG_PREDEC) { + subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2); + } + push_native(opts, opts->gen.scratch2); + if (reg > 7) { + areg_to_native(opts, reg-8, opts->gen.scratch1); + } else { + dreg_to_native(opts, reg, opts->gen.scratch1); + } + if (inst->extra.size == OPSIZE_LONG) { + call(code, opts->write_32_lowfirst); + } else { + call(code, opts->write_16); + } + pop_native(opts, opts->gen.scratch2); + if (inst->dst.addr_mode != MODE_AREG_PREDEC) { + addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2); + } + } + } + if (inst->dst.addr_mode == MODE_AREG_PREDEC) { + native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri); + } + } else { + //mem to reg + early_cycles = 4; + switch (inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + break; + case MODE_AREG_DISPLACE: + early_cycles += BUS; + reg = opts->gen.scratch2; + calc_areg_displace(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_AREG_INDEX_DISP8: + early_cycles += 6; + calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_PC_DISPLACE: + early_cycles += BUS; + ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1); + break; + case MODE_PC_INDEX_DISP8: + early_cycles += 6; + ldi_native(opts, inst->address+2, opts->gen.scratch1); + calc_index_disp8(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_ABSOLUTE: + early_cycles += 4; + case MODE_ABSOLUTE_SHORT: + early_cycles += 4; + ldi_native(opts, inst->src.params.immed, opts->gen.scratch1); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); + exit(1); + } + cycles(&opts->gen, early_cycles); + for(reg = 0; reg < 16; reg ++) { + if (inst->dst.params.immed & (1 << reg)) { + push_native(opts, opts->gen.scratch1); + if (inst->extra.size == OPSIZE_LONG) { + call(code, opts->read_32); + } else { + call(code, opts->read_16); + } + if (inst->extra.size == OPSIZE_WORD) { + sign_extend16_native(opts, opts->gen.scratch1); + } + if (reg > 7) { + native_to_areg(opts, opts->gen.scratch1, reg-8); + } else { + native_to_dreg(opts, opts->gen.scratch1, reg); + } + pop_native(opts, opts->gen.scratch1); + addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1); + } + } + if (inst->src.addr_mode == MODE_AREG_POSTINC) { + native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri); + } + } + //prefetch + cycles(&opts->gen, 4); +} + +void translate_m68k_nop(m68k_options *opts, m68kinst *inst) +{ + cycles(&opts->gen, BUS); +} + +void swap_ssp_usp(m68k_options * opts) +{ + areg_to_native(opts, 7, opts->gen.scratch2); + areg_to_native(opts, 8, opts->aregs[7]); + native_to_areg(opts, opts->gen.scratch2, 8); +} + +code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) +{ + address &= 0xFFFFFF; + address /= 2; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + return NULL; + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { + return NULL; + } + return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; +} + +code_ptr get_native_from_context(m68k_context * context, uint32_t address) +{ + return get_native_address(context->native_code_map, address); +} + +uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) +{ + address &= 0xFFFFFF; + address /= 2; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + return 0; + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { + return 0; + } + while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { + --address; + chunk = address / NATIVE_CHUNK_SIZE; + offset = address % NATIVE_CHUNK_SIZE; + } + return address*2; +} + +void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size) +{ + native_map_slot * native_code_map = context->native_code_map; + m68k_options * opts = context->options; + address &= 0xFFFFFF; + if (address > 0xE00000) { + context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11); + if (((address & 0x3FFF) + size) & 0xC000) { + context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11); + } + uint32_t slot = (address & 0xFFFF)/1024; + if (!opts->gen.ram_inst_sizes[slot]) { + opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512); + } + opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size; + } + address/= 2; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + native_code_map[chunk].base = native_addr; + native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); + memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); + } + uint32_t offset = address % NATIVE_CHUNK_SIZE; + native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; + for(address++,size-=2; size; address++,size-=2) { + chunk = address / NATIVE_CHUNK_SIZE; + offset = address % NATIVE_CHUNK_SIZE; + if (!native_code_map[chunk].base) { + native_code_map[chunk].base = native_addr; + native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); + memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); + } + native_code_map[chunk].offsets[offset] = EXTENSION_WORD; + } +} + +uint8_t get_native_inst_size(m68k_options * opts, uint32_t address) +{ + if (address < 0xE00000) { + return 0; + } + uint32_t slot = (address & 0xFFFF)/1024; + return opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512]; +} + +uint8_t m68k_is_terminal(m68kinst * inst) +{ + return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP + || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET + || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE); +} + +void m68k_handle_deferred(m68k_context * context) +{ + m68k_options * opts = context->options; + process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); + if (opts->gen.deferred) { + translate_m68k_stream(opts->gen.deferred->address, context); + } +} + +typedef enum { + RAW_FUNC = 1, + BINARY_ARITH, + UNARY_ARITH, + OP_FUNC +} impl_type; + +typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst); +typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); + +typedef struct { + union { + raw_fun raw; + uint32_t flag_mask; + op_fun op; + } impl; + impl_type itype; +} impl_info; + +#define RAW_IMPL(inst, fun) [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC } +#define OP_IMPL(inst, fun) [inst] = { .impl = { .op = fun }, .itype = OP_FUNC } +#define UNARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH } +#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH } + +impl_info m68k_impls[] = { + //math + BINARY_IMPL(M68K_ADD, X|N|Z|V|C), + BINARY_IMPL(M68K_SUB, X|N|Z|V|C), + //z flag is special cased for ADDX/SUBX + BINARY_IMPL(M68K_ADDX, X|N|V|C), + BINARY_IMPL(M68K_SUBX, X|N|V|C), + OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd), + OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd), + BINARY_IMPL(M68K_AND, N|Z|V0|C0), + BINARY_IMPL(M68K_EOR, N|Z|V0|C0), + BINARY_IMPL(M68K_OR, N|Z|V0|C0), + RAW_IMPL(M68K_CMP, translate_m68k_cmp), + OP_IMPL(M68K_DIVS, translate_m68k_div), + OP_IMPL(M68K_DIVU, translate_m68k_div), + OP_IMPL(M68K_MULS, translate_m68k_mul), + OP_IMPL(M68K_MULU, translate_m68k_mul), + RAW_IMPL(M68K_EXT, translate_m68k_ext), + UNARY_IMPL(M68K_NEG, X|N|Z|V|C), + OP_IMPL(M68K_NEGX, translate_m68k_negx), + UNARY_IMPL(M68K_NOT, N|Z|V|C), + UNARY_IMPL(M68K_TST, N|Z|V0|C0), + + //shift/rotate + OP_IMPL(M68K_ASL, translate_m68k_sl), + OP_IMPL(M68K_LSL, translate_m68k_sl), + OP_IMPL(M68K_ASR, translate_m68k_asr), + OP_IMPL(M68K_LSR, translate_m68k_lsr), + OP_IMPL(M68K_ROL, translate_m68k_rot), + OP_IMPL(M68K_ROR, translate_m68k_rot), + OP_IMPL(M68K_ROXL, translate_m68k_rot), + OP_IMPL(M68K_ROXR, translate_m68k_rot), + UNARY_IMPL(M68K_SWAP, N|Z|V0|C0), + + //bit + OP_IMPL(M68K_BCHG, translate_m68k_bit), + OP_IMPL(M68K_BCLR, translate_m68k_bit), + OP_IMPL(M68K_BSET, translate_m68k_bit), + OP_IMPL(M68K_BTST, translate_m68k_bit), + + //data movement + RAW_IMPL(M68K_MOVE, translate_m68k_move), + RAW_IMPL(M68K_MOVEM, translate_m68k_movem), + RAW_IMPL(M68K_MOVEP, translate_m68k_movep), + RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp), + RAW_IMPL(M68K_LEA, translate_m68k_lea_pea), + RAW_IMPL(M68K_PEA, translate_m68k_lea_pea), + RAW_IMPL(M68K_CLR, translate_m68k_clr), + OP_IMPL(M68K_EXG, translate_m68k_exg), + RAW_IMPL(M68K_SCC, translate_m68k_scc), + + //function calls and branches + RAW_IMPL(M68K_BCC, translate_m68k_bcc), + RAW_IMPL(M68K_BSR, translate_m68k_bsr), + RAW_IMPL(M68K_DBCC, translate_m68k_dbcc), + RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr), + RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr), + RAW_IMPL(M68K_RTS, translate_m68k_rts), + RAW_IMPL(M68K_RTE, translate_m68k_rte), + RAW_IMPL(M68K_RTR, translate_m68k_rtr), + RAW_IMPL(M68K_LINK, translate_m68k_link), + RAW_IMPL(M68K_UNLK, translate_m68k_unlk), + + //SR/CCR stuff + RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ori_ccr_sr), + RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ori_ccr_sr), + RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr), + RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr), + RAW_IMPL(M68K_ORI_CCR, translate_m68k_andi_ori_ccr_sr), + RAW_IMPL(M68K_ORI_SR, translate_m68k_andi_ori_ccr_sr), + OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr), + OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr), + OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr), + RAW_IMPL(M68K_STOP, translate_m68k_stop), + + //traps + OP_IMPL(M68K_CHK, translate_m68k_chk), + RAW_IMPL(M68K_TRAP, translate_m68k_trap), + RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal), + RAW_IMPL(M68K_INVALID, translate_m68k_invalid), + + //misc + RAW_IMPL(M68K_NOP, translate_m68k_nop), + RAW_IMPL(M68K_RESET, translate_m68k_reset), + + //currently unimplemented + //M68K_NBCD + //M68K_TAS + //M68K_TRAPV +}; + +void translate_m68k(m68k_options * opts, m68kinst * inst) +{ + check_cycles_int(&opts->gen, inst->address); + impl_info * info = m68k_impls + inst->op; + if (info->itype == RAW_FUNC) { + info->impl.raw(opts, inst); + return; + } + + host_ea src_op, dst_op; + if (inst->src.addr_mode != MODE_UNUSED) { + translate_m68k_op(inst, &src_op, opts, 0); + } + if (inst->dst.addr_mode != MODE_UNUSED) { + translate_m68k_op(inst, &dst_op, opts, 1); + } + if (info->itype == OP_FUNC) { + info->impl.op(opts, inst, &src_op, &dst_op); + } else if (info->itype == BINARY_ARITH) { + translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op); + } else if (info->itype == UNARY_ARITH) { + translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op); + } else { + m68k_disasm(inst, disasm_buf); + printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); + exit(1); + } +} + +void translate_m68k_stream(uint32_t address, m68k_context * context) +{ + m68kinst instbuf; + m68k_options * opts = context->options; + code_info *code = &opts->gen.code; + address &= 0xFFFFFF; + if(get_native_address(opts->gen.native_code_map, address)) { + return; + } + char disbuf[1024]; + uint16_t *encoded, *next; + if ((address & 0xFFFFFF) < 0x400000) { + encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; + } else if ((address & 0xFFFFFF) > 0xE00000) { + encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; + } else { + printf("attempt to translate non-memory address: %X\n", address); + exit(1); + } + do { + if (opts->address_log) { + fprintf(opts->address_log, "%X\n", address); + } + do { + if (address >= 0x400000 && address < 0xE00000) { + translate_out_of_bounds(code); + break; + } + code_ptr existing = get_native_address(opts->gen.native_code_map, address); + if (existing) { + jmp(code, existing); + break; + } + next = m68k_decode(encoded, &instbuf, address); + if (instbuf.op == M68K_INVALID) { + instbuf.src.params.immed = *encoded; + } + uint16_t m68k_size = (next-encoded)*2; + address += m68k_size; + encoded = next; + //m68k_disasm(&instbuf, disbuf); + //printf("%X: %s\n", instbuf.address, disbuf); + + //make sure the beginning of the code for an instruction is contiguous + check_code_prologue(code); + code_ptr start = code->cur; + translate_m68k(opts, &instbuf); + code_ptr after = code->cur; + map_native_address(context, instbuf.address, start, m68k_size, after-start); + } while(!m68k_is_terminal(&instbuf)); + process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); + if (opts->gen.deferred) { + address = opts->gen.deferred->address; + if ((address & 0xFFFFFF) < 0x400000) { + encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; + } else if ((address & 0xFFFFFF) > 0xE00000) { + encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; + } else { + printf("attempt to translate non-memory address: %X\n", address); + exit(1); + } + } else { + encoded = NULL; + } + } while(encoded != NULL); +} + +void * m68k_retranslate_inst(uint32_t address, m68k_context * context) +{ + m68k_options * opts = context->options; + code_info *code = &opts->gen.code; + uint8_t orig_size = get_native_inst_size(opts, address); + code_ptr orig_start = get_native_address(context->native_code_map, address); + uint32_t orig = address; + code_info orig_code; + orig_code.cur = orig_start; + orig_code.last = orig_start + orig_size + 5; + address &= 0xFFFF; + uint16_t *after, *inst = context->mem_pointers[1] + address/2; + m68kinst instbuf; + after = m68k_decode(inst, &instbuf, orig); + if (orig_size != MAX_NATIVE_SIZE) { + deferred_addr * orig_deferred = opts->gen.deferred; + + //make sure the beginning of the code for an instruction is contiguous + check_code_prologue(code); + code_ptr native_start = code->cur; + translate_m68k(opts, &instbuf); + code_ptr native_end = code->cur; + uint8_t is_terminal = m68k_is_terminal(&instbuf); + if ((native_end - native_start) <= orig_size) { + code_ptr native_next; + if (!is_terminal) { + native_next = get_native_address(context->native_code_map, orig + (after-inst)*2); + } + if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) { + remove_deferred_until(&opts->gen.deferred, orig_deferred); + code_info tmp; + tmp.cur = code->cur; + tmp.last = code->last; + code->cur = orig_code.cur; + code->last = orig_code.last; + translate_m68k(opts, &instbuf); + native_end = orig_code.cur = code->cur; + code->cur = tmp.cur; + code->last = tmp.last; + if (!is_terminal) { + nop_fill_or_jmp_next(&orig_code, orig_start + orig_size, native_next); + } + m68k_handle_deferred(context); + return orig_start; + } + } + + map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE); + + jmp(&orig_code, native_start); + if (!m68k_is_terminal(&instbuf)) { + code_ptr native_end = code->cur; + code->cur = native_start + MAX_NATIVE_SIZE; + code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2); + code_ptr tmp = code->cur; + code->cur = native_end; + jmp(code, rest); + code->cur = tmp; + } else { + code->cur = native_start + MAX_NATIVE_SIZE; + } + m68k_handle_deferred(context); + return native_start; + } else { + code_info tmp; + tmp.cur = code->cur; + tmp.last = code->last; + code->cur = orig_code.cur; + code->last = orig_code.last; + translate_m68k(opts, &instbuf); + if (!m68k_is_terminal(&instbuf)) { + jmp(code, get_native_address_trans(context, orig + (after-inst)*2)); + } + code->cur = tmp.cur; + code->last = tmp.last; + m68k_handle_deferred(context); + return orig_start; + } +} + +code_ptr get_native_address_trans(m68k_context * context, uint32_t address) +{ + address &= 0xFFFFFF; + code_ptr ret = get_native_address(context->native_code_map, address); + if (!ret) { + translate_m68k_stream(address, context); + ret = get_native_address(context->native_code_map, address); + } + return ret; +} + +void remove_breakpoint(m68k_context * context, uint32_t address) +{ + code_ptr native = get_native_address(context->native_code_map, address); + check_cycles_int(context->options, address); +} + +void start_68k_context(m68k_context * context, uint32_t address) +{ + code_ptr addr = get_native_address_trans(context, address); + m68k_options * options = context->options; + options->start_context(addr, context); +} + +void m68k_reset(m68k_context * context) +{ + //TODO: Make this actually use the normal read functions + context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1]; + uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3]; + start_68k_context(context, address); +} + + +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) +{ + memset(context, 0, sizeof(m68k_context)); + context->native_code_map = native_code_map; + context->options = opts; + context->int_cycle = 0xFFFFFFFF; + context->status = 0x27; +} diff -r 103d5cabbe14 -r f822d9216968 m68k_core.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m68k_core.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,79 @@ +/* + Copyright 2013 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#ifndef M68K_CORE_H_ +#define M68K_CORE_H_ +#include +#include +#include "backend.h" +//#include "68kinst.h" +struct m68kinst; + +#define NUM_MEM_AREAS 4 +#define NATIVE_MAP_CHUNKS (64*1024) +#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2) +#define MAX_NATIVE_SIZE 255 + +typedef void (*start_fun)(uint8_t * addr, void * context); + +typedef struct { + cpu_options gen; + + int8_t dregs[8]; + int8_t aregs[8]; + int8_t flag_regs[5]; + FILE *address_log; + code_ptr read_16; + code_ptr write_16; + code_ptr read_8; + code_ptr write_8; + code_ptr read_32; + code_ptr write_32_lowfirst; + code_ptr write_32_highfirst; + code_ptr do_sync; + code_ptr trap; + start_fun start_context; + code_ptr retrans_stub; + code_ptr native_addr; + code_ptr native_addr_and_sync; + code_ptr get_sr; + code_ptr set_sr; + code_ptr set_ccr; +} m68k_options; + +typedef struct { + uint8_t flags[5]; + uint8_t status; + uint16_t int_ack; + uint32_t dregs[8]; + uint32_t aregs[9]; + uint32_t target_cycle; //cycle at which the next synchronization or interrupt occurs + uint32_t current_cycle; + uint32_t sync_cycle; + uint32_t int_cycle; + uint32_t int_num; + uint16_t *mem_pointers[NUM_MEM_AREAS]; + void *video_context; + uint16_t reserved; + + native_map_slot *native_code_map; + void *options; + uint8_t ram_code_flags[32/8]; + void *system; +} m68k_context; + +void translate_m68k(m68k_options * opts, struct m68kinst * inst); +void translate_m68k_stream(uint32_t address, m68k_context * context); +void start_68k_context(m68k_context * context, uint32_t address); +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks); +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); +void m68k_reset(m68k_context * context); +void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); +void remove_breakpoint(m68k_context * context, uint32_t address); +m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context); +uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address); + +#endif //M68K_CORE_H_ + diff -r 103d5cabbe14 -r f822d9216968 m68k_core_x86.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m68k_core_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,2652 @@ +/* + Copyright 2013 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#include "gen_x86.h" +#include "m68k_core.h" +#include "m68k_internal.h" +#include "68kinst.h" +#include "mem.h" +#include "backend.h" +#include +#include +#include +#include + +#define CYCLES RAX +#define LIMIT RBP +#define CONTEXT RSI +#define SCRATCH1 RCX + +#ifdef X86_64 +#define SCRATCH2 RDI +#else +#define SCRATCH2 RBX +#endif + +enum { + FLAG_X, + FLAG_N, + FLAG_Z, + FLAG_V, + FLAG_C +}; + +void set_flag(m68k_options * opts, uint8_t val, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B); + } else { + mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B); + } + } +} + +void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset); + } else { + setcc_rind(&opts->gen.code, cond, opts->gen.context_reg); + } + } +} + +void check_flag(m68k_options *opts, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B); + } else { + cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); + } +} + +void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) +{ + if (opts->flag_regs[flag] >= 0) { + mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B); + } else { + mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B); + } + } +} + +void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B); + } else { + mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B); + } + } +} + +void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2) +{ + code_info *code = &opts->gen.code; + if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) { + mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B); + } else if(opts->flag_regs[flag1] >= 0) { + mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); + } else if (opts->flag_regs[flag2] >= 0) { + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B); + } else { + push_r(code, opts->gen.scratch1); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); + pop_r(code, opts->gen.scratch1); + } +} + +void update_flags(m68k_options *opts, uint32_t update_mask) +{ + uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C}; + for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag) + { + if (update_mask & X0 << (flag*3)) { + set_flag(opts, 0, flag); + } else if(update_mask & X1 << (flag*3)) { + set_flag(opts, 1, flag); + } else if(update_mask & X << (flag*3)) { + if (flag == FLAG_X) { + if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) { + flag_to_flag(opts, FLAG_C, FLAG_X); + } else if(update_mask & C0) { + set_flag(opts, 0, flag); + } else if(update_mask & C1) { + set_flag(opts, 1, flag); + } else { + set_flag_cond(opts, CC_C, flag); + } + } else { + set_flag_cond(opts, native_flags[flag], flag); + } + } + } +} + +void flag_to_carry(m68k_options * opts, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B); + } else { + bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); + } +} + +void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) +{ + if (opts->flag_regs[flag] >= 0) { + or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); + } else { + or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B); + } +} + +void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg) +{ + if (opts->flag_regs[flag] >= 0) { + xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B); + } else { + xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B); + } +} + +void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag) +{ + if (opts->flag_regs[flag] >= 0) { + xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B); + } else { + xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B); + } +} + +void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2) +{ + code_info *code = &opts->gen.code; + if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) { + cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B); + } else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) { + if (opts->flag_regs[flag2] >= 0) { + uint8_t tmp = flag1; + flag1 = flag2; + flag2 = tmp; + } + cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); + } else { + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B); + cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B); + } +} + +void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->aregs[reg] >= 0) { + mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D); + } else { + mov_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D); + } +} + +void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->dregs[reg] >= 0) { + mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D); + } else { + mov_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D); + } +} + +void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->aregs[reg] >= 0) { + movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D); + } else { + movsx_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_W, SZ_D); + } +} + +void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->dregs[reg] >= 0) { + movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D); + } else { + movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D); + } +} + +void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg) +{ + if (opts->aregs[reg] >= 0) { + mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D); + } else { + mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D); + } +} + +void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg) +{ + if (opts->dregs[reg] >= 0) { + mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D); + } else { + mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D); + } +} + +void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg) +{ + if (opts->aregs[reg] >= 0) { + mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D); + } else { + mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D); + } +} + +void ldi_native(m68k_options *opts, int32_t value, uint8_t reg) +{ + mov_ir(&opts->gen.code, value, reg, SZ_D); +} + +void addi_native(m68k_options *opts, int32_t value, uint8_t reg) +{ + add_ir(&opts->gen.code, value, reg, SZ_D); +} + +void subi_native(m68k_options *opts, int32_t value, uint8_t reg) +{ + sub_ir(&opts->gen.code, value, reg, SZ_D); +} + +void push_native(m68k_options *opts, uint8_t reg) +{ + push_r(&opts->gen.code, reg); +} + +void pop_native(m68k_options *opts, uint8_t reg) +{ + pop_r(&opts->gen.code, reg); +} + +void sign_extend16_native(m68k_options *opts, uint8_t reg) +{ + movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D); +} + +void addi_areg(m68k_options *opts, int32_t val, uint8_t reg) +{ + if (opts->aregs[reg] >= 0) { + add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); + } else { + add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); + } +} + +void subi_areg(m68k_options *opts, int32_t val, uint8_t reg) +{ + if (opts->aregs[reg] >= 0) { + sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); + } else { + sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); + } +} + +void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->aregs[reg] >= 0) { + add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D); + } else { + add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D); + } +} + +void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->dregs[reg] >= 0) { + add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D); + } else { + add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D); + } +} + +void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) +{ + areg_to_native(opts, op->params.regs.pri, native_reg); + add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D); +} + +void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) +{ + uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7; + if (op->params.regs.sec & 1) { + if (op->params.regs.sec & 0x10) { + add_areg_native(opts, sec_reg, native_reg); + } else { + add_dreg_native(opts, sec_reg, native_reg); + } + } else { + uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1; + if (op->params.regs.sec & 0x10) { + areg_to_native_sx(opts, sec_reg, other_reg); + } else { + dreg_to_native_sx(opts, sec_reg, other_reg); + } + add_rr(&opts->gen.code, other_reg, native_reg, SZ_D); + } + if (op->params.regs.displacement) { + add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D); + } +} + +void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) +{ + areg_to_native(opts, op->params.regs.pri, native_reg); + calc_index_disp8(opts, op, native_reg); +} + +void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst) +{ + code_info *code = &opts->gen.code; + m68k_op_info *op = dst ? &inst->dst : &inst->src; + int8_t reg = native_reg(op, opts); + uint8_t sec_reg; + int32_t dec_amount,inc_amount; + if (reg >= 0) { + ea->mode = MODE_REG_DIRECT; + if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { + movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D); + ea->base = opts->gen.scratch1; + } else { + ea->base = reg; + } + return; + } + switch (op->addr_mode) + { + case MODE_REG: + case MODE_AREG: + //We only get one memory parameter, so if the dst operand is a register in memory, + //we need to copy this to a temp register first if we're translating the src operand + if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) + || inst->op == M68K_EXG) { + + ea->mode = MODE_REG_DISPLACE8; + ea->base = opts->gen.context_reg; + ea->disp = reg_offset(op); + } else { + if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { + movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D); + } else { + mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size); + } + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + //we're explicitly handling the areg dest here, so we exit immediately + return; + } + break; + case MODE_AREG_PREDEC: + if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) { + push_r(code, opts->gen.scratch1); + } + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1)); + if (!dst) { + cycles(&opts->gen, PREDEC_PENALTY); + } + subi_areg(opts, dec_amount, op->params.regs.pri); + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1); + m68k_read_size(opts, inst->extra.size); + + if (dst) { + if (inst->src.addr_mode == MODE_AREG_PREDEC) { + //restore src operand to opts->gen.scratch2 + pop_r(code, opts->gen.scratch2); + } else { + //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later + areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2); + } + } + + if (op->addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1)); + addi_areg(opts, inc_amount, op->params.regs.pri); + } + ea->mode = MODE_REG_DIRECT; + ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1; + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, BUS); + calc_areg_displace(opts, op, opts->gen.scratch1); + if (dst) { + push_r(code, opts->gen.scratch1); + } + m68k_read_size(opts, inst->extra.size); + if (dst) { + pop_r(code, opts->gen.scratch2); + } + + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, 6); + calc_areg_index_disp8(opts, op, opts->gen.scratch1); + if (dst) { + push_r(code, opts->gen.scratch1); + } + m68k_read_size(opts, inst->extra.size); + if (dst) { + pop_r(code, opts->gen.scratch2); + } + + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + break; + case MODE_PC_DISPLACE: + cycles(&opts->gen, BUS); + mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D); + if (dst) { + push_r(code, opts->gen.scratch1); + } + m68k_read_size(opts, inst->extra.size); + if (dst) { + pop_r(code, opts->gen.scratch2); + } + + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, 6); + mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); + calc_index_disp8(opts, op, opts->gen.scratch1); + if (dst) { + push_r(code, opts->gen.scratch1); + } + m68k_read_size(opts, inst->extra.size); + if (dst) { + pop_r(code, opts->gen.scratch2); + } + + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS); + mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D); + if (dst) { + push_r(code, opts->gen.scratch1); + } + m68k_read_size(opts, inst->extra.size); + if (dst) { + pop_r(code, opts->gen.scratch2); + } + + ea->mode = MODE_REG_DIRECT; + ea->base = opts->gen.scratch1; + break; + case MODE_IMMEDIATE: + case MODE_IMMEDIATE_WORD: + if (inst->variant != VAR_QUICK) { + cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS); + } + ea->mode = MODE_IMMED; + ea->disp = op->params.immed; + //sign extend value when the destination is an address register + if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) { + ea->disp |= 0xFFFF0000; + } + return; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src"); + exit(1); + } + if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { + if (ea->mode == MODE_REG_DIRECT) { + movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D); + } else { + movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D); + ea->mode = MODE_REG_DIRECT; + } + ea->base = opts->gen.scratch1; + } +} + +void m68k_save_result(m68kinst * inst, m68k_options * opts) +{ + code_info *code = &opts->gen.code; + if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) { + if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { + areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + call(code, opts->write_8); + break; + case OPSIZE_WORD: + call(code, opts->write_16); + break; + case OPSIZE_LONG: + call(code, opts->write_32_lowfirst); + break; + } + } +} + +void translate_m68k_move(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int8_t reg, flags_reg, sec_reg; + uint8_t dir = 0; + int32_t offset; + int32_t inc_amount, dec_amount; + host_ea src; + translate_m68k_op(inst, &src, opts, 0); + reg = native_reg(&(inst->dst), opts); + + if (inst->dst.addr_mode != MODE_AREG) { + if (src.mode == MODE_REG_DIRECT) { + flags_reg = src.base; + } else { + if (reg >= 0) { + flags_reg = reg; + } else { + if(src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + src.mode = MODE_REG_DIRECT; + flags_reg = src.base = opts->gen.scratch1; + } + } + } + uint8_t size = inst->extra.size; + switch(inst->dst.addr_mode) + { + case MODE_AREG: + size = OPSIZE_LONG; + case MODE_REG: + if (reg >= 0) { + if (src.mode == MODE_REG_DIRECT) { + mov_rr(code, src.base, reg, size); + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, reg, size); + } else { + mov_ir(code, src.disp, reg, size); + } + } else if(src.mode == MODE_REG_DIRECT) { + mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size); + } else { + mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size); + } + break; + case MODE_AREG_PREDEC: + dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); + case MODE_AREG_INDIRECT: + case MODE_AREG_POSTINC: + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + if (inst->dst.addr_mode == MODE_AREG_PREDEC) { + subi_areg(opts, dec_amount, inst->dst.params.regs.pri); + } + areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, BUS); + calc_areg_displace(opts, &inst->dst, opts->gen.scratch2); + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, 6);//TODO: Check to make sure this is correct + //calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used + if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { + push_r(code, opts->gen.scratch1); + } + calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2); + if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { + pop_r(code, opts->gen.scratch1); + } + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + break; + case MODE_PC_DISPLACE: + cycles(&opts->gen, BUS); + mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D); + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, 6);//TODO: Check to make sure this is correct + mov_ir(code, inst->address, opts->gen.scratch2, SZ_D); + if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { + push_r(code, opts->gen.scratch1); + } + calc_index_disp8(opts, &inst->dst, opts->gen.scratch2); + if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { + pop_r(code, opts->gen.scratch1); + } + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + if (src.mode == MODE_REG_DIRECT) { + if (src.base != opts->gen.scratch1) { + mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size); + } else { + mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); + } + if (inst->dst.addr_mode == MODE_ABSOLUTE) { + cycles(&opts->gen, BUS*2); + } else { + cycles(&opts->gen, BUS); + } + mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); + exit(1); + } + + if (inst->dst.addr_mode != MODE_AREG) { + cmp_ir(code, 0, flags_reg, inst->extra.size); + update_flags(opts, N|Z|V0|C0); + } + if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { + m68k_write_size(opts, inst->extra.size); + if (inst->dst.addr_mode == MODE_AREG_POSTINC) { + inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); + addi_areg(opts, inc_amount, inst->dst.params.regs.pri); + } + } + + //add cycles for prefetch + cycles(&opts->gen, BUS); +} + +void translate_m68k_clr(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + update_flags(opts, N0|V0|C0|Z1); + int8_t reg = native_reg(&(inst->dst), opts); + if (reg >= 0) { + cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); + xor_rr(code, reg, reg, inst->extra.size); + return; + } + host_ea dst_op; + //TODO: fix timing + translate_m68k_op(inst, &dst_op, opts, 1); + if (dst_op.mode == MODE_REG_DIRECT) { + xor_rr(code, dst_op.base, dst_op.base, inst->extra.size); + } else { + mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_ext(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + host_ea dst_op; + uint8_t dst_size = inst->extra.size; + inst->extra.size--; + translate_m68k_op(inst, &dst_op, opts, 1); + if (dst_op.mode == MODE_REG_DIRECT) { + movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size); + cmp_ir(code, 0, dst_op.base, dst_size); + } else { + movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size); + cmp_ir(code, 0, opts->gen.scratch1, dst_size); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size); + } + inst->extra.size = dst_size; + update_flags(opts, N|V0|C0|Z); + //M68K EXT only operates on registers so no need for a call to save result here +} + +uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc) +{ + uint8_t cond = CC_NZ; + switch (cc) + { + case COND_HIGH: + cond = CC_Z; + case COND_LOW_SAME: + flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); + or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1); + break; + case COND_CARRY_CLR: + cond = CC_Z; + case COND_CARRY_SET: + check_flag(opts, FLAG_C); + break; + case COND_NOT_EQ: + cond = CC_Z; + case COND_EQ: + check_flag(opts, FLAG_Z); + break; + case COND_OVERF_CLR: + cond = CC_Z; + case COND_OVERF_SET: + check_flag(opts, FLAG_V); + break; + case COND_PLUS: + cond = CC_Z; + case COND_MINUS: + check_flag(opts, FLAG_N); + break; + case COND_GREATER_EQ: + cond = CC_Z; + case COND_LESS: + cmp_flags(opts, FLAG_N, FLAG_V); + break; + case COND_GREATER: + cond = CC_Z; + case COND_LESS_EQ: + flag_to_reg(opts, FLAG_V, opts->gen.scratch1); + xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1); + or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); + break; + } + return cond; +} + +void translate_m68k_bcc(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 10);//TODO: Adjust this for branch not taken case + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + 2; + if (inst->extra.cond == COND_TRUE) { + jump_m68k_abs(opts, after + disp); + } else { + code_ptr dest_addr = get_native_address(opts->gen.native_code_map, after + disp); + uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); + if (!dest_addr) { + opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 2); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = code->cur + 256; + } + jcc(code, cond, dest_addr); + } +} + +void translate_m68k_scc(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + uint8_t cond = inst->extra.cond; + host_ea dst_op; + inst->extra.size = OPSIZE_BYTE; + translate_m68k_op(inst, &dst_op, opts, 1); + if (cond == COND_TRUE || cond == COND_FALSE) { + if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { + cycles(&opts->gen, 6); + } else { + cycles(&opts->gen, BUS); + } + if (dst_op.mode == MODE_REG_DIRECT) { + mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B); + } else { + mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B); + } + } else { + uint8_t cc = m68k_eval_cond(opts, cond); + check_alloc_code(code, 6*MAX_INST_LEN); + code_ptr true_off = code->cur + 1; + jcc(code, cc, code->cur+2); + cycles(&opts->gen, BUS); + if (dst_op.mode == MODE_REG_DIRECT) { + mov_ir(code, 0, dst_op.base, SZ_B); + } else { + mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } + code_ptr end_off = code->cur+1; + jmp(code, code->cur+2); + *true_off = code->cur - (true_off+1); + cycles(&opts->gen, 6); + if (dst_op.mode == MODE_REG_DIRECT) { + mov_ir(code, 0xFF, dst_op.base, SZ_B); + } else { + mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B); + } + *end_off = code->cur - (end_off+1); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + //best case duration + cycles(&opts->gen, 10); + code_ptr skip_loc = NULL; + //TODO: Check if COND_TRUE technically valid here even though + //it's basically a slow NOP + if (inst->extra.cond != COND_FALSE) { + uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); + check_alloc_code(code, 6*MAX_INST_LEN); + skip_loc = code->cur + 1; + jcc(code, cond, code->cur + 2); + } + if (opts->dregs[inst->dst.params.regs.pri] >= 0) { + sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W); + cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); + cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); + } + code_ptr loop_end_loc = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + uint32_t after = inst->address + 2; + jump_m68k_abs(opts, after + inst->src.params.immed); + *loop_end_loc = code->cur - (loop_end_loc+1); + if (skip_loc) { + cycles(&opts->gen, 2); + *skip_loc = code->cur - (skip_loc+1); + cycles(&opts->gen, 2); + } else { + cycles(&opts->gen, 4); + } +} + +void translate_m68k_movep(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int8_t reg; + cycles(&opts->gen, BUS*2); + if (inst->src.addr_mode == MODE_REG) { + calc_areg_displace(opts, &inst->dst, opts->gen.scratch2); + reg = native_reg(&(inst->src), opts); + if (inst->extra.size == OPSIZE_LONG) { + if (reg >= 0) { + mov_rr(code, reg, opts->gen.scratch1, SZ_D); + shr_ir(code, 24, opts->gen.scratch1, SZ_D); + push_r(code, opts->gen.scratch2); + call(code, opts->write_8); + pop_r(code, opts->gen.scratch2); + mov_rr(code, reg, opts->gen.scratch1, SZ_D); + shr_ir(code, 16, opts->gen.scratch1, SZ_D); + + } else { + mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B); + push_r(code, opts->gen.scratch2); + call(code, opts->write_8); + pop_r(code, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B); + } + add_ir(code, 2, opts->gen.scratch2, SZ_D); + push_r(code, opts->gen.scratch2); + call(code, opts->write_8); + pop_r(code, opts->gen.scratch2); + add_ir(code, 2, opts->gen.scratch2, SZ_D); + } + if (reg >= 0) { + mov_rr(code, reg, opts->gen.scratch1, SZ_W); + shr_ir(code, 8, opts->gen.scratch1, SZ_W); + push_r(code, opts->gen.scratch2); + call(code, opts->write_8); + pop_r(code, opts->gen.scratch2); + mov_rr(code, reg, opts->gen.scratch1, SZ_W); + } else { + mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B); + push_r(code, opts->gen.scratch2); + call(code, opts->write_8); + pop_r(code, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B); + } + add_ir(code, 2, opts->gen.scratch2, SZ_D); + call(code, opts->write_8); + } else { + calc_areg_displace(opts, &inst->src, opts->gen.scratch1); + reg = native_reg(&(inst->dst), opts); + if (inst->extra.size == OPSIZE_LONG) { + if (reg >= 0) { + push_r(code, opts->gen.scratch1); + call(code, opts->read_8); + shl_ir(code, 24, opts->gen.scratch1, SZ_D); + mov_rr(code, opts->gen.scratch1, reg, SZ_D); + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + push_r(code, opts->gen.scratch1); + call(code, opts->read_8); + shl_ir(code, 16, opts->gen.scratch1, SZ_D); + or_rr(code, opts->gen.scratch1, reg, SZ_D); + } else { + push_r(code, opts->gen.scratch1); + call(code, opts->read_8); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B); + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + push_r(code, opts->gen.scratch1); + call(code, opts->read_8); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B); + } + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + } + push_r(code, opts->gen.scratch1); + call(code, opts->read_8); + if (reg >= 0) { + + shl_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->gen.scratch1, reg, SZ_W); + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + call(code, opts->read_8); + mov_rr(code, opts->gen.scratch1, reg, SZ_B); + } else { + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B); + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + call(code, opts->read_8); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B); + } + } +} + +typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size); +typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size); +typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size); +typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size); + +void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp) +{ + code_info *code = &opts->gen.code; + code_ptr end_off = NULL; + code_ptr nz_off = NULL; + code_ptr z_off = NULL; + if (inst->src.addr_mode == MODE_UNUSED) { + cycles(&opts->gen, BUS); + //Memory shift + shift_ir(code, 1, dst_op->base, SZ_W); + } else { + cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6); + if (src_op->mode == MODE_IMMED) { + if (src_op->disp != 1 && inst->op == M68K_ASL) { + set_flag(opts, 0, FLAG_V); + for (int i = 0; i < src_op->disp; i++) { + if (dst_op->mode == MODE_REG_DIRECT) { + shift_ir(code, 1, dst_op->base, inst->extra.size); + } else { + shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + check_alloc_code(code, 2*MAX_INST_LEN); + code_ptr after_flag_set = code->cur + 1; + jcc(code, CC_NO, code->cur + 2); + set_flag(opts, 1, FLAG_V); + *after_flag_set = code->cur - (after_flag_set+1); + } + } else { + if (dst_op->mode == MODE_REG_DIRECT) { + shift_ir(code, src_op->disp, dst_op->base, inst->extra.size); + } else { + shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + set_flag_cond(opts, CC_O, FLAG_V); + } + } else { + if (src_op->base != RCX) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, RCX, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B); + } + + } + and_ir(code, 63, RCX, SZ_D); + check_alloc_code(code, 7*MAX_INST_LEN); + nz_off = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + //Flag behavior for shift count of 0 is different for x86 than 68K + if (dst_op->mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op->base, inst->extra.size); + } else { + cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + set_flag_cond(opts, CC_Z, FLAG_Z); + set_flag_cond(opts, CC_S, FLAG_N); + set_flag(opts, 0, FLAG_C); + //For other instructions, this flag will be set below + if (inst->op == M68K_ASL) { + set_flag(opts, 0, FLAG_V); + } + z_off = code->cur + 1; + jmp(code, code->cur + 2); + *nz_off = code->cur - (nz_off + 1); + //add 2 cycles for every bit shifted + add_rr(code, RCX, CYCLES, SZ_D); + add_rr(code, RCX, CYCLES, SZ_D); + if (inst->op == M68K_ASL) { + //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB + //Easiest way to deal with this is to shift one bit at a time + set_flag(opts, 0, FLAG_V); + check_alloc_code(code, 5*MAX_INST_LEN); + code_ptr loop_start = code->cur; + if (dst_op->mode == MODE_REG_DIRECT) { + shift_ir(code, 1, dst_op->base, inst->extra.size); + } else { + shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + code_ptr after_flag_set = code->cur + 1; + jcc(code, CC_NO, code->cur + 2); + set_flag(opts, 1, FLAG_V); + *after_flag_set = code->cur - (after_flag_set+1); + loop(code, loop_start); + } else { + //x86 shifts modulo 32 for operand sizes less than 64-bits + //but M68K shifts modulo 64, so we need to check for large shifts here + cmp_ir(code, 32, RCX, SZ_B); + check_alloc_code(code, 14*MAX_INST_LEN); + code_ptr norm_shift_off = code->cur + 1; + jcc(code, CC_L, code->cur + 2); + if (special) { + code_ptr after_flag_set = NULL; + if (inst->extra.size == OPSIZE_LONG) { + code_ptr neq_32_off = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + + //set the carry bit to the lsb + if (dst_op->mode == MODE_REG_DIRECT) { + special(code, 1, dst_op->base, SZ_D); + } else { + special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D); + } + set_flag_cond(opts, CC_C, FLAG_C); + after_flag_set = code->cur + 1; + jmp(code, code->cur + 2); + *neq_32_off = code->cur - (neq_32_off+1); + } + set_flag(opts, 0, FLAG_C); + if (after_flag_set) { + *after_flag_set = code->cur - (after_flag_set+1); + } + set_flag(opts, 1, FLAG_Z); + set_flag(opts, 0, FLAG_N); + if (dst_op->mode == MODE_REG_DIRECT) { + xor_rr(code, dst_op->base, dst_op->base, inst->extra.size); + } else { + mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + } else { + if (dst_op->mode == MODE_REG_DIRECT) { + shift_ir(code, 31, dst_op->base, inst->extra.size); + shift_ir(code, 1, dst_op->base, inst->extra.size); + } else { + shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size); + shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + + } + end_off = code->cur + 1; + jmp(code, code->cur + 2); + *norm_shift_off = code->cur - (norm_shift_off+1); + if (dst_op->mode == MODE_REG_DIRECT) { + shift_clr(code, dst_op->base, inst->extra.size); + } else { + shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size); + } + } + } + + } + if (!special && end_off) { + *end_off = code->cur - (end_off + 1); + } + update_flags(opts, C|Z|N); + if (special && end_off) { + *end_off = code->cur - (end_off + 1); + } + //set X flag to same as C flag + if (opts->flag_regs[FLAG_C] >= 0) { + flag_to_flag(opts, FLAG_C, FLAG_X); + } else { + set_flag_cond(opts, CC_C, FLAG_X); + } + if (z_off) { + *z_off = code->cur - (z_off + 1); + } + if (inst->op != M68K_ASL) { + set_flag(opts, 0, FLAG_V); + } + if (inst->src.addr_mode == MODE_UNUSED) { + m68k_save_result(inst, opts); + } +} + +void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size) +{ + switch (inst->op) + { + case M68K_ADD: add_ir(code, val, dst, size); break; + case M68K_ADDX: adc_ir(code, val, dst, size); break; + case M68K_AND: and_ir(code, val, dst, size); break; + case M68K_BTST: bt_ir(code, val, dst, size); break; + case M68K_BSET: bts_ir(code, val, dst, size); break; + case M68K_BCLR: btr_ir(code, val, dst, size); break; + case M68K_BCHG: btc_ir(code, val, dst, size); break; + case M68K_CMP: cmp_ir(code, val, dst, size); break; + case M68K_EOR: xor_ir(code, val, dst, size); break; + case M68K_OR: or_ir(code, val, dst, size); break; + case M68K_ROL: rol_ir(code, val, dst, size); break; + case M68K_ROR: ror_ir(code, val, dst, size); break; + case M68K_ROXL: rcl_ir(code, val, dst, size); break; + case M68K_ROXR: rcr_ir(code, val, dst, size); break; + case M68K_SUB: sub_ir(code, val, dst, size); break; + case M68K_SUBX: sbb_ir(code, val, dst, size); break; + } +} + +void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size) +{ + switch (inst->op) + { + case M68K_ADD: add_irdisp(code, val, dst, disp, size); break; + case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break; + case M68K_AND: and_irdisp(code, val, dst, disp, size); break; + case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break; + case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break; + case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break; + case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break; + case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break; + case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break; + case M68K_OR: or_irdisp(code, val, dst, disp, size); break; + case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break; + case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break; + case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break; + case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break; + case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break; + case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break; + } +} + +void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size) +{ + switch (inst->op) + { + case M68K_ADD: add_rr(code, src, dst, size); break; + case M68K_ADDX: adc_rr(code, src, dst, size); break; + case M68K_AND: and_rr(code, src, dst, size); break; + case M68K_BTST: bt_rr(code, src, dst, size); break; + case M68K_BSET: bts_rr(code, src, dst, size); break; + case M68K_BCLR: btr_rr(code, src, dst, size); break; + case M68K_BCHG: btc_rr(code, src, dst, size); break; + case M68K_CMP: cmp_rr(code, src, dst, size); break; + case M68K_EOR: xor_rr(code, src, dst, size); break; + case M68K_OR: or_rr(code, src, dst, size); break; + case M68K_SUB: sub_rr(code, src, dst, size); break; + case M68K_SUBX: sbb_rr(code, src, dst, size); break; + } +} + +void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size) +{ + switch (inst->op) + { + case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break; + case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break; + case M68K_AND: and_rrdisp(code, src, dst, disp, size); break; + case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break; + case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break; + case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break; + case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break; + case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break; + case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break; + case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; + case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; + case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; + } +} + +void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size) +{ + switch (inst->op) + { + case M68K_ADD: add_rdispr(code, src, disp, dst, size); break; + case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break; + case M68K_AND: and_rdispr(code, src, disp, dst, size); break; + case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break; + case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break; + case M68K_OR: or_rdispr(code, src, disp, dst, size); break; + case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; + case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; + } +} + +void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS); + if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { + flag_to_carry(opts, FLAG_X); + } + uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; + if (src_op->mode == MODE_REG_DIRECT) { + if (dst_op->mode == MODE_REG_DIRECT) { + op_rr(code, inst, src_op->base, dst_op->base, size); + } else { + op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); + } + } else if (src_op->mode == MODE_REG_DISPLACE8) { + op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size); + } else { + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, src_op->disp, dst_op->base, size); + } else { + op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size); + } + } + if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) { + update_flags(opts, flag_mask); + if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { + check_alloc_code(code, 2*MAX_INST_LEN); + code_ptr after_flag_set = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + set_flag(opts, 0, FLAG_Z); + *after_flag_set = code->cur - (after_flag_set+1); + } + } + if (inst->op != M68K_CMP) { + m68k_save_result(inst, opts); + } +} + +void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + uint8_t size = inst->extra.size; + host_ea src_op, dst_op; + translate_m68k_op(inst, &src_op, opts, 0); + if (inst->dst.addr_mode == MODE_AREG_POSTINC) { + push_r(code, opts->gen.scratch1); + translate_m68k_op(inst, &dst_op, opts, 1); + pop_r(code, opts->gen.scratch2); + src_op.base = opts->gen.scratch2; + } else { + translate_m68k_op(inst, &dst_op, opts, 1); + if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { + size = OPSIZE_LONG; + } + } + translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op); +} + +void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size) +{ + switch(inst->op) + { + case M68K_NEG: neg_r(code, dst, size); break; + case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break; + case M68K_ROL: rol_clr(code, dst, size); break; + case M68K_ROR: ror_clr(code, dst, size); break; + case M68K_ROXL: rcl_clr(code, dst, size); break; + case M68K_ROXR: rcr_clr(code, dst, size); break; + case M68K_SWAP: rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break; + case M68K_TST: cmp_ir(code, 0, dst, size); break; + } +} + +void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size) +{ + switch(inst->op) + { + case M68K_NEG: neg_rdisp(code, dst, disp, size); break; + case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break; + case M68K_ROL: rol_clrdisp(code, dst, disp, size); break; + case M68K_ROR: ror_clrdisp(code, dst, disp, size); break; + case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break; + case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break; + case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break; + case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break; + } +} + +void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS); + if (dst_op->mode == MODE_REG_DIRECT) { + op_r(code, inst, dst_op->base, inst->extra.size); + } else { + op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, flag_mask); + m68k_save_result(inst, opts); +} + +void translate_m68k_invalid(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + if (inst->src.params.immed == 0x7100) { + retn(code); + return; + } + mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); + call(code, (code_ptr)m68k_invalid); +} + +void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + if (src_op->base != opts->gen.scratch2) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); + } + } + if (dst_op->base != opts->gen.scratch1) { + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B); + } else { + mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); + } + } + uint8_t other_reg; + //WARNING: This may need adjustment if register assignments change + if (opts->gen.scratch2 > RBX) { + other_reg = RAX; + xchg_rr(code, opts->gen.scratch2, RAX, SZ_D); + } else { + other_reg = opts->gen.scratch2; + } + mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B); + mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B); + and_ir(code, 0xF0, opts->gen.scratch1, SZ_B); + and_ir(code, 0xF0, other_reg, SZ_B); + and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B); + and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B); + //do op on low nibble + flag_to_carry(opts, FLAG_X); + if (inst->op == M68K_ABCD) { + adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); + } else { + sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); + } + cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B); + code_ptr no_adjust = code->cur+1; + //add correction factor if necessary + jcc(code, CC_B, no_adjust); + if (inst->op == M68K_ABCD) { + add_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); + } else { + sub_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); + } + *no_adjust = code->cur - (no_adjust+1); + //add low nibble result to one of the high nibble operands + add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B); + if (inst->op == M68K_ABCD) { + add_rr(code, other_reg, opts->gen.scratch1, SZ_B); + } else { + sub_rr(code, other_reg, opts->gen.scratch1, SZ_B); + } + if (opts->gen.scratch2 > RBX) { + mov_rr(code, opts->gen.scratch2, RAX, SZ_D); + } + set_flag(opts, 0, FLAG_C); + set_flag(opts, 0, FLAG_V); + code_ptr def_adjust = code->cur+1; + jcc(code, CC_C, def_adjust); + cmp_ir(code, 0xA0, opts->gen.scratch1, SZ_B); + no_adjust = code->cur+1; + jcc(code, CC_B, no_adjust); + *def_adjust = code->cur - (def_adjust + 1); + set_flag(opts, 1, FLAG_C); + if (inst->op == M68K_ABCD) { + add_ir(code, 0x60, opts->gen.scratch1, SZ_B); + } else { + sub_ir(code, 0x60, opts->gen.scratch1, SZ_B); + } + //V flag is set based on the result of the addition of the + //result and the correction factor + set_flag_cond(opts, CC_O, FLAG_V); + *no_adjust = code->cur - (no_adjust+1); + flag_to_flag(opts, FLAG_C, FLAG_X); + + cmp_ir(code, 0, opts->gen.scratch1, SZ_B); + set_flag_cond(opts, CC_S, FLAG_N); + jcc(code, CC_Z, code->cur + 4); + set_flag(opts, 0, FLAG_Z); + if (dst_op->base != opts->gen.scratch1) { + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B); + } else { + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B); + } + } + m68k_save_result(inst, opts); +} + +void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); +} + +void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); +} + +void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp); +} + +void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : ( + inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) + ); + if (src_op->mode == MODE_IMMED) { + if (inst->extra.size == OPSIZE_BYTE) { + src_op->disp &= 0x7; + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); + } else { + op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + } else { + if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) { + if (dst_op->base == opts->gen.scratch1) { + push_r(code, opts->gen.scratch2); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B); + } + src_op->base = opts->gen.scratch2; + } else { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); + } + src_op->base = opts->gen.scratch1; + } + } + uint8_t size = inst->extra.size; + if (dst_op->mode == MODE_REG_DISPLACE8) { + if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); + src_op->mode = MODE_REG_DIRECT; + } + src_op->base = opts->gen.scratch1; + } + //b### with register destination is modulo 32 + //x86 with a memory destination isn't modulo anything + //so use an and here to force the value to be modulo 32 + and_ir(code, 31, opts->gen.scratch1, SZ_D); + } else if(inst->dst.addr_mode != MODE_REG) { + //b### with memory destination is modulo 8 + //x86-64 doesn't support 8-bit bit operations + //so we fake it by forcing the bit number to be modulo 8 + and_ir(code, 7, src_op->base, SZ_D); + size = SZ_D; + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_rr(code, inst, src_op->base, dst_op->base, size); + } else { + op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); + } + if (src_op->base == opts->gen.scratch2) { + pop_r(code, opts->gen.scratch2); + } + } + //x86 sets the carry flag to the value of the bit tested + //68K sets the zero flag to the complement of the bit tested + set_flag_cond(opts, CC_NC, FLAG_Z); + if (inst->op != M68K_BTST) { + m68k_save_result(inst, opts); + } +} + +void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 6); + if (dst_op->mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op->base, inst->extra.size); + } else { + cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + uint32_t isize; + switch(inst->src.addr_mode) + { + case MODE_AREG_DISPLACE: + case MODE_AREG_INDEX_DISP8: + case MODE_ABSOLUTE_SHORT: + case MODE_PC_INDEX_DISP8: + case MODE_PC_DISPLACE: + case MODE_IMMEDIATE: + isize = 4; + break; + case MODE_ABSOLUTE: + isize = 6; + break; + default: + isize = 2; + } + //make sure we won't start a new chunk in the middle of these branches + check_alloc_code(code, MAX_INST_LEN * 11); + code_ptr passed = code->cur + 1; + jcc(code, CC_GE, code->cur + 2); + set_flag(opts, 1, FLAG_N); + mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *passed = code->cur - (passed+1); + if (dst_op->mode == MODE_REG_DIRECT) { + if (src_op->mode == MODE_REG_DIRECT) { + cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); + } else if(src_op->mode == MODE_REG_DISPLACE8) { + cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size); + } else { + cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size); + } + } else if(dst_op->mode == MODE_REG_DISPLACE8) { + if (src_op->mode == MODE_REG_DIRECT) { + cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size); + } else { + cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + } + passed = code->cur + 1; + jcc(code, CC_LE, code->cur + 2); + set_flag(opts, 0, FLAG_N); + mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *passed = code->cur - (passed+1); + cycles(&opts->gen, 4); +} + +void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + check_alloc_code(code, MAX_NATIVE_SIZE); + //TODO: cycle exact division + cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); + set_flag(opts, 0, FLAG_C); + push_r(code, RDX); + push_r(code, RAX); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, RAX, SZ_D); + } else { + mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D); + } + if (src_op->mode == MODE_IMMED) { + mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D); + } else if (src_op->mode == MODE_REG_DIRECT) { + if (inst->op == M68K_DIVS) { + movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); + } else { + movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); + } + } else if (src_op->mode == MODE_REG_DISPLACE8) { + if (inst->op == M68K_DIVS) { + movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } else { + movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } + } + uint32_t isize = 2; + switch(inst->src.addr_mode) + { + case MODE_AREG_DISPLACE: + case MODE_AREG_INDEX_DISP8: + case MODE_ABSOLUTE_SHORT: + case MODE_PC_INDEX_DISP8: + case MODE_IMMEDIATE: + isize = 4; + break; + case MODE_ABSOLUTE: + isize = 6; + break; + } + cmp_ir(code, 0, opts->gen.scratch2, SZ_D); + check_alloc_code(code, 6*MAX_INST_LEN); + code_ptr not_zero = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + pop_r(code, RAX); + pop_r(code, RDX); + mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); + jmp(code, opts->trap); + *not_zero = code->cur - (not_zero+1); + if (inst->op == M68K_DIVS) { + cdq(code); + } else { + xor_rr(code, RDX, RDX, SZ_D); + } + if (inst->op == M68K_DIVS) { + idiv_r(code, opts->gen.scratch2, SZ_D); + } else { + div_r(code, opts->gen.scratch2, SZ_D); + } + code_ptr skip_sec_check, norm_off; + if (inst->op == M68K_DIVS) { + cmp_ir(code, 0x8000, RAX, SZ_D); + skip_sec_check = code->cur + 1; + jcc(code, CC_GE, code->cur + 2); + cmp_ir(code, -0x8000, RAX, SZ_D); + norm_off = code->cur + 1; + jcc(code, CC_L, code->cur + 2); + } else { + cmp_ir(code, 0x10000, RAX, SZ_D); + norm_off = code->cur + 1; + jcc(code, CC_NC, code->cur + 2); + } + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, RDX, dst_op->base, SZ_W); + shl_ir(code, 16, dst_op->base, SZ_D); + mov_rr(code, RAX, dst_op->base, SZ_W); + } else { + mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W); + shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D); + mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W); + } + cmp_ir(code, 0, RAX, SZ_W); + pop_r(code, RAX); + pop_r(code, RDX); + update_flags(opts, V0|Z|N); + code_ptr end_off = code->cur + 1; + jmp(code, code->cur + 2); + *norm_off = code->cur - (norm_off + 1); + if (inst->op == M68K_DIVS) { + *skip_sec_check = code->cur - (skip_sec_check+1); + } + pop_r(code, RAX); + pop_r(code, RDX); + set_flag(opts, 1, FLAG_V); + *end_off = code->cur - (end_off + 1); +} + +void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 6); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, dst_op->base, SZ_D); + mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); + } else { + mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D); + mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); + } + } else { + mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D); + if (src_op->mode == MODE_REG_DIRECT) { + mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D); + mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); + mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); + } + } +} + +void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the parameter + if (src_op->mode == MODE_IMMED) { + mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D); + } else if (src_op->mode == MODE_REG_DIRECT) { + if (inst->op == M68K_MULS) { + movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); + } else { + movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); + } + } else { + if (inst->op == M68K_MULS) { + movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); + } else { + movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); + } + } + uint8_t dst_reg; + if (dst_op->mode == MODE_REG_DIRECT) { + dst_reg = dst_op->base; + if (inst->op == M68K_MULS) { + movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); + } else { + movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); + } + } else { + dst_reg = opts->gen.scratch2; + if (inst->op == M68K_MULS) { + movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } else { + movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); + } + } + imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); + if (dst_op->mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D); + } + cmp_ir(code, 0, dst_reg, SZ_D); + update_flags(opts, N|Z|V0|C0); +} + +void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS); + if (dst_op->mode == MODE_REG_DIRECT) { + if (dst_op->base == opts->gen.scratch1) { + push_r(code, opts->gen.scratch2); + xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size); + flag_to_carry(opts, FLAG_X); + sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size); + mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size); + pop_r(code, opts->gen.scratch2); + } else { + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); + flag_to_carry(opts, FLAG_X); + sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size); + mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size); + } + } else { + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); + flag_to_carry(opts, FLAG_X); + sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size); + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size); + } + set_flag_cond(opts, CC_C, FLAG_C); + code_ptr after_flag_set = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + set_flag(opts, 0, FLAG_Z); + *after_flag_set = code->cur - (after_flag_set+1); + set_flag_cond(opts, CC_S, FLAG_N); + set_flag_cond(opts, CC_O, FLAG_V); + if (opts->flag_regs[FLAG_C] >= 0) { + flag_to_flag(opts, FLAG_C, FLAG_X); + } else { + set_flag_cond(opts, CC_C, FLAG_X); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + int32_t init_flags = C|V0; + if (inst->src.addr_mode == MODE_UNUSED) { + cycles(&opts->gen, BUS); + //Memory rotate + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + flag_to_carry(opts, FLAG_X); + init_flags |= X; + } + op_ir(code, inst, 1, dst_op->base, inst->extra.size); + update_flags(opts, init_flags); + cmp_ir(code, 0, dst_op->base, inst->extra.size); + update_flags(opts, Z|N); + m68k_save_result(inst, opts); + } else { + if (src_op->mode == MODE_IMMED) { + cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2); + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + flag_to_carry(opts, FLAG_X); + init_flags |= X; + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); + } else { + op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, init_flags); + } else { + if (src_op->mode == MODE_REG_DIRECT) { + if (src_op->base != opts->gen.scratch1) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); + } + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); + } + and_ir(code, 63, opts->gen.scratch1, SZ_D); + code_ptr zero_off = code->cur + 1; + jcc(code, CC_Z, code->cur + 2); + add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); + add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); + cmp_ir(code, 32, opts->gen.scratch1, SZ_B); + code_ptr norm_off = code->cur + 1; + jcc(code, CC_L, code->cur + 2); + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + flag_to_carry(opts, FLAG_X); + init_flags |= X; + } else { + sub_ir(code, 32, opts->gen.scratch1, SZ_B); + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_ir(code, inst, 31, dst_op->base, inst->extra.size); + op_ir(code, inst, 1, dst_op->base, inst->extra.size); + } else { + op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size); + op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size); + } + + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + set_flag_cond(opts, CC_C, FLAG_X); + sub_ir(code, 32, opts->gen.scratch1, SZ_B); + *norm_off = code->cur - (norm_off+1); + flag_to_carry(opts, FLAG_X); + } else { + *norm_off = code->cur - (norm_off+1); + } + if (dst_op->mode == MODE_REG_DIRECT) { + op_r(code, inst, dst_op->base, inst->extra.size); + } else { + op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, init_flags); + code_ptr end_off = code->cur + 1; + jmp(code, code->cur + 2); + *zero_off = code->cur - (zero_off+1); + if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { + //Carry flag is set to X flag when count is 0, this is different from ROR/ROL + flag_to_flag(opts, FLAG_X, FLAG_C); + } else { + set_flag(opts, 0, FLAG_C); + } + *end_off = code->cur - (end_off+1); + } + if (dst_op->mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op->base, inst->extra.size); + } else { + cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); + } + update_flags(opts, Z|N); + } +} + +void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); +#else + push_r(code, opts->gen.context_reg); +#endif + call(code, (code_ptr)print_regs_exit); +} + +#define BIT_SUPERVISOR 5 + +void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 20); + //TODO: If ANDI to SR, trap if not in supervisor mode + uint32_t flag_mask = 0; + uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1; + for (int i = 0; i < 5; i++) + { + if ((base_flag == X0) ^ (inst->src.params.immed & 1 << i) > 0) + { + flag_mask |= base_flag << ((4 - i) * 3); + } + } + update_flags(opts, flag_mask); + if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) { + if (inst->op == M68K_ANDI_SR) { + and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + } else { + or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + } + if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) { + //leave supervisor mode + swap_ssp_usp(opts); + } + if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700) + || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) { + call(code, opts->do_sync); + } + } +} + +void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + cycles(&opts->gen, 20); + //TODO: If ANDI to SR, trap if not in supervisor mode + if (inst->src.params.immed & 0x1) { + xor_flag(opts, 1, FLAG_C); + } + if (inst->src.params.immed & 0x2) { + xor_flag(opts, 1, FLAG_V); + } + if (inst->src.params.immed & 0x4) { + xor_flag(opts, 1, FLAG_Z); + } + if (inst->src.params.immed & 0x8) { + xor_flag(opts, 1, FLAG_N); + } + if (inst->src.params.immed & 0x10) { + xor_flag(opts, 1, FLAG_X); + } + if (inst->op == M68K_ORI_SR) { + xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (inst->src.params.immed & 0x700) { + call(code, opts->do_sync); + } + } +} + +void set_all_flags(m68k_options *opts, uint8_t flags) +{ + uint32_t flag_mask = flags & 0x10 ? X1 : X0; + flag_mask |= flags & 0x8 ? N1 : N0; + flag_mask |= flags & 0x4 ? Z1 : Z0; + flag_mask |= flags & 0x2 ? V1 : V0; + flag_mask |= flags & 0x1 ? C1 : C0; + update_flags(opts, flag_mask); +} + +void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + //TODO: Privilege check for MOVE to SR + if (src_op->mode == MODE_IMMED) { + set_all_flags(opts, src_op->disp); + if (inst->op == M68K_MOVE_SR) { + mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { + //leave supervisor mode + swap_ssp_usp(opts); + } + call(code, opts->do_sync); + } + cycles(&opts->gen, 12); + } else { + if (src_op->base != opts->gen.scratch1) { + if (src_op->mode == MODE_REG_DIRECT) { + mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W); + } else { + mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W); + } + } + call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); + cycles(&opts->gen, 12); + } +} + +void translate_m68k_stop(m68k_options *opts, m68kinst *inst) +{ + //TODO: Trap if not in system mode + //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction + //possibly even 12 since that's how long MOVE to SR takes + //On further thought prefetch + the fact that this stops the CPU may make + //Motorola's accounting make sense here + code_info *code = &opts->gen.code; + cycles(&opts->gen, BUS*2); + set_all_flags(opts, inst->src.params.immed); + mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { + //leave supervisor mode + swap_ssp_usp(opts); + } + code_ptr loop_top = code->cur; + call(code, opts->do_sync); + cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + code_ptr normal_cycle_up = code->cur + 1; + jcc(code, CC_A, code->cur + 2); + cycles(&opts->gen, BUS); + code_ptr after_cycle_up = code->cur + 1; + jmp(code, code->cur + 2); + *normal_cycle_up = code->cur - (normal_cycle_up + 1); + mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + *after_cycle_up = code->cur - (after_cycle_up+1); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); + jcc(code, CC_C, loop_top); +} + +void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) +{ + code_info *code = &opts->gen.code; + //TODO: Trap if not in system mode + call(code, opts->get_sr); + if (dst_op->mode == MODE_REG_DIRECT) { + mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); + } else { + mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); + } + m68k_save_result(inst, opts); +} + +void translate_m68k_reset(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); +#else + push_r(code, opts->gen.context_reg); +#endif + call(code, (code_ptr)print_regs_exit); +} + +void translate_m68k_rte(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + //TODO: Trap if not in system mode + //Read saved SR + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_16); + addi_areg(opts, 2, 7); + call(code, opts->set_sr); + //Read saved PC + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_32); + addi_areg(opts, 4, 7); + //Check if we've switched to user mode and swap stack pointers if needed + bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + code_ptr end_off = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + swap_ssp_usp(opts); + *end_off = code->cur - (end_off+1); + //Get native address, sync components, recalculate integer points and jump to returned address + call(code, opts->native_addr_and_sync); + jmp_r(code, opts->gen.scratch1); +} + +void translate_out_of_bounds(code_info *code) +{ + xor_rr(code, RDI, RDI, SZ_D); +#ifdef X86_32 + push_r(code, RDI); +#endif + call(code, (code_ptr)exit); +} + +void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) +{ + if (next_inst == old_end && next_inst - code->cur < 2) { + while (code->cur < old_end) { + *(code->cur++) = 0x90; //NOP + } + } else { + jmp(code, next_inst); + } +} + +m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) +{ + uint32_t inst_start = get_instruction_start(context->native_code_map, address | 0xFF0000); + if (inst_start) { + m68k_options * options = context->options; + code_info *code = &options->gen.code; + code_ptr dst = get_native_address(context->native_code_map, inst_start); + code_info orig; + orig.cur = dst; + orig.last = dst + 128; + mov_ir(&orig, inst_start, options->gen.scratch2, SZ_D); + + if (!options->retrans_stub) { + options->retrans_stub = code->cur; + call(code, options->gen.save_context); + push_r(code, options->gen.context_reg); +#ifdef X86_32 + push_r(code, options->gen.context_reg); + push_r(code, options->gen.scratch2); +#endif + call(code, (code_ptr)m68k_retranslate_inst); +#ifdef X86_32 + add_ir(code, 8, RSP, SZ_D); +#endif + pop_r(code, options->gen.context_reg); + mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); + call(code, options->gen.load_context); + jmp_r(code, options->gen.scratch1); + } + jmp(&orig, options->retrans_stub); + } + return context; +} + +void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_handler) +{ + static code_ptr bp_stub = NULL; + m68k_options * opts = context->options; + code_info native; + native.cur = get_native_address_trans(context, address); + native.last = native.cur + 128; + code_ptr start_native = native.cur; + mov_ir(&native, address, opts->gen.scratch1, SZ_D); + if (!bp_stub) { + code_info *code = &opts->gen.code; + check_alloc_code(code, 5); + bp_stub = code->cur; + call(&native, bp_stub); + + //Calculate length of prologue + check_cycles_int(&opts->gen, address); + int check_int_size = code->cur-bp_stub; + code->cur = bp_stub; + + //Save context and call breakpoint handler + call(code, opts->gen.save_context); + push_r(code, opts->gen.scratch1); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); + mov_rr(code, opts->gen.scratch1, RSI, SZ_D); +#else + push_r(code, opts->gen.scratch1); + push_r(code, opts->gen.context_reg); +#endif + call(code, bp_handler); +#ifdef X86_32 + add_ir(code, 8, RSP, SZ_D); +#endif + mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); + //Restore context + call(code, opts->gen.load_context); + pop_r(code, opts->gen.scratch1); + //do prologue stuff + cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); + code_ptr jmp_off = code->cur + 1; + jcc(code, CC_NC, code->cur + 7); + call(code, opts->gen.handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); + //jump back to body of translated instruction + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - (native.cur-start_native), opts->gen.scratch1, SZ_PTR); + jmp_r(code, opts->gen.scratch1); + } else { + call(&native, bp_stub); + } +} + +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks) +{ + memset(opts, 0, sizeof(*opts)); + opts->gen.address_size = SZ_D; + opts->gen.address_mask = 0xFFFFFF; + opts->gen.byte_swap = 1; + opts->gen.max_address = 0x1000000; + opts->gen.bus_cycles = BUS; + opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers); + opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags); + opts->gen.ram_flags_shift = 11; + for (int i = 0; i < 8; i++) + { + opts->dregs[i] = opts->aregs[i] = -1; + } +#ifdef X86_64 + opts->dregs[0] = R10; + opts->dregs[1] = R11; + opts->dregs[2] = R12; + opts->dregs[3] = R8; + opts->aregs[0] = R13; + opts->aregs[1] = R14; + opts->aregs[2] = R9; + opts->aregs[7] = R15; + + opts->flag_regs[0] = -1; + opts->flag_regs[1] = RBX; + opts->flag_regs[2] = RDX; + opts->flag_regs[3] = BH; + opts->flag_regs[4] = DH; + + opts->gen.scratch2 = RDI; +#else + opts->dregs[0] = RDX; + opts->aregs[7] = RDI; + + for (int i = 0; i < 5; i++) + { + opts->flag_regs[i] = -1; + } + opts->gen.scratch2 = RBX; +#endif + opts->gen.context_reg = RSI; + opts->gen.cycles = RAX; + opts->gen.limit = RBP; + opts->gen.scratch1 = RCX; + + + opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); + opts->gen.deferred = NULL; + opts->gen.ram_inst_sizes = malloc(sizeof(uint8_t *) * 64); + memset(opts->gen.ram_inst_sizes, 0, sizeof(uint8_t *) * 64); + + code_info *code = &opts->gen.code; + init_code_info(code); + + opts->gen.save_context = code->cur; + for (int i = 0; i < 5; i++) + if (opts->flag_regs[i] >= 0) { + mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B); + } + for (int i = 0; i < 8; i++) + { + if (opts->dregs[i] >= 0) { + mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D); + } + if (opts->aregs[i] >= 0) { + mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D); + } + } + mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D); + retn(code); + + opts->gen.load_context = code->cur; + for (int i = 0; i < 5; i++) + if (opts->flag_regs[i] >= 0) { + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B); + } + for (int i = 0; i < 8; i++) + { + if (opts->dregs[i] >= 0) { + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D); + } + if (opts->aregs[i] >= 0) { + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D); + } + } + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), CYCLES, SZ_D); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), LIMIT, SZ_D); + retn(code); + + opts->start_context = (start_fun)code->cur; +#ifdef X86_64 + if (opts->gen.scratch2 != RDI) { + mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR); + } + //save callee save registers + push_r(code, RBP); + push_r(code, R12); + push_r(code, R13); + push_r(code, R14); + push_r(code, R15); +#else + //save callee save registers + push_r(code, RBP); + push_r(code, RBX); + push_r(code, RSI); + push_r(code, RDI); + + mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D); + mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D); +#endif + call(code, opts->gen.load_context); + call_r(code, opts->gen.scratch2); + call(code, opts->gen.save_context); +#ifdef X86_64 + //restore callee save registers + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); +#else + pop_r(code, RDI); + pop_r(code, RSI); + pop_r(code, RBX); + pop_r(code, RBP); +#endif + retn(code); + + opts->native_addr = code->cur; + call(code, opts->gen.save_context); + push_r(code, opts->gen.context_reg); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); //move context to 1st arg reg + mov_rr(code, opts->gen.scratch1, RSI, SZ_D); //move address to 2nd arg reg +#else + push_r(code, opts->gen.scratch1); + push_r(code, opts->gen.context_reg); +#endif + call(code, (code_ptr)get_native_address_trans); +#ifdef X86_32 + add_ir(code, 8, RSP, SZ_D); +#endif + mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg + pop_r(code, opts->gen.context_reg); + call(code, opts->gen.load_context); + retn(code); + + opts->native_addr_and_sync = code->cur; + call(code, opts->gen.save_context); + push_r(code, opts->gen.scratch1); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); + xor_rr(code, RSI, RSI, SZ_D); + test_ir(code, 8, RSP, SZ_PTR); //check stack alignment + code_ptr do_adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, (code_ptr)sync_components); + code_ptr no_adjust_rsp = code->cur + 1; + jmp(code, code->cur + 2); + *do_adjust_rsp = code->cur - (do_adjust_rsp+1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_PTR); + *no_adjust_rsp = code->cur - (no_adjust_rsp+1); + pop_r(code, RSI); + push_r(code, RAX); + mov_rr(code, RAX, RDI, SZ_PTR); + call(code, (code_ptr)get_native_address_trans); +#else + //TODO: Add support for pushing a constant in gen_x86 + xor_rr(code, RAX, RAX, SZ_D); + push_r(code, RAX); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_D); + pop_r(code, RSI); //restore saved address from opts->gen.scratch1 + push_r(code, RAX); //save context pointer for later + push_r(code, RSI); //2nd arg -- address + push_r(code, RAX); //1st arg -- context pointer + call(code, (code_ptr)get_native_address_trans); + add_ir(code, 8, RSP, SZ_D); +#endif + + mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg + pop_r(code, opts->gen.context_reg); + call(code, opts->gen.load_context); + retn(code); + + opts->gen.handle_cycle_limit = code->cur; + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D); + code_ptr skip_sync = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + opts->do_sync = code->cur; + push_r(code, opts->gen.scratch1); + push_r(code, opts->gen.scratch2); + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); + xor_rr(code, RSI, RSI, SZ_D); + test_ir(code, 8, RSP, SZ_D); + code_ptr adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, (code_ptr)sync_components); + code_ptr no_adjust = code->cur + 1; + jmp(code, code->cur + 2); + *adjust_rsp = code->cur - (adjust_rsp + 1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_PTR); + *no_adjust = code->cur - (no_adjust+1); +#else + //TODO: Add support for pushing a constant in gen_x86 + xor_rr(code, RAX, RAX, SZ_D); + push_r(code, RAX); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_D); +#endif + mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); + call(code, opts->gen.load_context); + pop_r(code, opts->gen.scratch2); + pop_r(code, opts->gen.scratch1); + *skip_sync = code->cur - (skip_sync+1); + retn(code); + + opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write; + + opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL); + opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL); + opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL); + opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL); + + opts->read_32 = code->cur; + push_r(code, opts->gen.scratch1); + call(code, opts->read_16); + mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W); + pop_r(code, opts->gen.scratch1); + push_r(code, opts->gen.scratch2); + add_ir(code, 2, opts->gen.scratch1, SZ_D); + call(code, opts->read_16); + pop_r(code, opts->gen.scratch2); + movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D); + shl_ir(code, 16, opts->gen.scratch2, SZ_D); + or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D); + retn(code); + + opts->write_32_lowfirst = code->cur; + push_r(code, opts->gen.scratch2); + push_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch2, SZ_D); + call(code, opts->write_16); + pop_r(code, opts->gen.scratch1); + pop_r(code, opts->gen.scratch2); + shr_ir(code, 16, opts->gen.scratch1, SZ_D); + jmp(code, opts->write_16); + + opts->write_32_highfirst = code->cur; + push_r(code, opts->gen.scratch1); + push_r(code, opts->gen.scratch2); + shr_ir(code, 16, opts->gen.scratch1, SZ_D); + call(code, opts->write_16); + pop_r(code, opts->gen.scratch2); + pop_r(code, opts->gen.scratch1); + add_ir(code, 2, opts->gen.scratch2, SZ_D); + jmp(code, opts->write_16); + + opts->get_sr = code->cur; + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); + shl_ir(code, 8, opts->gen.scratch1, SZ_W); + if (opts->flag_regs[FLAG_X] >= 0) { + mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B); + } else { + int8_t offset = offsetof(m68k_context, flags); + if (offset) { + mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B); + } else { + mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B); + } + } + for (int flag = FLAG_N; flag <= FLAG_C; flag++) + { + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + if (opts->flag_regs[flag] >= 0) { + or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B); + } else { + or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B); + } + } + retn(code); + + opts->set_sr = code->cur; + for (int flag = FLAG_C; flag >= FLAG_X; flag--) + { + rcr_ir(code, 1, opts->gen.scratch1, SZ_B); + if (opts->flag_regs[flag] >= 0) { + setcc_r(code, CC_C, opts->flag_regs[flag]); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + setcc_rdisp(code, CC_C, opts->gen.context_reg, offset); + } else { + setcc_rind(code, CC_C, opts->gen.context_reg); + } + } + } + shr_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + retn(code); + + opts->set_ccr = code->cur; + for (int flag = FLAG_C; flag >= FLAG_X; flag--) + { + rcr_ir(code, 1, opts->gen.scratch1, SZ_B); + if (opts->flag_regs[flag] >= 0) { + setcc_r(code, CC_C, opts->flag_regs[flag]); + } else { + int8_t offset = offsetof(m68k_context, flags) + flag; + if (offset) { + setcc_rdisp(code, CC_C, opts->gen.context_reg, offset); + } else { + setcc_rind(code, CC_C, opts->gen.context_reg); + } + } + } + retn(code); + + opts->gen.handle_cycle_limit_int = code->cur; + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), CYCLES, SZ_D); + code_ptr do_int = code->cur + 1; + jcc(code, CC_NC, code->cur + 2); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D); + skip_sync = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + call(code, opts->gen.save_context); +#ifdef X86_64 + mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); + mov_rr(code, opts->gen.scratch1, RSI, SZ_D); + test_ir(code, 8, RSP, SZ_D); + adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); + call(code, (code_ptr)sync_components); + no_adjust = code->cur + 1; + jmp(code, code->cur + 2); + *adjust_rsp = code->cur - (adjust_rsp + 1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_PTR); + *no_adjust = code->cur - (no_adjust+1); +#else + push_r(code, opts->gen.scratch1); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)sync_components); + add_ir(code, 8, RSP, SZ_D); +#endif + mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); + jmp(code, opts->gen.load_context); + *skip_sync = code->cur - (skip_sync+1); + retn(code); + *do_int = code->cur - (do_int+1); + //set target cycle to sync cycle + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), LIMIT, SZ_D); + //swap USP and SSP if not already in supervisor mode + bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + code_ptr already_supervisor = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + swap_ssp_usp(opts); + *already_supervisor = code->cur - (already_supervisor+1); + //save PC + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + //save status register + subi_areg(opts, 2, 7); + call(code, opts->get_sr); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //update status register + and_irdisp(code, 0xF8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B); + or_ir(code, 0x20, opts->gen.scratch1, SZ_B); + or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + //calculate interrupt vector address + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_D); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W); + shl_ir(code, 2, opts->gen.scratch1, SZ_D); + add_ir(code, 0x60, opts->gen.scratch1, SZ_D); + call(code, opts->read_32); + call(code, opts->native_addr_and_sync); + cycles(&opts->gen, 24); + //discard function return address + pop_r(code, opts->gen.scratch2); + jmp_r(code, opts->gen.scratch1); + + opts->trap = code->cur; + push_r(code, opts->gen.scratch2); + //swap USP and SSP if not already in supervisor mode + bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + already_supervisor = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + swap_ssp_usp(opts); + *already_supervisor = code->cur - (already_supervisor+1); + //save PC + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + //save status register + subi_areg(opts, 2, 7); + call(code, opts->get_sr); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //set supervisor bit + or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + //calculate vector address + pop_r(code, opts->gen.scratch1); + shl_ir(code, 2, opts->gen.scratch1, SZ_D); + call(code, opts->read_32); + call(code, opts->native_addr_and_sync); + cycles(&opts->gen, 18); + jmp_r(code, opts->gen.scratch1); +} diff -r 103d5cabbe14 -r f822d9216968 m68k_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m68k_internal.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,116 @@ +/* + Copyright 2014 Michael Pavone + This file is part of BlastEm. + BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. +*/ +#ifndef M68K_INTERNAL_H_ +#define M68K_INTERNAL_H_ + +#include "68kinst.h" + +//functions implemented in host CPU specfic file +void translate_out_of_bounds(code_info *code); +void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg); +void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg); +void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg); +void ldi_native(m68k_options *opts, int32_t value, uint8_t reg); +void addi_native(m68k_options *opts, int32_t value, uint8_t reg); +void subi_native(m68k_options *opts, int32_t value, uint8_t reg); +void push_native(m68k_options *opts, uint8_t reg); +void pop_native(m68k_options *opts, uint8_t reg); +void sign_extend16_native(m68k_options *opts, uint8_t reg); +void addi_areg(m68k_options *opts, int32_t val, uint8_t reg); +void subi_areg(m68k_options *opts, int32_t val, uint8_t reg); +void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); +void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg); +void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg); +void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg); +void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst); + +//functions implemented in m68k_core.c +int8_t native_reg(m68k_op_info * op, m68k_options * opts); +size_t dreg_offset(uint8_t reg); +size_t areg_offset(uint8_t reg); +size_t reg_offset(m68k_op_info *op); +void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst); +void print_regs_exit(m68k_context * context); +void m68k_read_size(m68k_options *opts, uint8_t size); +void m68k_write_size(m68k_options *opts, uint8_t size); +void push_const(m68k_options *opts, int32_t value); +void jump_m68k_abs(m68k_options * opts, uint32_t address); +void swap_ssp_usp(m68k_options * opts); +code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address); +void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size); +uint8_t get_native_inst_size(m68k_options * opts, uint32_t address); +uint8_t m68k_is_terminal(m68kinst * inst); +void m68k_handle_deferred(m68k_context * context); +code_ptr get_native_address_trans(m68k_context * context, uint32_t address); +void * m68k_retranslate_inst(uint32_t address, m68k_context * context); + +//individual instructions +void translate_m68k_bcc(m68k_options * opts, m68kinst * inst); +void translate_m68k_scc(m68k_options * opts, m68kinst * inst); +void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst); +void translate_m68k_rtr(m68k_options *opts, m68kinst * inst); +void translate_m68k_trap(m68k_options *opts, m68kinst *inst); +void translate_m68k_move(m68k_options * opts, m68kinst * inst); +void translate_m68k_movep(m68k_options * opts, m68kinst * inst); +void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op); +void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op); +void translate_m68k_invalid(m68k_options *opts, m68kinst *inst); +void translate_m68k_cmp(m68k_options * opts, m68kinst * inst); +void translate_m68k_clr(m68k_options * opts, m68kinst * inst); +void translate_m68k_ext(m68k_options * opts, m68kinst * inst); +void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_illegal(m68k_options *opts, m68kinst *inst); +void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst); +void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst); +void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_stop(m68k_options *opts, m68kinst *inst); +void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); +void translate_m68k_reset(m68k_options *opts, m68kinst *inst); +void translate_m68k_rte(m68k_options *opts, m68kinst *inst); + +//flag update bits +#define X0 0x0001 +#define X1 0x0002 +#define X 0x0004 +#define N0 0x0008 +#define N1 0x0010 +#define N 0x0020 +#define Z0 0x0040 +#define Z1 0x0080 +#define Z 0x0100 +#define V0 0x0200 +#define V1 0x0400 +#define V 0x0800 +#define C0 0x1000 +#define C1 0x2000 +#define C 0x4000 + +#define BUS 4 +#define PREDEC_PENALTY 2 +extern char disasm_buf[1024]; + +m68k_context * sync_components(m68k_context * context, uint32_t address); + +void m68k_invalid(); +void bcd_add(); +void bcd_sub(); + +#endif //M68K_INTERNAL_H_ diff -r 103d5cabbe14 -r f822d9216968 m68k_to_x86.c --- a/m68k_to_x86.c Tue Dec 16 01:10:54 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4561 +0,0 @@ -/* - Copyright 2013 Michael Pavone - This file is part of BlastEm. - BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. -*/ -#include "gen_x86.h" -#include "m68k_to_x86.h" -#include "68kinst.h" -#include "mem.h" -#include "x86_backend.h" -#include -#include -#include -#include - -#define BUS 4 -#define PREDEC_PENALTY 2 -#define CYCLES RAX -#define LIMIT RBP -#define SCRATCH1 RCX -#define SCRATCH2 RDI -#define CONTEXT RSI - -#define FLAG_N RBX -#define FLAG_V BH -#define FLAG_Z RDX -#define FLAG_C DH - -char disasm_buf[1024]; - -m68k_context * sync_components(m68k_context * context, uint32_t address); - -void handle_cycle_limit(); -void m68k_save_context(); -void m68k_load_context(); -void m68k_modified_ret_addr(); -void m68k_native_addr(); -void m68k_native_addr_and_sync(); -void m68k_invalid(); -void m68k_retrans_stub(); -void set_sr(); -void set_ccr(); -void get_sr(); -void do_sync(); -void bcd_add(); -void bcd_sub(); -void m68k_start_context(uint8_t * addr, m68k_context * context); -void debug_print_sr(); - -uint8_t * cycles(uint8_t * dst, uint32_t num) -{ - dst = add_ir(dst, num, CYCLES, SZ_D); - return dst; -} - -uint8_t * check_cycles_int(uint8_t * dst, uint32_t address, x86_68k_options * opts) -{ - dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = mov_ir(dst, address, SCRATCH1, SZ_D); - dst = call(dst, opts->handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); - return dst; -} - -uint8_t * check_cycles(uint8_t * dst) -{ - dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = call(dst, (uint8_t *)handle_cycle_limit); - *jmp_off = dst - (jmp_off+1); - return dst; -} - -int8_t native_reg(m68k_op_info * op, x86_68k_options * opts) -{ - if (op->addr_mode == MODE_REG) { - return opts->dregs[op->params.regs.pri]; - } - if (op->addr_mode == MODE_AREG) { - return opts->aregs[op->params.regs.pri]; - } - return -1; -} - -//must be called with an m68k_op_info that uses a register -size_t reg_offset(m68k_op_info *op) -{ - if (op->addr_mode == MODE_REG) { - return offsetof(m68k_context, dregs) + sizeof(uint32_t) * op->params.regs.pri; - } - return offsetof(m68k_context, aregs) + sizeof(uint32_t) * op->params.regs.pri; -} - -void print_regs_exit(m68k_context * context) -{ - printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]); - for (int i = 0; i < 8; i++) { - printf("d%d: %X\n", i, context->dregs[i]); - } - for (int i = 0; i < 8; i++) { - printf("a%d: %X\n", i, context->aregs[i]); - } - exit(0); -} - -uint8_t * translate_m68k_src(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts) -{ - int8_t reg = native_reg(&(inst->src), opts); - uint8_t sec_reg; - int32_t dec_amount,inc_amount; - if (reg >= 0) { - ea->mode = MODE_REG_DIRECT; - if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { - out = movsx_rr(out, reg, SCRATCH1, SZ_W, SZ_D); - ea->base = SCRATCH1; - } else { - ea->base = reg; - } - return out; - } - switch (inst->src.addr_mode) - { - case MODE_REG: - case MODE_AREG: - //We only get one memory parameter, so if the dst operand is a register in memory, - //we need to copy this to a temp register first - reg = native_reg(&(inst->dst), opts); - if (reg >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) - || inst->op == M68K_EXG) { - - ea->mode = MODE_REG_DISPLACE8; - ea->base = CONTEXT; - ea->disp = reg_offset(&(inst->src)); - } else { - if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { - out = movsx_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_W, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, inst->extra.size); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - //we're explicitly handling the areg dest here, so we exit immediately - return out; - } - break; - case MODE_AREG_PREDEC: - dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 :1)); - out = cycles(out, PREDEC_PENALTY); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - out = sub_ir(out, dec_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); - } else { - out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->src)), SZ_D); - } - case MODE_AREG_INDIRECT: - case MODE_AREG_POSTINC: - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - - if (inst->src.addr_mode == MODE_AREG_POSTINC) { - inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->src.params.regs.pri == 7 ? 2 : 1)); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - out = add_ir(out, inc_amount, opts->aregs[inst->src.params.regs.pri], SZ_D); - } else { - out = add_irdisp8(out, inc_amount, CONTEXT, reg_offset(&(inst->src)), SZ_D); - } - } - ea->mode = MODE_REG_DIRECT; - ea->base = (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? SCRATCH2 : SCRATCH1; - break; - case MODE_AREG_DISPLACE: - out = cycles(out, BUS); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_AREG_INDEX_DISP8: - out = cycles(out, 6); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_PC_DISPLACE: - out = cycles(out, BUS); - out = mov_ir(out, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_PC_INDEX_DISP8: - out = cycles(out, 6); - out = mov_ir(out, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - out = add_ir(out, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - if (inst->src.addr_mode == MODE_ABSOLUTE) { - out = cycles(out, BUS*2); - } else { - out = cycles(out, BUS); - } - out = mov_ir(out, inst->src.params.immed, SCRATCH1, SZ_D); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_IMMEDIATE: - case MODE_IMMEDIATE_WORD: - if (inst->variant != VAR_QUICK) { - out = cycles(out, (inst->extra.size == OPSIZE_LONG && inst->src.addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS); - } - ea->mode = MODE_IMMED; - ea->disp = inst->src.params.immed; - if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) { - ea->disp |= 0xFFFF0000; - } - return out; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); - } - if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { - if (ea->mode == MODE_REG_DIRECT) { - out = movsx_rr(out, ea->base, SCRATCH1, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, ea->base, ea->disp, SCRATCH1, SZ_W, SZ_D); - ea->mode = MODE_REG_DIRECT; - } - ea->base = SCRATCH1; - } - return out; -} - -uint8_t * translate_m68k_dst(m68kinst * inst, x86_ea * ea, uint8_t * out, x86_68k_options * opts, uint8_t fake_read) -{ - int8_t reg = native_reg(&(inst->dst), opts), sec_reg; - int32_t dec_amount, inc_amount; - if (reg >= 0) { - ea->mode = MODE_REG_DIRECT; - ea->base = reg; - return out; - } - switch (inst->dst.addr_mode) - { - case MODE_REG: - case MODE_AREG: - ea->mode = MODE_REG_DISPLACE8; - ea->base = CONTEXT; - ea->disp = reg_offset(&(inst->dst)); - break; - case MODE_AREG_PREDEC: - if (inst->src.addr_mode == MODE_AREG_PREDEC) { - out = push_r(out, SCRATCH1); - } - dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); - } else { - out = sub_irdisp8(out, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - case MODE_AREG_INDIRECT: - case MODE_AREG_POSTINC: - if (fake_read) { - out = cycles(out, inst->extra.size == OPSIZE_LONG ? 8 : 4); - } else { - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH1, SZ_D); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - } - if (inst->src.addr_mode == MODE_AREG_PREDEC) { - //restore src operand to SCRATCH2 - out =pop_r(out, SCRATCH2); - } else { - //save reg value in SCRATCH2 so we can use it to save the result in memory later - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - } - - if (inst->dst.addr_mode == MODE_AREG_POSTINC) { - inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = add_ir(out, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); - } else { - out = add_irdisp8(out, inc_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_AREG_DISPLACE: - out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); - reg = fake_read ? SCRATCH2 : SCRATCH1; - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], reg, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), reg, SZ_D); - } - out = add_ir(out, inst->dst.params.regs.displacement, reg, SZ_D); - if (!fake_read) { - out = push_r(out, SCRATCH1); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - out = pop_r(out, SCRATCH2); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_AREG_INDEX_DISP8: - out = cycles(out, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH1, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH1, SZ_D); - } - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->dst.params.regs.displacement) { - out = add_ir(out, inst->dst.params.regs.displacement, SCRATCH1, SZ_D); - } - if (fake_read) { - out = mov_rr(out, SCRATCH1, SCRATCH2, SZ_D); - } else { - out = push_r(out, SCRATCH1); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - out = pop_r(out, SCRATCH2); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_PC_DISPLACE: - out = cycles(out, fake_read ? BUS+(inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : BUS); - out = mov_ir(out, inst->dst.params.regs.displacement + inst->address+2, fake_read ? SCRATCH2 : SCRATCH1, SZ_D); - if (!fake_read) { - out = push_r(out, SCRATCH1); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - out = pop_r(out, SCRATCH2); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_PC_INDEX_DISP8: - out = cycles(out, fake_read ? (6 + inst->extra.size == OPSIZE_LONG ? 8 : 4) : 6); - out = mov_ir(out, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = add_rr(out, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = add_rr(out, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - out = add_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - out = movsx_rr(out, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - out = movsx_rdisp8r(out, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - out = add_rr(out, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->dst.params.regs.displacement) { - out = add_ir(out, inst->dst.params.regs.displacement, SCRATCH1, SZ_D); - } - if (fake_read) { - out = mov_rr(out, SCRATCH1, SCRATCH2, SZ_D); - } else { - out = push_r(out, SCRATCH1); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - out = pop_r(out, SCRATCH2); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - //Add cycles for reading address from instruction stream - out = cycles(out, (inst->dst.addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS) + (fake_read ? (inst->extra.size == OPSIZE_LONG ? BUS*2 : BUS) : 0)); - out = mov_ir(out, inst->dst.params.immed, fake_read ? SCRATCH2 : SCRATCH1, SZ_D); - if (!fake_read) { - out = push_r(out, SCRATCH1); - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->read_8); - break; - case OPSIZE_WORD: - out = call(out, opts->read_16); - break; - case OPSIZE_LONG: - out = call(out, opts->read_32); - break; - } - out = pop_r(out, SCRATCH2); - } - ea->mode = MODE_REG_DIRECT; - ea->base = SCRATCH1; - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); - exit(1); - } - return out; -} - -uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts) -{ - if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { - if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - out = call(out, opts->write_8); - break; - case OPSIZE_WORD: - out = call(out, opts->write_16); - break; - case OPSIZE_LONG: - out = call(out, opts->write_32_lowfirst); - break; - } - } - return out; -} - -uint8_t * get_native_address(native_map_slot * native_code_map, uint32_t address) -{ - address &= 0xFFFFFF; - address /= 2; - uint32_t chunk = address / NATIVE_CHUNK_SIZE; - if (!native_code_map[chunk].base) { - return NULL; - } - uint32_t offset = address % NATIVE_CHUNK_SIZE; - if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { - return NULL; - } - return native_code_map[chunk].base + native_code_map[chunk].offsets[offset]; -} - -uint8_t * get_native_from_context(m68k_context * context, uint32_t address) -{ - return get_native_address(context->native_code_map, address); -} - -uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) -{ - address &= 0xFFFFFF; - address /= 2; - uint32_t chunk = address / NATIVE_CHUNK_SIZE; - if (!native_code_map[chunk].base) { - return 0; - } - uint32_t offset = address % NATIVE_CHUNK_SIZE; - if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { - return 0; - } - while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) { - --address; - chunk = address / NATIVE_CHUNK_SIZE; - offset = address % NATIVE_CHUNK_SIZE; - } - return address*2; -} - -void map_native_address(m68k_context * context, uint32_t address, uint8_t * native_addr, uint8_t size, uint8_t native_size) -{ - native_map_slot * native_code_map = context->native_code_map; - x86_68k_options * opts = context->options; - address &= 0xFFFFFF; - if (address > 0xE00000) { - context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11); - if (((address & 0x3FFF) + size) & 0xC000) { - context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11); - } - uint32_t slot = (address & 0xFFFF)/1024; - if (!opts->ram_inst_sizes[slot]) { - opts->ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512); - } - opts->ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size; - } - address/= 2; - uint32_t chunk = address / NATIVE_CHUNK_SIZE; - if (!native_code_map[chunk].base) { - native_code_map[chunk].base = native_addr; - native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); - memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); - } - uint32_t offset = address % NATIVE_CHUNK_SIZE; - native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; - for(address++,size-=2; size; address++,size-=2) { - chunk = address / NATIVE_CHUNK_SIZE; - offset = address % NATIVE_CHUNK_SIZE; - if (!native_code_map[chunk].base) { - native_code_map[chunk].base = native_addr; - native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); - memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); - } - native_code_map[chunk].offsets[offset] = EXTENSION_WORD; - } -} - -uint8_t get_native_inst_size(x86_68k_options * opts, uint32_t address) -{ - if (address < 0xE00000) { - return 0; - } - uint32_t slot = (address & 0xFFFF)/1024; - return opts->ram_inst_sizes[slot][((address & 0xFFFF)/2)%512]; -} - -uint8_t * translate_m68k_move(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int8_t reg, flags_reg, sec_reg; - uint8_t dir = 0; - int32_t offset; - int32_t inc_amount, dec_amount; - x86_ea src; - dst = translate_m68k_src(inst, &src, dst, opts); - reg = native_reg(&(inst->dst), opts); - if (inst->dst.addr_mode != MODE_AREG) { - //update statically set flags - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - } - - if (inst->dst.addr_mode != MODE_AREG) { - if (src.mode == MODE_REG_DIRECT) { - flags_reg = src.base; - } else { - if (reg >= 0) { - flags_reg = reg; - } else { - if(src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - src.mode = MODE_REG_DIRECT; - flags_reg = src.base = SCRATCH1; - } - } - } - uint8_t size = inst->extra.size; - switch(inst->dst.addr_mode) - { - case MODE_AREG: - size = OPSIZE_LONG; - case MODE_REG: - if (reg >= 0) { - if (src.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src.base, reg, size); - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, reg, size); - } else { - dst = mov_ir(dst, src.disp, reg, size); - } - } else if(src.mode == MODE_REG_DIRECT) { - dst = mov_rrdisp8(dst, src.base, CONTEXT, reg_offset(&(inst->dst)), size); - } else { - dst = mov_irdisp8(dst, src.disp, CONTEXT, reg_offset(&(inst->dst)), size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - break; - case MODE_AREG_PREDEC: - dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = sub_ir(dst, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); - } else { - dst = sub_irdisp8(dst, dec_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - case MODE_AREG_INDIRECT: - case MODE_AREG_POSTINC: - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - if (inst->dst.addr_mode == MODE_AREG_POSTINC) { - inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = add_ir(dst, inc_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D); - } else { - dst = add_irdisp8(dst, inc_amount, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - } - break; - case MODE_AREG_DISPLACE: - dst = cycles(dst, BUS); - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - break; - case MODE_AREG_INDEX_DISP8: - dst = cycles(dst, 6);//TODO: Check to make sure this is correct - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } - } else { - if (src.base == SCRATCH1) { - dst = push_r(dst, SCRATCH1); - } - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D); - if (src.base == SCRATCH1) { - dst = pop_r(dst, SCRATCH1); - } - } - if (inst->dst.params.regs.displacement) { - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - } - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - break; - case MODE_PC_DISPLACE: - dst = cycles(dst, BUS); - dst = mov_ir(dst, inst->dst.params.regs.displacement + inst->address+2, SCRATCH2, SZ_D); - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - break; - case MODE_PC_INDEX_DISP8: - dst = cycles(dst, 6);//TODO: Check to make sure this is correct - dst = mov_ir(dst, inst->address, SCRATCH2, SZ_D); - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } - } else { - if (src.base == SCRATCH1) { - dst = push_r(dst, SCRATCH1); - } - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D); - if (src.base == SCRATCH1) { - dst = pop_r(dst, SCRATCH1); - } - } - if (inst->dst.params.regs.displacement) { - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - } - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - if (src.mode == MODE_REG_DIRECT) { - if (src.base != SCRATCH1) { - dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); - } - } else if (src.mode == MODE_REG_DISPLACE8) { - dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); - } else { - dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); - } - if (inst->dst.addr_mode == MODE_ABSOLUTE) { - dst = cycles(dst, BUS*2); - } else { - dst = cycles(dst, BUS); - } - dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D); - if (inst->dst.addr_mode != MODE_AREG) { - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - dst = call(dst, opts->write_8); - break; - case OPSIZE_WORD: - dst = call(dst, opts->write_16); - break; - case OPSIZE_LONG: - dst = call(dst, opts->write_32_highfirst); - break; - } - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); - exit(1); - } - - //add cycles for prefetch - dst = cycles(dst, BUS); - return dst; -} - -uint8_t * translate_m68k_movem(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int8_t bit,reg,sec_reg; - uint8_t early_cycles; - if(inst->src.addr_mode == MODE_REG) { - //reg to mem - early_cycles = 8; - int8_t dir; - switch (inst->dst.addr_mode) - { - case MODE_AREG_INDIRECT: - case MODE_AREG_PREDEC: - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - break; - case MODE_AREG_DISPLACE: - early_cycles += BUS; - reg = SCRATCH2; - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - break; - case MODE_AREG_INDEX_DISP8: - early_cycles += 6; - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } - } else { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D); - } - if (inst->dst.params.regs.displacement) { - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - } - break; - case MODE_PC_DISPLACE: - early_cycles += BUS; - dst = mov_ir(dst, inst->dst.params.regs.displacement + inst->address+2, SCRATCH2, SZ_D); - break; - case MODE_PC_INDEX_DISP8: - early_cycles += 6; - dst = mov_ir(dst, inst->address+2, SCRATCH2, SZ_D); - sec_reg = (inst->dst.params.regs.sec >> 1) & 0x7; - if (inst->dst.params.regs.sec & 1) { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } - } else { - if (inst->dst.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D); - } - if (inst->dst.params.regs.displacement) { - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - } - break; - case MODE_ABSOLUTE: - early_cycles += 4; - case MODE_ABSOLUTE_SHORT: - early_cycles += 4; - dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D); - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); - exit(1); - } - if (inst->dst.addr_mode == MODE_AREG_PREDEC) { - reg = 15; - dir = -1; - } else { - reg = 0; - dir = 1; - } - dst = cycles(dst, early_cycles); - for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) { - if (inst->src.params.immed & (1 << bit)) { - if (inst->dst.addr_mode == MODE_AREG_PREDEC) { - dst = sub_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH2, SZ_D); - } - dst = push_r(dst, SCRATCH2); - if (reg > 7) { - if (opts->aregs[reg-8] >= 0) { - dst = mov_rr(dst, opts->aregs[reg-8], SCRATCH1, inst->extra.size); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), SCRATCH1, inst->extra.size); - } - } else { - if (opts->dregs[reg] >= 0) { - dst = mov_rr(dst, opts->dregs[reg], SCRATCH1, inst->extra.size); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), SCRATCH1, inst->extra.size); - } - } - if (inst->extra.size == OPSIZE_LONG) { - dst = call(dst, opts->write_32_lowfirst); - } else { - dst = call(dst, opts->write_16); - } - dst = pop_r(dst, SCRATCH2); - if (inst->dst.addr_mode != MODE_AREG_PREDEC) { - dst = add_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH2, SZ_D); - } - } - } - if (inst->dst.addr_mode == MODE_AREG_PREDEC) { - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, SCRATCH2, opts->aregs[inst->dst.params.regs.pri], SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - } - } else { - //mem to reg - early_cycles = 4; - switch (inst->src.addr_mode) - { - case MODE_AREG_INDIRECT: - case MODE_AREG_POSTINC: - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - break; - case MODE_AREG_DISPLACE: - early_cycles += BUS; - reg = SCRATCH2; - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - break; - case MODE_AREG_INDEX_DISP8: - early_cycles += 6; - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - break; - case MODE_PC_DISPLACE: - early_cycles += BUS; - dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D); - break; - case MODE_PC_INDEX_DISP8: - early_cycles += 6; - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - break; - case MODE_ABSOLUTE: - early_cycles += 4; - case MODE_ABSOLUTE_SHORT: - early_cycles += 4; - dst = mov_ir(dst, inst->src.params.immed, SCRATCH1, SZ_D); - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); - } - dst = cycles(dst, early_cycles); - for(reg = 0; reg < 16; reg ++) { - if (inst->dst.params.immed & (1 << reg)) { - dst = push_r(dst, SCRATCH1); - if (inst->extra.size == OPSIZE_LONG) { - dst = call(dst, opts->read_32); - } else { - dst = call(dst, opts->read_16); - } - if (inst->extra.size == OPSIZE_WORD) { - dst = movsx_rr(dst, SCRATCH1, SCRATCH1, SZ_W, SZ_D); - } - if (reg > 7) { - if (opts->aregs[reg-8] >= 0) { - dst = mov_rr(dst, SCRATCH1, opts->aregs[reg-8], SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * (reg-8), SZ_D); - } - } else { - if (opts->dregs[reg] >= 0) { - dst = mov_rr(dst, SCRATCH1, opts->dregs[reg], SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t) * (reg), SZ_D); - } - } - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, SCRATCH1, SZ_D); - } - } - if (inst->src.addr_mode == MODE_AREG_POSTINC) { - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, SCRATCH1, opts->aregs[inst->src.params.regs.pri], SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->src)), SZ_D); - } - } - } - //prefetch - dst = cycles(dst, 4); - return dst; -} - -uint8_t * translate_m68k_clr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - dst = mov_ir(dst, 0, FLAG_N, SZ_B); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = mov_ir(dst, 1, FLAG_Z, SZ_B); - int8_t reg = native_reg(&(inst->dst), opts); - if (reg >= 0) { - dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 6 : 4)); - return xor_rr(dst, reg, reg, inst->extra.size); - } - x86_ea dst_op; - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, dst_op.base, dst_op.base, inst->extra.size); - } else { - dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - dst = m68k_save_result(inst, dst, opts); - return dst; -} - -uint8_t * translate_m68k_ext(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - x86_ea dst_op; - uint8_t dst_size = inst->extra.size; - inst->extra.size--; - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = movsx_rr(dst, dst_op.base, dst_op.base, inst->extra.size, dst_size); - dst = cmp_ir(dst, 0, dst_op.base, dst_size); - } else { - dst = movsx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, inst->extra.size, dst_size); - dst = cmp_ir(dst, 0, SCRATCH1, dst_size); - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, dst_size); - } - inst->extra.size = dst_size; - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - //M68K EXT only operates on registers so no need for a call to save result here - return dst; -} - -uint8_t * translate_m68k_lea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int8_t dst_reg = native_reg(&(inst->dst), opts), sec_reg; - switch(inst->src.addr_mode) - { - case MODE_AREG_INDIRECT: - dst = cycles(dst, BUS); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - if (dst_reg >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D); - } else { - dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); - } - } else { - if (dst_reg >= 0) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, dst_reg, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); - } - } - break; - case MODE_AREG_DISPLACE: - dst = cycles(dst, 8); - if (dst_reg >= 0) { - if (inst->src.params.regs.pri != inst->dst.params.regs.pri) { - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], dst_reg, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), dst_reg, SZ_D); - } - } - dst = add_ir(dst, inst->src.params.regs.displacement, dst_reg, SZ_D); - } else { - if (inst->src.params.regs.pri != inst->dst.params.regs.pri) { - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rrdisp8(dst, opts->aregs[inst->src.params.regs.pri], CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - } - dst = add_irdisp8(dst, inst->src.params.regs.displacement, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - break; - case MODE_AREG_INDEX_DISP8: - dst = cycles(dst, 12); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH2, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH2, SZ_D); - } - if (dst_reg >= 0) { - dst = mov_rr(dst, SCRATCH2, dst_reg, SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - break; - case MODE_PC_DISPLACE: - dst = cycles(dst, 8); - if (dst_reg >= 0) { - dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, dst_reg, SZ_D); - } else { - dst = mov_irdisp8(dst, inst->src.params.regs.displacement + inst->address+2, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->dst.params.regs.pri, SZ_D); - } - break; - case MODE_PC_INDEX_DISP8: - dst = cycles(dst, BUS*3); - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - if (dst_reg >= 0) { - dst = mov_rr(dst, SCRATCH1, dst_reg, SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - dst = cycles(dst, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2); - if (dst_reg >= 0) { - dst = mov_ir(dst, inst->src.params.immed, dst_reg, SZ_D); - } else { - dst = mov_irdisp8(dst, inst->src.params.immed, CONTEXT, reg_offset(&(inst->dst)), SZ_D); - } - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); - } - return dst; -} - -uint8_t * translate_m68k_pea(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t sec_reg; - switch(inst->src.addr_mode) - { - case MODE_AREG_INDIRECT: - dst = cycles(dst, BUS); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); - } - break; - case MODE_AREG_DISPLACE: - dst = cycles(dst, 8); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - break; - case MODE_AREG_INDEX_DISP8: - dst = cycles(dst, 6);//TODO: Check to make sure this is correct - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - break; - case MODE_PC_DISPLACE: - dst = cycles(dst, 8); - dst = mov_ir(dst, inst->src.params.regs.displacement + inst->address+2, SCRATCH1, SZ_D); - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - dst = cycles(dst, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2); - dst = mov_ir(dst, inst->src.params.immed, SCRATCH1, SZ_D); - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_lowfirst); - return dst; -} - -uint8_t * translate_m68k_bsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int32_t disp = inst->src.params.immed; - uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4); - //TODO: Add cycles in the right place relative to pushing the return address on the stack - dst = cycles(dst, 10); - dst = mov_ir(dst, after, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - uint8_t * dest_addr = get_native_address(opts->native_code_map, (inst->address+2) + disp); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, (inst->address+2) + disp, dst + 1); - //dummy address to be replaced later - dest_addr = dst + 256; - } - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call(dst, (char *)dest_addr); - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } else { - dst = jmp(dst, (char *)dest_addr); - } - return dst; -} - -uint8_t * translate_m68k_bcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - dst = cycles(dst, 10);//TODO: Adjust this for branch not taken case - int32_t disp = inst->src.params.immed; - uint32_t after = inst->address + 2; - uint8_t * dest_addr = get_native_address(opts->native_code_map, after + disp); - if (inst->extra.cond == COND_TRUE) { - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, after + disp, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - dst = jmp(dst, dest_addr); - } else { - uint8_t cond = CC_NZ; - switch (inst->extra.cond) - { - case COND_HIGH: - cond = CC_Z; - case COND_LOW_SAME: - dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B); - break; - case COND_CARRY_CLR: - cond = CC_Z; - case COND_CARRY_SET: - dst = cmp_ir(dst, 0, FLAG_C, SZ_B); - break; - case COND_NOT_EQ: - cond = CC_Z; - case COND_EQ: - dst = cmp_ir(dst, 0, FLAG_Z, SZ_B); - break; - case COND_OVERF_CLR: - cond = CC_Z; - case COND_OVERF_SET: - dst = cmp_ir(dst, 0, FLAG_V, SZ_B); - break; - case COND_PLUS: - cond = CC_Z; - case COND_MINUS: - dst = cmp_ir(dst, 0, FLAG_N, SZ_B); - break; - case COND_GREATER_EQ: - cond = CC_Z; - case COND_LESS: - dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B); - break; - case COND_GREATER: - cond = CC_Z; - case COND_LESS_EQ: - dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B); - dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - break; - } - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, after + disp, dst + 2); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - dst = jcc(dst, cond, dest_addr); - } - return dst; -} - -uint8_t * translate_m68k_scc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t cond = inst->extra.cond; - x86_ea dst_op; - inst->extra.size = OPSIZE_BYTE; - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 1); - if (cond == COND_TRUE || cond == COND_FALSE) { - if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) { - dst = cycles(dst, 6); - } else { - dst = cycles(dst, BUS); - } - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_ir(dst, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B); - } else { - dst = mov_irdisp8(dst, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B); - } - } else { - uint8_t cc = CC_NZ; - switch (cond) - { - case COND_HIGH: - cc = CC_Z; - case COND_LOW_SAME: - dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B); - break; - case COND_CARRY_CLR: - cc = CC_Z; - case COND_CARRY_SET: - dst = cmp_ir(dst, 0, FLAG_C, SZ_B); - break; - case COND_NOT_EQ: - cc = CC_Z; - case COND_EQ: - dst = cmp_ir(dst, 0, FLAG_Z, SZ_B); - break; - case COND_OVERF_CLR: - cc = CC_Z; - case COND_OVERF_SET: - dst = cmp_ir(dst, 0, FLAG_V, SZ_B); - break; - case COND_PLUS: - cc = CC_Z; - case COND_MINUS: - dst = cmp_ir(dst, 0, FLAG_N, SZ_B); - break; - case COND_GREATER_EQ: - cc = CC_Z; - case COND_LESS: - dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B); - break; - case COND_GREATER: - cc = CC_Z; - case COND_LESS_EQ: - dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B); - dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - break; - } - uint8_t *true_off = dst + 1; - dst = jcc(dst, cc, dst+2); - dst = cycles(dst, BUS); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_ir(dst, 0, dst_op.base, SZ_B); - } else { - dst = mov_irdisp8(dst, 0, dst_op.base, dst_op.disp, SZ_B); - } - uint8_t *end_off = dst+1; - dst = jmp(dst, dst+2); - *true_off = dst - (true_off+1); - dst = cycles(dst, 6); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_ir(dst, 0xFF, dst_op.base, SZ_B); - } else { - dst = mov_irdisp8(dst, 0xFF, dst_op.base, dst_op.disp, SZ_B); - } - *end_off = dst - (end_off+1); - } - dst = m68k_save_result(inst, dst, opts); - return dst; -} - -uint8_t * translate_m68k_jmp(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t * dest_addr, sec_reg; - uint32_t m68k_addr; - switch(inst->src.addr_mode) - { - case MODE_AREG_INDIRECT: - dst = cycles(dst, BUS*2); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - break; - case MODE_AREG_INDEX_DISP8: - dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - //32-bit index register - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - //16-bit index register - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - break; - case MODE_PC_DISPLACE: - dst = cycles(dst, 10); - m68k_addr = inst->src.params.regs.displacement + inst->address + 2; - if ((m68k_addr & 0xFFFFFF) < 0x400000) { - dest_addr = get_native_address(opts->native_code_map, m68k_addr); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - dst = jmp(dst, dest_addr); - } else { - dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - } - break; - case MODE_PC_INDEX_DISP8: - dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - dst = cycles(dst, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10); - m68k_addr = inst->src.params.immed; - if ((m68k_addr & 0xFFFFFF) < 0x400000) { - dest_addr = get_native_address(opts->native_code_map, m68k_addr); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - dst = jmp(dst, dest_addr); - } else { - dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - } - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%s\naddress mode %d not yet supported (jmp)\n", disasm_buf, inst->src.addr_mode); - exit(1); - } - return dst; -} - -uint8_t * translate_m68k_jsr(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t * dest_addr, sec_reg; - uint32_t after; - uint32_t m68k_addr; - switch(inst->src.addr_mode) - { - case MODE_AREG_INDIRECT: - dst = cycles(dst, BUS*2); - dst = mov_ir(dst, inst->address + 2, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - break; - case MODE_AREG_DISPLACE: - dst = cycles(dst, BUS*2); - dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + 4 * inst->src.params.regs.pri, SCRATCH1, SZ_D); - } - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - break; - case MODE_AREG_INDEX_DISP8: - dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct - dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - break; - case MODE_PC_DISPLACE: - //TODO: Add cycles in the right place relative to pushing the return address on the stack - dst = cycles(dst, 10); - dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - m68k_addr = inst->src.params.regs.displacement + inst->address + 2; - if ((m68k_addr & 0xFFFFFF) < 0x400000) { - dest_addr = get_native_address(opts->native_code_map, m68k_addr); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call(dst, (char *)dest_addr); - } else { - dst = jmp(dst, dest_addr); - } - } else { - dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - } - if (opts->flags & OPT_NATIVE_CALL_STACK) { - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } - break; - case MODE_PC_INDEX_DISP8: - dst = cycles(dst, BUS*3);//TODO: CHeck that this is correct - dst = mov_ir(dst, inst->address + 4, SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - sec_reg = (inst->src.params.regs.sec >> 1) & 0x7; - if (inst->src.params.regs.sec & 1) { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->aregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = add_rr(dst, opts->dregs[sec_reg], SCRATCH1, SZ_D); - } else { - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH1, SZ_D); - } - } - } else { - if (inst->src.params.regs.sec & 0x10) { - if (opts->aregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->aregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } else { - if (opts->dregs[sec_reg] >= 0) { - dst = movsx_rr(dst, opts->dregs[sec_reg], SCRATCH2, SZ_W, SZ_D); - } else { - dst = movsx_rdisp8r(dst, CONTEXT, offsetof(m68k_context, dregs) + sizeof(uint32_t)*sec_reg, SCRATCH2, SZ_W, SZ_D); - } - } - dst = add_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - break; - case MODE_ABSOLUTE: - case MODE_ABSOLUTE_SHORT: - //TODO: Add cycles in the right place relative to pushing the return address on the stack - dst = cycles(dst, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10); - dst = mov_ir(dst, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4), SCRATCH1, SZ_D); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = push_r(dst, SCRATCH1); - } - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_highfirst); - m68k_addr = inst->src.params.immed; - if ((m68k_addr & 0xFFFFFF) < 0x400000) { - dest_addr = get_native_address(opts->native_code_map, m68k_addr); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, m68k_addr, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call(dst, (char *)dest_addr); - } else { - dst = jmp(dst, dest_addr); - } - } else { - dst = mov_ir(dst, m68k_addr, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)m68k_native_addr); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = call_r(dst, SCRATCH1); - } else { - dst = jmp_r(dst, SCRATCH1); - } - } - if (opts->flags & OPT_NATIVE_CALL_STACK) { - //would add_ir(dst, 8, RSP, SZ_Q) be faster here? - dst = pop_r(dst, SCRATCH1); - } - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%s\naddress mode %d not yet supported (jsr)\n", disasm_buf, inst->src.addr_mode); - exit(1); - } - return dst; -} - -uint8_t * translate_m68k_rts(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - //TODO: Add cycles - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = add_ir(dst, 4, opts->aregs[7], SZ_D); - dst = call(dst, opts->read_32); - if (opts->flags & OPT_NATIVE_CALL_STACK) { - dst = cmp_rdisp8r(dst, RSP, 8, SCRATCH1, SZ_D); - dst = jcc(dst, CC_NZ, dst+3); - dst = retn(dst); - dst = jmp(dst, (char *)m68k_modified_ret_addr); - } else { - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - } - return dst; -} - -uint8_t * translate_m68k_dbcc(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - //best case duration - dst = cycles(dst, 10); - uint8_t * skip_loc = NULL; - //TODO: Check if COND_TRUE technically valid here even though - //it's basically a slow NOP - if (inst->extra.cond != COND_FALSE) { - uint8_t cond = CC_NZ; - switch (inst->extra.cond) - { - case COND_HIGH: - cond = CC_Z; - case COND_LOW_SAME: - dst = mov_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_C, SCRATCH1, SZ_B); - break; - case COND_CARRY_CLR: - cond = CC_Z; - case COND_CARRY_SET: - dst = cmp_ir(dst, 0, FLAG_C, SZ_B); - break; - case COND_NOT_EQ: - cond = CC_Z; - case COND_EQ: - dst = cmp_ir(dst, 0, FLAG_Z, SZ_B); - break; - case COND_OVERF_CLR: - cond = CC_Z; - case COND_OVERF_SET: - dst = cmp_ir(dst, 0, FLAG_V, SZ_B); - break; - case COND_PLUS: - cond = CC_Z; - case COND_MINUS: - dst = cmp_ir(dst, 0, FLAG_N, SZ_B); - break; - case COND_GREATER_EQ: - cond = CC_Z; - case COND_LESS: - dst = cmp_rr(dst, FLAG_N, FLAG_V, SZ_B); - break; - case COND_GREATER: - cond = CC_Z; - case COND_LESS_EQ: - dst = mov_rr(dst, FLAG_V, SCRATCH1, SZ_B); - dst = xor_rr(dst, FLAG_N, SCRATCH1, SZ_B); - dst = or_rr(dst, FLAG_Z, SCRATCH1, SZ_B); - break; - } - skip_loc = dst + 1; - dst = jcc(dst, cond, dst + 2); - } - if (opts->dregs[inst->dst.params.regs.pri] >= 0) { - dst = sub_ir(dst, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W); - dst = cmp_ir(dst, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W); - } else { - dst = sub_irdisp8(dst, 1, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); - dst = cmp_irdisp8(dst, -1, CONTEXT, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W); - } - uint8_t *loop_end_loc = dst+1; - dst = jcc(dst, CC_Z, dst+2); - uint32_t after = inst->address + 2; - uint8_t * dest_addr = get_native_address(opts->native_code_map, after + inst->src.params.immed); - if (!dest_addr) { - opts->deferred = defer_address(opts->deferred, after + inst->src.params.immed, dst + 1); - //dummy address to be replaced later, make sure it generates a 4-byte displacement - dest_addr = dst + 256; - } - dst = jmp(dst, dest_addr); - *loop_end_loc = dst - (loop_end_loc+1); - if (skip_loc) { - dst = cycles(dst, 2); - *skip_loc = dst - (skip_loc+1); - dst = cycles(dst, 2); - } else { - dst = cycles(dst, 4); - } - return dst; -} - -uint8_t * translate_m68k_link(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int8_t reg = native_reg(&(inst->src), opts); - //compensate for displacement word - dst = cycles(dst, BUS); - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - if (reg >= 0) { - dst = mov_rr(dst, reg, SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - dst = call(dst, opts->write_32_highfirst); - if (reg >= 0) { - dst = mov_rr(dst, opts->aregs[7], reg, SZ_D); - } else { - dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, reg_offset(&(inst->src)), SZ_D); - } - dst = add_ir(dst, inst->dst.params.immed, opts->aregs[7], SZ_D); - //prefetch - dst = cycles(dst, BUS); - return dst; -} - -uint8_t * translate_m68k_movep(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - int8_t reg; - dst = cycles(dst, BUS*2); - if (inst->src.addr_mode == MODE_REG) { - if (opts->aregs[inst->dst.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D); - } - if (inst->dst.params.regs.displacement) { - dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D); - } - reg = native_reg(&(inst->src), opts); - if (inst->extra.size == OPSIZE_LONG) { - if (reg >= 0) { - dst = mov_rr(dst, reg, SCRATCH1, SZ_D); - dst = shr_ir(dst, 24, SCRATCH1, SZ_D); - dst = push_r(dst, SCRATCH2); - dst = call(dst, opts->write_8); - dst = pop_r(dst, SCRATCH2); - dst = mov_rr(dst, reg, SCRATCH1, SZ_D); - dst = shr_ir(dst, 16, SCRATCH1, SZ_D); - - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+3, SCRATCH1, SZ_B); - dst = push_r(dst, SCRATCH2); - dst = call(dst, opts->write_8); - dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+2, SCRATCH1, SZ_B); - } - dst = add_ir(dst, 2, SCRATCH2, SZ_D); - dst = push_r(dst, SCRATCH2); - dst = call(dst, opts->write_8); - dst = pop_r(dst, SCRATCH2); - dst = add_ir(dst, 2, SCRATCH2, SZ_D); - } - if (reg >= 0) { - dst = mov_rr(dst, reg, SCRATCH1, SZ_W); - dst = shr_ir(dst, 8, SCRATCH1, SZ_W); - dst = push_r(dst, SCRATCH2); - dst = call(dst, opts->write_8); - dst = pop_r(dst, SCRATCH2); - dst = mov_rr(dst, reg, SCRATCH1, SZ_W); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src))+1, SCRATCH1, SZ_B); - dst = push_r(dst, SCRATCH2); - dst = call(dst, opts->write_8); - dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_B); - } - dst = add_ir(dst, 2, SCRATCH2, SZ_D); - dst = call(dst, opts->write_8); - } else { - if (opts->aregs[inst->src.params.regs.pri] >= 0) { - dst = mov_rr(dst, opts->aregs[inst->src.params.regs.pri], SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, reg_offset(&(inst->src)), SCRATCH1, SZ_D); - } - if (inst->src.params.regs.displacement) { - dst = add_ir(dst, inst->src.params.regs.displacement, SCRATCH1, SZ_D); - } - reg = native_reg(&(inst->dst), opts); - if (inst->extra.size == OPSIZE_LONG) { - if (reg >= 0) { - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_8); - dst = shl_ir(dst, 24, SCRATCH1, SZ_D); - dst = mov_rr(dst, SCRATCH1, reg, SZ_D); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_8); - dst = shl_ir(dst, 16, SCRATCH1, SZ_D); - dst = or_rr(dst, SCRATCH1, reg, SZ_D); - } else { - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_8); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+3, SZ_B); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_8); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+2, SZ_B); - } - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - } - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_8); - if (reg >= 0) { - - dst = shl_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_rr(dst, SCRATCH1, reg, SZ_W); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - dst = call(dst, opts->read_8); - dst = mov_rr(dst, SCRATCH1, reg, SZ_B); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst))+1, SZ_B); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - dst = call(dst, opts->read_8); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, reg_offset(&(inst->dst)), SZ_B); - } - } - return dst; -} - -uint8_t * translate_m68k_cmp(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t size = inst->extra.size; - x86_ea src_op, dst_op; - dst = translate_m68k_src(inst, &src_op, dst, opts); - if (inst->dst.addr_mode == MODE_AREG_POSTINC) { - dst = push_r(dst, SCRATCH1); - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0); - dst = pop_r(dst, SCRATCH2); - src_op.base = SCRATCH2; - } else { - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0); - if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { - size = OPSIZE_LONG; - } - } - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = cmp_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, src_op.disp, dst_op.base, size); - } else { - dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - return dst; -} - -typedef uint8_t * (*shift_ir_t)(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size); -typedef uint8_t * (*shift_irdisp8_t)(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size); -typedef uint8_t * (*shift_clr_t)(uint8_t * out, uint8_t dst, uint8_t size); -typedef uint8_t * (*shift_clrdisp8_t)(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size); - -uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, x86_68k_options * opts, shift_ir_t shift_ir, shift_irdisp8_t shift_irdisp8, shift_clr_t shift_clr, shift_clrdisp8_t shift_clrdisp8, shift_ir_t special, shift_irdisp8_t special_disp8) -{ - uint8_t * end_off = NULL; - uint8_t * nz_off = NULL; - uint8_t * z_off = NULL; - if (inst->src.addr_mode == MODE_UNUSED) { - dst = cycles(dst, BUS); - //Memory shift - dst = shift_ir(dst, 1, dst_op->base, SZ_W); - } else { - dst = cycles(dst, inst->extra.size == OPSIZE_LONG ? 8 : 6); - if (src_op->mode == MODE_IMMED) { - if (src_op->disp != 1 && inst->op == M68K_ASL) { - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - for (int i = 0; i < src_op->disp; i++) { - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); - } else { - dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); - } - //dst = setcc_r(dst, CC_O, FLAG_V); - dst = jcc(dst, CC_NO, dst+4); - dst = mov_ir(dst, 1, FLAG_V, SZ_B); - } - } else { - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size); - } else { - dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); - } - dst = setcc_r(dst, CC_O, FLAG_V); - } - } else { - if (src_op->base != RCX) { - if (src_op->mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op->base, RCX, SZ_B); - } else { - dst = mov_rdisp8r(dst, src_op->base, src_op->disp, RCX, SZ_B); - } - - } - dst = and_ir(dst, 63, RCX, SZ_D); - nz_off = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - //Flag behavior for shift count of 0 is different for x86 than 68K - if (dst_op->mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, 0, dst_op->base, inst->extra.size); - } else { - dst = cmp_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size); - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - //For other instructions, this flag will be set below - if (inst->op == M68K_ASL) { - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - } - z_off = dst+1; - dst = jmp(dst, dst+2); - *nz_off = dst - (nz_off + 1); - //add 2 cycles for every bit shifted - dst = add_rr(dst, RCX, CYCLES, SZ_D); - dst = add_rr(dst, RCX, CYCLES, SZ_D); - if (inst->op == M68K_ASL) { - //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB - //Easiest way to deal with this is to shift one bit at a time - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - uint8_t * loop_start = dst; - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); - } else { - dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); - } - //dst = setcc_r(dst, CC_O, FLAG_V); - dst = jcc(dst, CC_NO, dst+4); - dst = mov_ir(dst, 1, FLAG_V, SZ_B); - dst = loop(dst, loop_start); - } else { - //x86 shifts modulo 32 for operand sizes less than 64-bits - //but M68K shifts modulo 64, so we need to check for large shifts here - dst = cmp_ir(dst, 32, RCX, SZ_B); - uint8_t * norm_shift_off = dst + 1; - dst = jcc(dst, CC_L, dst+2); - if (special) { - if (inst->extra.size == OPSIZE_LONG) { - uint8_t * neq_32_off = dst + 1; - dst = jcc(dst, CC_NZ, dst+2); - - //set the carry bit to the lsb - if (dst_op->mode == MODE_REG_DIRECT) { - dst = special(dst, 1, dst_op->base, SZ_D); - } else { - dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = jmp(dst, dst+4); - *neq_32_off = dst - (neq_32_off+1); - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = mov_ir(dst, 1, FLAG_Z, SZ_B); - dst = mov_ir(dst, 0, FLAG_N, SZ_B); - if (dst_op->mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size); - } else { - dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size); - } - } else { - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_ir(dst, 31, dst_op->base, inst->extra.size); - dst = shift_ir(dst, 1, dst_op->base, inst->extra.size); - } else { - dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size); - dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size); - } - - } - end_off = dst+1; - dst = jmp(dst, dst+2); - *norm_shift_off = dst - (norm_shift_off+1); - if (dst_op->mode == MODE_REG_DIRECT) { - dst = shift_clr(dst, dst_op->base, inst->extra.size); - } else { - dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size); - } - } - } - - } - if (!special && end_off) { - *end_off = dst - (end_off + 1); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - if (special && end_off) { - *end_off = dst - (end_off + 1); - } - //set X flag to same as C flag - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - if (z_off) { - *z_off = dst - (z_off + 1); - } - if (inst->op != M68K_ASL) { - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - } - if (inst->src.addr_mode == MODE_UNUSED) { - dst = m68k_save_result(inst, dst, opts); - } - return dst; -} - -#define BIT_SUPERVISOR 5 - -uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts) -{ - uint8_t * end_off, *zero_off, *norm_off; - uint8_t dst_reg; - dst = check_cycles_int(dst, inst->address, opts); - if (inst->op == M68K_MOVE) { - return translate_m68k_move(dst, inst, opts); - } else if(inst->op == M68K_LEA) { - return translate_m68k_lea(dst, inst, opts); - } else if(inst->op == M68K_PEA) { - return translate_m68k_pea(dst, inst, opts); - } else if(inst->op == M68K_BSR) { - return translate_m68k_bsr(dst, inst, opts); - } else if(inst->op == M68K_BCC) { - return translate_m68k_bcc(dst, inst, opts); - } else if(inst->op == M68K_JMP) { - return translate_m68k_jmp(dst, inst, opts); - } else if(inst->op == M68K_JSR) { - return translate_m68k_jsr(dst, inst, opts); - } else if(inst->op == M68K_RTS) { - return translate_m68k_rts(dst, inst, opts); - } else if(inst->op == M68K_DBCC) { - return translate_m68k_dbcc(dst, inst, opts); - } else if(inst->op == M68K_CLR) { - return translate_m68k_clr(dst, inst, opts); - } else if(inst->op == M68K_MOVEM) { - return translate_m68k_movem(dst, inst, opts); - } else if(inst->op == M68K_LINK) { - return translate_m68k_link(dst, inst, opts); - } else if(inst->op == M68K_EXT) { - return translate_m68k_ext(dst, inst, opts); - } else if(inst->op == M68K_SCC) { - return translate_m68k_scc(dst, inst, opts); - } else if(inst->op == M68K_MOVEP) { - return translate_m68k_movep(dst, inst, opts); - } else if(inst->op == M68K_INVALID) { - if (inst->src.params.immed == 0x7100) { - return retn(dst); - } - dst = mov_ir(dst, inst->address, SCRATCH1, SZ_D); - return call(dst, (uint8_t *)m68k_invalid); - } else if(inst->op == M68K_CMP) { - return translate_m68k_cmp(dst, inst, opts); - } - x86_ea src_op, dst_op; - if (inst->src.addr_mode != MODE_UNUSED) { - dst = translate_m68k_src(inst, &src_op, dst, opts); - } - if (inst->dst.addr_mode != MODE_UNUSED) { - dst = translate_m68k_dst(inst, &dst_op, dst, opts, 0); - } - uint8_t size; - switch(inst->op) - { - case M68K_ABCD: - if (src_op.base != SCRATCH2) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B); - } - } - if (dst_op.base != SCRATCH1) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B); - } else { - dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B); - } - } - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - dst = jcc(dst, CC_NC, dst+5); - dst = add_ir(dst, 1, SCRATCH1, SZ_B); - dst = call(dst, (uint8_t *)bcd_add); - dst = mov_rr(dst, CH, FLAG_C, SZ_B); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = cmp_ir(dst, 0, SCRATCH1, SZ_B); - dst = jcc(dst, CC_Z, dst+4); - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - if (dst_op.base != SCRATCH1) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B); - } - } - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_ADD: - dst = cycles(dst, BUS); - size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = add_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = add_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = add_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = add_ir(dst, src_op.disp, dst_op.base, size); - } else { - dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size); - } - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - } - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_ADDX: - dst = cycles(dst, BUS); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = adc_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else { - dst = adc_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = adc_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = adc_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = adc_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = jcc(dst, CC_Z, dst+4); - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_AND: - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = and_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else { - dst = and_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = and_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = and_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = and_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_ANDI_CCR: - case M68K_ANDI_SR: - dst = cycles(dst, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode - if (!(inst->src.params.immed & 0x1)) { - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - } - if (!(inst->src.params.immed & 0x2)) { - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - } - if (!(inst->src.params.immed & 0x4)) { - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - } - if (!(inst->src.params.immed & 0x8)) { - dst = mov_ir(dst, 0, FLAG_N, SZ_B); - } - if (!(inst->src.params.immed & 0x10)) { - dst = mov_irind(dst, 0, CONTEXT, SZ_B); - } - if (inst->op == M68K_ANDI_SR) { - dst = and_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_B); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_B); - } - //dst = call(dst, (uint8_t *)debug_print_sr); - if (inst->src.params.immed & 0x700) { - dst = call(dst, (uint8_t *)do_sync); - } - } - break; - case M68K_ASL: - case M68K_LSL: - dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shl_ir, shl_irdisp8, shl_clr, shl_clrdisp8, shr_ir, shr_irdisp8); - break; - case M68K_ASR: - dst = translate_shift(dst, inst, &src_op, &dst_op, opts, sar_ir, sar_irdisp8, sar_clr, sar_clrdisp8, NULL, NULL); - break; - case M68K_LSR: - dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shr_ir, shr_irdisp8, shr_clr, shr_clrdisp8, shl_ir, shl_irdisp8); - break; - case M68K_BCHG: - case M68K_BCLR: - case M68K_BSET: - case M68K_BTST: - dst = cycles(dst, inst->extra.size == OPSIZE_BYTE ? 4 : ( - inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) - ); - if (src_op.mode == MODE_IMMED) { - if (inst->extra.size == OPSIZE_BYTE) { - src_op.disp &= 0x7; - } - if (inst->op == M68K_BTST) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = bt_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = bt_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (inst->op == M68K_BSET) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = bts_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = bts_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (inst->op == M68K_BCLR) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = btr_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = btr_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = btc_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = btc_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - } else { - if (src_op.mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op.base != SCRATCH1 && src_op.base != SCRATCH2)) { - if (dst_op.base == SCRATCH1) { - dst = push_r(dst, SCRATCH2); - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B); - } - src_op.base = SCRATCH2; - } else { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B); - } - src_op.base = SCRATCH1; - } - } - uint8_t size = inst->extra.size; - if (dst_op.mode == MODE_REG_DISPLACE8) { - if (src_op.base != SCRATCH1 && src_op.base != SCRATCH2) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_D); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D); - src_op.mode = MODE_REG_DIRECT; - } - src_op.base = SCRATCH1; - } - //b### with register destination is modulo 32 - //x86 with a memory destination isn't modulo anything - //so use an and here to force the value to be modulo 32 - dst = and_ir(dst, 31, SCRATCH1, SZ_D); - } else if(inst->dst.addr_mode != MODE_REG) { - //b### with memory destination is modulo 8 - //x86-64 doesn't support 8-bit bit operations - //so we fake it by forcing the bit number to be modulo 8 - dst = and_ir(dst, 7, src_op.base, SZ_D); - size = SZ_D; - } - if (inst->op == M68K_BTST) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = bt_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = bt_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else if (inst->op == M68K_BSET) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = bts_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = bts_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else if (inst->op == M68K_BCLR) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = btr_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = btr_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = btc_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = btc_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } - if (src_op.base == SCRATCH2) { - dst = pop_r(dst, SCRATCH2); - } - } - //x86 sets the carry flag to the value of the bit tested - //68K sets the zero flag to the complement of the bit tested - dst = setcc_r(dst, CC_NC, FLAG_Z); - if (inst->op != M68K_BTST) { - dst = m68k_save_result(inst, dst, opts); - } - break; - case M68K_CHK: - { - dst = cycles(dst, 6); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - } else { - dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - uint32_t isize; - switch(inst->src.addr_mode) - { - case MODE_AREG_DISPLACE: - case MODE_AREG_INDEX_DISP8: - case MODE_ABSOLUTE_SHORT: - case MODE_PC_INDEX_DISP8: - case MODE_PC_DISPLACE: - case MODE_IMMEDIATE: - isize = 4; - break; - case MODE_ABSOLUTE: - isize = 6; - break; - default: - isize = 2; - } - uint8_t * passed = dst+1; - dst = jcc(dst, CC_GE, dst+2); - dst = mov_ir(dst, 1, FLAG_N, SZ_B); - dst = mov_ir(dst, VECTOR_CHK, SCRATCH2, SZ_D); - dst = mov_ir(dst, inst->address+isize, SCRATCH1, SZ_D); - dst = jmp(dst, opts->trap); - *passed = dst - (passed+1); - if (dst_op.mode == MODE_REG_DIRECT) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = cmp_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else if(src_op.mode == MODE_REG_DISPLACE8) { - dst = cmp_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = cmp_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } - } else if(dst_op.mode == MODE_REG_DISPLACE8) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = cmp_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = cmp_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - passed = dst+1; - dst = jcc(dst, CC_LE, dst+2); - dst = mov_ir(dst, 0, FLAG_N, SZ_B); - dst = mov_ir(dst, VECTOR_CHK, SCRATCH2, SZ_D); - dst = mov_ir(dst, inst->address+isize, SCRATCH1, SZ_D); - dst = jmp(dst, opts->trap); - *passed = dst - (passed+1); - dst = cycles(dst, 4); - break; - } - case M68K_DIVS: - case M68K_DIVU: - { - //TODO: cycle exact division - dst = cycles(dst, inst->op == M68K_DIVS ? 158 : 140); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = push_r(dst, RDX); - dst = push_r(dst, RAX); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, dst_op.base, RAX, SZ_D); - } else { - dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, RAX, SZ_D); - } - if (src_op.mode == MODE_IMMED) { - dst = mov_ir(dst, (src_op.disp & 0x8000) && inst->op == M68K_DIVS ? src_op.disp | 0xFFFF0000 : src_op.disp, SCRATCH2, SZ_D); - } else if (src_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_DIVS) { - dst = movsx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D); - } else { - dst = movzx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - if (inst->op == M68K_DIVS) { - dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D); - } else { - dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D); - } - } - dst = cmp_ir(dst, 0, SCRATCH2, SZ_D); - uint8_t * not_zero = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - dst = pop_r(dst, RAX); - dst = pop_r(dst, RDX); - dst = mov_ir(dst, VECTOR_INT_DIV_ZERO, SCRATCH2, SZ_D); - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - dst = jmp(dst, opts->trap); - *not_zero = dst - (not_zero+1); - if (inst->op == M68K_DIVS) { - dst = cdq(dst); - } else { - dst = xor_rr(dst, RDX, RDX, SZ_D); - } - if (inst->op == M68K_DIVS) { - dst = idiv_r(dst, SCRATCH2, SZ_D); - } else { - dst = div_r(dst, SCRATCH2, SZ_D); - } - uint8_t * skip_sec_check; - if (inst->op == M68K_DIVS) { - dst = cmp_ir(dst, 0x8000, RAX, SZ_D); - skip_sec_check = dst + 1; - dst = jcc(dst, CC_GE, dst+2); - dst = cmp_ir(dst, -0x8000, RAX, SZ_D); - norm_off = dst+1; - dst = jcc(dst, CC_L, dst+2); - } else { - dst = cmp_ir(dst, 0x10000, RAX, SZ_D); - norm_off = dst+1; - dst = jcc(dst, CC_NC, dst+2); - } - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, RDX, dst_op.base, SZ_W); - dst = shl_ir(dst, 16, dst_op.base, SZ_D); - dst = mov_rr(dst, RAX, dst_op.base, SZ_W); - } else { - dst = mov_rrdisp8(dst, RDX, dst_op.base, dst_op.disp, SZ_W); - dst = shl_irdisp8(dst, 16, dst_op.base, dst_op.disp, SZ_D); - dst = mov_rrdisp8(dst, RAX, dst_op.base, dst_op.disp, SZ_W); - } - dst = cmp_ir(dst, 0, RAX, SZ_W); - dst = pop_r(dst, RAX); - dst = pop_r(dst, RDX); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - end_off = dst+1; - dst = jmp(dst, dst+2); - *norm_off = dst - (norm_off + 1); - if (inst->op == M68K_DIVS) { - *skip_sec_check = dst - (skip_sec_check+1); - } - dst = pop_r(dst, RAX); - dst = pop_r(dst, RDX); - dst = mov_ir(dst, 1, FLAG_V, SZ_B); - *end_off = dst - (end_off + 1); - break; - } - case M68K_EOR: - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else { - dst = xor_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = xor_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = xor_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = xor_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_EORI_CCR: - case M68K_EORI_SR: - dst = cycles(dst, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode - if (inst->src.params.immed & 0x1) { - dst = xor_ir(dst, 1, FLAG_C, SZ_B); - } - if (inst->src.params.immed & 0x2) { - dst = xor_ir(dst, 1, FLAG_V, SZ_B); - } - if (inst->src.params.immed & 0x4) { - dst = xor_ir(dst, 1, FLAG_Z, SZ_B); - } - if (inst->src.params.immed & 0x8) { - dst = xor_ir(dst, 1, FLAG_N, SZ_B); - } - if (inst->src.params.immed & 0x10) { - dst = xor_irdisp8(dst, 1, CONTEXT, 0, SZ_B); - } - if (inst->op == M68K_ORI_SR) { - dst = xor_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B); - //dst = call(dst, (uint8_t *)debug_print_sr); - if (inst->src.params.immed & 0x700) { - dst = call(dst, (uint8_t *)do_sync); - } - } - break; - case M68K_EXG: - dst = cycles(dst, 6); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, dst_op.base, SCRATCH2, SZ_D); - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, dst_op.base, SZ_D); - dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); - } - } else { - dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_D); - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, SZ_D); - dst = mov_rr(dst, SCRATCH2, src_op.base, SZ_D); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH2, src_op.base, src_op.disp, SZ_D); - } - } - break; - case M68K_ILLEGAL: - dst = call(dst, (uint8_t *)m68k_save_context); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = call(dst, (uint8_t *)print_regs_exit); - break; - case M68K_MOVE_FROM_SR: - //TODO: Trap if not in system mode - dst = call(dst, (uint8_t *)get_sr); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_W); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_W); - } - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_MOVE_CCR: - case M68K_MOVE_SR: - //TODO: Privilege check for MOVE to SR - if (src_op.mode == MODE_IMMED) { - dst = mov_ir(dst, src_op.disp & 0x1, FLAG_C, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 1) & 0x1, FLAG_V, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 2) & 0x1, FLAG_Z, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 3) & 0x1, FLAG_N, SZ_B); - dst = mov_irind(dst, (src_op.disp >> 4) & 0x1, CONTEXT, SZ_B); - if (inst->op == M68K_MOVE_SR) { - dst = mov_irdisp8(dst, (src_op.disp >> 8), CONTEXT, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - } - //dst = call(dst, (uint8_t *)debug_print_sr); - dst = call(dst, (uint8_t *)do_sync); - } - dst = cycles(dst, 12); - } else { - if (src_op.base != SCRATCH1) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W); - } - } - dst = call(dst, (uint8_t *)(inst->op == M68K_MOVE_SR ? set_sr : set_ccr)); - dst = cycles(dst, 12); - - } - break; - case M68K_MOVE_USP: - dst = cycles(dst, BUS); - //TODO: Trap if not in supervisor mode - //dst = bt_irdisp8(dst, BIT_SUPERVISOR, CONTEXT, offsetof(m68k_context, status), SZ_B); - if (inst->src.addr_mode == MODE_UNUSED) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, dst_op.base, SZ_D); - } else { - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D); - } - } else { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rrdisp8(dst, src_op.base, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - } - } - break; - //case M68K_MOVEP: - case M68K_MULS: - case M68K_MULU: - dst = cycles(dst, 70); //TODO: Calculate the actual value based on the value of the parameter - if (src_op.mode == MODE_IMMED) { - dst = mov_ir(dst, inst->op == M68K_MULU ? (src_op.disp & 0xFFFF) : ((src_op.disp & 0x8000) ? src_op.disp | 0xFFFF0000 : src_op.disp), SCRATCH1, SZ_D); - } else if (src_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_MULS) { - dst = movsx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D); - } else { - dst = movzx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D); - } - } else { - if (inst->op == M68K_MULS) { - dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D); - } else { - dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D); - } - } - if (dst_op.mode == MODE_REG_DIRECT) { - dst_reg = dst_op.base; - if (inst->op == M68K_MULS) { - dst = movsx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D); - } else { - dst = movzx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D); - } - } else { - dst_reg = SCRATCH2; - if (inst->op == M68K_MULS) { - dst = movsx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D); - } else { - dst = movzx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D); - } - } - dst = imul_rr(dst, SCRATCH1, dst_reg, SZ_D); - if (dst_op.mode == MODE_REG_DISPLACE8) { - dst = mov_rrdisp8(dst, dst_reg, dst_op.base, dst_op.disp, SZ_D); - } - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = cmp_ir(dst, 0, dst_reg, SZ_D); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - break; - //case M68K_NBCD: - case M68K_NEG: - dst = cycles(dst, BUS); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = neg_r(dst, dst_op.base, inst->extra.size); - } else { - dst = neg_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_NEGX: - dst = cycles(dst, BUS); - if (dst_op.mode == MODE_REG_DIRECT) { - if (dst_op.base == SCRATCH1) { - dst = push_r(dst, SCRATCH2); - dst = xor_rr(dst, SCRATCH2, SCRATCH2, inst->extra.size); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - dst = sbb_rr(dst, dst_op.base, SCRATCH2, inst->extra.size); - dst = mov_rr(dst, SCRATCH2, dst_op.base, inst->extra.size); - dst = pop_r(dst, SCRATCH2); - } else { - dst = xor_rr(dst, SCRATCH1, SCRATCH1, inst->extra.size); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - dst = sbb_rr(dst, dst_op.base, SCRATCH1, inst->extra.size); - dst = mov_rr(dst, SCRATCH1, dst_op.base, inst->extra.size); - } - } else { - dst = xor_rr(dst, SCRATCH1, SCRATCH1, inst->extra.size); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - dst = sbb_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, inst->extra.size); - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, inst->extra.size); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = jcc(dst, CC_Z, dst+4); - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - break; - case M68K_NOP: - dst = cycles(dst, BUS); - break; - case M68K_NOT: - if (dst_op.mode == MODE_REG_DIRECT) { - dst = not_r(dst, dst_op.base, inst->extra.size); - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - } else { - dst = not_rdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_OR: - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = or_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else { - dst = or_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = or_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = or_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = or_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_ORI_CCR: - case M68K_ORI_SR: - dst = cycles(dst, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode - if (inst->src.params.immed & 0x1) { - dst = mov_ir(dst, 1, FLAG_C, SZ_B); - } - if (inst->src.params.immed & 0x2) { - dst = mov_ir(dst, 1, FLAG_V, SZ_B); - } - if (inst->src.params.immed & 0x4) { - dst = mov_ir(dst, 1, FLAG_Z, SZ_B); - } - if (inst->src.params.immed & 0x8) { - dst = mov_ir(dst, 1, FLAG_N, SZ_B); - } - if (inst->src.params.immed & 0x10) { - dst = mov_irind(dst, 1, CONTEXT, SZ_B); - } - if (inst->op == M68K_ORI_SR) { - dst = or_irdisp8(dst, inst->src.params.immed >> 8, CONTEXT, offsetof(m68k_context, status), SZ_B); - //dst = call(dst, (uint8_t *)debug_print_sr); - if (inst->src.params.immed & 0x700) { - dst = call(dst, (uint8_t *)do_sync); - } - } - break; - case M68K_RESET: - dst = call(dst, (uint8_t *)m68k_save_context); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = call(dst, (uint8_t *)print_regs_exit); - break; - case M68K_ROL: - case M68K_ROR: - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - if (inst->src.addr_mode == MODE_UNUSED) { - dst = cycles(dst, BUS); - //Memory rotate - if (inst->op == M68K_ROL) { - dst = rol_ir(dst, 1, dst_op.base, inst->extra.size); - } else { - dst = ror_ir(dst, 1, dst_op.base, inst->extra.size); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = m68k_save_result(inst, dst, opts); - } else { - if (src_op.mode == MODE_IMMED) { - dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROL) { - dst = rol_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = ror_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROL) { - dst = rol_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = ror_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - } else { - if (src_op.mode == MODE_REG_DIRECT) { - if (src_op.base != SCRATCH1) { - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B); - } - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B); - } - dst = and_ir(dst, 63, SCRATCH1, SZ_D); - zero_off = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D); - dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D); - dst = cmp_ir(dst, 32, SCRATCH1, SZ_B); - norm_off = dst+1; - dst = jcc(dst, CC_L, dst+2); - dst = sub_ir(dst, 32, SCRATCH1, SZ_B); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROL) { - dst = rol_ir(dst, 31, dst_op.base, inst->extra.size); - dst = rol_ir(dst, 1, dst_op.base, inst->extra.size); - } else { - dst = ror_ir(dst, 31, dst_op.base, inst->extra.size); - dst = ror_ir(dst, 1, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROL) { - dst = rol_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size); - dst = rol_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = ror_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size); - dst = ror_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size); - } - } - *norm_off = dst - (norm_off+1); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROL) { - dst = rol_clr(dst, dst_op.base, inst->extra.size); - } else { - dst = ror_clr(dst, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROL) { - dst = rol_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = ror_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - end_off = dst + 1; - dst = jmp(dst, dst+2); - *zero_off = dst - (zero_off+1); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - *end_off = dst - (end_off+1); - } - if (dst_op.mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - } else { - dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - break; - case M68K_ROXL: - case M68K_ROXR: - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - if (inst->src.addr_mode == MODE_UNUSED) { - dst = cycles(dst, BUS); - //Memory rotate - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (inst->op == M68K_ROXL) { - dst = rcl_ir(dst, 1, dst_op.base, inst->extra.size); - } else { - dst = rcr_ir(dst, 1, dst_op.base, inst->extra.size); - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = m68k_save_result(inst, dst, opts); - } else { - if (src_op.mode == MODE_IMMED) { - dst = cycles(dst, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op.disp*2); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROXL) { - dst = rcl_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = rcr_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROXL) { - dst = rcl_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = rcr_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - } else { - if (src_op.mode == MODE_REG_DIRECT) { - if (src_op.base != SCRATCH1) { - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_B); - } - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_B); - } - dst = and_ir(dst, 63, SCRATCH1, SZ_D); - zero_off = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D); - dst = add_rr(dst, SCRATCH1, CYCLES, SZ_D); - dst = cmp_ir(dst, 32, SCRATCH1, SZ_B); - norm_off = dst+1; - dst = jcc(dst, CC_L, dst+2); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROXL) { - dst = rcl_ir(dst, 31, dst_op.base, inst->extra.size); - dst = rcl_ir(dst, 1, dst_op.base, inst->extra.size); - } else { - dst = rcr_ir(dst, 31, dst_op.base, inst->extra.size); - dst = rcr_ir(dst, 1, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROXL) { - dst = rcl_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size); - dst = rcl_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = rcr_irdisp8(dst, 31, dst_op.base, dst_op.disp, inst->extra.size); - dst = rcr_irdisp8(dst, 1, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_rind(dst, CC_C, CONTEXT); - dst = sub_ir(dst, 32, SCRATCH1, SZ_B); - *norm_off = dst - (norm_off+1); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (dst_op.mode == MODE_REG_DIRECT) { - if (inst->op == M68K_ROXL) { - dst = rcl_clr(dst, dst_op.base, inst->extra.size); - } else { - dst = rcr_clr(dst, dst_op.base, inst->extra.size); - } - } else { - if (inst->op == M68K_ROXL) { - dst = rcl_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - } else { - dst = rcr_clrdisp8(dst, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - end_off = dst + 1; - dst = jmp(dst, dst+2); - *zero_off = dst - (zero_off+1); - //Carry flag is set to X flag when count is 0, this is different from ROR/ROL - dst = mov_rindr(dst, CONTEXT, FLAG_C, SZ_B); - *end_off = dst - (end_off+1); - } - if (dst_op.mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size); - } else { - dst = cmp_irdisp8(dst, 0, dst_op.base, dst_op.disp, inst->extra.size); - } - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - } - break; - case M68K_RTE: - //TODO: Trap if not in system mode - //Read saved SR - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = call(dst, opts->read_16); - dst = add_ir(dst, 2, opts->aregs[7], SZ_D); - dst = call(dst, (uint8_t *)set_sr); - //Read saved PC - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = call(dst, opts->read_32); - dst = add_ir(dst, 4, opts->aregs[7], SZ_D); - //Check if we've switched to user mode and swap stack pointers if needed - dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B); - end_off = dst+1; - dst = jcc(dst, CC_C, dst+2); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - *end_off = dst - (end_off+1); - //Get native address, sync components, recalculate integer points and jump to returned address - dst = call(dst, (uint8_t *)m68k_native_addr_and_sync); - dst = jmp_r(dst, SCRATCH1); - break; - case M68K_RTR: - //Read saved CCR - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = call(dst, opts->read_16); - dst = add_ir(dst, 2, opts->aregs[7], SZ_D); - dst = call(dst, (uint8_t *)set_ccr); - //Read saved PC - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = call(dst, opts->read_32); - dst = add_ir(dst, 4, opts->aregs[7], SZ_D); - //Get native address and jump to it - dst = call(dst, (uint8_t *)m68k_native_addr); - dst = jmp_r(dst, SCRATCH1); - break; - case M68K_SBCD: - if (src_op.base != SCRATCH2) { - if (src_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B); - } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B); - } - } - if (dst_op.base != SCRATCH1) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B); - } else { - dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B); - } - } - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - dst = jcc(dst, CC_NC, dst+5); - dst = sub_ir(dst, 1, SCRATCH1, SZ_B); - dst = call(dst, (uint8_t *)bcd_sub); - dst = mov_rr(dst, CH, FLAG_C, SZ_B); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = cmp_ir(dst, 0, SCRATCH1, SZ_B); - dst = jcc(dst, CC_Z, dst+4); - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - if (dst_op.base != SCRATCH1) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B); - } - } - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_STOP: { - //TODO: Trap if not in system mode - //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction - //possibly even 12 since that's how long MOVE to SR takes - dst = cycles(dst, BUS*2); - dst = mov_ir(dst, src_op.disp & 0x1, FLAG_C, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 1) & 0x1, FLAG_V, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 2) & 0x1, FLAG_Z, SZ_B); - dst = mov_ir(dst, (src_op.disp >> 3) & 0x1, FLAG_N, SZ_B); - dst = mov_irind(dst, (src_op.disp >> 4) & 0x1, CONTEXT, SZ_B); - dst = mov_irdisp8(dst, (src_op.disp >> 8), CONTEXT, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - } - uint8_t * loop_top = dst; - dst = call(dst, (uint8_t *)do_sync); - dst = cmp_rr(dst, LIMIT, CYCLES, SZ_D); - uint8_t * normal_cycle_up = dst + 1; - dst = jcc(dst, CC_A, dst+2); - dst = cycles(dst, BUS); - uint8_t * after_cycle_up = dst + 1; - dst = jmp(dst, dst+2); - *normal_cycle_up = dst - (normal_cycle_up + 1); - dst = mov_rr(dst, LIMIT, CYCLES, SZ_D); - *after_cycle_up = dst - (after_cycle_up+1); - dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D); - dst = jcc(dst, CC_C, loop_top); - break; - } - case M68K_SUB: - size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = sub_rr(dst, src_op.base, dst_op.base, size); - } else { - dst = sub_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = sub_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = sub_ir(dst, src_op.disp, dst_op.base, size); - } else { - dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size); - } - } - if (inst->dst.addr_mode != MODE_AREG) { - dst = setcc_r(dst, CC_C, FLAG_C); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - } - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_SUBX: - dst = cycles(dst, BUS); - dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B); - if (src_op.mode == MODE_REG_DIRECT) { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = sbb_rr(dst, src_op.base, dst_op.base, inst->extra.size); - } else { - dst = sbb_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, inst->extra.size); - } - } else if (src_op.mode == MODE_REG_DISPLACE8) { - dst = sbb_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, inst->extra.size); - } else { - if (dst_op.mode == MODE_REG_DIRECT) { - dst = sbb_ir(dst, src_op.disp, dst_op.base, inst->extra.size); - } else { - dst = sbb_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size); - } - } - dst = setcc_r(dst, CC_C, FLAG_C); - dst = jcc(dst, CC_Z, dst+4); - dst = mov_ir(dst, 0, FLAG_Z, SZ_B); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = setcc_r(dst, CC_O, FLAG_V); - dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B); - dst = m68k_save_result(inst, dst, opts); - break; - case M68K_SWAP: - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - dst = rol_ir(dst, 16, src_op.base, SZ_D); - dst = cmp_ir(dst, 0, src_op.base, SZ_D); - } else{ - dst = rol_irdisp8(dst, 16, src_op.base, src_op.disp, SZ_D); - dst = cmp_irdisp8(dst, 0, src_op.base, src_op.disp, SZ_D); - } - - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - break; - //case M68K_TAS: - case M68K_TRAP: - dst = mov_ir(dst, src_op.disp + VECTOR_TRAP_0, SCRATCH2, SZ_D); - dst = mov_ir(dst, inst->address+2, SCRATCH1, SZ_D); - dst = jmp(dst, opts->trap); - break; - //case M68K_TRAPV: - case M68K_TST: - dst = cycles(dst, BUS); - if (src_op.mode == MODE_REG_DIRECT) { - dst = cmp_ir(dst, 0, src_op.base, inst->extra.size); - } else { //M68000 doesn't support immedate operand for tst, so this must be MODE_REG_DISPLACE8 - dst = cmp_irdisp8(dst, 0, src_op.base, src_op.disp, inst->extra.size); - } - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - break; - case M68K_UNLK: - dst = cycles(dst, BUS); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, dst_op.base, opts->aregs[7], SZ_D); - } else { - dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, opts->aregs[7], SZ_D); - } - dst = mov_rr(dst, opts->aregs[7], SCRATCH1, SZ_D); - dst = call(dst, opts->read_32); - if (dst_op.mode == MODE_REG_DIRECT) { - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_D); - } else { - dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_D); - } - dst = add_ir(dst, 4, opts->aregs[7], SZ_D); - break; - default: - m68k_disasm(inst, disasm_buf); - printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); - exit(1); - } - return dst; -} - -uint8_t m68k_is_terminal(m68kinst * inst) -{ - return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP - || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET - || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE); -} - -void m68k_handle_deferred(m68k_context * context) -{ - x86_68k_options * opts = context->options; - process_deferred(&opts->deferred, context, (native_addr_func)get_native_from_context); - if (opts->deferred) { - translate_m68k_stream(opts->deferred->address, context); - } -} - -uint8_t * translate_m68k_stream(uint32_t address, m68k_context * context) -{ - m68kinst instbuf; - x86_68k_options * opts = context->options; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - address &= 0xFFFFFF; - if(get_native_address(opts->native_code_map, address)) { - return dst; - } - char disbuf[1024]; - uint16_t *encoded, *next; - if ((address & 0xFFFFFF) < 0x400000) { - encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; - } else if ((address & 0xFFFFFF) > 0xE00000) { - encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); - } - do { - if (opts->address_log) { - fprintf(opts->address_log, "%X\n", address); - } - do { - if (dst_end-dst < MAX_NATIVE_SIZE) { - if (dst_end-dst < 5) { - puts("out of code memory, not enough space for jmp to next chunk"); - exit(1); - } - size_t size = 1024*1024; - opts->cur_code = alloc_code(&size); - opts->code_end = opts->cur_code + size; - jmp(dst, opts->cur_code); - dst = opts->cur_code; - dst_end = opts->code_end; - } - if (address >= 0x400000 && address < 0xE00000) { - dst = xor_rr(dst, RDI, RDI, SZ_D); - dst = call(dst, (uint8_t *)exit); - break; - } - uint8_t * existing = get_native_address(opts->native_code_map, address); - if (existing) { - dst = jmp(dst, existing); - break; - } - next = m68k_decode(encoded, &instbuf, address); - if (instbuf.op == M68K_INVALID) { - instbuf.src.params.immed = *encoded; - } - uint16_t m68k_size = (next-encoded)*2; - address += m68k_size; - encoded = next; - //m68k_disasm(&instbuf, disbuf); - //printf("%X: %s\n", instbuf.address, disbuf); - uint8_t * after = translate_m68k(dst, &instbuf, opts); - map_native_address(context, instbuf.address, dst, m68k_size, after-dst); - dst = after; - } while(!m68k_is_terminal(&instbuf)); - process_deferred(&opts->deferred, context, (native_addr_func)get_native_from_context); - if (opts->deferred) { - address = opts->deferred->address; - if ((address & 0xFFFFFF) < 0x400000) { - encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; - } else if ((address & 0xFFFFFF) > 0xE00000) { - encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); - } - } else { - encoded = NULL; - } - } while(encoded != NULL); - opts->cur_code = dst; - return dst; -} - -uint8_t * get_native_address_trans(m68k_context * context, uint32_t address) -{ - address &= 0xFFFFFF; - uint8_t * ret = get_native_address(context->native_code_map, address); - if (!ret) { - translate_m68k_stream(address, context); - ret = get_native_address(context->native_code_map, address); - } - return ret; -} - -void * m68k_retranslate_inst(uint32_t address, m68k_context * context) -{ - x86_68k_options * opts = context->options; - uint8_t orig_size = get_native_inst_size(opts, address); - uint8_t * orig_start = get_native_address(context->native_code_map, address); - uint32_t orig = address; - address &= 0xFFFF; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - uint16_t *after, *inst = context->mem_pointers[1] + address/2; - m68kinst instbuf; - after = m68k_decode(inst, &instbuf, orig); - if (orig_size != MAX_NATIVE_SIZE) { - if (dst_end - dst < 128) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - opts->cur_code = dst; - } - deferred_addr * orig_deferred = opts->deferred; - uint8_t * native_end = translate_m68k(dst, &instbuf, opts); - uint8_t is_terminal = m68k_is_terminal(&instbuf); - if ((native_end - dst) <= orig_size) { - uint8_t * native_next; - if (!is_terminal) { - native_next = get_native_address(context->native_code_map, orig + (after-inst)*2); - } - if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5))) { - remove_deferred_until(&opts->deferred, orig_deferred); - native_end = translate_m68k(orig_start, &instbuf, opts); - if (!is_terminal) { - if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { - while (native_end < orig_start + orig_size) { - *(native_end++) = 0x90; //NOP - } - } else { - jmp(native_end, native_next); - } - } - m68k_handle_deferred(context); - return orig_start; - } - } - - map_native_address(context, instbuf.address, dst, (after-inst)*2, MAX_NATIVE_SIZE); - opts->cur_code = dst+MAX_NATIVE_SIZE; - jmp(orig_start, dst); - if (!m68k_is_terminal(&instbuf)) { - jmp(native_end, get_native_address_trans(context, orig + (after-inst)*2)); - } - m68k_handle_deferred(context); - return dst; - } else { - dst = translate_m68k(orig_start, &instbuf, opts); - if (!m68k_is_terminal(&instbuf)) { - dst = jmp(dst, get_native_address_trans(context, orig + (after-inst)*2)); - } - m68k_handle_deferred(context); - return orig_start; - } -} - -m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) -{ - uint32_t inst_start = get_instruction_start(context->native_code_map, address | 0xFF0000); - if (inst_start) { - uint8_t * dst = get_native_address(context->native_code_map, inst_start); - dst = mov_ir(dst, inst_start, SCRATCH2, SZ_D); - dst = jmp(dst, (uint8_t *)m68k_retrans_stub); - } - return context; -} - -void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler) -{ - static uint8_t * bp_stub = NULL; - uint8_t * native = get_native_address_trans(context, address); - uint8_t * start_native = native; - native = mov_ir(native, address, SCRATCH1, SZ_D); - if (!bp_stub) { - x86_68k_options * opts = context->options; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - if (dst_end - dst < 128) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - } - bp_stub = dst; - native = call(native, bp_stub); - - //Calculate length of prologue - dst = check_cycles_int(dst, address, opts); - int check_int_size = dst-bp_stub; - dst = bp_stub; - - //Save context and call breakpoint handler - dst = call(dst, (uint8_t *)m68k_save_context); - dst = push_r(dst, SCRATCH1); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = mov_rr(dst, SCRATCH1, RSI, SZ_D); - dst = call(dst, bp_handler); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - //Restore context - dst = call(dst, (uint8_t *)m68k_load_context); - dst = pop_r(dst, SCRATCH1); - //do prologue stuff - dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = call(dst, opts->handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); - //jump back to body of translated instruction - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q); - dst = jmp_r(dst, SCRATCH1); - opts->cur_code = dst; - } else { - native = call(native, bp_stub); - } -} - -void remove_breakpoint(m68k_context * context, uint32_t address) -{ - uint8_t * native = get_native_address(context->native_code_map, address); - check_cycles_int(native, address, context->options); -} - -void start_68k_context(m68k_context * context, uint32_t address) -{ - uint8_t * addr = get_native_address_trans(context, address); - m68k_start_context(addr, context); -} - -void m68k_reset(m68k_context * context) -{ - //TODO: Make this actually use the normal read functions - context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1]; - uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3]; - start_68k_context(context, address); -} - -typedef enum { - READ_16, - READ_8, - WRITE_16, - WRITE_8 -} ftype; - -uint8_t * gen_mem_fun(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type) -{ - uint8_t * dst = opts->cur_code; - uint8_t * start = dst; - dst = check_cycles(dst); - dst = cycles(dst, BUS); - dst = and_ir(dst, 0xFFFFFF, SCRATCH1, SZ_D); - uint8_t *lb_jcc = NULL, *ub_jcc = NULL; - uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8; - uint8_t adr_reg = is_write ? SCRATCH2 : SCRATCH1; - uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ; - uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B; - for (uint32_t chunk = 0; chunk < num_chunks; chunk++) - { - if (memmap[chunk].start > 0) { - dst = cmp_ir(dst, memmap[chunk].start, adr_reg, SZ_D); - lb_jcc = dst + 1; - dst = jcc(dst, CC_C, dst+2); - } - if (memmap[chunk].end < 0x1000000) { - dst = cmp_ir(dst, memmap[chunk].end, adr_reg, SZ_D); - ub_jcc = dst + 1; - dst = jcc(dst, CC_NC, dst+2); - } - - if (memmap[chunk].mask != 0xFFFFFF) { - dst = and_ir(dst, memmap[chunk].mask, adr_reg, SZ_D); - } - void * cfun; - switch (fun_type) - { - case READ_16: - cfun = memmap[chunk].read_16; - break; - case READ_8: - cfun = memmap[chunk].read_8; - break; - case WRITE_16: - cfun = memmap[chunk].write_16; - break; - case WRITE_8: - cfun = memmap[chunk].write_8; - break; - default: - cfun = NULL; - } - if(memmap[chunk].buffer && memmap[chunk].flags & access_flag) { - if (memmap[chunk].flags & MMAP_PTR_IDX) { - if (memmap[chunk].flags & MMAP_FUNC_NULL) { - dst = cmp_irdisp8(dst, 0, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, SZ_Q); - uint8_t * not_null = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - dst = call(dst, (uint8_t *)m68k_save_context); - if (is_write) { - //SCRATCH2 is RDI, so no need to move it there - dst = mov_rr(dst, SCRATCH1, RDX, size); - } else { - dst = push_r(dst, CONTEXT); - dst = mov_rr(dst, SCRATCH1, RDI, SZ_D); - } - dst = test_ir(dst, 8, RSP, SZ_D); - uint8_t *adjust_rsp = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - dst = call(dst, cfun); - uint8_t *no_adjust = dst+1; - dst = jmp(dst, dst+2); - *adjust_rsp = dst - (adjust_rsp + 1); - dst = sub_ir(dst, 8, RSP, SZ_Q); - dst = call(dst, cfun); - dst = add_ir(dst, 8, RSP, SZ_Q); - *no_adjust = dst - (no_adjust + 1); - if (is_write) { - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - } else { - dst = pop_r(dst, CONTEXT); - dst = mov_rr(dst, RAX, SCRATCH1, size); - } - dst = jmp(dst, (uint8_t *)m68k_load_context); - - *not_null = dst - (not_null + 1); - } - if (size == SZ_B) { - dst = xor_ir(dst, 1, adr_reg, SZ_D); - } - dst = add_rdisp8r(dst, CONTEXT, offsetof(m68k_context, mem_pointers) + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_Q); - if (is_write) { - dst = mov_rrind(dst, SCRATCH1, SCRATCH2, size); - - } else { - dst = mov_rindr(dst, SCRATCH1, SCRATCH1, size); - } - } else { - uint8_t tmp_size = size; - if (size == SZ_B) { - if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { - dst = bt_ir(dst, 0, adr_reg, SZ_D); - uint8_t * good_addr = dst + 1; - dst = jcc(dst, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, dst+2); - if (!is_write) { - dst = mov_ir(dst, 0xFF, SCRATCH1, SZ_B); - } - dst = retn(dst); - *good_addr = dst - (good_addr + 1); - dst = shr_ir(dst, 1, adr_reg, SZ_D); - } else { - dst = xor_ir(dst, 1, adr_reg, SZ_D); - } - } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { - tmp_size = SZ_B; - dst = shr_ir(dst, 1, adr_reg, SZ_D); - if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) { - dst = shr_ir(dst, 8, SCRATCH1, SZ_W); - } - } - if ((int64_t)memmap[chunk].buffer <= 0x7FFFFFFF && (int64_t)memmap[chunk].buffer >= -2147483648) { - if (is_write) { - dst = mov_rrdisp32(dst, SCRATCH1, SCRATCH2, (int64_t)memmap[chunk].buffer, tmp_size); - } else { - dst = mov_rdisp32r(dst, SCRATCH1, (int64_t)memmap[chunk].buffer, SCRATCH1, tmp_size); - } - } else { - if (is_write) { - dst = push_r(dst, SCRATCH1); - dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH1, SZ_Q); - dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_Q); - dst = pop_r(dst, SCRATCH1); - dst = mov_rrind(dst, SCRATCH1, SCRATCH2, tmp_size); - } else { - dst = mov_ir(dst, (int64_t)memmap[chunk].buffer, SCRATCH2, SZ_Q); - dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 1, SCRATCH1, tmp_size); - } - } - if (size != tmp_size && !is_write) { - if (memmap[chunk].flags & MMAP_ONLY_EVEN) { - dst = shl_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_ir(dst, 0xFF, SCRATCH1, SZ_B); - } else { - dst = or_ir(dst, 0xFF00, SCRATCH1, SZ_W); - } - } - } - if (is_write && (memmap[chunk].flags & MMAP_CODE)) { - dst = mov_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - dst = shr_ir(dst, 11, SCRATCH1, SZ_D); - dst = bt_rrdisp32(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, ram_code_flags), SZ_D); - uint8_t * not_code = dst+1; - dst = jcc(dst, CC_NC, dst+2); - dst = call(dst, (uint8_t *)m68k_save_context); - dst = call(dst, (uint8_t *)m68k_handle_code_write); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - dst = call(dst, (uint8_t *)m68k_load_context); - *not_code = dst - (not_code+1); - } - dst = retn(dst); - } else if (cfun) { - dst = call(dst, (uint8_t *)m68k_save_context); - if (is_write) { - //SCRATCH2 is RDI, so no need to move it there - dst = mov_rr(dst, SCRATCH1, RDX, size); - } else { - dst = push_r(dst, CONTEXT); - dst = mov_rr(dst, SCRATCH1, RDI, SZ_D); - } - dst = test_ir(dst, 8, RSP, SZ_D); - uint8_t *adjust_rsp = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - dst = call(dst, cfun); - uint8_t *no_adjust = dst+1; - dst = jmp(dst, dst+2); - *adjust_rsp = dst - (adjust_rsp + 1); - dst = sub_ir(dst, 8, RSP, SZ_Q); - dst = call(dst, cfun); - dst = add_ir(dst, 8, RSP, SZ_Q); - *no_adjust = dst - (no_adjust+1); - if (is_write) { - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - } else { - dst = pop_r(dst, CONTEXT); - dst = mov_rr(dst, RAX, SCRATCH1, size); - } - dst = jmp(dst, (uint8_t *)m68k_load_context); - } else { - //Not sure the best course of action here - if (!is_write) { - dst = mov_ir(dst, size == SZ_B ? 0xFF : 0xFFFF, SCRATCH1, size); - } - dst = retn(dst); - } - if (lb_jcc) { - *lb_jcc = dst - (lb_jcc+1); - lb_jcc = NULL; - } - if (ub_jcc) { - *ub_jcc = dst - (ub_jcc+1); - ub_jcc = NULL; - } - } - if (!is_write) { - dst = mov_ir(dst, size == SZ_B ? 0xFF : 0xFFFF, SCRATCH1, size); - } - dst = retn(dst); - opts->cur_code = dst; - return start; -} - -void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks) -{ - memset(opts, 0, sizeof(*opts)); - for (int i = 0; i < 8; i++) - opts->dregs[i] = opts->aregs[i] = -1; - opts->dregs[0] = R10; - opts->dregs[1] = R11; - opts->dregs[2] = R12; - opts->dregs[3] = R8; - opts->aregs[0] = R13; - opts->aregs[1] = R14; - opts->aregs[2] = R9; - opts->aregs[7] = R15; - opts->native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); - memset(opts->native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); - opts->deferred = NULL; - size_t size = 1024 * 1024; - opts->cur_code = alloc_code(&size); - opts->code_end = opts->cur_code + size; - opts->ram_inst_sizes = malloc(sizeof(uint8_t *) * 64); - memset(opts->ram_inst_sizes, 0, sizeof(uint8_t *) * 64); - - opts->read_16 = gen_mem_fun(opts, memmap, num_chunks, READ_16); - opts->read_8 = gen_mem_fun(opts, memmap, num_chunks, READ_8); - opts->write_16 = gen_mem_fun(opts, memmap, num_chunks, WRITE_16); - opts->write_8 = gen_mem_fun(opts, memmap, num_chunks, WRITE_8); - - uint8_t * dst = opts->cur_code; - - opts->read_32 = dst; - dst = push_r(dst, SCRATCH1); - dst = call(dst, opts->read_16); - dst = mov_rr(dst, SCRATCH1, SCRATCH2, SZ_W); - dst = pop_r(dst, SCRATCH1); - dst = push_r(dst, SCRATCH2); - dst = add_ir(dst, 2, SCRATCH1, SZ_D); - dst = call(dst, opts->read_16); - dst = pop_r(dst, SCRATCH2); - dst = movzx_rr(dst, SCRATCH1, SCRATCH1, SZ_W, SZ_D); - dst = shl_ir(dst, 16, SCRATCH2, SZ_D); - dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_D); - dst = retn(dst); - - opts->write_32_lowfirst = dst; - dst = push_r(dst, SCRATCH2); - dst = push_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH2, SZ_D); - dst = call(dst, opts->write_16); - dst = pop_r(dst, SCRATCH1); - dst = pop_r(dst, SCRATCH2); - dst = shr_ir(dst, 16, SCRATCH1, SZ_D); - dst = jmp(dst, opts->write_16); - - opts->write_32_highfirst = dst; - dst = push_r(dst, SCRATCH1); - dst = push_r(dst, SCRATCH2); - dst = shr_ir(dst, 16, SCRATCH1, SZ_D); - dst = call(dst, opts->write_16); - dst = pop_r(dst, SCRATCH2); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, 2, SCRATCH2, SZ_D); - dst = jmp(dst, opts->write_16); - - opts->handle_cycle_limit_int = dst; - dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_cycle), CYCLES, SZ_D); - uint8_t * do_int = dst+1; - dst = jcc(dst, CC_NC, dst+2); - dst = cmp_rdisp8r(dst, CONTEXT, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D); - uint8_t * skip_sync = dst+1; - dst = jcc(dst, CC_C, dst+2); - dst = call(dst, (uint8_t *)m68k_save_context); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = mov_rr(dst, SCRATCH1, RSI, SZ_D); - dst = test_ir(dst, 8, RSP, SZ_D); - uint8_t *adjust_rsp = dst+1; - dst = jcc(dst, CC_NZ, dst+2); - dst = call(dst, (uint8_t *)sync_components); - uint8_t *no_adjust = dst+1; - dst = jmp(dst, dst+2); - *adjust_rsp = dst - (adjust_rsp + 1); - dst = sub_ir(dst, 8, RSP, SZ_Q); - dst = call(dst, (uint8_t *)sync_components); - dst = add_ir(dst, 8, RSP, SZ_Q); - *no_adjust = dst - (no_adjust+1); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - dst = jmp(dst, (uint8_t *)m68k_load_context); - *skip_sync = dst - (skip_sync+1); - dst = retn(dst); - *do_int = dst - (do_int+1); - //set target cycle to sync cycle - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, sync_cycle), LIMIT, SZ_D); - //swap USP and SSP if not already in supervisor mode - dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B); - uint8_t *already_supervisor = dst+1; - dst = jcc(dst, CC_C, dst+2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH2, SZ_D); - dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - dst = mov_rr(dst, SCRATCH2, opts->aregs[7], SZ_D); - *already_supervisor = dst - (already_supervisor+1); - //save PC - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_lowfirst); - //save status register - dst = sub_ir(dst, 2, opts->aregs[7], SZ_D); - dst = call(dst, (uint8_t *)get_sr); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_16); - //update status register - dst = and_irdisp8(dst, 0xF8, CONTEXT, offsetof(m68k_context, status), SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_num), SCRATCH1, SZ_B); - dst = or_ir(dst, 0x20, SCRATCH1, SZ_B); - dst = or_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, status), SZ_B); - //calculate interrupt vector address - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, int_num), SCRATCH1, SZ_D); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(m68k_context, int_ack), SZ_W); - dst = shl_ir(dst, 2, SCRATCH1, SZ_D); - dst = add_ir(dst, 0x60, SCRATCH1, SZ_D); - dst = call(dst, opts->read_32); - dst = call(dst, (uint8_t *)m68k_native_addr_and_sync); - dst = cycles(dst, 24); - //discard function return address - dst = pop_r(dst, SCRATCH2); - dst = jmp_r(dst, SCRATCH1); - - opts->trap = dst; - dst = push_r(dst, SCRATCH2); - //swap USP and SSP if not already in supervisor mode - dst = bt_irdisp8(dst, 5, CONTEXT, offsetof(m68k_context, status), SZ_B); - already_supervisor = dst+1; - dst = jcc(dst, CC_C, dst+2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SCRATCH2, SZ_D); - dst = mov_rrdisp8(dst, opts->aregs[7], CONTEXT, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_D); - dst = mov_rr(dst, SCRATCH2, opts->aregs[7], SZ_D); - *already_supervisor = dst - (already_supervisor+1); - //save PC - dst = sub_ir(dst, 4, opts->aregs[7], SZ_D); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_32_lowfirst); - //save status register - dst = sub_ir(dst, 2, opts->aregs[7], SZ_D); - dst = call(dst, (uint8_t *)get_sr); - dst = mov_rr(dst, opts->aregs[7], SCRATCH2, SZ_D); - dst = call(dst, opts->write_16); - //set supervisor bit - dst = or_irdisp8(dst, 0x20, CONTEXT, offsetof(m68k_context, status), SZ_B); - //calculate vector address - dst = pop_r(dst, SCRATCH1); - dst = shl_ir(dst, 2, SCRATCH1, SZ_D); - dst = call(dst, opts->read_32); - dst = call(dst, (uint8_t *)m68k_native_addr_and_sync); - dst = cycles(dst, 18); - dst = jmp_r(dst, SCRATCH1); - - opts->cur_code = dst; -} - -void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) -{ - memset(context, 0, sizeof(m68k_context)); - context->native_code_map = native_code_map; - context->options = opts; - context->int_cycle = 0xFFFFFFFF; - context->status = 0x27; -} - diff -r 103d5cabbe14 -r f822d9216968 m68k_to_x86.h --- a/m68k_to_x86.h Tue Dec 16 01:10:54 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - Copyright 2013 Michael Pavone - This file is part of BlastEm. - BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. -*/ -#ifndef M68K_TO_X86_H_ -#define M68K_TO_X86_H_ -#include -#include -#include "x86_backend.h" -//#include "68kinst.h" -struct m68kinst; - -#define NUM_MEM_AREAS 4 -#define NATIVE_MAP_CHUNKS (64*1024) -#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2) -#define MAX_NATIVE_SIZE 255 - -#define OPT_NATIVE_CALL_STACK 0x1 - -typedef struct { - uint32_t flags; - int8_t dregs[8]; - int8_t aregs[8]; - native_map_slot *native_code_map; - deferred_addr *deferred; - uint8_t *cur_code; - uint8_t *code_end; - uint8_t **ram_inst_sizes; - FILE *address_log; - uint8_t *read_16; - uint8_t *write_16; - uint8_t *read_8; - uint8_t *write_8; - uint8_t *read_32; - uint8_t *write_32_lowfirst; - uint8_t *write_32_highfirst; - uint8_t *handle_cycle_limit_int; - uint8_t *trap; -} x86_68k_options; - -typedef struct { - uint8_t flags[5]; - uint8_t status; - uint16_t int_ack; - uint32_t dregs[8]; - uint32_t aregs[9]; - uint32_t target_cycle; //cycle at which the next synchronization or interrupt occurs - uint32_t current_cycle; - uint32_t sync_cycle; - uint32_t int_cycle; - uint32_t int_num; - uint16_t *mem_pointers[NUM_MEM_AREAS]; - void *video_context; - uint16_t reserved; - - native_map_slot *native_code_map; - void *options; - uint8_t ram_code_flags[32/8]; - void *system; -} m68k_context; - -uint8_t * translate_m68k(uint8_t * dst, struct m68kinst * inst, x86_68k_options * opts); -uint8_t * translate_m68k_stream(uint32_t address, m68k_context * context); -void start_68k_context(m68k_context * context, uint32_t address); -void init_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks); -void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); -void m68k_reset(m68k_context * context); -void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); -void remove_breakpoint(m68k_context * context, uint32_t address); -m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context); - -#endif //M68K_TO_X86_H_ - diff -r 103d5cabbe14 -r f822d9216968 runtime.S --- a/runtime.S Tue Dec 16 01:10:54 2014 -0800 +++ b/runtime.S Tue Dec 30 19:11:34 2014 -0800 @@ -1,57 +1,4 @@ - .global handle_cycle_limit - .global do_sync -handle_cycle_limit: - cmp 84(%rsi), %eax - jb skip_sync -do_sync: - push %rcx - push %rdi - call m68k_save_context - mov %rsi, %rdi - xor %esi, %esi - test $8, %esp - jnz adjust_rsp - call sync_components - jmp done_adjust -adjust_rsp: - sub $8, %rsp - call sync_components - add $8, %rsp -done_adjust: - mov %rax, %rsi - call m68k_load_context - pop %rdi - pop %rcx -skip_sync: - ret - -sr_msg_int: - .asciz "SR set to $%X due to interrupt\n" -debug_print_sr_int: - call m68k_save_context - push %rsi - lea sr_msg_int(%rip), %rdi - movzxb 5(%rsi), %rsi - xor %rax, %rax - call printf - pop %rsi - call m68k_load_context - ret - -sr_msg: - .asciz "SR set to $%X\n" - .global debug_print_sr -debug_print_sr: - call m68k_save_context - push %rsi - lea sr_msg(%rip), %rdi - movzxb 5(%rsi), %rsi - xor %rax, %rax - call printf - pop %rsi - call m68k_load_context - ret invalid_msg: .asciz "Invalid instruction at %X\n" @@ -65,221 +12,5 @@ mov $1, %rdi call exit - .global bcd_add -bcd_add: - xchg %rax, %rdi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - add %ah, %ch - cmp $10, %ch - jb no_adjust - add $6, %ch -no_adjust: - add %ch, %al - add %al, %cl - mov $0, %ch - jc def_adjust - cmp $0xA0, %cl - jb no_adjust_h -def_adjust: - add $0x60, %cl - mov $1, %ch -no_adjust_h: - - mov %rdi, %rax - ret - - .global bcd_sub -bcd_sub: - xchg %rax, %rdi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - sub %ah, %ch - cmp $10, %ch - jb no_adjusts - sub $6, %ch -no_adjusts: - add %ch, %cl - sub %al, %cl - mov $0, %ch - jc def_adjusts - cmp $0xA0, %cl - jb no_adjust_hs -def_adjusts: - sub $0x60, %cl - mov $1, %ch -no_adjust_hs: - - mov %rdi, %rax - ret - - .global get_sr -get_sr: - mov 5(%rsi), %cl - shl $8, %cx - mov (%rsi), %cl - shl $1, %cl - or %bl, %cl - shl $1, %cl - or %dl, %cl - shl $1, %cl - or %bh, %cl - shl $1, %cl - or %dh, %cl - ret - - .global set_sr -set_sr: - mov %cl, %dh - and $1, %dh - shr $1, %cl - mov %cl, %bh - and $1, %bh - shr $1, %cl - mov %cl, %dl - and $1, %dl - shr $1, %cl - mov %cl, %bl - and $1, %bl - shr $1, %cl - and $1, %cl - mov %cl, (%rsi) - shr $8, %cx - mov %cl, 5(%rsi) - /* call debug_print_sr */ - ret - .global set_ccr -set_ccr: - mov %cl, %dh - and $1, %dh - shr $1, %cl - mov %cl, %bh - and $1, %bh - shr $1, %cl - mov %cl, %dl - and $1, %dl - shr $1, %cl - mov %cl, %bl - and $1, %bl - shr $1, %cl - and $1, %cl - mov %cl, (%rsi) - ret - .global m68k_modified_ret_addr -m68k_modified_ret_addr: - add $16, %rsp - call m68k_native_addr - jmp *%rcx - - .global m68k_native_addr_and_sync -m68k_native_addr_and_sync: - call m68k_save_context - push %rcx - mov %rsi, %rdi - xor %esi, %esi - test $8, %rsp - jnz adjust_rsp_na - call sync_components - jmp no_adjust_rsp_na -adjust_rsp_na: - sub $8, %rsp - call sync_components - add $8, %rsp -no_adjust_rsp_na: - pop %rsi - push %rax - mov %rax, %rdi - call get_native_address_trans - mov %rax, %rcx - pop %rsi - call m68k_load_context - ret - - .global m68k_native_addr -m68k_native_addr: - call m68k_save_context - push %rsi - mov %rsi, %rdi - mov %ecx, %esi - call get_native_address_trans - mov %rax, %rcx - pop %rsi - call m68k_load_context - ret - - .global m68k_retrans_stub -m68k_retrans_stub: - call m68k_save_context - push %rsi - call m68k_retranslate_inst - pop %rsi - mov %rax, %rcx - call m68k_load_context - jmp *%rcx - - .global m68k_save_context -m68k_save_context: - mov %bl, 1(%rsi) /* N Flag */ - mov %dl, 2(%rsi) /* Z flag */ - mov %bh, 3(%rsi) /* V flag */ - mov %dh, 4(%rsi) /* C flag */ - mov %r10d, 8(%rsi) /* d0 */ - mov %r11d, 12(%rsi) /* d1 */ - mov %r12d, 16(%rsi) /* d2 */ - mov %r8d, 20(%rsi) /* d3 */ - mov %r13d, 40(%rsi) /* a0 */ - mov %r14d, 44(%rsi) /* a1 */ - mov %r9d, 48(%rsi) /* a2 */ - mov %r15d, 68(%rsi) /* a7 */ - mov %eax, 80(%rsi) /* current cycle count */ - ret - - .global m68k_load_context -m68k_load_context: - mov 1(%rsi), %bl /* N Flag */ - mov 2(%rsi), %dl /* Z flag */ - mov 3(%rsi), %bh /* V flag */ - mov 4(%rsi), %dh /* C flag */ - mov 8(%rsi), %r10d /* d0 */ - mov 12(%rsi), %r11d /* d1 */ - mov 16(%rsi), %r12d /* d2 */ - mov 20(%rsi), %r8d /* d3 */ - mov 40(%rsi), %r13d /* a0 */ - mov 44(%rsi), %r14d /* a1 */ - mov 48(%rsi), %r9d /* a2 */ - mov 68(%rsi), %r15d /* a7 */ - mov 76(%rsi), %ebp /* target cycle count */ - mov 80(%rsi), %eax /* current cycle count */ - ret - - .global m68k_start_context -m68k_start_context: - push %rbp - push %r12 - push %r13 - push %r14 - push %r15 - - call m68k_load_context - call *%rdi - call m68k_save_context - - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp - - ret diff -r 103d5cabbe14 -r f822d9216968 runtime_32.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runtime_32.S Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,17 @@ + + +invalid_msg: + .asciz "Invalid instruction at %X\n" + + .global m68k_invalid +m68k_invalid: + push %ecx + push invalid_msg + xor %eax, %eax + call printf + push $1 + call exit + + + + diff -r 103d5cabbe14 -r f822d9216968 test_arm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test_arm.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,29 @@ +#include +#include "gen_arm.h" + +typedef int32_t (*fib_fun)(int32_t); + +int main(int arc, char **argv) +{ + code_info code; + init_code_info(&code); + uint32_t *fib = code.cur; + subi(&code, r0, r0, 2, SET_COND); + movi_cc(&code, r0, 1, NO_COND, CC_LT); + bx_cc(&code, lr, CC_LT); + pushm(&code, LR | R4); + mov(&code, r4, r0, NO_COND); + bl(&code, fib); + mov(&code, r1, r0, NO_COND); + addi(&code, r0, r4, 1, NO_COND); + mov(&code, r4, r1, NO_COND); + bl(&code, fib); + add(&code, r0, r4, r0, NO_COND); + popm(&code, LR | R4); + bx(&code, lr); + + fib_fun fibc = (fib_fun)fib; + printf("fib(10): %d\n", fibc(10)); + + return 0; +} diff -r 103d5cabbe14 -r f822d9216968 test_x86.c --- a/test_x86.c Tue Dec 16 01:10:54 2014 -0800 +++ b/test_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -1,10 +1,10 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "gen_x86.h" -#include "m68k_to_x86.h" +#include "m68k_core.h" #include #include diff -r 103d5cabbe14 -r f822d9216968 testcases.txt --- a/testcases.txt Tue Dec 16 01:10:54 2014 -0800 +++ b/testcases.txt Tue Dec 30 19:11:34 2014 -0800 @@ -1,87 +1,88 @@ Name Sizes Src Modes Dst Modes -#add bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#add bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#adda wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#addi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#addq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#addx bwl d d -#addx bwl -(a) -(a) -#and bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#and bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#andi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#asl bwl d;#(1-8) d -#asr bwl d;#(1-8) d -#lsl bwl d;#(1-8) d -#lsr bwl d;#(1-8) d -#sub bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#sub bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#suba wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#subi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#subq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#subx bwl d d -#subx bwl -(a) -(a) -#bchg b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bchg l d;#(0-255) d -#bset b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bset l d;#(0-255) d -#bclr b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bclr l d;#(0-255) d -#btst b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#btst l d;#(0-255) d -#rol bwl d;#(1-8) d -#ror bwl d;#(1-8) d -#abcd b d d -#abcd b -(a) -(a) -#sbcd b d d -#sbcd b -(a) -(a) -#muls w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#mulu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#move bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#movea wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#moveq l #(-128-127) d -#roxl bwl d;#(1-8) d -#roxr bwl d;#(1-8) d -#divs w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#divu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#chk w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#cmp bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#cmpa wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#cmpi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#cmpm bwl (a)+ (a)+ -#eor bwl d d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#eori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#exg l d d;a -#exg l a a -#link w a #n -#or bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#or bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#clr bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ext wl d -#neg bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#negx bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#not bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#pea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) -#rol w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ror w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#roxl w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#roxr w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#st b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sf b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#shi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sls b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#scc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#scs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sne b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#seq b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#svc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#svs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#spl b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#smi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sge b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#slt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sgt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sle b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#swap w d +add bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +add bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +adda wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +addi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +addq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +addx bwl d d +addx bwl -(a) -(a) +and bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +and bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +andi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +asl bwl d;#(1-8) d +asr bwl d;#(1-8) d +lsl bwl d;#(1-8) d +lsr bwl d;#(1-8) d +sub bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +sub bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +suba wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +subi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +subq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +subx bwl d d +subx bwl -(a) -(a) +bchg b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bchg l d;#(0-255) d +bset b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bset l d;#(0-255) d +bclr b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bclr l d;#(0-255) d +btst b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +btst l d;#(0-255) d +rol bwl d;#(1-8) d +ror bwl d;#(1-8) d +abcd b d d +abcd b -(a) -(a) +sbcd b d d +sbcd b -(a) -(a) +muls w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +mulu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +move bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +movea wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +moveq l #(-128-127) d +roxl bwl d;#(1-8) d +roxr bwl d;#(1-8) d +divs w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +divu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +chk w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +cmp bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +cmpa wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +cmpi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +cmpm bwl (a)+ (a)+ +eor bwl d d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +eori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +exg l d d;a +exg l a a +link w a #n +or bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +or bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +clr bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ext wl d +neg bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +negx bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +not bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +pea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) +rol w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ror w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +roxl w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +roxr w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +st b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sf b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +shi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sls b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +scc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +scs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sne b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +seq b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +svc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +svs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +spl b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +smi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sge b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +slt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sgt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sle b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +swap w d tst bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +lea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) a diff -r 103d5cabbe14 -r f822d9216968 trans.c --- a/trans.c Tue Dec 16 01:10:54 2014 -0800 +++ b/trans.c Tue Dec 30 19:11:34 2014 -0800 @@ -1,10 +1,10 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "68kinst.h" -#include "m68k_to_x86.h" +#include "m68k_core.h" #include "mem.h" #include #include @@ -24,14 +24,15 @@ unsigned short *filebuf; char disbuf[1024]; unsigned short * cur; - x86_68k_options opts; + m68k_options opts; m68k_context context; FILE * f = fopen(argv[1], "rb"); fseek(f, 0, SEEK_END); filesize = ftell(f); fseek(f, 0, SEEK_SET); - filebuf = malloc(filesize > 0x400000 ? filesize : 0x400000); - fread(filebuf, 2, filesize/2, f); + filebuf = malloc(0x400000); + memset(filebuf, 0, 0x400000); + fread(filebuf, 2, filesize/2 > 0x200000 ? 0x200000 : filesize/2, f); fclose(f); for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) { @@ -43,14 +44,15 @@ memmap[0].mask = 0xFFFFFF; memmap[0].flags = MMAP_READ; memmap[0].buffer = filebuf; - + memmap[1].start = 0xE00000; memmap[1].end = 0x1000000; memmap[1].mask = 0xFFFF; memmap[1].flags = MMAP_READ | MMAP_WRITE | MMAP_CODE; memmap[1].buffer = malloc(64 * 1024); - init_x86_68k_opts(&opts, memmap, 2); - init_68k_context(&context, opts.native_code_map, &opts); + memset(memmap[1].buffer, 0, 64 * 1024); + init_m68k_opts(&opts, memmap, 2); + init_68k_context(&context, opts.gen.native_code_map, &opts); context.mem_pointers[0] = memmap[0].buffer; context.mem_pointers[1] = memmap[1].buffer; context.target_cycle = context.sync_cycle = 0x80000000; diff -r 103d5cabbe14 -r f822d9216968 util.c --- a/util.c Tue Dec 16 01:10:54 2014 -0800 +++ b/util.c Tue Dec 30 19:11:34 2014 -0800 @@ -94,7 +94,8 @@ free(linktext); linktext = NULL; } - } while (linksize > cursize); + } while ((linksize+1) > cursize); + linktext[linksize] = 0; return linktext; } diff -r 103d5cabbe14 -r f822d9216968 vgmplay.c --- a/vgmplay.c Tue Dec 16 01:10:54 2014 -0800 +++ b/vgmplay.c Tue Dec 30 19:11:34 2014 -0800 @@ -101,7 +101,7 @@ { } -uint8_t headless = 0; +int headless = 0; #define CYCLE_LIMIT MCLKS_NTSC/60 #define MAX_SOUND_CYCLES 100000 diff -r 103d5cabbe14 -r f822d9216968 x86_backend.c --- a/x86_backend.c Tue Dec 16 01:10:54 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - Copyright 2013 Michael Pavone - This file is part of BlastEm. - BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. -*/ -#include "x86_backend.h" -#include - -deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest) -{ - deferred_addr * new_head = malloc(sizeof(deferred_addr)); - new_head->next = old_head; - new_head->address = address & 0xFFFFFF; - new_head->dest = dest; - return new_head; -} - -void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to) -{ - for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr) - { - *head_ptr = cur->next; - free(cur); - } -} - -void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native) -{ - deferred_addr * cur = *head_ptr; - deferred_addr **last_next = head_ptr; - while(cur) - { - uint8_t * native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address); - if (native) { - int32_t disp = native - (cur->dest + 4); - uint8_t * out = cur->dest; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *out = disp; - *last_next = cur->next; - free(cur); - cur = *last_next; - } else { - last_next = &(cur->next); - cur = cur->next; - } - } -} - diff -r 103d5cabbe14 -r f822d9216968 x86_backend.h --- a/x86_backend.h Tue Dec 16 01:10:54 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - Copyright 2013 Michael Pavone - This file is part of BlastEm. - BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. -*/ -#ifndef X86_BACKEND_H_ -#define X86_BACKEND_H_ - -#include - -#define INVALID_OFFSET 0xFFFFFFFF -#define EXTENSION_WORD 0xFFFFFFFE - -typedef struct { - int32_t disp; - uint8_t mode; - uint8_t base; - uint8_t index; - uint8_t cycles; -} x86_ea; - -typedef struct { - uint8_t *base; - int32_t *offsets; -} native_map_slot; - -typedef struct deferred_addr { - struct deferred_addr *next; - uint8_t *dest; - uint32_t address; -} deferred_addr; - - -#define MMAP_READ 0x01 -#define MMAP_WRITE 0x02 -#define MMAP_CODE 0x04 -#define MMAP_PTR_IDX 0x08 -#define MMAP_ONLY_ODD 0x10 -#define MMAP_ONLY_EVEN 0x20 -#define MMAP_FUNC_NULL 0x40 - -typedef uint16_t (*read_16_fun)(uint32_t address, void * context); -typedef uint8_t (*read_8_fun)(uint32_t address, void * context); -typedef void * (*write_16_fun)(uint32_t address, void * context, uint16_t value); -typedef void * (*write_8_fun)(uint32_t address, void * context, uint8_t value); - -typedef struct { - uint32_t start; - uint32_t end; - uint32_t mask; - uint16_t ptr_index; - uint16_t flags; - void * buffer; - read_16_fun read_16; - write_16_fun write_16; - read_8_fun read_8; - write_8_fun write_8; -} memmap_chunk; - -typedef uint8_t * (*native_addr_func)(void * context, uint32_t address); - -deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest); -void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to); -void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native); - -#endif //X86_BACKEND_H_ - diff -r 103d5cabbe14 -r f822d9216968 z80_to_x86.c --- a/z80_to_x86.c Tue Dec 16 01:10:54 2014 -0800 +++ b/z80_to_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -28,23 +28,7 @@ #define dprintf #endif -void z80_read_byte(); -void z80_read_word(); -void z80_write_byte(); -void z80_write_word_highfirst(); -void z80_write_word_lowfirst(); -void z80_save_context(); -void z80_native_addr(); -void z80_do_sync(); -void z80_handle_cycle_limit_int(); -void z80_retrans_stub(); -void z80_io_read(); -void z80_io_write(); -void z80_halt(); -void z80_save_context(); -void z80_load_context(); - -uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native); +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst); uint8_t z80_size(z80inst * inst) { @@ -56,24 +40,9 @@ return SZ_B; } -uint8_t * zcycles(uint8_t * dst, uint32_t num_cycles) -{ - return add_ir(dst, num_cycles, ZCYCLES, SZ_D); -} - -uint8_t * z80_check_cycles_int(uint8_t * dst, uint16_t address) +void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) { - dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = mov_ir(dst, address, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); - return dst; -} - -uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts) -{ + code_info *code = &opts->gen.code; if (inst->reg == Z80_USE_IMMED) { ea->mode = MODE_IMMED; ea->disp = inst->immed; @@ -83,12 +52,12 @@ ea->mode = MODE_REG_DIRECT; if (inst->reg == Z80_IYH) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { - dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - ea->base = SCRATCH1; + mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + ea->base = opts->gen.scratch1; } else { ea->base = opts->regs[Z80_IYL]; - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if(opts->regs[inst->reg] >= 0) { ea->base = opts->regs[inst->reg]; @@ -98,64 +67,64 @@ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ea->base = opts->regs[z80_low_reg(inst->reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) { //temp regs require REX prefix too ea->base = opts->regs[z80_low_reg(inst->reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } } else { ea->mode = MODE_REG_DISPLACE8; - ea->base = CONTEXT; + ea->base = opts->gen.context_reg; ea->disp = offsetof(z80_context, regs) + inst->reg; } } - return dst; } -uint8_t * z80_save_reg(uint8_t * dst, z80inst * inst, x86_z80_options * opts) +void z80_save_reg(z80inst * inst, z80_options * opts) { + code_info *code = &opts->gen.code; if (inst->reg == Z80_IYH) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B); - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } else { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if (opts->regs[inst->reg] >= AH && opts->regs[inst->reg] <= BH) { if ((inst->addr_mode & 0x1F) == Z80_REG) { uint8_t other_reg = opts->regs[inst->ea_reg]; if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); } } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) { //temp regs require REX prefix too - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); } } - return dst; } -uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify) +void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify) { + code_info *code = &opts->gen.code; uint8_t size, reg, areg; ea->mode = MODE_REG_DIRECT; - areg = read ? SCRATCH1 : SCRATCH2; + areg = read ? opts->gen.scratch1 : opts->gen.scratch2; switch(inst->addr_mode & 0x1F) { case Z80_REG: if (inst->ea_reg == Z80_IYH) { if (inst->reg == Z80_IYL) { - dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - ea->base = SCRATCH1; + mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + ea->base = opts->gen.scratch1; } else { ea->base = opts->regs[Z80_IYL]; - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if(opts->regs[inst->ea_reg] >= 0) { ea->base = opts->regs[inst->ea_reg]; @@ -164,7 +133,7 @@ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ea->base = opts->regs[z80_low_reg(inst->ea_reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } } else { @@ -174,70 +143,70 @@ } break; case Z80_REG_INDIRECT: - dst = mov_rr(dst, opts->regs[inst->ea_reg], areg, SZ_W); + mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W); size = z80_size(inst); if (read) { if (modify) { - //dst = push_r(dst, SCRATCH1); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W); + //push_r(code, opts->gen.scratch1); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - dst = call(dst, (uint8_t *)z80_read_word); + call(code, opts->read_16); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_IMMED: ea->mode = MODE_IMMED; ea->disp = inst->immed; break; case Z80_IMMED_INDIRECT: - dst = mov_ir(dst, inst->immed, areg, SZ_W); + mov_ir(code, inst->immed, areg, SZ_W); size = z80_size(inst); if (read) { /*if (modify) { - dst = push_r(dst, SCRATCH1); + push_r(code, opts->gen.scratch1); }*/ if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - dst = call(dst, (uint8_t *)z80_read_word); + call(code, opts->read_16); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_ir(code, inst->immed, opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: reg = opts->regs[(inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY]; - dst = mov_rr(dst, reg, areg, SZ_W); - dst = add_ir(dst, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); + mov_rr(code, reg, areg, SZ_W); + add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); size = z80_size(inst); if (read) { if (modify) { - //dst = push_r(dst, SCRATCH1); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W); + //push_r(code, opts->gen.scratch1); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - dst = call(dst, (uint8_t *)z80_read_word); + call(code, opts->read_16); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_UNUSED: ea->mode = MODE_UNUSED; @@ -246,32 +215,30 @@ fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F); exit(1); } - return dst; } -uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, x86_z80_options * opts) +void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts) { if ((inst->addr_mode & 0x1F) == Z80_REG) { if (inst->ea_reg == Z80_IYH) { if (inst->reg == Z80_IYL) { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B); - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } else { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { uint8_t other_reg = opts->regs[inst->reg]; if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W); } } } - return dst; } -uint8_t * z80_save_result(uint8_t * dst, z80inst * inst) +void z80_save_result(z80_options *opts, z80inst * inst) { switch(inst->addr_mode & 0x1f) { @@ -280,12 +247,11 @@ case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: if (z80_size(inst) == SZ_B) { - dst = call(dst, (uint8_t *)z80_write_byte); + call(&opts->gen.code, opts->write_8); } else { - dst = call(dst, (uint8_t *)z80_write_word_lowfirst); + call(&opts->gen.code, opts->write_16_lowfirst); } } - return dst; } enum { @@ -332,15 +298,16 @@ exit(0); } -uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address, uint8_t interp) +void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp) { - uint32_t cycles; - x86_ea src_op, dst_op; + uint32_t num_cycles; + host_ea src_op, dst_op; uint8_t size; - x86_z80_options *opts = context->options; - uint8_t * start = dst; + z80_options *opts = context->options; + uint8_t * start = opts->gen.code.cur; + code_info *code = &opts->gen.code; if (!interp) { - dst = z80_check_cycles_int(dst, address); + check_cycles_int(&opts->gen, address); if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { zbreakpoint_patch(context, address, start); } @@ -353,253 +320,253 @@ { case Z80_REG: case Z80_REG_INDIRECT: - cycles = size == SZ_B ? 4 : 6; + num_cycles = size == SZ_B ? 4 : 6; if (inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } if (inst->reg == Z80_I || inst->ea_reg == Z80_I) { - cycles += 5; + num_cycles += 5; } break; case Z80_IMMED: - cycles = size == SZ_B ? 7 : 10; + num_cycles = size == SZ_B ? 7 : 10; break; case Z80_IMMED_INDIRECT: - cycles = 10; + num_cycles = 10; break; case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: - cycles = 16; + num_cycles = 16; break; } if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode & Z80_DIR) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); + translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); } else { - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + translate_z80_reg(inst, &dst_op, opts); } if (src_op.mode == MODE_REG_DIRECT) { if(dst_op.mode == MODE_REG_DISPLACE8) { - dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); + mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size); } else { - dst = mov_rr(dst, src_op.base, dst_op.base, size); + mov_rr(code, src_op.base, dst_op.base, size); } } else if(src_op.mode == MODE_IMMED) { - dst = mov_ir(dst, src_op.disp, dst_op.base, size); + mov_ir(code, src_op.disp, dst_op.base, size); } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); + mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); } if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) { //ld a, i sets some flags //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);; - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH1, SZ_B); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zf_off(ZF_PV), SZ_B); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);; + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), SCRATCH1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); if (inst->addr_mode & Z80_DIR) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); } break; case Z80_PUSH: - dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); + cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B); - dst = shl_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zf_off(ZF_S), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_Z), SCRATCH1, SZ_B); - dst = shl_ir(dst, 2, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_H), SCRATCH1, SZ_B); - dst = shl_ir(dst, 2, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_PV), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_N), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_C), SCRATCH1, SZ_B); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + shl_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B); + shl_ir(code, 2, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B); + shl_ir(code, 2, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B); } else { - dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); } - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, opts->write_16_highfirst); //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_POP: - dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word); - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); + cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, opts->read_16); + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = bt_ir(dst, 0, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = bt_ir(dst, 1, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_N)); - dst = bt_ir(dst, 2, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_PV)); - dst = bt_ir(dst, 4, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_H)); - dst = bt_ir(dst, 6, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_Z)); - dst = bt_ir(dst, 7, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_S)); - dst = shr_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + bt_ir(code, 0, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + bt_ir(code, 1, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N)); + bt_ir(code, 2, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_PV)); + bt_ir(code, 4, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H)); + bt_ir(code, 6, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_Z)); + bt_ir(code, 7, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S)); + shr_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); } else { - dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, SCRATCH1, src_op.base, SZ_W); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, opts->gen.scratch1, src_op.base, SZ_W); } //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_EX: if (inst->addr_mode == Z80_REG || inst->reg == Z80_HL) { - cycles = 4; + num_cycles = 4; } else { - cycles = 8; + num_cycles = 8; } - dst = zcycles(dst, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode == Z80_REG) { if(inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_A), SZ_B); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B); //Flags are currently word aligned, so we can move //them efficiently a word at a time for (int f = ZF_C; f < ZF_NUM; f+=2) { - dst = mov_rdisp8r(dst, CONTEXT, zf_off(f), SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zaf_off(f), SCRATCH2, SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zaf_off(f), SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zf_off(f), SZ_W); + mov_rdispr(code, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W); } } else { - dst = xchg_rr(dst, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); + xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); } } else { - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, opts->regs[inst->reg], SCRATCH1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 1); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, opts->write_8); + cycles(&opts->gen, 1); uint8_t high_reg = z80_high_reg(inst->reg); uint8_t use_reg; //even though some of the upper halves can be used directly //the limitations on mixing *H regs with the REX prefix //prevent us from taking advantage of it use_reg = opts->regs[inst->reg]; - dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = add_ir(dst, 1, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, use_reg, SCRATCH1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = add_ir(dst, 1, SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + ror_ir(code, 8, use_reg, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + add_ir(code, 1, opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + add_ir(code, 1, opts->gen.scratch2, SZ_W); + call(code, opts->write_8); //restore reg to normal rotation - dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = zcycles(dst, 2); + ror_ir(code, 8, use_reg, SZ_W); + cycles(&opts->gen, 2); } break; case Z80_EXX: - dst = zcycles(dst, 4); - dst = mov_rr(dst, opts->regs[Z80_BC], SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_C), SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zar_off(Z80_L), SZ_W); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_E), SZ_W); + cycles(&opts->gen, 4); + mov_rr(code, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); break; case Z80_LDI: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 2); - dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, opts->write_8); + cycles(&opts->gen, 2); + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDIR: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, opts->write_8); + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); - uint8_t * cont = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 7); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + uint8_t * cont = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this - dst = jmp(dst, start); - *cont = dst - (cont + 1); - dst = zcycles(dst, 2); + jmp(code, start); + *cont = code->cur - (cont + 1); + cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } case Z80_LDD: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 2); - dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, opts->write_8); + cycles(&opts->gen, 2); + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDDR: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, opts->write_8); + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); - uint8_t * cont = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 7); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + uint8_t * cont = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this - dst = jmp(dst, start); - *cont = dst - (cont + 1); - dst = zcycles(dst, 2); + jmp(code, start); + *cont = code->cur - (cont + 1); + cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } /*case Z80_CPI: @@ -608,634 +575,644 @@ case Z80_CPDR: break;*/ case Z80_ADD: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = add_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + add_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + add_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_ADC: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { - dst = adc_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + adc_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = adc_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + adc_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_SUB: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = sub_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + sub_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + sub_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_SBC: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { - dst = sbb_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + sbb_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = sbb_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_AND: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = and_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + and_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = and_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + and_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_OR: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = or_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + or_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = or_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + or_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_XOR: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + xor_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = xor_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + xor_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_CP: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = cmp_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + cmp_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = cmp_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + cmp_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_INC: - cycles = 4; + num_cycles = 4; if (inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 6; + num_cycles += 6; } else if(z80_size(inst) == SZ_W) { - cycles += 2; + num_cycles += 2; } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); if (dst_op.mode == MODE_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - dst = add_ir(dst, 1, dst_op.base, z80_size(inst)); + add_ir(code, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); - dst = z80_save_result(dst, inst); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); + z80_save_result(opts, inst); break; case Z80_DEC: - cycles = 4; + num_cycles = 4; if (inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 6; + num_cycles += 6; } else if(z80_size(inst) == SZ_W) { - cycles += 2; + num_cycles += 2; } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); if (dst_op.mode == MODE_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - dst = sub_ir(dst, 1, dst_op.base, z80_size(inst)); + sub_ir(code, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); - dst = z80_save_result(dst, inst); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); + z80_save_result(opts, inst); break; //case Z80_DAA: case Z80_CPL: - dst = zcycles(dst, 4); - dst = not_r(dst, opts->regs[Z80_A], SZ_B); + cycles(&opts->gen, 4); + not_r(code, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_NEG: - dst = zcycles(dst, 8); - dst = neg_r(dst, opts->regs[Z80_A], SZ_B); + cycles(&opts->gen, 8); + neg_r(code, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_CCF: - dst = zcycles(dst, 4); - dst = xor_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + cycles(&opts->gen, 4); + xor_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_SCF: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + cycles(&opts->gen, 4); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_NOP: if (inst->immed == 42) { - dst = call(dst, (uint8_t *)z80_save_context); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = jmp(dst, (uint8_t *)z80_print_regs_exit); + call(code, opts->gen.save_context); + mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); + jmp(code, (uint8_t *)z80_print_regs_exit); } else { - dst = zcycles(dst, 4 * inst->immed); + cycles(&opts->gen, 4 * inst->immed); } break; - case Z80_HALT: - dst = zcycles(dst, 4); - dst = mov_ir(dst, address, SCRATCH1, SZ_W); - uint8_t * call_inst = dst; - dst = call(dst, (uint8_t *)z80_halt); - dst = jmp(dst, call_inst); + case Z80_HALT: { + cycles(&opts->gen, 4); + mov_ir(code, address, opts->gen.scratch1, SZ_W); + uint8_t * call_inst = code->cur; + mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D); + sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D); + and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D); + add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); + cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + code_ptr skip_last = code->cur+1; + jcc(code, CC_NB, code->cur+2); + cycles(&opts->gen, 4); + *skip_last = code->cur - (skip_last+1); + call(code, opts->gen.handle_cycle_limit_int); + jmp(code, call_inst); break; + } case Z80_DI: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff2), SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, sync_cycle), ZLIMIT, SZ_D); - dst = mov_irdisp8(dst, 0xFFFFFFFF, CONTEXT, offsetof(z80_context, int_cycle), SZ_D); + cycles(&opts->gen, 4); + mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); + mov_irdisp(code, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D); break; case Z80_EI: - dst = zcycles(dst, 4); - dst = mov_rrdisp32(dst, ZCYCLES, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D); - dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff2), SZ_B); + cycles(&opts->gen, 4); + mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles - dst = add_irdisp32(dst, 4, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D); - dst = call(dst, (uint8_t *)z80_do_sync); + add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + call(code, opts->do_sync); break; case Z80_IM: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, inst->immed, CONTEXT, offsetof(z80_context, im), SZ_B); + cycles(&opts->gen, 4); + mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); break; case Z80_RLC: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = rol_ir(dst, 1, dst_op.base, SZ_B); + rol_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rlca does not set these flags - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RL: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); - dst = rcl_ir(dst, 1, dst_op.base, SZ_B); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + rcl_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rla does not set these flags - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RRC: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = ror_ir(dst, 1, dst_op.base, SZ_B); + ror_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rrca does not set these flags - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RR: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); - dst = rcr_ir(dst, 1, dst_op.base, SZ_B); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + rcr_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rra does not set these flags - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SLA: case Z80_SLL: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = shl_ir(dst, 1, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); + shl_ir(code, 1, dst_op.base, SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); if (inst->op == Z80_SLL) { - dst = or_ir(dst, 1, dst_op.base, SZ_B); + or_ir(code, 1, dst_op.base, SZ_B); } if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SRA: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = sar_ir(dst, 1, dst_op.base, SZ_B); + sar_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SRL: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = shr_ir(dst, 1, dst_op.base, SZ_B); + shr_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RLD: - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x24, A = 0x31 - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B); - dst = shl_ir(dst, 4, SCRATCH1, SZ_W); - dst = and_ir(dst, 0xF, SCRATCH2, SZ_W); - dst = and_ir(dst, 0xFFF, SCRATCH1, SZ_W); - dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); - dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W); - //SCRATCH1 = 0x0124 - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = zcycles(dst, 4); - dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); + shl_ir(code, 4, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF, opts->gen.scratch2, SZ_W); + and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B); + or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + //opts->gen.scratch1 = 0x0124 + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + cycles(&opts->gen, 4); + or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + call(code, opts->write_8); break; case Z80_RRD: - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x41, A = 0x32 - dst = movzx_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B, SZ_W); - dst = ror_ir(dst, 4, SCRATCH1, SZ_W); - dst = shl_ir(dst, 4, SCRATCH2, SZ_W); - dst = and_ir(dst, 0xF00F, SCRATCH1, SZ_W); - dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); - //SCRATCH1 = 0x2001 - //SCRATCH2 = 0x0040 - dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W); - //SCRATCH1 = 0x2041 - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = zcycles(dst, 4); - dst = shr_ir(dst, 4, SCRATCH1, SZ_B); - dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); + ror_ir(code, 4, opts->gen.scratch1, SZ_W); + shl_ir(code, 4, opts->gen.scratch2, SZ_W); + and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B); + //opts->gen.scratch1 = 0x2001 + //opts->gen.scratch2 = 0x0040 + or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + //opts->gen.scratch1 = 0x2041 + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + cycles(&opts->gen, 4); + shr_ir(code, 4, opts->gen.scratch1, SZ_B); + or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + call(code, opts->write_8); break; case Z80_BIT: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1244,27 +1221,27 @@ } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4 - dst = zcycles(dst, 1); + cycles(&opts->gen, 1); } - dst = bt_ir(dst, bit, src_op.base, size); - dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + bt_ir(code, bit, src_op.base, size); + setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); if (inst->immed == 7) { - dst = cmp_ir(dst, 0, src_op.base, size); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + cmp_ir(code, 0, src_op.base, size); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } else { - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); } break; } case Z80_SET: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1273,40 +1250,40 @@ } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, MODIFY); } if (inst->reg != Z80_USE_IMMED) { - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = zcycles(dst, 1); + cycles(&opts->gen, 1); } - dst = bts_ir(dst, bit, src_op.base, size); + bts_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { if (dst_op.base >= R8) { - dst = ror_ir(dst, 8, src_op.base, SZ_W); - dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); - dst = ror_ir(dst, 8, src_op.base, SZ_W); + ror_ir(code, 8, src_op.base, SZ_W); + mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); + ror_ir(code, 8, src_op.base, SZ_W); } else { - dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); } } else { - dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B); + mov_rr(code, src_op.base, dst_op.base, SZ_B); } } if ((inst->addr_mode & 0x1F) != Z80_REG) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (inst->reg != Z80_USE_IMMED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } break; } case Z80_RES: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1315,361 +1292,361 @@ } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, MODIFY); } if (inst->reg != Z80_USE_IMMED) { - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = zcycles(dst, 1); + cycles(&opts->gen, 1); } - dst = btr_ir(dst, bit, src_op.base, size); + btr_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { if (dst_op.base >= R8) { - dst = ror_ir(dst, 8, src_op.base, SZ_W); - dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); - dst = ror_ir(dst, 8, src_op.base, SZ_W); + ror_ir(code, 8, src_op.base, SZ_W); + mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); + ror_ir(code, 8, src_op.base, SZ_W); } else { - dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); } } else { - dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B); + mov_rr(code, src_op.base, dst_op.base, SZ_B); } } if (inst->addr_mode != Z80_REG) { - dst = z80_save_result(dst, inst); + z80_save_result(opts, inst); if (inst->reg != Z80_USE_IMMED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } break; } case Z80_JP: { - cycles = 4; + num_cycles = 4; if (inst->addr_mode != Z80_REG_INDIRECT) { - cycles += 6; + num_cycles += 6; } else if(inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } - dst = zcycles(dst, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { if (inst->addr_mode == Z80_REG_INDIRECT) { - dst = mov_rr(dst, opts->regs[inst->ea_reg], SCRATCH1, SZ_W); + mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); } - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_JPCC: { - dst = zcycles(dst, 7);//T States: 4,3 + cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 5);//T States: 5 + uint8_t *no_jump_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = inst->immed; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; } case Z80_JR: { - dst = zcycles(dst, 12);//T States: 4,3,5 + cycles(&opts->gen, 12);//T States: 4,3,5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_JRCC: { - dst = zcycles(dst, 7);//T States: 4,3 + cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; } - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 5);//T States: 5 + uint8_t *no_jump_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; } case Z80_DJNZ: - dst = zcycles(dst, 8);//T States: 5,3 - dst = sub_ir(dst, 1, opts->regs[Z80_B], SZ_B); - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 5);//T States: 5 + cycles(&opts->gen, 8);//T States: 5,3 + sub_ir(code, 1, opts->regs[Z80_B], SZ_B); + uint8_t *no_jump_off = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; case Z80_CALL: { - dst = zcycles(dst, 11);//T States: 4,3,4 - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + cycles(&opts->gen, 11);//T States: 4,3,4 + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, opts->write_16_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_CALLCC: - dst = zcycles(dst, 10);//T States: 4,3,3 (false case) + cycles(&opts->gen, 10);//T States: 4,3,3 (false case) uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_call_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 1);//Last of the above T states takes an extra cycle in the true case - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + uint8_t *no_call_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, opts->write_16_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_call_off = dst - (no_call_off+1); + *no_call_off = code->cur - (no_call_off+1); break; case Z80_RET: - dst = zcycles(dst, 4);//T States: 4 - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + cycles(&opts->gen, 4);//T States: 4 + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, opts->read_16);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RETCC: { - dst = zcycles(dst, 5);//T States: 5 + cycles(&opts->gen, 5);//T States: 5 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_call_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); - *no_call_off = dst - (no_call_off+1); + uint8_t *no_call_off = code->cur+1; + jcc(code, cond, code->cur+2); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, opts->read_16);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + *no_call_off = code->cur - (no_call_off+1); break; } case Z80_RETI: //For some systems, this may need a callback for signalling interrupt routine completion - dst = zcycles(dst, 8);//T States: 4, 4 - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + cycles(&opts->gen, 8);//T States: 4, 4 + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, opts->read_16);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RETN: - dst = zcycles(dst, 8);//T States: 4, 4 - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH2, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(z80_context, iff1), SZ_B); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + cycles(&opts->gen, 8);//T States: 4, 4 + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + call(code, opts->read_16);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RST: { //RST is basically CALL to an address in page 0 - dst = zcycles(dst, 5);//T States: 5 - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 1, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + cycles(&opts->gen, 5);//T States: 5 + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 1, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, opts->write_16_highfirst);//T States: 3, 3 + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst = code->cur + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); break; } case Z80_IN: - dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if (inst->addr_mode == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_B); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH1, SZ_B); + mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); } - dst = call(dst, (uint8_t *)z80_io_read); - translate_z80_reg(inst, &dst_op, dst, opts); - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B); - dst = z80_save_reg(dst, inst, opts); + call(code, opts->read_io); + translate_z80_reg(inst, &dst_op, opts); + mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); + z80_save_reg(inst, opts); break; /*case Z80_INI: case Z80_INIR: case Z80_IND: case Z80_INDR:*/ case Z80_OUT: - dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_B); + mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH2, SZ_B); + mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); } - translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B); - dst = call(dst, (uint8_t *)z80_io_write); - dst = z80_save_reg(dst, inst, opts); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); + call(code, opts->write_io); + z80_save_reg(inst, opts); break; /*case Z80_OUTI: case Z80_OTIR: @@ -1685,7 +1662,6 @@ exit(1); } } - return dst; } uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) @@ -1704,45 +1680,45 @@ fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); exit(1); } - x86_z80_options * opts = context->options; - if (opts->code_end - opts->cur_code < ZMAX_NATIVE_SIZE) { - size_t size = 1024*1024; - opts->cur_code = alloc_code(&size); - opts->code_end = opts->cur_code + size; - } - context->interp_code[opcode] = opts->cur_code; - opts->cur_code = translate_z80inst(&inst, opts->cur_code, context, 0, 1); - opts->cur_code = mov_rdisp8r(opts->cur_code, CONTEXT, offsetof(z80_context, pc), SCRATCH1, SZ_W); - opts->cur_code = add_ir(opts->cur_code, after - codebuf, SCRATCH1, SZ_W); - opts->cur_code = call(opts->cur_code, (uint8_t *)z80_native_addr); - opts->cur_code = jmp_r(opts->cur_code, SCRATCH1); + + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_alloc_code(code, ZMAX_NATIVE_SIZE); + context->interp_code[opcode] = code->cur; + translate_z80inst(&inst, context, 0, 1); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W); + add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); } return context->interp_code[opcode]; } -uint8_t * z80_make_interp_stub(z80_context * context, uint16_t address) +code_info z80_make_interp_stub(z80_context * context, uint16_t address) { - x86_z80_options *opts = context->options; - uint8_t *dst = opts->cur_code; + z80_options *opts = context->options; + code_info * code = &opts->gen.code; + check_alloc_code(code, 32); + code_info stub = {code->cur, NULL}; //TODO: make this play well with the breakpoint code - dst = mov_ir(dst, address, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); + mov_ir(code, address, opts->gen.scratch1, SZ_W); + call(code, opts->read_8); //normal opcode fetch is already factored into instruction timing //back out the base 3 cycles from a read here //not quite perfect, but it will have to do for now - dst = sub_ir(dst, 3, ZCYCLES, SZ_D); - dst = z80_check_cycles_int(dst, address); - dst = call(dst, (uint8_t *)z80_save_context); - dst = mov_rr(dst, SCRATCH1, RDI, SZ_B); - dst = mov_irdisp8(dst, address, CONTEXT, offsetof(z80_context, pc), SZ_W); - dst = push_r(dst, CONTEXT); - dst = call(dst, (uint8_t *)z80_interp_handler); - dst = mov_rr(dst, RAX, SCRATCH1, SZ_Q); - dst = pop_r(dst, CONTEXT); - dst = call(dst, (uint8_t *)z80_load_context); - dst = jmp_r(dst, SCRATCH1); - opts->code_end = dst; - return dst; + cycles(&opts->gen, -3); + check_cycles_int(&opts->gen, address); + call(code, opts->gen.save_context); + mov_rr(code, opts->gen.scratch1, RDI, SZ_B); + mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)z80_interp_handler); + mov_rr(code, RAX, opts->gen.scratch1, SZ_Q); + pop_r(code, opts->gen.context_reg); + call(code, opts->gen.load_context); + jmp_r(code, opts->gen.scratch1); + stub.last = code->cur; + return stub; } @@ -1764,24 +1740,24 @@ return map->base + map->offsets[address]; } -uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address) +uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address) { //TODO: Fix for addresses >= 0x4000 if (address >= 0x4000) { return 0; } - return opts->ram_inst_sizes[address & 0x1FFF]; + return opts->gen.ram_inst_sizes[0][address & 0x1FFF]; } void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size) { uint32_t orig_address = address; native_map_slot *map; - x86_z80_options * opts = context->options; + z80_options * opts = context->options; if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - opts->ram_inst_sizes[address] = native_size; + opts->gen.ram_inst_sizes[0][address] = native_size; context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); } else { @@ -1837,10 +1813,12 @@ { uint32_t inst_start = z80_get_instruction_start(context->static_code_map, address); if (inst_start != INVALID_INSTRUCTION_START) { - uint8_t * dst = z80_get_native_address(context, inst_start); - dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", dst, inst_start, address); - dst = mov_ir(dst, inst_start, SCRATCH1, SZ_D); - dst = call(dst, (uint8_t *)z80_retrans_stub); + code_ptr dst = z80_get_native_address(context, inst_start); + code_info code = {dst, dst+16}; + z80_options * opts = context->options; + dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); + mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); + call(&code, opts->retrans_stub); } return context; } @@ -1860,22 +1838,21 @@ void z80_handle_deferred(z80_context * context) { - x86_z80_options * opts = context->options; - process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); - if (opts->deferred) { - translate_z80_stream(context, opts->deferred->address); + z80_options * opts = context->options; + process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address); + if (opts->gen.deferred) { + translate_z80_stream(context, opts->gen.deferred->address); } } void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) { char disbuf[80]; - x86_z80_options * opts = context->options; + z80_options * opts = context->options; uint8_t orig_size = z80_get_native_inst_size(opts, address); uint32_t orig = address; address &= 0x1FFF; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; + code_info *code = &opts->gen.code; uint8_t *after, *inst = context->mem_pointers[0] + address; z80inst instbuf; dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start); @@ -1889,19 +1866,15 @@ } #endif if (orig_size != ZMAX_NATIVE_SIZE) { - if (dst_end - dst < ZMAX_NATIVE_SIZE) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - opts->cur_code = dst; - } - deferred_addr * orig_deferred = opts->deferred; - uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address, 0); + check_alloc_code(code, ZMAX_NATIVE_SIZE); + code_ptr start = code->cur; + deferred_addr * orig_deferred = opts->gen.deferred; + translate_z80inst(&instbuf, context, address, 0); /* if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { - remove_deferred_until(&opts->deferred, orig_deferred); + remove_deferred_until(&opts->gen.deferred, orig_deferred); native_end = translate_z80inst(&instbuf, orig_start, context, address, 0); if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { while (native_end < orig_start + orig_size) { @@ -1913,20 +1886,27 @@ z80_handle_deferred(context); return orig_start; } - } - */ - z80_map_native_address(context, address, dst, after-inst, ZMAX_NATIVE_SIZE); - opts->cur_code = dst+ZMAX_NATIVE_SIZE; - jmp(orig_start, dst); + }*/ + z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE); + code_info tmp_code = {orig_start, orig_start + 16}; + jmp(&tmp_code, start); + tmp_code = *code; + code->cur = start + ZMAX_NATIVE_SIZE; if (!z80_is_terminal(&instbuf)) { - jmp(native_end, z80_get_native_address_trans(context, address + after-inst)); + jmp(&tmp_code, z80_get_native_address_trans(context, address + after-inst)); } z80_handle_deferred(context); - return dst; + return start; } else { - dst = translate_z80inst(&instbuf, orig_start, context, address, 0); + code_info tmp_code = *code; + code->cur = orig_start; + code->last = orig_start + ZMAX_NATIVE_SIZE; + translate_z80inst(&instbuf, context, address, 0); + code_info tmp2 = *code; + *code = tmp_code; if (!z80_is_terminal(&instbuf)) { - dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst)); + + jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst)); } z80_handle_deferred(context); return orig_start; @@ -1939,7 +1919,7 @@ if (z80_get_native_address(context, address)) { return; } - x86_z80_options * opts = context->options; + z80_options * opts = context->options; uint32_t start_address = address; uint8_t * encoded = NULL, *next; if (address < 0x4000) { @@ -1951,27 +1931,18 @@ z80inst inst; dprintf("translating Z80 code at address %X\n", address); do { - if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) { - if (opts->code_end-opts->cur_code < 5) { - puts("out of code memory, not enough space for jmp to next chunk"); - exit(1); - } - size_t size = 1024*1024; - opts->cur_code = alloc_code(&size); - opts->code_end = opts->cur_code + size; - jmp(opts->cur_code, opts->cur_code); - } if (address >= 0x4000) { - uint8_t *native_start = opts->cur_code; - uint8_t *after = z80_make_interp_stub(context, address); - z80_map_native_address(context, address, opts->cur_code, 1, after - native_start); + code_info stub = z80_make_interp_stub(context, address); + z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur); break; } uint8_t * existing = z80_get_native_address(context, address); if (existing) { - opts->cur_code = jmp(opts->cur_code, existing); + jmp(&opts->gen.code, existing); break; } + //make sure prologue is in a contiguous chunk of code + check_code_prologue(&opts->gen.code); next = z80_decode(encoded, &inst); #ifdef DO_DEBUG_PRINT z80_disasm(&inst, disbuf, address); @@ -1981,9 +1952,9 @@ printf("%X\t%s\n", address, disbuf); } #endif - uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address, 0); - z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code); - opts->cur_code = after; + code_ptr start = opts->gen.code.cur; + translate_z80inst(&inst, context, address, 0); + z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start); address += next-encoded; if (address > 0xFFFF) { address &= 0xFFFF; @@ -1992,9 +1963,9 @@ encoded = next; } } while (!z80_is_terminal(&inst)); - process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); - if (opts->deferred) { - address = opts->deferred->address; + process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address); + if (opts->gen.deferred) { + address = opts->gen.deferred->address; dprintf("defferred address: %X\n", address); if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); @@ -2008,8 +1979,18 @@ } } -void init_x86_z80_opts(x86_z80_options * options) +void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) { + memset(options, 0, sizeof(*options)); + + options->gen.address_size = SZ_W; + options->gen.address_mask = 0xFFFF; + options->gen.max_address = 0x10000; + options->gen.bus_cycles = 3; + options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers); + options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags); + options->gen.ram_flags_shift = 7; + options->flags = 0; options->regs[Z80_B] = BH; options->regs[Z80_C] = RBX; @@ -2031,15 +2012,285 @@ options->regs[Z80_AF] = -1; options->regs[Z80_IX] = RDX; options->regs[Z80_IY] = R8; - size_t size = 1024 * 1024; - options->cur_code = alloc_code(&size); - options->code_end = options->cur_code + size; - options->ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000); - memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000); - options->deferred = NULL; + + options->bank_reg = R15; + options->bank_pointer = R12; + + options->gen.context_reg = RSI; + options->gen.cycles = RBP; + options->gen.limit = RDI; + options->gen.scratch1 = R13; + options->gen.scratch2 = R14; + + options->gen.native_code_map = malloc(sizeof(native_map_slot)); + memset(options->gen.native_code_map, 0, sizeof(native_map_slot)); + options->gen.deferred = NULL; + options->gen.ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000 + sizeof(uint8_t *)); + options->gen.ram_inst_sizes[0] = (uint8_t *)(options->gen.ram_inst_sizes + 1); + memset(options->gen.ram_inst_sizes[0], 0, sizeof(uint8_t) * 0x2000); + + code_info *code = &options->gen.code; + init_code_info(code); + + options->save_context_scratch = code->cur; + mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); + mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_W); + + options->gen.save_context = code->cur; + for (int i = 0; i <= Z80_A; i++) + { + int reg; + uint8_t size; + if (i < Z80_I) { + reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0); + size = SZ_W; + } else { + reg = i; + size = SZ_B; +} + if (options->regs[reg] >= 0) { + mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size); + } + if (size == SZ_W) { + i++; + } + } + if (options->regs[Z80_SP] >= 0) { + mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W); + } + mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); + mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); + mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); + mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); + retn(code); + + options->load_context_scratch = code->cur; + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W); + options->gen.load_context = code->cur; + for (int i = 0; i <= Z80_A; i++) + { + int reg; + uint8_t size; + if (i < Z80_I) { + reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0); + size = SZ_W; + } else { + reg = i; + size = SZ_B; + } + if (options->regs[reg] >= 0) { + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size); + } + if (size == SZ_W) { + i++; + } + } + if (options->regs[Z80_SP] >= 0) { + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W); + } + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); + retn(code); + + options->native_addr = code->cur; + call(code, options->gen.save_context); + push_r(code, options->gen.context_reg); + mov_rr(code, options->gen.context_reg, RDI, SZ_PTR); + movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D); + call(code, (code_ptr)z80_get_native_address_trans); + mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); + pop_r(code, options->gen.context_reg); + call(code, options->gen.load_context); + retn(code); + + options->gen.handle_cycle_limit = code->cur; + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); + code_ptr no_sync = code->cur+1; + jcc(code, CC_B, no_sync); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, pc), SZ_W); + call(code, options->save_context_scratch); + pop_r(code, RAX); //return address in read/write func + pop_r(code, RBX); //return address in translated code + sub_ir(code, 5, RAX, SZ_PTR); //adjust return address to point to the call that got us here + mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR); + //restore callee saved registers + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); + pop_r(code, RBX); + *no_sync = code->cur - (no_sync + 1); + //return to caller of z80_run + retn(code); + + options->gen.handle_code_write = (code_ptr)z80_handle_code_write; + + options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc); + options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc); + + options->gen.handle_cycle_limit_int = code->cur; + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D); + code_ptr skip_int = code->cur+1; + jcc(code, CC_B, skip_int); + //set limit to the cycle limit + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.limit, SZ_D); + //disable interrupts + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + cycles(&options->gen, 7); + //save return address (in scratch1) to Z80 stack + sub_ir(code, 2, options->regs[Z80_SP], SZ_W); + mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); + //we need to do check_cycles and cycles outside of the write_8 call + //so that the stack has the correct depth if we need to return to C + //for a synchronization + check_cycles(&options->gen); + cycles(&options->gen, 3); + //save word to write before call to write_8_noinc + push_r(code, options->gen.scratch1); + call(code, options->write_8_noinc); + //restore word to write + pop_r(code, options->gen.scratch1); + //write high byte to SP+1 + mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + check_cycles(&options->gen); + cycles(&options->gen, 3); + call(code, options->write_8_noinc); + //dispose of return address as we'll be jumping somewhere else + pop_r(code, options->gen.scratch2); + //TODO: Support interrupt mode 0 and 2 + mov_ir(code, 0x38, options->gen.scratch1, SZ_W); + call(code, options->native_addr); + jmp_r(code, options->gen.scratch1); + *skip_int = code->cur - (skip_int+1); + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); + code_ptr skip_sync = code->cur + 1; + jcc(code, CC_B, skip_sync); + options->do_sync = code->cur; + call(code, options->gen.save_context); + pop_rind(code, options->gen.context_reg); + //restore callee saved registers + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); + pop_r(code, RBX); + //return to caller of z80_run + *skip_sync = code->cur - (skip_sync+1); + retn(code); + + options->read_io = code->cur; + check_cycles(&options->gen); + cycles(&options->gen, 4); + //Genesis has no IO hardware and always returns FF + //eventually this should use a second memory map array + mov_ir(code, 0xFF, options->gen.scratch1, SZ_B); + retn(code); + + options->write_io = code->cur; + check_cycles(&options->gen); + cycles(&options->gen, 4); + retn(code); + + options->read_16 = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: figure out how to handle the extra wait state for word reads to bank area + //may also need special handling to avoid too much stack depth when acces is blocked + push_r(code, options->gen.scratch1); + call(code, options->read_8_noinc); + mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B); + pop_r(code, options->gen.scratch1); + add_ir(code, 1, options->gen.scratch1, SZ_W); + cycles(&options->gen, 3); + check_cycles(&options->gen); + call(code, options->read_8_noinc); + shl_ir(code, 8, options->gen.scratch1, SZ_W); + mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B); + retn(code); + + options->write_16_highfirst = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + push_r(code, options->gen.scratch2); + push_r(code, options->gen.scratch1); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + call(code, options->write_8_noinc); + pop_r(code, options->gen.scratch1); + pop_r(code, options->gen.scratch2); + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: Check if we can get away with TCO here + call(code, options->write_8_noinc); + retn(code); + + options->write_16_lowfirst = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + push_r(code, options->gen.scratch2); + push_r(code, options->gen.scratch1); + call(code, options->write_8_noinc); + pop_r(code, options->gen.scratch1); + pop_r(code, options->gen.scratch2); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: Check if we can get away with TCO here + call(code, options->write_8_noinc); + retn(code); + + options->retrans_stub = code->cur; + //pop return address + pop_r(code, options->gen.scratch2); + call(code, options->gen.save_context); + //adjust pointer before move and call instructions that got us here + sub_ir(code, 11, options->gen.scratch2, SZ_PTR); + mov_rr(code, options->gen.scratch1, RDI, SZ_D); + mov_rr(code, options->gen.scratch2, RDX, SZ_PTR); + push_r(code, options->gen.context_reg); + call(code, (code_ptr)z80_retranslate_inst); + pop_r(code, options->gen.context_reg); + mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); + call(code, options->gen.load_context); + jmp_r(code, options->gen.scratch1); + + options->run = (z80_run_fun)code->cur; + //save callee save registers + push_r(code, RBX); + push_r(code, RBP); + push_r(code, R12); + push_r(code, R13); + push_r(code, R14); + push_r(code, R15); + mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); + call(code, options->load_context_scratch); + cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + code_ptr no_extra = code->cur+1; + jcc(code, CC_Z, no_extra); + push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc)); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + *no_extra = code->cur - (no_extra + 1); + jmp_rind(code, options->gen.context_reg); } -void init_z80_context(z80_context * context, x86_z80_options * options) +void * z80_gen_bank_write(uint32_t start_address, void * voptions) +{ + z80_options * options = voptions; + //TODO: Handle writes to bank register + return options; +} + +void init_z80_context(z80_context * context, z80_options * options) { memset(context, 0, sizeof(*context)); context->static_code_map = malloc(sizeof(*context->static_code_map)); @@ -2052,6 +2303,7 @@ context->int_cycle = 0xFFFFFFFF; context->int_pulse_start = 0xFFFFFFFF; context->int_pulse_end = 0xFFFFFFFF; + context->run = options->run; } void z80_reset(z80_context * context) @@ -2062,55 +2314,52 @@ context->extra_pc = NULL; } -uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native) +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) { - native = mov_ir(native, address, SCRATCH1, SZ_W); - native = call(native, context->bp_stub); - return native; + code_info code = {dst, dst+16}; + mov_ir(&code, address, SCRATCH1, SZ_W); + call(&code, context->bp_stub); + return code.cur-dst; } void zcreate_stub(z80_context * context) { - x86_z80_options * opts = context->options; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - if (dst_end - dst < 128) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - } - context->bp_stub = dst; + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_code_prologue(code); + context->bp_stub = code->cur; //Calculate length of prologue - int check_int_size = z80_check_cycles_int(dst, 0) - dst; + check_cycles_int(&opts->gen, 0); + int check_int_size = code->cur-context->bp_stub; + code->cur = context->bp_stub; //Calculate length of patch - int patch_size = zbreakpoint_patch(context, 0, dst) - dst; + int patch_size = zbreakpoint_patch(context, 0, code->cur); //Save context and call breakpoint handler - dst = call(dst, (uint8_t *)z80_save_context); - dst = push_r(dst, SCRATCH1); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = mov_rr(dst, SCRATCH1, RSI, SZ_W); - dst = call(dst, context->bp_handler); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + call(code, opts->gen.save_context); + push_r(code, opts->gen.scratch1); + mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); + mov_rr(code, opts->gen.scratch1, RSI, SZ_W); + call(code, context->bp_handler); + mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); //Restore context - dst = call(dst, (uint8_t *)z80_load_context); - dst = pop_r(dst, SCRATCH1); + call(code, opts->gen.load_context); + pop_r(code, opts->gen.scratch1); //do prologue stuff - dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q); - dst = push_r(dst, SCRATCH1); - dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); + cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); + uint8_t * jmp_off = code->cur+1; + jcc(code, CC_NC, code->cur + 7); + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + push_r(code, opts->gen.scratch1); + jmp(code, opts->gen.handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); //jump back to body of translated instruction - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q); - dst = jmp_r(dst, SCRATCH1); - opts->cur_code = dst; + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + jmp_r(code, opts->gen.scratch1); } void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) @@ -2134,8 +2383,12 @@ context->breakpoint_flags[address / sizeof(uint8_t)] &= ~(1 << (address % sizeof(uint8_t))); uint8_t * native = z80_get_native_address(context, address); if (native) { - z80_check_cycles_int(native, address); + z80_options * opts = context->options; + code_info tmp_code = opts->gen.code; + opts->gen.code.cur = native; + opts->gen.code.last = native + 16; + check_cycles_int(&opts->gen, address); + opts->gen.code = tmp_code; } } - diff -r 103d5cabbe14 -r f822d9216968 z80_to_x86.h --- a/z80_to_x86.h Tue Dec 16 01:10:54 2014 -0800 +++ b/z80_to_x86.h Tue Dec 30 19:11:34 2014 -0800 @@ -1,12 +1,12 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef Z80_TO_X86_H_ #define Z80_TO_X86_H_ #include "z80inst.h" -#include "x86_backend.h" +#include "backend.h" #define ZNUM_MEM_AREAS 4 #define ZMAX_NATIVE_SIZE 128 @@ -21,14 +21,31 @@ ZF_NUM }; +typedef void (*z80_run_fun)(void * context); + typedef struct { - uint8_t * cur_code; - uint8_t * code_end; - uint8_t *ram_inst_sizes; - deferred_addr * deferred; + cpu_options gen; + code_ptr save_context_scratch; + code_ptr load_context_scratch; + code_ptr native_addr; + code_ptr retrans_stub; + code_ptr do_sync; + code_ptr read_8; + code_ptr write_8; + code_ptr read_8_noinc; + code_ptr write_8_noinc; + code_ptr read_16; + code_ptr write_16_highfirst; + code_ptr write_16_lowfirst; + code_ptr read_io; + code_ptr write_io; + uint32_t flags; int8_t regs[Z80_UNUSED]; -} x86_z80_options; + int8_t bank_reg; + int8_t bank_pointer; + z80_run_fun run; +} z80_options; typedef struct { void * native_pc; @@ -51,11 +68,12 @@ uint32_t int_cycle; native_map_slot * static_code_map; native_map_slot * banked_code_map; - void * options; + z80_options * options; void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; - uint16_t pc; + z80_run_fun run; + uint16_t pc; uint32_t int_pulse_start; uint32_t int_pulse_end; uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; @@ -66,15 +84,16 @@ } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -void init_x86_z80_opts(x86_z80_options * options); -void init_z80_context(z80_context * context, x86_z80_options * options); -uint8_t * z80_get_native_address(z80_context * context, uint32_t address); -uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address); +void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks); +void init_z80_context(z80_context * context, z80_options * options); +code_ptr z80_get_native_address(z80_context * context, uint32_t address); +code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); z80_context * z80_handle_code_write(uint32_t address, z80_context * context); void z80_run(z80_context * context); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); +void * z80_gen_bank_write(uint32_t start_address, void * voptions); #endif //Z80_TO_X86_H_ diff -r 103d5cabbe14 -r f822d9216968 zcompare.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/zcompare.py Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,58 @@ +#!/usr/bin/env python +from glob import glob +import subprocess +from sys import exit,argv + +prefixes = [] +skip = set() +for i in range(1, len(argv)): + if '.' in argv[i]: + f = open(argv[i]) + for line in f: + parts = line.split() + for part in parts: + if part.endswith('.bin'): + skip.add(part) + f.close() + print 'Skipping',len(skip),'entries from previous report.' + else: + prefixes.append(argv[i]) + +for path in glob('ztests/*/*.bin'): + if path in skip: + continue + if prefixes: + good = False + fname = path.split('/')[-1] + for prefix in prefixes: + if fname.startswith(prefix): + good = True + break + if not good: + continue + try: + b = subprocess.check_output(['./ztestrun', path]) + try: + m = subprocess.check_output(['gxz80/gxzrun', path]) + #_,_,b = b.partition('\n') + if b != m: + print '-----------------------------' + print 'Mismatch in ' + path + print 'blastem output:' + print b + print 'gxz80 output:' + print m + print '-----------------------------' + else: + print path, 'passed' + except subprocess.CalledProcessError as e: + print '-----------------------------' + print 'gxz80 exited with code', e.returncode, 'for test', path + print 'blastem output:' + print b + print '-----------------------------' + except subprocess.CalledProcessError as e: + print '-----------------------------' + print 'blastem exited with code', e.returncode, 'for test', path + print '-----------------------------' + diff -r 103d5cabbe14 -r f822d9216968 ztestgen.c --- a/ztestgen.c Tue Dec 16 01:10:54 2014 -0800 +++ b/ztestgen.c Tue Dec 30 19:11:34 2014 -0800 @@ -24,6 +24,7 @@ #define PRE_IX 0xDD #define PRE_IY 0xFD #define LD_IR16 0x01 +#define INC_R8 0x04 #define LD_IR8 0x06 #define LD_RR8 0x40 #define AND_R 0xA0 @@ -143,6 +144,43 @@ } } +uint8_t * inc_r(uint8_t *dst, uint8_t reg) +{ + if (reg == Z80_IXH || reg == Z80_IXL) { + *(dst++) = PRE_IX; + return inc_r(dst, reg - (Z80_IXL - Z80_L)); + } else if(reg == Z80_IYH || reg == Z80_IYL) { + *(dst++) = PRE_IY; + return inc_r(dst, reg - (Z80_IYL - Z80_L)); + } else { + *(dst++) = INC_R8 | reg << 3; + return dst; + } +} + +void mark_used8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t reg, uint8_t init_value) +{ + reg_usage[reg] = 1; + reg_values[reg] = init_value; + uint8_t word_reg = z80_word_reg(reg); + if (word_reg != Z80_UNUSED) { + reg_usage[word_reg] = 1; + reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); + } +} + +uint8_t alloc_reg8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t init_value) +{ + for (uint8_t reg = 0; reg < Z80_BC; reg++) + { + if (!reg_usage[reg]) { + mark_used8(reg_usage, reg_values, reg, init_value); + return reg; + } + } + return Z80_UNUSED; +} + void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) { z80inst copy; @@ -184,12 +222,7 @@ reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF; reg_usage[z80_low_reg(inst->ea_reg)] = 1; } else { - reg_values[inst->ea_reg] = rand() % 256; - uint8_t word_reg = z80_word_reg(inst->ea_reg); - if (word_reg != Z80_UNUSED) { - reg_usage[word_reg] = 1; - reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); - } + mark_used8(reg_usage, reg_values, inst->ea_reg, rand() % 256); } break; case Z80_REG_INDIRECT: @@ -255,6 +288,10 @@ } reg_usage[inst->reg] = 1; } + uint8_t counter_reg = Z80_UNUSED; + if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) { + counter_reg = alloc_reg8(reg_usage, reg_values, 0); + } puts("--------------"); for (uint8_t reg = 0; reg < Z80_UNUSED; reg++) { if (reg_values[reg]) { @@ -293,11 +330,26 @@ //setup other regs for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) { - if (reg != Z80_AF && reg != Z80_SP) { - cur = ld_ir16(cur, reg, reg_values[reg]); + if (reg != Z80_AF && reg != Z80_SP && (inst->op != Z80_JP || addr_mode != Z80_REG_INDIRECT || inst->ea_reg != reg)) { + if (i == 1 && (z80_high_reg(reg) == counter_reg || z80_low_reg(reg) == counter_reg)) { + if (z80_high_reg(reg) == counter_reg) { + if (reg_usage[z80_low_reg(reg)]) { + cur = ld_ir8(cur, z80_low_reg(reg), reg_values[z80_low_reg(reg)]); + } + } else if (reg_usage[z80_high_reg(reg)]) { + cur = ld_ir8(cur, z80_high_reg(reg), reg_values[z80_high_reg(reg)]); + } + } else { + cur = ld_ir16(cur, reg, reg_values[reg]); + } } } + if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) { + uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1 + i; + cur = ld_ir16(cur, inst->ea_reg, address); + } + //copy instruction if (instlen == 3) { memcpy(cur, instbuf, 2); @@ -310,6 +362,12 @@ //immed/displacement byte(s) if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) { *(cur++) = inst->ea_reg; + } else if ((inst->op == Z80_JP || inst->op == Z80_JPCC) && addr_mode == Z80_IMMED) { + uint16_t address = cur - prog + 3 + i; //2 for immed address, 1/2 for instruction(s) to skip + *(cur++) = address; + *(cur++) = address >> 8; + } else if(inst->op == Z80_JR || inst->op == Z80_JRCC) { + *(cur++) = 1 + i; //skip one or 2 instructions based on value of i } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) { *(cur++) = inst->immed & 0xFF; if (word_sized) { @@ -325,6 +383,13 @@ if (instlen == 3) { *(cur++) = instbuf[2]; } + if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) { + cur = inc_r(cur, counter_reg); + if (i) { + //inc twice on second iteration so we can differentiate the two + cur = inc_r(cur, counter_reg); + } + } if (!i) { //Save AF from first run cur = push(cur, Z80_AF); @@ -399,7 +464,7 @@ uint8_t should_skip(z80inst * inst) { - return inst->op >= Z80_JP || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT + return inst->op >= Z80_DJNZ || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT || inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP || inst->op == Z80_DI || inst->op == Z80_EI; } diff -r 103d5cabbe14 -r f822d9216968 ztestrun.c --- a/ztestrun.c Tue Dec 16 01:10:54 2014 -0800 +++ b/ztestrun.c Tue Dec 30 19:11:34 2014 -0800 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "z80inst.h" @@ -11,7 +11,6 @@ #include uint8_t z80_ram[0x2000]; -uint16_t cart[0x200000]; #define MCLKS_PER_Z80 15 //TODO: Figure out the exact value for this @@ -19,26 +18,26 @@ #define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) #define CYCLE_NEVER 0xFFFFFFFF -uint8_t z80_read_ym(uint16_t location, z80_context * context) +uint8_t z80_unmapped_read(uint32_t location, void * context) { return 0xFF; } -z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) +void * z80_unmapped_write(uint32_t location, void * context, uint8_t value) { return context; } -z80_context * z80_vdp_port_write(uint16_t location, z80_context * context, uint8_t value) -{ - return context; -} +const memmap_chunk z80_map[] = { + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x4000, 0x10000, 0xFFFF, 0, 0, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write} +}; int main(int argc, char ** argv) { long filesize; uint8_t *filebuf; - x86_z80_options opts; + z80_options opts; z80_context context; if (argc < 2) { fputs("usage: transz80 zrom [cartrom]\n", stderr); @@ -54,47 +53,29 @@ fseek(f, 0, SEEK_SET); fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); fclose(f); - if (argc > 2) { - f = fopen(argv[2], "rb"); - if (!f) { - fprintf(stderr, "unable to open file %s\n", argv[2]); - exit(1); - } - fseek(f, 0, SEEK_END); - filesize = ftell(f); - fseek(f, 0, SEEK_SET); - fread(cart, 1, filesize < sizeof(cart) ? filesize : sizeof(cart), f); - fclose(f); - for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur) - { - *cur = (*cur >> 8) | (*cur << 8); - } - } - init_x86_z80_opts(&opts); + init_x86_z80_opts(&opts, z80_map, 2); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; context.sync_cycle = context.target_cycle = 1000; context.int_cycle = CYCLE_NEVER; - //cartridge/bank - context.mem_pointers[1] = context.mem_pointers[2] = (uint8_t *)cart; z80_reset(&context); while (context.current_cycle < 1000) { - z80_run(&context); + context.run(&context); } - printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C], - context.regs[Z80_D], context.regs[Z80_E], - (context.regs[Z80_H] << 8) | context.regs[Z80_L], - (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], - (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], + context.regs[Z80_D], context.regs[Z80_E], + (context.regs[Z80_H] << 8) | context.regs[Z80_L], + (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], + (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], context.sp, context.im, context.iff1, context.iff2); printf("Flags: SZVNC\n" " %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]); puts("--Alternate Regs--"); - printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n", + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n", context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C], - context.alt_regs[Z80_D], context.alt_regs[Z80_E], + context.alt_regs[Z80_D], context.alt_regs[Z80_E], (context.alt_regs[Z80_H] << 8) | context.alt_regs[Z80_L]); return 0; }