main m68k_core.c
   1/*
   2 Copyright 2014 Michael Pavone
   3 This file is part of BlastEm.
   4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
   5*/
   6#include "m68k_core.h"
   7#include "m68k_internal.h"
   8#include "68kinst.h"
   9#include "backend.h"
  10#include "gen.h"
  11#include "util.h"
  12#include "serialize.h"
  13#include <stdio.h>
  14#include <stddef.h>
  15#include <stdlib.h>
  16#include <string.h>
  17
  18char disasm_buf[1024];
  19
  20int8_t native_reg(m68k_op_info * op, m68k_options * opts)
  21{
  22	if (op->addr_mode == MODE_REG) {
  23		return opts->dregs[op->params.regs.pri];
  24	}
  25	if (op->addr_mode == MODE_AREG) {
  26		return opts->aregs[op->params.regs.pri];
  27	}
  28	return -1;
  29}
  30
  31size_t dreg_offset(uint8_t reg)
  32{
  33	return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg;
  34}
  35
  36size_t areg_offset(uint8_t reg)
  37{
  38	return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg;
  39}
  40
  41//must be called with an m68k_op_info that uses a register
  42size_t reg_offset(m68k_op_info *op)
  43{
  44	return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri);
  45}
  46
  47void m68k_print_regs(m68k_context * context)
  48{
  49	printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
  50	for (int i = 0; i < 8; i++) {
  51		printf("d%d: %X\n", i, context->dregs[i]);
  52	}
  53	for (int i = 0; i < 8; i++) {
  54		printf("a%d: %X\n", i, context->aregs[i]);
  55	}
  56}
  57
  58void m68k_read_size(m68k_options *opts, uint8_t size)
  59{
  60	switch (size)
  61	{
  62	case OPSIZE_BYTE:
  63		call(&opts->gen.code, opts->read_8);
  64		break;
  65	case OPSIZE_WORD:
  66		call(&opts->gen.code, opts->read_16);
  67		break;
  68	case OPSIZE_LONG:
  69		call(&opts->gen.code, opts->read_32);
  70		break;
  71	}
  72}
  73
  74void m68k_write_size(m68k_options *opts, uint8_t size, uint8_t lowfirst)
  75{
  76	switch (size)
  77	{
  78	case OPSIZE_BYTE:
  79		call(&opts->gen.code, opts->write_8);
  80		break;
  81	case OPSIZE_WORD:
  82		call(&opts->gen.code, opts->write_16);
  83		break;
  84	case OPSIZE_LONG:
  85		if (lowfirst) {
  86			call(&opts->gen.code, opts->write_32_lowfirst);
  87		} else {
  88			call(&opts->gen.code, opts->write_32_highfirst);
  89		}
  90		break;
  91	}
  92}
  93
  94void m68k_save_result(m68kinst * inst, m68k_options * opts)
  95{
  96	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) {
  97		if (inst->dst.addr_mode == MODE_AREG_PREDEC && 
  98			((inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) || (inst->op == M68K_NBCD))
  99		) {
 100			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
 101		}
 102		m68k_write_size(opts, inst->extra.size, 1);
 103	}
 104}
 105
 106static void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst)
 107{
 108	code_info *code = &opts->gen.code;
 109	int8_t dst_reg = inst->op == M68K_PEA ? opts->gen.scratch1 : native_reg(&(inst->dst), opts);
 110	switch(inst->src.addr_mode)
 111	{
 112	case MODE_AREG_INDIRECT:
 113		cycles(&opts->gen, BUS);
 114		if (dst_reg >= 0) {
 115			areg_to_native(opts, inst->src.params.regs.pri, dst_reg);
 116		} else {
 117			if (opts->aregs[inst->src.params.regs.pri] >= 0) {
 118				native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri);
 119			} else {
 120				areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
 121				native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 122			}
 123		}
 124		break;
 125	case MODE_AREG_DISPLACE:
 126		cycles(&opts->gen, 8);
 127		calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1);
 128		if (dst_reg < 0) {
 129			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 130		}
 131		break;
 132	case MODE_AREG_INDEX_DISP8:
 133		cycles(&opts->gen, 12);
 134		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)) {
 135			dst_reg = opts->gen.scratch1;
 136		}
 137		calc_areg_index_disp8(opts, &inst->src, dst_reg);
 138		if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
 139			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 140		}
 141		break;
 142	case MODE_PC_DISPLACE:
 143		cycles(&opts->gen, 8);
 144		if (inst->op == M68K_PEA) {
 145			ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, dst_reg);
 146		} else {
 147			ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri);
 148		}
 149		break;
 150	case MODE_PC_INDEX_DISP8:
 151		cycles(&opts->gen, BUS*3);
 152		if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
 153			dst_reg = opts->gen.scratch1;
 154		}
 155		ldi_native(opts, inst->address+2, dst_reg);
 156		calc_index_disp8(opts, &inst->src, dst_reg);
 157		if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
 158			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 159		}
 160		break;
 161	case MODE_ABSOLUTE:
 162	case MODE_ABSOLUTE_SHORT:
 163		cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
 164		if (inst->op == M68K_PEA) {
 165			ldi_native(opts, inst->src.params.immed, dst_reg);
 166		} else {
 167			ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri);
 168		}
 169		break;
 170	default:
 171		m68k_disasm(inst, disasm_buf);
 172		fatal_error("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
 173	}
 174	if (inst->op == M68K_PEA) {
 175		subi_areg(opts, 4, 7);
 176		areg_to_native(opts, 7, opts->gen.scratch2);
 177		call(code, opts->write_32_lowfirst);
 178	}
 179}
 180
 181static void push_const(m68k_options *opts, int32_t value)
 182{
 183	ldi_native(opts, value, opts->gen.scratch1);
 184	subi_areg(opts, 4, 7);
 185	areg_to_native(opts, 7, opts->gen.scratch2);
 186	call(&opts->gen.code, opts->write_32_highfirst);
 187}
 188
 189void jump_m68k_abs(m68k_options * opts, uint32_t address)
 190{
 191	code_info *code = &opts->gen.code;
 192	code_ptr dest_addr = get_native_address(opts, address);
 193	if (!dest_addr) {
 194		opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1);
 195		//dummy address to be replaced later, make sure it generates a 4-byte displacement
 196		dest_addr = code->cur + 256;
 197	}
 198	jmp(code, dest_addr);
 199	//this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed
 200	//since instruction retranslation patches the original native instruction location
 201}
 202
 203static void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
 204{
 205	code_info *code = &opts->gen.code;
 206	int32_t disp = inst->src.params.immed;
 207	uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
 208	//TODO: Add cycles in the right place relative to pushing the return address on the stack
 209	cycles(&opts->gen, 10);
 210	push_const(opts, after);
 211	jump_m68k_abs(opts, inst->address + 2 + disp);
 212}
 213
 214static void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
 215{
 216	uint8_t is_jsr = inst->op == M68K_JSR;
 217	code_info *code = &opts->gen.code;
 218	code_ptr dest_addr;
 219	uint8_t sec_reg;
 220	uint32_t after;
 221	uint32_t m68k_addr;
 222	switch(inst->src.addr_mode)
 223	{
 224	case MODE_AREG_INDIRECT:
 225		cycles(&opts->gen, BUS*2);
 226		if (is_jsr) {
 227			push_const(opts, inst->address+2);
 228		}
 229		areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
 230		call(code, opts->native_addr);
 231		jmp_r(code, opts->gen.scratch1);
 232		break;
 233	case MODE_AREG_DISPLACE:
 234		cycles(&opts->gen, BUS*2);
 235		if (is_jsr) {
 236			push_const(opts, inst->address+4);
 237		}
 238		calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
 239		call(code, opts->native_addr);
 240		jmp_r(code, opts->gen.scratch1);
 241		break;
 242	case MODE_AREG_INDEX_DISP8:
 243		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
 244		if (is_jsr) {
 245			push_const(opts, inst->address+4);
 246		}
 247		calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
 248		call(code, opts->native_addr);
 249		jmp_r(code, opts->gen.scratch1);
 250		break;
 251	case MODE_PC_DISPLACE:
 252		//TODO: Add cycles in the right place relative to pushing the return address on the stack
 253		cycles(&opts->gen, 10);
 254		if (is_jsr) {
 255			push_const(opts, inst->address+4);
 256		}
 257		jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
 258		break;
 259	case MODE_PC_INDEX_DISP8:
 260		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
 261		if (is_jsr) {
 262			push_const(opts, inst->address+4);
 263		}
 264		ldi_native(opts, inst->address+2, opts->gen.scratch1);
 265		calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
 266		call(code, opts->native_addr);
 267		jmp_r(code, opts->gen.scratch1);
 268		break;
 269	case MODE_ABSOLUTE:
 270	case MODE_ABSOLUTE_SHORT:
 271		//TODO: Add cycles in the right place relative to pushing the return address on the stack
 272		cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
 273		if (is_jsr) {
 274			push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4));
 275		}
 276		jump_m68k_abs(opts, inst->src.params.immed);
 277		break;
 278	default:
 279		m68k_disasm(inst, disasm_buf);
 280		fatal_error("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
 281	}
 282}
 283
 284static void translate_m68k_unlk(m68k_options * opts, m68kinst * inst)
 285{
 286	cycles(&opts->gen, BUS);
 287	if (inst->dst.params.regs.pri != 7) {
 288		areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]);
 289	}
 290	areg_to_native(opts, 7, opts->gen.scratch1);
 291	call(&opts->gen.code, opts->read_32);
 292	native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 293	if (inst->dst.params.regs.pri != 7) {
 294		addi_areg(opts, 4, 7);
 295	}
 296}
 297
 298static void translate_m68k_link(m68k_options * opts, m68kinst * inst)
 299{
 300	//compensate for displacement word
 301	cycles(&opts->gen, BUS);
 302	subi_areg(opts, 4, 7);
 303	areg_to_native(opts, 7, opts->gen.scratch2);
 304	areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
 305	call(&opts->gen.code, opts->write_32_highfirst);
 306	native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri);
 307	addi_areg(opts, inst->dst.params.immed, 7);
 308	//prefetch
 309	cycles(&opts->gen, BUS);
 310}
 311
 312static void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
 313{
 314	code_info *code = &opts->gen.code;
 315	areg_to_native(opts, 7, opts->gen.scratch1);
 316	addi_areg(opts, 4, 7);
 317	call(code, opts->read_32);
 318	cycles(&opts->gen, 2*BUS);
 319	call(code, opts->native_addr);
 320	jmp_r(code, opts->gen.scratch1);
 321}
 322
 323static void translate_m68k_rtr(m68k_options *opts, m68kinst * inst)
 324{
 325	code_info *code = &opts->gen.code;
 326	//Read saved CCR
 327	areg_to_native(opts, 7, opts->gen.scratch1);
 328	call(code, opts->read_16);
 329	addi_areg(opts, 2, 7);
 330	call(code, opts->set_ccr);
 331	//Read saved PC
 332	areg_to_native(opts, 7, opts->gen.scratch1);
 333	call(code, opts->read_32);
 334	addi_areg(opts, 4, 7);
 335	//Get native address and jump to it
 336	call(code, opts->native_addr);
 337	jmp_r(code, opts->gen.scratch1);
 338}
 339
 340static void translate_m68k_trap(m68k_options *opts, m68kinst *inst)
 341{
 342	code_info *code = &opts->gen.code;
 343	uint32_t vector, pc = inst->address;
 344	switch (inst->op)
 345	{
 346	case M68K_TRAP:
 347		vector = inst->src.params.immed + VECTOR_TRAP_0;
 348		pc += 2;
 349		break;
 350	case M68K_A_LINE_TRAP:
 351		vector = VECTOR_LINE_1010;
 352		break;
 353	case M68K_F_LINE_TRAP:
 354		vector = VECTOR_LINE_1111;
 355		break;
 356	}
 357	ldi_native(opts, vector, opts->gen.scratch2);
 358	ldi_native(opts, pc, opts->gen.scratch1);
 359	jmp(code, opts->trap);
 360}
 361
 362static void translate_m68k_illegal(m68k_options *opts, m68kinst *inst)
 363{
 364	code_info *code = &opts->gen.code;
 365	cycles(&opts->gen, BUS);
 366	ldi_native(opts, VECTOR_ILLEGAL_INST, opts->gen.scratch2);
 367	ldi_native(opts, inst->address, opts->gen.scratch1);
 368	jmp(code, opts->trap);
 369}
 370
 371static void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst)
 372{
 373	m68k_trap_if_not_supervisor(opts, inst);
 374	cycles(&opts->gen, BUS);
 375	int8_t reg;
 376	if (inst->src.addr_mode == MODE_UNUSED) {
 377		reg = native_reg(&inst->dst, opts);
 378		if (reg < 0) {
 379			reg = opts->gen.scratch1;
 380		}
 381		areg_to_native(opts, 8, reg);
 382		if (reg == opts->gen.scratch1) {
 383			native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
 384		}
 385	} else {
 386		reg = native_reg(&inst->src, opts);
 387		if (reg < 0) {
 388			reg = opts->gen.scratch1;
 389			areg_to_native(opts, inst->src.params.regs.pri, reg);
 390		}
 391		native_to_areg(opts, reg, 8);
 392	}
 393}
 394
 395static void translate_movem_regtomem_reglist(m68k_options * opts, m68kinst *inst)
 396{
 397	code_info *code = &opts->gen.code;
 398	int8_t bit,reg,dir;
 399	if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
 400		reg = 15;
 401		dir = -1;
 402	} else {
 403		reg = 0;
 404		dir = 1;
 405	}
 406	for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
 407		if (inst->src.params.immed & (1 << bit)) {
 408			if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
 409				subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
 410			}
 411			push_native(opts, opts->gen.scratch2);
 412			if (reg > 7) {
 413				areg_to_native(opts, reg-8, opts->gen.scratch1);
 414			} else {
 415				dreg_to_native(opts, reg, opts->gen.scratch1);
 416			}
 417			if (inst->extra.size == OPSIZE_LONG) {
 418				call(code, opts->write_32_lowfirst);
 419			} else {
 420				call(code, opts->write_16);
 421			}
 422			pop_native(opts, opts->gen.scratch2);
 423			if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
 424				addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
 425			}
 426		}
 427	}
 428}
 429
 430static void translate_movem_memtoreg_reglist(m68k_options * opts, m68kinst *inst)
 431{
 432	code_info *code = &opts->gen.code;
 433	for(uint8_t reg = 0; reg < 16; reg ++) {
 434		if (inst->dst.params.immed & (1 << reg)) {
 435			push_native(opts, opts->gen.scratch1);
 436			if (inst->extra.size == OPSIZE_LONG) {
 437				call(code, opts->read_32);
 438			} else {
 439				call(code, opts->read_16);
 440			}
 441			if (inst->extra.size == OPSIZE_WORD) {
 442				sign_extend16_native(opts, opts->gen.scratch1);
 443			}
 444			if (reg > 7) {
 445				native_to_areg(opts, opts->gen.scratch1, reg-8);
 446			} else {
 447				native_to_dreg(opts, opts->gen.scratch1, reg);
 448			}
 449			pop_native(opts, opts->gen.scratch1);
 450			addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
 451		}
 452	}
 453}
 454
 455static code_ptr get_movem_impl(m68k_options *opts, m68kinst *inst)
 456{
 457	uint8_t reg_to_mem = inst->src.addr_mode == MODE_REG;
 458	uint8_t size = inst->extra.size;
 459	int8_t dir = reg_to_mem && inst->dst.addr_mode == MODE_AREG_PREDEC ? -1 : 1;
 460	uint16_t reglist = reg_to_mem ? inst->src.params.immed : inst->dst.params.immed;
 461	for (uint32_t i = 0; i < opts->num_movem; i++)
 462	{
 463		if (
 464			opts->big_movem[i].reglist == reglist && opts->big_movem[i].reg_to_mem == reg_to_mem
 465			&& opts->big_movem[i].size == size && opts->big_movem[i].dir == dir
 466		) {
 467			return opts->big_movem[i].impl;
 468		}
 469	}
 470	if (opts->num_movem == opts->movem_storage) {
 471		if (!opts->movem_storage) {
 472			opts->movem_storage = 4;
 473		} else {
 474			opts->movem_storage *= 2;
 475		}
 476		opts->big_movem = realloc(opts->big_movem, sizeof(movem_fun) * opts->movem_storage);
 477	}
 478	if (!opts->extra_code.cur) {
 479		init_code_info(&opts->extra_code);
 480	}
 481	check_alloc_code(&opts->extra_code, 512);
 482	code_ptr impl = opts->extra_code.cur;
 483	code_info tmp = opts->gen.code;
 484	opts->gen.code = opts->extra_code;
 485	if (reg_to_mem) {
 486		translate_movem_regtomem_reglist(opts, inst);
 487	} else {
 488		translate_movem_memtoreg_reglist(opts, inst);
 489	}
 490	opts->extra_code = opts->gen.code;
 491	opts->gen.code = tmp;
 492	
 493	rts(&opts->extra_code);
 494	return impl;
 495}
 496
 497static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
 498{
 499	code_info *code = &opts->gen.code;
 500	uint8_t early_cycles;
 501	uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed;
 502	{	
 503		//TODO: Move this popcount alg to a utility function
 504		uint16_t a = (num_regs & 0b1010101010101010) >> 1;
 505		uint16_t b = num_regs & 0b0101010101010101;
 506		num_regs = a + b;
 507		a = (num_regs & 0b1100110011001100) >> 2;
 508		b = num_regs & 0b0011001100110011;
 509		num_regs = a + b;
 510		a = (num_regs & 0b1111000011110000) >> 4;
 511		b = num_regs & 0b0000111100001111;
 512		num_regs = a + b;
 513		a = (num_regs & 0b1111111100000000) >> 8;
 514		b = num_regs & 0b0000000011111111;
 515		num_regs = a + b;
 516	}
 517	if(inst->src.addr_mode == MODE_REG) {
 518		//reg to mem
 519		early_cycles = 8;
 520		switch (inst->dst.addr_mode)
 521		{
 522		case MODE_AREG_INDIRECT:
 523		case MODE_AREG_PREDEC:
 524			areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
 525			break;
 526		case MODE_AREG_DISPLACE:
 527			early_cycles += BUS;
 528			calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
 529			break;
 530		case MODE_AREG_INDEX_DISP8:
 531			early_cycles += 6;
 532			calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
 533			break;
 534		case MODE_PC_DISPLACE:
 535			early_cycles += BUS;
 536			ldi_native(opts, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2);
 537			break;
 538		case MODE_PC_INDEX_DISP8:
 539			early_cycles += 6;
 540			ldi_native(opts, inst->address+2, opts->gen.scratch2);
 541			calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
 542		case MODE_ABSOLUTE:
 543			early_cycles += 4;
 544		case MODE_ABSOLUTE_SHORT:
 545			early_cycles += 4;
 546			ldi_native(opts, inst->dst.params.immed, opts->gen.scratch2);
 547			break;
 548		default:
 549			m68k_disasm(inst, disasm_buf);
 550			fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
 551		}
 552		
 553		cycles(&opts->gen, early_cycles);
 554		if (num_regs <= 9) {
 555			translate_movem_regtomem_reglist(opts, inst);
 556		} else {
 557			call(code, get_movem_impl(opts, inst));
 558		}
 559		if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
 560			native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
 561		}
 562	} else {
 563		//mem to reg
 564		early_cycles = 8; //includes prefetch
 565		switch (inst->src.addr_mode)
 566		{
 567		case MODE_AREG_INDIRECT:
 568		case MODE_AREG_POSTINC:
 569			areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
 570			break;
 571		case MODE_AREG_DISPLACE:
 572			early_cycles += BUS;
 573			calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
 574			break;
 575		case MODE_AREG_INDEX_DISP8:
 576			early_cycles += 6;
 577			calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
 578			break;
 579		case MODE_PC_DISPLACE:
 580			early_cycles += BUS;
 581			ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
 582			break;
 583		case MODE_PC_INDEX_DISP8:
 584			early_cycles += 6;
 585			ldi_native(opts, inst->address+2, opts->gen.scratch1);
 586			calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
 587			break;
 588		case MODE_ABSOLUTE:
 589			early_cycles += 4;
 590		case MODE_ABSOLUTE_SHORT:
 591			early_cycles += 4;
 592			ldi_native(opts, inst->src.params.immed, opts->gen.scratch1);
 593			break;
 594		default:
 595			m68k_disasm(inst, disasm_buf);
 596			fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
 597		}
 598		cycles(&opts->gen, early_cycles);
 599		
 600		if (num_regs <= 9) {
 601			translate_movem_memtoreg_reglist(opts, inst);
 602		} else {
 603			call(code, get_movem_impl(opts, inst));
 604		}
 605		if (inst->src.addr_mode == MODE_AREG_POSTINC) {
 606			native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
 607		}
 608		//Extra read
 609		call(code, opts->read_16);
 610	}
 611}
 612
 613static void translate_m68k_nop(m68k_options *opts, m68kinst *inst)
 614{
 615	cycles(&opts->gen, BUS);
 616}
 617
 618void swap_ssp_usp(m68k_options * opts)
 619{
 620	areg_to_native(opts, 7, opts->gen.scratch2);
 621	areg_to_native(opts, 8, opts->aregs[7]);
 622	native_to_areg(opts, opts->gen.scratch2, 8);
 623}
 624
 625static void translate_m68k_rte(m68k_options *opts, m68kinst *inst)
 626{
 627	m68k_trap_if_not_supervisor(opts, inst);
 628	
 629	code_info *code = &opts->gen.code;
 630	//Read saved SR
 631	areg_to_native(opts, 7, opts->gen.scratch1);
 632	call(code, opts->read_16);
 633	addi_areg(opts, 2, 7);
 634	call(code, opts->set_sr);
 635	//Read saved PC
 636	areg_to_native(opts, 7, opts->gen.scratch1);
 637	call(code, opts->read_32);
 638	addi_areg(opts, 4, 7);
 639	check_user_mode_swap_ssp_usp(opts);
 640	cycles(&opts->gen, 2*BUS);
 641	//Get native address, sync components, recalculate integer points and jump to returned address
 642	call(code, opts->native_addr_and_sync);
 643	jmp_r(code, opts->gen.scratch1);
 644}
 645
 646code_ptr get_native_address(m68k_options *opts, uint32_t address)
 647{
 648	native_map_slot * native_code_map = opts->gen.native_code_map;
 649	
 650	memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
 651	if (mem_chunk) {
 652		//calculate the lowest alias for this address
 653		address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
 654	} else {
 655		address &= opts->gen.address_mask;
 656	}
 657	uint32_t chunk = address / NATIVE_CHUNK_SIZE;
 658	if (!native_code_map[chunk].base) {
 659		return NULL;
 660	}
 661	uint32_t offset = address % NATIVE_CHUNK_SIZE;
 662	if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
 663		return NULL;
 664	}
 665	return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
 666}
 667
 668code_ptr get_native_from_context(m68k_context * context, uint32_t address)
 669{
 670	return get_native_address(context->options, address);
 671}
 672
 673uint32_t get_instruction_start(m68k_options *opts, uint32_t address)
 674{
 675	native_map_slot * native_code_map = opts->gen.native_code_map;
 676	memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
 677	if (mem_chunk) {
 678		//calculate the lowest alias for this address
 679		address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
 680	} else {
 681		address &= opts->gen.address_mask;
 682	}
 683	
 684	uint32_t chunk = address / NATIVE_CHUNK_SIZE;
 685	if (!native_code_map[chunk].base) {
 686		return 0;
 687	}
 688	uint32_t offset = address % NATIVE_CHUNK_SIZE;
 689	if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
 690		return 0;
 691	}
 692	while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD)
 693	{
 694		--address;
 695		chunk = address / NATIVE_CHUNK_SIZE;
 696		offset = address % NATIVE_CHUNK_SIZE;
 697	}
 698	return address;
 699}
 700
 701static void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size)
 702{
 703	m68k_options * opts = context->options;
 704	native_map_slot * native_code_map = opts->gen.native_code_map;
 705	uint32_t meta_off;
 706	memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
 707	if (mem_chunk) {
 708		if (mem_chunk->flags & MMAP_CODE) {
 709			uint32_t masked = (address - mem_chunk->start) & mem_chunk->mask;
 710			uint32_t final_off = masked + meta_off;
 711			uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
 712			context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
 713
 714			uint32_t slot = final_off / 1024;
 715			if (!opts->gen.ram_inst_sizes[slot]) {
 716				opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
 717			}
 718			opts->gen.ram_inst_sizes[slot][(final_off/2) & 511] = native_size;
 719
 720			//TODO: Deal with case in which end of instruction is in a different memory chunk
 721			masked = (address + size - 1) & mem_chunk->mask;
 722			final_off = masked + meta_off;
 723			ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
 724			context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
 725		}
 726		//calculate the lowest alias for this address
 727		address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
 728	} else {
 729		address &= opts->gen.address_mask;
 730	}
 731	
 732	uint32_t chunk = address / NATIVE_CHUNK_SIZE;
 733	if (!native_code_map[chunk].base) {
 734		native_code_map[chunk].base = native_addr;
 735		native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
 736		memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
 737	}
 738	uint32_t offset = address % NATIVE_CHUNK_SIZE;
 739	native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
 740	for(address++,size-=1; size; address++,size-=1) {
 741		address &= opts->gen.address_mask;
 742		chunk = address / NATIVE_CHUNK_SIZE;
 743		offset = address % NATIVE_CHUNK_SIZE;
 744		if (!native_code_map[chunk].base) {
 745			native_code_map[chunk].base = native_addr;
 746			native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
 747			memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
 748		}
 749		if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
 750			//TODO: Better handling of overlapping instructions
 751			native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
 752		}
 753	}
 754}
 755
 756static uint8_t get_native_inst_size(m68k_options * opts, uint32_t address)
 757{
 758	uint32_t meta_off;
 759	memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
 760	if (chunk) {
 761		meta_off += (address - chunk->start) & chunk->mask;
 762	}
 763	uint32_t slot = meta_off/1024;
 764	return opts->gen.ram_inst_sizes[slot][(meta_off/2)%512];
 765}
 766
 767uint8_t m68k_is_terminal(m68kinst * inst)
 768{
 769	return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
 770		|| inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID
 771		|| (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
 772}
 773
 774static void m68k_handle_deferred(m68k_context * context)
 775{
 776	m68k_options * opts = context->options;
 777	process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
 778	if (opts->gen.deferred) {
 779		translate_m68k_stream(opts->gen.deferred->address, context);
 780	}
 781}
 782
 783uint16_t m68k_get_ir(m68k_context *context)
 784{
 785	uint32_t inst_addr = get_instruction_start(context->options, context->last_prefetch_address-2);
 786	uint16_t *native_addr = get_native_pointer(inst_addr, (void **)context->mem_pointers, &context->options->gen);
 787	if (native_addr) {
 788		return *native_addr;
 789	}
 790	fprintf(stderr, "M68K: Failed to calculate value of IR. Last prefetch address: %X\n", context->last_prefetch_address);
 791	return 0xFFFF;
 792}
 793
 794static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address)
 795{
 796	for (uint32_t i = 0; i < context->num_breakpoints; i++)
 797	{
 798		if (context->breakpoints[i].address == address) {
 799			return context->breakpoints[i].handler;
 800		}
 801	}
 802	return NULL;
 803}
 804
 805void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler)
 806{
 807	if (!find_breakpoint(context, address)) {
 808		if (context->bp_storage == context->num_breakpoints) {
 809			context->bp_storage *= 2;
 810			if (context->bp_storage < 4) {
 811				context->bp_storage = 4;
 812			}
 813			context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint));
 814		}
 815		context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){
 816			.handler = bp_handler,
 817			.address = address
 818		};
 819		m68k_breakpoint_patch(context, address, bp_handler, NULL);
 820	}
 821}
 822
 823m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address)
 824{
 825	m68k_debug_handler handler = find_breakpoint(context, address);
 826	if (handler) {
 827		handler(context, address);
 828	} else {
 829		//spurious breakoint?
 830		warning("Spurious breakpoing at %X\n", address);
 831		remove_breakpoint(context, address);
 832	}
 833	
 834	return context;
 835}
 836
 837typedef enum {
 838	RAW_FUNC = 1,
 839	BINARY_ARITH,
 840	UNARY_ARITH,
 841	OP_FUNC
 842} impl_type;
 843
 844typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst);
 845typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
 846
 847typedef struct {
 848	union {
 849		raw_fun  raw;
 850		uint32_t flag_mask;
 851		op_fun   op;
 852	} impl;
 853	impl_type itype;
 854} impl_info;
 855
 856#define RAW_IMPL(inst, fun)     [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC }
 857#define OP_IMPL(inst, fun)      [inst] = { .impl = { .op = fun }, .itype = OP_FUNC }
 858#define UNARY_IMPL(inst, mask)  [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH }
 859#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH }
 860
 861static impl_info m68k_impls[] = {
 862	//math
 863	BINARY_IMPL(M68K_ADD, X|N|Z|V|C),
 864	BINARY_IMPL(M68K_SUB, X|N|Z|V|C),
 865	//z flag is special cased for ADDX/SUBX
 866	BINARY_IMPL(M68K_ADDX, X|N|V|C),
 867	BINARY_IMPL(M68K_SUBX, X|N|V|C),
 868	OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd),
 869	OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd),
 870	OP_IMPL(M68K_NBCD, translate_m68k_abcd_sbcd),
 871	BINARY_IMPL(M68K_AND, N|Z|V0|C0),
 872	BINARY_IMPL(M68K_EOR, N|Z|V0|C0),
 873	BINARY_IMPL(M68K_OR, N|Z|V0|C0),
 874	RAW_IMPL(M68K_CMP, translate_m68k_cmp),
 875	OP_IMPL(M68K_DIVS, translate_m68k_div),
 876	OP_IMPL(M68K_DIVU, translate_m68k_div),
 877	OP_IMPL(M68K_MULS, translate_m68k_mul),
 878	OP_IMPL(M68K_MULU, translate_m68k_mul),
 879	RAW_IMPL(M68K_EXT, translate_m68k_ext),
 880	UNARY_IMPL(M68K_NEG, X|N|Z|V|C),
 881	OP_IMPL(M68K_NEGX, translate_m68k_negx),
 882	UNARY_IMPL(M68K_NOT, N|Z|V|C),
 883	UNARY_IMPL(M68K_TST, N|Z|V0|C0),
 884
 885	//shift/rotate
 886	OP_IMPL(M68K_ASL, translate_m68k_sl),
 887	OP_IMPL(M68K_LSL, translate_m68k_sl),
 888	OP_IMPL(M68K_ASR, translate_m68k_asr),
 889	OP_IMPL(M68K_LSR, translate_m68k_lsr),
 890	OP_IMPL(M68K_ROL, translate_m68k_rot),
 891	OP_IMPL(M68K_ROR, translate_m68k_rot),
 892	OP_IMPL(M68K_ROXL, translate_m68k_rot),
 893	OP_IMPL(M68K_ROXR, translate_m68k_rot),
 894	UNARY_IMPL(M68K_SWAP, N|Z|V0|C0),
 895
 896	//bit
 897	OP_IMPL(M68K_BCHG, translate_m68k_bit),
 898	OP_IMPL(M68K_BCLR, translate_m68k_bit),
 899	OP_IMPL(M68K_BSET, translate_m68k_bit),
 900	OP_IMPL(M68K_BTST, translate_m68k_bit),
 901
 902	//data movement
 903	RAW_IMPL(M68K_MOVE, translate_m68k_move),
 904	RAW_IMPL(M68K_MOVEM, translate_m68k_movem),
 905	RAW_IMPL(M68K_MOVEP, translate_m68k_movep),
 906	RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp),
 907	RAW_IMPL(M68K_LEA, translate_m68k_lea_pea),
 908	RAW_IMPL(M68K_PEA, translate_m68k_lea_pea),
 909	UNARY_IMPL(M68K_CLR, N0|V0|C0|Z1),
 910	OP_IMPL(M68K_EXG, translate_m68k_exg),
 911	RAW_IMPL(M68K_SCC, translate_m68k_scc),
 912
 913	//function calls and branches
 914	RAW_IMPL(M68K_BCC, translate_m68k_bcc),
 915	RAW_IMPL(M68K_BSR, translate_m68k_bsr),
 916	RAW_IMPL(M68K_DBCC, translate_m68k_dbcc),
 917	RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr),
 918	RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr),
 919	RAW_IMPL(M68K_RTS, translate_m68k_rts),
 920	RAW_IMPL(M68K_RTE, translate_m68k_rte),
 921	RAW_IMPL(M68K_RTR, translate_m68k_rtr),
 922	RAW_IMPL(M68K_LINK, translate_m68k_link),
 923	RAW_IMPL(M68K_UNLK, translate_m68k_unlk),
 924
 925	//SR/CCR stuff
 926	RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ori_ccr_sr),
 927	RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ori_ccr_sr),
 928	RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr),
 929	RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr),
 930	RAW_IMPL(M68K_ORI_CCR, translate_m68k_andi_ori_ccr_sr),
 931	RAW_IMPL(M68K_ORI_SR, translate_m68k_andi_ori_ccr_sr),
 932	OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr),
 933	OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr),
 934	OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr),
 935	RAW_IMPL(M68K_STOP, translate_m68k_stop),
 936
 937	//traps
 938	OP_IMPL(M68K_CHK, translate_m68k_chk),
 939	RAW_IMPL(M68K_TRAP, translate_m68k_trap),
 940	RAW_IMPL(M68K_A_LINE_TRAP, translate_m68k_trap),
 941	RAW_IMPL(M68K_F_LINE_TRAP, translate_m68k_trap),
 942	RAW_IMPL(M68K_TRAPV, translate_m68k_trapv),
 943	RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal),
 944	RAW_IMPL(M68K_INVALID, translate_m68k_illegal),
 945
 946	//misc
 947	RAW_IMPL(M68K_NOP, translate_m68k_nop),
 948	RAW_IMPL(M68K_RESET, translate_m68k_reset),
 949	RAW_IMPL(M68K_TAS, translate_m68k_tas),
 950};
 951
 952static void translate_m68k(m68k_context *context, m68kinst * inst)
 953{
 954	m68k_options * opts = context->options;
 955	if (inst->address & 1) {
 956		translate_m68k_odd(opts, inst);
 957		return;
 958	}
 959	code_ptr start = opts->gen.code.cur;
 960	check_cycles_int(&opts->gen, inst->address);
 961	
 962	m68k_debug_handler bp;
 963	if ((bp = find_breakpoint(context, inst->address))) {
 964		m68k_breakpoint_patch(context, inst->address, bp, start);
 965	}
 966	
 967	//log_address(&opts->gen, inst->address, "M68K: %X @ %d\n");
 968	if (
 969		(inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE) 
 970		|| (inst->dst.addr_mode > MODE_AREG && inst->dst.addr_mode < MODE_IMMEDIATE)
 971		|| (inst->op == M68K_BCC && (inst->src.params.immed & 1))
 972	) {
 973		//Not accurate for all cases, but probably good enough for now
 974		m68k_set_last_prefetch(opts, inst->address + inst->bytes);
 975	}
 976	impl_info * info = m68k_impls + inst->op;
 977	if (info->itype == RAW_FUNC) {
 978		info->impl.raw(opts, inst);
 979		return;
 980	}
 981
 982	host_ea src_op, dst_op;
 983	uint8_t needs_int_latch = 0;
 984	if (inst->src.addr_mode != MODE_UNUSED) {
 985		needs_int_latch |= translate_m68k_op(inst, &src_op, opts, 0);
 986	}
 987	if (inst->dst.addr_mode != MODE_UNUSED) {
 988		needs_int_latch |= translate_m68k_op(inst, &dst_op, opts, 1);
 989	}
 990	if (needs_int_latch) {
 991		m68k_check_cycles_int_latch(opts);
 992	}
 993	if (info->itype == OP_FUNC) {
 994		info->impl.op(opts, inst, &src_op, &dst_op);
 995	} else if (info->itype == BINARY_ARITH) {
 996		translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op);
 997	} else if (info->itype == UNARY_ARITH) {
 998		translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op);
 999	} else {
1000		m68k_disasm(inst, disasm_buf);
1001		fatal_error("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
1002	}
1003	if (opts->gen.code.stack_off) {
1004		m68k_disasm(inst, disasm_buf);
1005		fatal_error("Stack offset is %X after %X: %s\n", opts->gen.code.stack_off, inst->address, disasm_buf);
1006	}
1007}
1008
1009void translate_m68k_stream(uint32_t address, m68k_context * context)
1010{
1011	m68kinst instbuf;
1012	m68k_options * opts = context->options;
1013	code_info *code = &opts->gen.code;
1014	if(get_native_address(opts, address)) {
1015		return;
1016	}
1017	uint16_t *encoded, *next;
1018	do {
1019		if (opts->address_log) {
1020			fprintf(opts->address_log, "%X\n", address);
1021			fflush(opts->address_log);
1022		}
1023		do {
1024			encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1025			if (!encoded) {
1026				code_ptr start = code->cur;
1027				translate_out_of_bounds(opts, address);
1028				code_ptr after = code->cur;
1029				map_native_address(context, address, start, 2, after-start);
1030				break;
1031			}
1032			code_ptr existing = get_native_address(opts, address);
1033			if (existing) {
1034				jmp(code, existing);
1035				break;
1036			}
1037			next = m68k_decode(encoded, &instbuf, address);
1038			if (instbuf.op == M68K_INVALID) {
1039				instbuf.src.params.immed = *encoded;
1040			}
1041			uint16_t m68k_size = (next-encoded)*2;
1042			address += m68k_size;
1043			//char disbuf[1024];
1044			//m68k_disasm(&instbuf, disbuf);
1045			//printf("%X: %s\n", instbuf.address, disbuf);
1046
1047			//make sure the beginning of the code for an instruction is contiguous
1048			check_code_prologue(code);
1049			code_ptr start = code->cur;
1050			translate_m68k(context, &instbuf);
1051			code_ptr after = code->cur;
1052			map_native_address(context, instbuf.address, start, m68k_size, after-start);
1053		} while(!m68k_is_terminal(&instbuf) && !(address & 1));
1054		process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
1055		if (opts->gen.deferred) {
1056			address = opts->gen.deferred->address;
1057		}
1058	} while(opts->gen.deferred);
1059}
1060
1061void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
1062{
1063	m68k_options * opts = context->options;
1064	code_info *code = &opts->gen.code;
1065	uint8_t orig_size = get_native_inst_size(opts, address);
1066	code_ptr orig_start = get_native_address(context->options, address);
1067	uint32_t orig = address;
1068	code_info orig_code = {orig_start, orig_start + orig_size + 5, 0};
1069	uint16_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1070	m68kinst instbuf;
1071	after = m68k_decode(inst, &instbuf, orig);
1072	if (orig_size != MAX_NATIVE_SIZE) {
1073		deferred_addr * orig_deferred = opts->gen.deferred;
1074
1075		//make sure we have enough code space for the max size instruction
1076		check_alloc_code(code, MAX_NATIVE_SIZE);
1077		code_ptr native_start = code->cur;
1078		translate_m68k(context, &instbuf);
1079		code_ptr native_end = code->cur;
1080		/*uint8_t is_terminal = m68k_is_terminal(&instbuf);
1081		if ((native_end - native_start) <= orig_size) {
1082			code_ptr native_next;
1083			if (!is_terminal) {
1084				native_next = get_native_address(context->native_code_map, orig + (after-inst)*2);
1085			}
1086			if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) {
1087				printf("Using original location: %p\n", orig_code.cur);
1088				remove_deferred_until(&opts->gen.deferred, orig_deferred);
1089				code_info tmp;
1090				tmp.cur = code->cur;
1091				tmp.last = code->last;
1092				code->cur = orig_code.cur;
1093				code->last = orig_code.last;
1094				translate_m68k(context, &instbuf);
1095				native_end = orig_code.cur = code->cur;
1096				code->cur = tmp.cur;
1097				code->last = tmp.last;
1098				if (!is_terminal) {
1099					nop_fill_or_jmp_next(&orig_code, orig_start + orig_size, native_next);
1100				}
1101				m68k_handle_deferred(context);
1102				return orig_start;
1103			}
1104		}*/
1105
1106		map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE);
1107
1108		jmp(&orig_code, native_start);
1109		if (!m68k_is_terminal(&instbuf)) {
1110			code_ptr native_end = code->cur;
1111			code->cur = native_start + MAX_NATIVE_SIZE;
1112			code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2);
1113			code_info tmp_code = {
1114				.cur = native_end,
1115				.last = native_start + MAX_NATIVE_SIZE,
1116				.stack_off = code->stack_off
1117			};
1118			jmp(&tmp_code, rest);
1119		} else {
1120			code->cur = native_start + MAX_NATIVE_SIZE;
1121		}
1122		m68k_handle_deferred(context);
1123		return native_start;
1124	} else {
1125		code_info tmp = *code;
1126		*code = orig_code;
1127		translate_m68k(context, &instbuf);
1128		orig_code = *code;
1129		*code = tmp;
1130		if (!m68k_is_terminal(&instbuf)) {
1131			jmp(&orig_code, get_native_address_trans(context, orig + (after-inst)*2));
1132		}
1133		m68k_handle_deferred(context);
1134		return orig_start;
1135	}
1136}
1137
1138code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
1139{
1140	code_ptr ret = get_native_address(context->options, address);
1141	if (!ret) {
1142		translate_m68k_stream(address, context);
1143		ret = get_native_address(context->options, address);
1144	}
1145	return ret;
1146}
1147
1148void remove_breakpoint(m68k_context * context, uint32_t address)
1149{
1150	for (uint32_t i = 0; i < context->num_breakpoints; i++)
1151	{
1152		if (context->breakpoints[i].address == address) {
1153			if (i != (context->num_breakpoints-1)) {
1154				context->breakpoints[i] = context->breakpoints[context->num_breakpoints-1];
1155			}
1156			context->num_breakpoints--;
1157			break;
1158		}
1159	}
1160	code_ptr native = get_native_address(context->options, address);
1161	if (!native) {
1162		return;
1163	}
1164	code_info tmp = context->options->gen.code;
1165	context->options->gen.code.cur = native;
1166	context->options->gen.code.last = native + MAX_NATIVE_SIZE;
1167	check_cycles_int(&context->options->gen, address);
1168	context->options->gen.code = tmp;
1169}
1170
1171void start_68k_context(m68k_context * context, uint32_t address)
1172{
1173	code_ptr addr = get_native_address_trans(context, address);
1174	m68k_options * options = context->options;
1175	options->start_context(addr, context);
1176}
1177
1178void resume_68k(m68k_context *context)
1179{
1180	code_ptr addr = context->resume_pc;
1181	context->resume_pc = NULL;
1182	m68k_options * options = context->options;
1183	context->should_return = 0;
1184	options->start_context(addr, context);
1185}
1186
1187void m68k_reset(m68k_context * context)
1188{
1189	//TODO: Actually execute the M68K reset vector rather than simulating some of its behavior
1190	uint16_t *reset_vec = get_native_pointer(0, (void **)context->mem_pointers, &context->options->gen);
1191	context->aregs[7] = reset_vec[0] << 16 | reset_vec[1];
1192	uint32_t address = reset_vec[2] << 16 | reset_vec[3];
1193	start_68k_context(context, address);
1194}
1195
1196void m68k_options_free(m68k_options *opts)
1197{
1198	for (uint32_t address = 0; address < opts->gen.address_mask; address += NATIVE_CHUNK_SIZE)
1199	{
1200		uint32_t chunk = address / NATIVE_CHUNK_SIZE;
1201		if (opts->gen.native_code_map[chunk].base) {
1202			free(opts->gen.native_code_map[chunk].offsets);
1203		}
1204	}
1205	free(opts->gen.native_code_map);
1206	uint32_t ram_inst_slots = ram_size(&opts->gen) / 1024;
1207	for (uint32_t i = 0; i < ram_inst_slots; i++)
1208	{
1209		free(opts->gen.ram_inst_sizes[i]);
1210	}
1211	free(opts->gen.ram_inst_sizes);
1212	free(opts->big_movem);
1213	free(opts);
1214}
1215
1216
1217m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler)
1218{
1219	m68k_context * context = calloc(1, sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8);
1220	context->options = opts;
1221	context->int_cycle = CYCLE_NEVER;
1222	context->status = 0x27;
1223	context->reset_handler = (code_ptr)reset_handler;
1224	return context;
1225}
1226
1227void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf)
1228{
1229	for (int i = 0; i < 8; i++)
1230	{
1231		save_int32(buf, context->dregs[i]);
1232	}
1233	for (int i = 0; i < 9; i++)
1234	{
1235		save_int32(buf, context->aregs[i]);
1236	}
1237	save_int32(buf, pc);
1238	uint16_t sr = context->status << 3;
1239	for (int flag = 4; flag >= 0; flag--) {
1240		sr <<= 1;
1241		sr |= context->flags[flag] != 0;
1242	}
1243	save_int16(buf, sr);
1244	save_int32(buf, context->current_cycle);
1245	save_int32(buf, context->int_cycle);
1246	save_int8(buf, context->int_num);
1247	save_int8(buf, context->int_pending);
1248	save_int8(buf, context->trace_pending);
1249}
1250
1251void m68k_deserialize(deserialize_buffer *buf, void *vcontext)
1252{
1253	m68k_context *context = vcontext;
1254	for (int i = 0; i < 8; i++)
1255	{
1256		context->dregs[i] = load_int32(buf);
1257	}
1258	for (int i = 0; i < 9; i++)
1259	{
1260		context->aregs[i] = load_int32(buf);
1261	}
1262	//hack until both PC and IR registers are represented properly
1263	context->last_prefetch_address = load_int32(buf);
1264	uint16_t sr = load_int16(buf);
1265	context->status = sr >> 8;
1266	for (int flag = 0; flag < 5; flag++)
1267	{
1268		context->flags[flag] = sr & 1;
1269		sr >>= 1;
1270	}
1271	context->current_cycle = load_int32(buf);
1272	context->int_cycle = load_int32(buf);
1273	context->int_num = load_int8(buf);
1274	context->int_pending = load_int8(buf);
1275	context->trace_pending = load_int8(buf);
1276}