summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore9
-rw-r--r--.hgtags1
-rw-r--r--68kinst.c1
-rw-r--r--Makefile60
-rw-r--r--backend.c (renamed from x86_backend.c)8
-rw-r--r--backend.h (renamed from x86_backend.h)64
-rw-r--r--backend_x86.c288
-rw-r--r--blastem.c114
-rw-r--r--blastem.h2
-rwxr-xr-xcomparetests.py52
-rw-r--r--debug.c60
-rw-r--r--debug.h2
-rw-r--r--dis.c2
-rw-r--r--gdb_remote.c2
-rw-r--r--gen.c15
-rw-r--r--gen.h25
-rw-r--r--gen_arm.c550
-rw-r--r--gen_arm.h153
-rw-r--r--gen_x86.c1074
-rw-r--r--gen_x86.h284
-rwxr-xr-xgentests.py8
-rw-r--r--m68k_core.c939
-rw-r--r--m68k_core.h (renamed from m68k_to_x86.h)57
-rw-r--r--m68k_core_x86.c2652
-rw-r--r--m68k_internal.h116
-rw-r--r--m68k_to_x86.c4561
-rw-r--r--runtime.S269
-rw-r--r--runtime_32.S17
-rw-r--r--test_arm.c29
-rw-r--r--test_x86.c4
-rw-r--r--testcases.txt169
-rw-r--r--trans.c18
-rw-r--r--util.c3
-rw-r--r--vgmplay.c2
-rw-r--r--z80_to_x86.c2131
-rw-r--r--z80_to_x86.h45
-rwxr-xr-xzcompare.py58
-rw-r--r--ztestgen.c83
-rw-r--r--ztestrun.c53
39 files changed, 7354 insertions, 6626 deletions
diff --git a/.hgignore b/.hgignore
index 9133381..b27d1e8 100644
--- a/.hgignore
+++ b/.hgignore
@@ -6,15 +6,22 @@ syntax: glob
*.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 --git a/.hgtags b/.hgtags
index b61ab5f..a084a67 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1 +1,2 @@
949c7d8756931ca19d93d6de5cc507405a007937 v0.1.0
+6b7a96d0eda8ed9f1a1436c3ac590a1c4db94f27 v0.2.0
diff --git a/68kinst.c b/68kinst.c
index a05c75c..f53aabe 100644
--- a/68kinst.c
+++ b/68kinst.c
@@ -1097,6 +1097,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 --git a/Makefile b/Makefile
index 833c4ae..c81b86d 100644
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,12 @@ LIBS=sdl
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 @@ ifdef M68010
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 @@ vgmplay : vgmplay.o render_sdl.o $(CONFIGOBJS) $(AUDIOOBJS)
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 --git a/x86_backend.c b/backend.c
index c5c441a..eaae9d7 100644
--- a/x86_backend.c
+++ b/backend.c
@@ -1,9 +1,9 @@
/*
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 "x86_backend.h"
+#include "backend.h"
#include <stdlib.h>
deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
@@ -30,10 +30,10 @@ void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_fun
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);
+ 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);
- uint8_t * out = cur->dest;
+ code_ptr out = cur->dest;
*(out++) = disp;
disp >>= 8;
*(out++) = disp;
diff --git a/x86_backend.h b/backend.h
index 57c1e21..18c3752 100644
--- a/x86_backend.h
+++ b/backend.h
@@ -1,23 +1,32 @@
/*
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 X86_BACKEND_H_
-#define X86_BACKEND_H_
+#ifndef BACKEND_H_
+#define BACKEND_H_
#include <stdint.h>
+#include <stdio.h>
+#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;
- uint8_t cycles;
-} x86_ea;
+} host_ea;
+#else
+typedef struct {
+ int32_t disp;
+ uint8_t mode;
+ uint8_t base;
+} host_ea;
+#endif
typedef struct {
uint8_t *base;
@@ -26,10 +35,43 @@ typedef struct {
typedef struct deferred_addr {
struct deferred_addr *next;
- uint8_t *dest;
+ 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
@@ -38,6 +80,7 @@ typedef struct deferred_addr {
#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);
@@ -63,5 +106,12 @@ deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_
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_
+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 --git a/backend_x86.c b/backend_x86.c
new file mode 100644
index 0000000..71eaf28
--- /dev/null
+++ b/backend_x86.c
@@ -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 --git a/blastem.c b/blastem.c
index de2d5a5..ddbf8ae 100644
--- a/blastem.c
+++ b/blastem.c
@@ -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 @@ uint8_t new_busack = 0;
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 @@ void sync_z80(z80_context * z_context, uint32_t mclks)
}
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 @@ m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8
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 vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
}
}
+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 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value
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 @@ uint16_t io_read_w(uint32_t location, m68k_context * context)
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 @@ z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t val
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 save_sram()
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 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u
}
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 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u
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 @@ void detect_region()
}
}
}
+#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 @@ int main(int argc, char ** argv)
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 --git a/blastem.h b/blastem.h
index 112ebfa..46d0b1b 100644
--- a/blastem.h
+++ b/blastem.h
@@ -7,7 +7,7 @@
#define BLASTEM_H_
#include <stdint.h>
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
#include "z80_to_x86.h"
#include "ym2612.h"
#include "vdp.h"
diff --git a/comparetests.py b/comparetests.py
index ce62ae2..3448fd4 100755
--- a/comparetests.py
+++ b/comparetests.py
@@ -18,6 +18,49 @@ for i in range(1, len(argv)):
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 @@ for path in glob('generated_tests/*/*.bin'):
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 --git a/debug.c b/debug.c
index c9f9293..fa0e26e 100644
--- a/debug.c
+++ b/debug.c
@@ -82,6 +82,8 @@ void strip_nl(char * buf)
}
}
+#ifndef NO_Z80
+
void zdebugger_print(z80_context * context, char format_char, char * param)
{
uint32_t value;
@@ -460,6 +462,8 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
return context;
}
+#endif
+
m68k_context * debugger(m68k_context * context, uint32_t address)
{
static char last_cmd[1024];
@@ -527,19 +531,49 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
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 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
}
break;
}
+#ifndef NO_Z80
case 'z': {
genesis_context * gen = context->system;
//Z80 debug commands
@@ -736,6 +771,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
}
break;
}
+#endif
case 'q':
puts("Quitting");
exit(0);
diff --git a/debug.h b/debug.h
index 2a05f27..1b61efd 100644
--- a/debug.h
+++ b/debug.h
@@ -2,7 +2,7 @@
#define DEBUG_H_
#include <stdint.h>
-#include "m68k_to_x86.h"
+#include "m68k_core.h"
typedef struct disp_def {
struct disp_def * next;
diff --git a/dis.c b/dis.c
index 8b447f3..17dbc56 100644
--- a/dis.c
+++ b/dis.c
@@ -292,7 +292,7 @@ int main(int argc, char ** argv)
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 --git a/gdb_remote.c b/gdb_remote.c
index bf4d0f6..dd6a98a 100644
--- a/gdb_remote.c
+++ b/gdb_remote.c
@@ -145,7 +145,9 @@ void write_byte(m68k_context * context, uint32_t address, uint8_t value)
} 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 --git a/gen.c b/gen.c
new file mode 100644
index 0000000..8f1b5f5
--- /dev/null
+++ b/gen.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#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 --git a/gen.h b/gen.h
new file mode 100644
index 0000000..e1492fc
--- /dev/null
+++ b/gen.h
@@ -0,0 +1,25 @@
+#ifndef GEN_H_
+#define GEN_H_
+#include <stdint.h>
+
+#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 --git a/gen_arm.c b/gen_arm.c
new file mode 100644
index 0000000..5d9fab6
--- /dev/null
+++ b/gen_arm.c
@@ -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 <stdio.h>
+#include <stdlib.h>
+
+#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 --git a/gen_arm.h b/gen_arm.h
new file mode 100644
index 0000000..749f78c
--- /dev/null
+++ b/gen_arm.h
@@ -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 <stdint.h>
+#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 --git a/gen_x86.c b/gen_x86.c
index e7fa009..b1988fe 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -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 <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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 @@ enum {
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,11 +223,13 @@ uint8_t * x86_rr_sizedir(uint8_t * out, uint16_t opcode, uint8_t src, uint8_t ds
*(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)
{
+ 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) {
@@ -218,69 +268,28 @@ uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8
} 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)
-{
- //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);
- }
+ if (disp < 128 && disp >= -128) {
+ *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
} else {
- opcode |= BIT_SIZE;
+ *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
}
- opcode |= dir;
- if (opcode >= 0x100) {
- *(out++) = opcode >> 8;
- *(out++) = opcode;
- } else {
- *(out++) = opcode;
- }
- *(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 @@ uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t
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 @@ uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_
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 @@ uint8_t * x86_r_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t dst, u
}
*(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 @@ uint8_t * x86_rdisp8_size(uint8_t * out, uint8_t opcode, uint8_t opex, uint8_t d
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,11 +512,13 @@ uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode
*(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)
{
+ 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;
@@ -507,56 +543,19 @@ uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val,
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)
-{
- 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;
+ 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++) = opcode;
- *(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 @@ uint8_t * x86_irdisp32(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val
*(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 @@ uint8_t * x86_shiftrot_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst
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 @@ uint8_t * x86_shiftrot_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_
}
*(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 @@ uint8_t * x86_shiftrot_clr(uint8_t * out, uint8_t op_ex, uint8_t dst, uint8_t si
*(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 @@ uint8_t * x86_shiftrot_clrdisp8(uint8_t * out, uint8_t op_ex, uint8_t dst, int8_
}
*(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);
-}
-
-uint8_t * ror_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
-{
- return x86_shiftrot_ir(out, OP_EX_ROR, 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 * rcl_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_RCL, val, dst, size);
+ x86_shiftrot_ir(code, OP_EX_ROL, val, dst, size);
}
-uint8_t * rcr_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_RCR, val, dst, size);
+ x86_shiftrot_ir(code, OP_EX_ROR, val, dst, size);
}
-uint8_t * shl_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_SHL, val, dst, size);
+ x86_shiftrot_ir(code, OP_EX_RCL, val, dst, size);
}
-uint8_t * shr_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_SHR, val, dst, size);
+ x86_shiftrot_ir(code, OP_EX_RCR, val, dst, size);
}
-uint8_t * sar_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_SAR, val, dst, size);
+ x86_shiftrot_ir(code, OP_EX_SHL, val, dst, size);
}
-uint8_t * rol_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void shr_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_SHR, val, dst, size);
}
-uint8_t * ror_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_ROR, val, dst_base, disp, size);
+ x86_shiftrot_ir(code, OP_EX_SAR, val, dst, size);
}
-uint8_t * rcl_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_RCL, val, dst_base, disp, size);
+ x86_shiftrot_irdisp(code, OP_EX_ROL, 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 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_RCR, val, dst_base, disp, size);
+ x86_shiftrot_irdisp(code, OP_EX_ROR, 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 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_SHL, val, dst_base, disp, size);
+ x86_shiftrot_irdisp(code, OP_EX_RCL, 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 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_SHR, val, dst_base, disp, size);
+ x86_shiftrot_irdisp(code, OP_EX_RCR, 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 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_SAR, val, dst_base, disp, size);
+ x86_shiftrot_irdisp(code, OP_EX_SHL, val, dst_base, disp, size);
}
-uint8_t * rol_clr(uint8_t * out, uint8_t dst, 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_clr(out, OP_EX_ROL, dst, size);
+ x86_shiftrot_irdisp(code, OP_EX_SHR, val, dst_base, disp, size);
}
-uint8_t * ror_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_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)
-{
- 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)
+void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, 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);
}
-
-uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
+void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
{
- return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
}
-uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
}
-uint8_t * and_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_AND, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_OR, src, dst_base, disp, size, 0);
}
-uint8_t * and_ir(uint8_t * out, int32_t val, 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_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_OR, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_AND, src, dst, size);
}
-uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
}
-uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
}
-uint8_t * xor_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_XOR, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_AND, src, dst_base, disp, size, 0);
}
-uint8_t * xor_ir(uint8_t * out, int32_t val, 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_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_AND, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_XOR, src, dst, size);
}
-uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
}
-uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
}
-uint8_t * sub_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_SUB, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_XOR, src, dst_base, disp, size, 0);
}
-uint8_t * sub_ir(uint8_t * out, int32_t val, 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_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_XOR, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_SUB, src, dst, size);
}
-uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
}
-uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
}
-uint8_t * sbb_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_SBB, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_SUB, src, dst_base, disp, size, 0);
}
-uint8_t * sbb_ir(uint8_t * out, int32_t val, 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_ir(out, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_SUB, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * sbb_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_SBB, src, dst, size);
}
-uint8_t * sbb_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_SBB, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
}
-uint8_t * sbb_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
}
-uint8_t * cmp_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_CMP, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_SBB, src, dst_base, disp, size, 0);
}
-uint8_t * cmp_ir(uint8_t * out, int32_t val, 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_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_SBB, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_CMP, src, dst, size);
}
-uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
}
-uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
}
-uint8_t * test_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP_TEST, src, dst, size);
+ x86_rrdisp_sizedir(code, OP_CMP, src, dst_base, disp, size, 0);
}
-uint8_t * test_ir(uint8_t * out, int32_t val, 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_ir(out, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
+ x86_rrdisp_sizedir(code, OP_CMP, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * test_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
+void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_irdisp8(out, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
+ x86_rr_sizedir(code, OP_TEST, src, dst, size);
}
-uint8_t * test_rrdisp8(uint8_t * out, uint8_t src, 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_rrdisp8_sizedir(out, OP_TEST, src, dst_base, disp, size, 0);
+ x86_ir(code, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
}
-uint8_t * test_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, 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)
{
- return x86_rrdisp8_sizedir(out, OP_TEST, dst, src_base, disp, size, BIT_DIR);
+ x86_irdisp(code, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
}
-uint8_t * imul_rr(uint8_t * out, uint8_t src, 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_rr_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
+ x86_rrdisp_sizedir(code, OP_TEST, src, dst_base, disp, size, 0);
}
-uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, 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_rrdisp8_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
+ x86_rrdisp_sizedir(code, OP_TEST, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size)
+void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return x86_r_size(out, OP_NOT_NEG, OP_EX_NOT, dst, size);
+ x86_rr_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
}
-uint8_t * neg_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_NEG, dst, size);
+ x86_rrdisp_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
}
-uint8_t * not_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void not_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_NOT, dst, size);
}
-uint8_t * neg_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_NEG, dst_base, disp, size);
+ x86_r_size(code, OP_NOT_NEG, OP_EX_NEG, dst, size);
}
-uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size)
+void not_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_NOT, dst_base, disp, size);
}
-uint8_t * imul_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_IMUL, dst, size);
+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
}
-uint8_t * div_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_DIV, dst, size);
+ x86_r_size(code, OP_NOT_NEG, OP_EX_MUL, dst, size);
}
-uint8_t * idiv_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_IDIV, dst, size);
+ x86_r_size(code, OP_NOT_NEG, OP_EX_IMUL, dst, size);
}
-uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size)
+void div_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_DIV, dst, size);
}
-uint8_t * imul_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_IMUL, dst_base, disp, size);
+ x86_r_size(code, OP_NOT_NEG, OP_EX_IDIV, dst, size);
}
-uint8_t * div_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_DIV, dst_base, disp, size);
+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size);
}
-uint8_t * idiv_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_IDIV, dst_base, disp, size);
+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size);
}
-uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void div_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_DIV, 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 idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
{
- return x86_rrdisp8_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size);
}
-uint8_t * mov_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_rr_sizedir(code, OP_MOV, src, dst, size);
}
-uint8_t * mov_rrdisp32(uint8_t * out, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
+void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
{
- return x86_rrdisp32_sizedir(out, OP_MOV, src, dst_base, disp, size, 0);
+ x86_rrdisp_sizedir(code, OP_MOV, src, dst_base, disp, size, 0);
}
-uint8_t * mov_rdisp32r(uint8_t * out, uint8_t src_base, int32_t disp, uint8_t dst, 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, dst, src_base, disp, size, BIT_DIR);
+ x86_rrdisp_sizedir(code, OP_MOV, dst, src_base, disp, size, BIT_DIR);
}
-uint8_t * mov_rrind(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
+void mov_rrind(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, src, dst, size, 0);
}
-uint8_t * mov_rindr(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, dst, src, size, BIT_DIR);
+ x86_rrind_sizedir(code, OP_MOV, dst, src, size, BIT_DIR);
}
-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_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
{
- return x86_rrindex_sizedir(out, OP_MOV, src, dst_base, dst_index, scale, size, 0);
+ x86_rrindex_sizedir(code, OP_MOV, src, dst_base, dst_index, scale, size, 0);
}
-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_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, dst, src_base, src_index, scale, size, BIT_DIR);
+ x86_rrindex_sizedir(code, 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)
+void mov_ir(code_info *code, 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 @@ uint8_t * mov_ir(uint8_t * out, int64_t val, uint8_t dst, uint8_t size)
}
}
}
- 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 @@ uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint
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 @@ uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint
*(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 @@ uint8_t * mov_irind(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
*(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 @@ uint8_t * movsx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, ui
*(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 @@ uint8_t * movsx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, ui
*(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 @@ uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, ui
*(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 @@ uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, ui
}
*(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 @@ uint8_t * xchg_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
}
*(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;
+}
+
+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;
}
-uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst)
+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 @@ uint8_t * setcc_r(uint8_t * out, uint8_t cc, uint8_t dst)
*(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 @@ uint8_t * setcc_rind(uint8_t * out, uint8_t cc, uint8_t dst)
*(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,11 +1636,13 @@ uint8_t * bit_rr(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst, uint8_t s
*(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)
{
+ check_alloc_code(code, 9);
+ code_ptr out = code->cur;
if (size == SZ_W) {
*(out++) = PRE_SIZE;
}
@@ -1570,43 +1663,23 @@ uint8_t * bit_rrdisp8(uint8_t * out, uint8_t op2, uint8_t src, uint8_t dst_base,
}
*(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)
-{
- 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++;
+ 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;
}
- *(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;
+ 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 @@ uint8_t * bit_ir(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t
*(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 @@ uint8_t * bit_irdisp8(uint8_t * out, uint8_t op_ex, uint8_t val, uint8_t dst_bas
}
*(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);
+ return bit_rrdisp(code, 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)
+void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
{
- return bit_rrdisp32(out, OP2_BT, src, dst_base, dst_disp, size);
+ return bit_ir(code, OP_EX_BT, val, dst, size);
}
-uint8_t * bt_ir(uint8_t * out, 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)
{
- return bit_ir(out, OP_EX_BT, val, dst, size);
+ return bit_irdisp(code, OP_EX_BT, val, dst_base, dst_disp, size);
}
-uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return bit_irdisp8(out, OP_EX_BT, val, dst_base, dst_disp, size);
+ return bit_rr(code, OP2_BTS, src, dst, size);
}
-uint8_t * bts_rr(uint8_t * out, 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)
{
- return bit_rr(out, OP2_BTS, src, dst, size);
+ return bit_rrdisp(code, OP2_BTS, src, dst_base, dst_disp, size);
}
-uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
{
- return bit_rrdisp8(out, OP2_BTS, src, dst_base, dst_disp, size);
+ return bit_ir(code, OP_EX_BTS, val, dst, size);
}
-uint8_t * bts_ir(uint8_t * out, 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)
{
- return bit_ir(out, OP_EX_BTS, val, dst, size);
+ return bit_irdisp(code, OP_EX_BTS, val, dst_base, dst_disp, size);
}
-uint8_t * bts_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_disp, uint8_t size)
+void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
{
- return bit_irdisp8(out, OP_EX_BTS, val, dst_base, dst_disp, 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)
-{
- 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)
+void jcc(code_info *code, uint8_t cc, code_ptr 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 @@ uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
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 @@ uint8_t * jmp(uint8_t * out, uint8_t * dest)
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;
+}
+
+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;
}
-uint8_t * call(uint8_t * out, uint8_t * fun)
+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 @@ uint8_t * call(uint8_t * out, uint8_t * fun)
*(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 --git a/gen_x86.h b/gen_x86.h
index 83983f6..97bb9c2 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -7,6 +7,7 @@
#define GEN_X86_H_
#include <stdint.h>
+#include "gen.h"
enum {
RAX = 0,
@@ -35,7 +36,9 @@ enum {
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 @@ enum {
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 @@ enum {
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 --git a/gentests.py b/gentests.py
index 000f73e..428d6a0 100755
--- a/gentests.py
+++ b/gentests.py
@@ -178,9 +178,17 @@ class Indexed(object):
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 --git a/m68k_core.c b/m68k_core.c
new file mode 100644
index 0000000..7fc31e3
--- /dev/null
+++ b/m68k_core.c
@@ -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 <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 --git a/m68k_to_x86.h b/m68k_core.h
index 68009c8..370aa1e 100644
--- a/m68k_to_x86.h
+++ b/m68k_core.h
@@ -1,13 +1,13 @@
/*
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 M68K_TO_X86_H_
-#define M68K_TO_X86_H_
+#ifndef M68K_CORE_H_
+#define M68K_CORE_H_
#include <stdint.h>
#include <stdio.h>
-#include "x86_backend.h"
+#include "backend.h"
//#include "68kinst.h"
struct m68kinst;
@@ -16,28 +16,32 @@ struct m68kinst;
#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2)
#define MAX_NATIVE_SIZE 255
-#define OPT_NATIVE_CALL_STACK 0x1
+typedef void (*start_fun)(uint8_t * addr, void * context);
typedef struct {
- uint32_t flags;
+ cpu_options gen;
+
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;
+ int8_t flag_regs[5];
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;
+ 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];
@@ -53,22 +57,23 @@ typedef struct {
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 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_x86_68k_opts(x86_68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks);
+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_TO_X86_H_
+#endif //M68K_CORE_H_
diff --git a/m68k_core_x86.c b/m68k_core_x86.c
new file mode 100644
index 0000000..7e97886
--- /dev/null
+++ b/m68k_core_x86.c
@@ -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 <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <ea> 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 --git a/m68k_internal.h b/m68k_internal.h
new file mode 100644
index 0000000..a556505
--- /dev/null
+++ b/m68k_internal.h
@@ -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 --git a/m68k_to_x86.c b/m68k_to_x86.c
deleted file mode 100644
index 4a6f7fb..0000000
--- a/m68k_to_x86.c
+++ /dev/null
@@ -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 <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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 <ea> 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 --git a/runtime.S b/runtime.S
index 36ecfff..5595eb1 100644
--- a/runtime.S
+++ b/runtime.S
@@ -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 @@ m68k_invalid:
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 --git a/runtime_32.S b/runtime_32.S
new file mode 100644
index 0000000..50117f1
--- /dev/null
+++ b/runtime_32.S
@@ -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 --git a/test_arm.c b/test_arm.c
new file mode 100644
index 0000000..4e2aee4
--- /dev/null
+++ b/test_arm.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#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 --git a/test_x86.c b/test_x86.c
index e13a814..588ef5d 100644
--- a/test_x86.c
+++ b/test_x86.c
@@ -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 <stdio.h>
#include <stddef.h>
diff --git a/testcases.txt b/testcases.txt
index b7f7d34..c0f2692 100644
--- a/testcases.txt
+++ b/testcases.txt
@@ -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 --git a/trans.c b/trans.c
index ac4bf22..2f98e91 100644
--- a/trans.c
+++ b/trans.c
@@ -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 <stdio.h>
#include <stdlib.h>
@@ -24,14 +24,15 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 --git a/util.c b/util.c
index 0b8d8cb..2bc3109 100644
--- a/util.c
+++ b/util.c
@@ -94,7 +94,8 @@ char * readlink_alloc(char * path)
free(linktext);
linktext = NULL;
}
- } while (linksize > cursize);
+ } while ((linksize+1) > cursize);
+ linktext[linksize] = 0;
return linktext;
}
diff --git a/vgmplay.c b/vgmplay.c
index 3132a13..f29a9a5 100644
--- a/vgmplay.c
+++ b/vgmplay.c
@@ -101,7 +101,7 @@ void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
{
}
-uint8_t headless = 0;
+int headless = 0;
#define CYCLE_LIMIT MCLKS_NTSC/60
#define MAX_SOUND_CYCLES 100000
diff --git a/z80_to_x86.c b/z80_to_x86.c
index b529766..6da2321 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -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 @@ uint8_t z80_size(z80inst * inst)
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)
-{
- 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)
+void translate_z80_reg(z80inst * inst, host_ea * ea, 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 @@ uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_
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 @@ uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_
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 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o
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 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o
}
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 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o
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 @@ uint8_t * z80_save_result(uint8_t * dst, z80inst * inst)
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 @@ void z80_print_regs_exit(z80_context * context)
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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
{
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);
- }
- dst = z80_save_reg(dst, inst, opts);
- dst = z80_save_ea(dst, inst, opts);
+ 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);
+ }
+ 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);
-
- 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);
+ 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);
+
+ 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);
-
- 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);
+ 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);
+
+ 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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
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));
-
- 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_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));
+
+ 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));
-
- 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_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));
+
+ 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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
} 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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
} 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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
} 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 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context
exit(1);
}
}
- return dst;
}
uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
@@ -1704,45 +1680,45 @@ uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
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 @@ uint8_t * z80_get_native_address(z80_context * context, uint32_t address)
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 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
{
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 @@ uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address)
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 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o
}
#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 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 translate_z80_stream(z80_context * context, uint32_t address)
}
}
-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 @@ void init_x86_z80_opts(x86_z80_options * options)
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;
-void init_z80_context(z80_context * context, x86_z80_options * options)
+ 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 * 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 @@ void init_z80_context(z80_context * context, x86_z80_options * options)
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 @@ void z80_reset(z80_context * context)
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 @@ void zremove_breakpoint(z80_context * context, uint16_t address)
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 --git a/z80_to_x86.h b/z80_to_x86.h
index fdf7866..71d6f10 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -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 @@ enum {
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 @@ typedef struct {
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 @@ typedef struct {
} 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 --git a/zcompare.py b/zcompare.py
new file mode 100755
index 0000000..d6eacea
--- /dev/null
+++ b/zcompare.py
@@ -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 --git a/ztestgen.c b/ztestgen.c
index e74c38a..bbdc22b 100644
--- a/ztestgen.c
+++ b/ztestgen.c
@@ -24,6 +24,7 @@ extern char * z80_regs[Z80_USE_IMMED];
#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 * and_r(uint8_t * dst, uint8_t reg)
}
}
+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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
}
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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
//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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
//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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
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 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
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 --git a/ztestrun.c b/ztestrun.c
index 9f500f1..1c7c6d8 100644
--- a/ztestrun.c
+++ b/ztestrun.c
@@ -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 <stdlib.h>
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 @@ uint16_t cart[0x200000];
#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 @@ int main(int argc, char ** argv)
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;
}