annotate m68k_core_x86.c @ 1021:4a92889e2889 v0.4.0

Fix OS X build
author Michael Pavone <pavone@retrodev.com>
date Wed, 04 May 2016 00:50:20 -0700
parents 784bc1e45e80
children 7267bc1ab547
rev   line source
pavone@467 1 /*
pavone@467 2 Copyright 2013 Michael Pavone
pavone@485 3 This file is part of BlastEm.
pavone@467 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.
pavone@467 5 */
pavone@14 6 #include "gen_x86.h"
pavone@569 7 #include "m68k_core.h"
pavone@570 8 #include "m68k_internal.h"
pavone@208 9 #include "68kinst.h"
pavone@95 10 #include "mem.h"
pavone@557 11 #include "backend.h"
pavone@792 12 #include "util.h"
pavone@18 13 #include <stdio.h>
pavone@18 14 #include <stddef.h>
pavone@18 15 #include <stdlib.h>
pavone@18 16 #include <string.h>
pavone@14 17
pavone@546 18 enum {
pavone@546 19 FLAG_X,
pavone@546 20 FLAG_N,
pavone@546 21 FLAG_Z,
pavone@546 22 FLAG_V,
pavone@546 23 FLAG_C
pavone@546 24 };
pavone@14 25
pavone@569 26 void set_flag(m68k_options * opts, uint8_t val, uint8_t flag)
pavone@546 27 {
pavone@546 28 if (opts->flag_regs[flag] >= 0) {
pavone@567 29 mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
pavone@546 30 } else {
pavone@546 31 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@546 32 if (offset) {
pavone@567 33 mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B);
pavone@546 34 } else {
pavone@567 35 mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B);
pavone@546 36 }
pavone@546 37 }
pavone@546 38 }
pavone@546 39
pavone@569 40 void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag)
pavone@546 41 {
pavone@546 42 if (opts->flag_regs[flag] >= 0) {
pavone@567 43 setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]);
pavone@546 44 } else {
pavone@546 45 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@546 46 if (offset) {
pavone@567 47 setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset);
pavone@546 48 } else {
pavone@567 49 setcc_rind(&opts->gen.code, cond, opts->gen.context_reg);
pavone@546 50 }
pavone@546 51 }
pavone@546 52 }
pavone@546 53
pavone@569 54 void check_flag(m68k_options *opts, uint8_t flag)
pavone@546 55 {
pavone@546 56 if (opts->flag_regs[flag] >= 0) {
pavone@567 57 cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
pavone@546 58 } else {
pavone@567 59 cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
pavone@546 60 }
pavone@546 61 }
pavone@546 62
pavone@569 63 void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
pavone@546 64 {
pavone@546 65 if (opts->flag_regs[flag] >= 0) {
pavone@567 66 mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
pavone@546 67 } else {
pavone@546 68 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@546 69 if (offset) {
pavone@567 70 mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B);
pavone@546 71 } else {
pavone@567 72 mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B);
pavone@546 73 }
pavone@546 74 }
pavone@546 75 }
pavone@546 76
pavone@569 77 void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag)
pavone@546 78 {
pavone@546 79 if (opts->flag_regs[flag] >= 0) {
pavone@567 80 mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B);
pavone@546 81 } else {
pavone@546 82 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@546 83 if (offset) {
pavone@567 84 mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B);
pavone@546 85 } else {
pavone@567 86 mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B);
pavone@546 87 }
pavone@546 88 }
pavone@546 89 }
pavone@546 90
pavone@569 91 void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2)
pavone@546 92 {
pavone@567 93 code_info *code = &opts->gen.code;
pavone@546 94 if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
pavone@567 95 mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
pavone@546 96 } else if(opts->flag_regs[flag1] >= 0) {
pavone@567 97 mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
pavone@546 98 } else if (opts->flag_regs[flag2] >= 0) {
pavone@567 99 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B);
pavone@546 100 } else {
pavone@567 101 push_r(code, opts->gen.scratch1);
pavone@567 102 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
pavone@567 103 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
pavone@567 104 pop_r(code, opts->gen.scratch1);
pavone@546 105 }
pavone@546 106 }
pavone@546 107
pavone@576 108 void update_flags(m68k_options *opts, uint32_t update_mask)
pavone@576 109 {
pavone@576 110 uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C};
pavone@576 111 for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag)
pavone@576 112 {
pavone@576 113 if (update_mask & X0 << (flag*3)) {
pavone@576 114 set_flag(opts, 0, flag);
pavone@576 115 } else if(update_mask & X1 << (flag*3)) {
pavone@576 116 set_flag(opts, 1, flag);
pavone@576 117 } else if(update_mask & X << (flag*3)) {
pavone@576 118 if (flag == FLAG_X) {
pavone@576 119 if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) {
pavone@576 120 flag_to_flag(opts, FLAG_C, FLAG_X);
pavone@576 121 } else if(update_mask & C0) {
pavone@576 122 set_flag(opts, 0, flag);
pavone@576 123 } else if(update_mask & C1) {
pavone@576 124 set_flag(opts, 1, flag);
pavone@576 125 } else {
pavone@576 126 set_flag_cond(opts, CC_C, flag);
pavone@576 127 }
pavone@576 128 } else {
pavone@576 129 set_flag_cond(opts, native_flags[flag], flag);
pavone@576 130 }
pavone@576 131 }
pavone@576 132 }
pavone@576 133 }
pavone@576 134
pavone@569 135 void flag_to_carry(m68k_options * opts, uint8_t flag)
pavone@546 136 {
pavone@546 137 if (opts->flag_regs[flag] >= 0) {
pavone@567 138 bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
pavone@546 139 } else {
pavone@567 140 bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
pavone@546 141 }
pavone@546 142 }
pavone@546 143
pavone@569 144 void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
pavone@546 145 {
pavone@546 146 if (opts->flag_regs[flag] >= 0) {
pavone@567 147 or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
pavone@546 148 } else {
pavone@567 149 or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
pavone@546 150 }
pavone@546 151 }
pavone@546 152
pavone@569 153 void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
pavone@546 154 {
pavone@546 155 if (opts->flag_regs[flag] >= 0) {
pavone@567 156 xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
pavone@546 157 } else {
pavone@567 158 xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
pavone@546 159 }
pavone@546 160 }
pavone@546 161
pavone@569 162 void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag)
pavone@546 163 {
pavone@546 164 if (opts->flag_regs[flag] >= 0) {
pavone@567 165 xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
pavone@546 166 } else {
pavone@567 167 xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
pavone@546 168 }
pavone@546 169 }
pavone@546 170
pavone@569 171 void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2)
pavone@546 172 {
pavone@567 173 code_info *code = &opts->gen.code;
pavone@546 174 if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
pavone@567 175 cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
pavone@546 176 } else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) {
pavone@546 177 if (opts->flag_regs[flag2] >= 0) {
pavone@546 178 uint8_t tmp = flag1;
pavone@546 179 flag1 = flag2;
pavone@546 180 flag2 = tmp;
pavone@546 181 }
pavone@567 182 cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
pavone@546 183 } else {
pavone@567 184 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
pavone@567 185 cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
pavone@546 186 }
pavone@546 187 }
pavone@546 188
pavone@574 189 void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 190 {
pavone@574 191 if (opts->aregs[reg] >= 0) {
pavone@574 192 mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
pavone@574 193 } else {
pavone@574 194 mov_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
pavone@574 195 }
pavone@574 196 }
pavone@574 197
pavone@574 198 void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 199 {
pavone@574 200 if (opts->dregs[reg] >= 0) {
pavone@574 201 mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
pavone@574 202 } else {
pavone@574 203 mov_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
pavone@574 204 }
pavone@574 205 }
pavone@574 206
pavone@574 207 void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 208 {
pavone@574 209 if (opts->aregs[reg] >= 0) {
pavone@574 210 movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D);
pavone@574 211 } else {
pavone@574 212 movsx_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_W, SZ_D);
pavone@574 213 }
pavone@574 214 }
pavone@574 215
pavone@574 216 void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 217 {
pavone@574 218 if (opts->dregs[reg] >= 0) {
pavone@574 219 movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D);
pavone@686 220 } else {
pavone@574 221 movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D);
pavone@574 222 }
pavone@686 223 }
pavone@574 224
pavone@574 225 void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
pavone@682 226 {
pavone@574 227 if (opts->aregs[reg] >= 0) {
pavone@574 228 mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D);
pavone@686 229 } else {
pavone@574 230 mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D);
pavone@686 231 }
pavone@686 232 }
pavone@574 233
pavone@574 234 void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
pavone@574 235 {
pavone@574 236 if (opts->dregs[reg] >= 0) {
pavone@574 237 mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D);
pavone@686 238 } else {
pavone@574 239 mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D);
pavone@686 240 }
pavone@574 241 }
pavone@574 242
pavone@574 243 void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg)
pavone@574 244 {
pavone@574 245 if (opts->aregs[reg] >= 0) {
pavone@574 246 mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D);
pavone@686 247 } else {
pavone@574 248 mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D);
pavone@686 249 }
pavone@574 250 }
pavone@574 251
pavone@574 252 void ldi_native(m68k_options *opts, int32_t value, uint8_t reg)
pavone@686 253 {
pavone@574 254 mov_ir(&opts->gen.code, value, reg, SZ_D);
pavone@686 255 }
pavone@574 256
pavone@588 257 void addi_native(m68k_options *opts, int32_t value, uint8_t reg)
pavone@588 258 {
pavone@588 259 add_ir(&opts->gen.code, value, reg, SZ_D);
pavone@682 260 }
pavone@588 261
pavone@588 262 void subi_native(m68k_options *opts, int32_t value, uint8_t reg)
pavone@588 263 {
pavone@588 264 sub_ir(&opts->gen.code, value, reg, SZ_D);
pavone@686 265 }
pavone@588 266
pavone@588 267 void push_native(m68k_options *opts, uint8_t reg)
pavone@588 268 {
pavone@588 269 push_r(&opts->gen.code, reg);
pavone@686 270 }
pavone@588 271
pavone@588 272 void pop_native(m68k_options *opts, uint8_t reg)
pavone@686 273 {
pavone@588 274 pop_r(&opts->gen.code, reg);
pavone@686 275 }
pavone@588 276
pavone@588 277 void sign_extend16_native(m68k_options *opts, uint8_t reg)
pavone@588 278 {
pavone@588 279 movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D);
pavone@686 280 }
pavone@588 281
pavone@574 282 void addi_areg(m68k_options *opts, int32_t val, uint8_t reg)
pavone@574 283 {
pavone@574 284 if (opts->aregs[reg] >= 0) {
pavone@574 285 add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
pavone@686 286 } else {
pavone@574 287 add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
pavone@686 288 }
pavone@574 289 }
pavone@574 290
pavone@574 291 void subi_areg(m68k_options *opts, int32_t val, uint8_t reg)
pavone@574 292 {
pavone@574 293 if (opts->aregs[reg] >= 0) {
pavone@574 294 sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
pavone@686 295 } else {
pavone@574 296 sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
pavone@686 297 }
pavone@686 298 }
pavone@574 299
pavone@574 300 void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 301 {
pavone@574 302 if (opts->aregs[reg] >= 0) {
pavone@574 303 add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
pavone@686 304 } else {
pavone@574 305 add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
pavone@686 306 }
pavone@574 307 }
pavone@574 308
pavone@574 309 void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
pavone@574 310 {
pavone@574 311 if (opts->dregs[reg] >= 0) {
pavone@574 312 add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
pavone@686 313 } else {
pavone@574 314 add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
pavone@686 315 }
pavone@686 316 }
pavone@574 317
pavone@574 318 void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
pavone@686 319 {
pavone@574 320 areg_to_native(opts, op->params.regs.pri, native_reg);
pavone@751 321 add_ir(&opts->gen.code, op->params.regs.displacement & 0x8000 ? op->params.regs.displacement | 0xFFFF0000 : op->params.regs.displacement, native_reg, SZ_D);
pavone@686 322 }
pavone@574 323
pavone@574 324 void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
pavone@686 325 {
pavone@574 326 uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7;
pavone@574 327 if (op->params.regs.sec & 1) {
pavone@574 328 if (op->params.regs.sec & 0x10) {
pavone@574 329 add_areg_native(opts, sec_reg, native_reg);
pavone@686 330 } else {
pavone@574 331 add_dreg_native(opts, sec_reg, native_reg);
pavone@686 332 }
pavone@686 333 } else {
pavone@574 334 uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
pavone@574 335 if (op->params.regs.sec & 0x10) {
pavone@574 336 areg_to_native_sx(opts, sec_reg, other_reg);
pavone@686 337 } else {
pavone@574 338 dreg_to_native_sx(opts, sec_reg, other_reg);
pavone@686 339 }
pavone@574 340 add_rr(&opts->gen.code, other_reg, native_reg, SZ_D);
pavone@686 341 }
pavone@574 342 if (op->params.regs.displacement) {
pavone@574 343 add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D);
pavone@686 344 }
pavone@686 345 }
pavone@574 346
pavone@574 347 void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
pavone@686 348 {
pavone@574 349 areg_to_native(opts, op->params.regs.pri, native_reg);
pavone@574 350 calc_index_disp8(opts, op, native_reg);
pavone@574 351 }
pavone@574 352
pavone@582 353 void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst)
pavone@567 354 {
pavone@567 355 code_info *code = &opts->gen.code;
pavone@571 356 m68k_op_info *op = dst ? &inst->dst : &inst->src;
pavone@571 357 int8_t reg = native_reg(op, opts);
pavone@81 358 uint8_t sec_reg;
pavone@682 359 int32_t dec_amount, inc_amount;
pavone@14 360 if (reg >= 0) {
pavone@18 361 ea->mode = MODE_REG_DIRECT;
pavone@571 362 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
pavone@567 363 movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D);
pavone@567 364 ea->base = opts->gen.scratch1;
pavone@181 365 } else {
pavone@686 366 ea->base = reg;
pavone@686 367 }
pavone@567 368 return;
pavone@14 369 }
pavone@571 370 switch (op->addr_mode)
pavone@14 371 {
pavone@14 372 case MODE_REG:
pavone@14 373 case MODE_AREG:
pavone@18 374 //We only get one memory parameter, so if the dst operand is a register in memory,
pavone@571 375 //we need to copy this to a temp register first if we're translating the src operand
pavone@571 376 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)
pavone@18 377 || inst->op == M68K_EXG) {
pavone@447 378
pavone@686 379 ea->mode = MODE_REG_DISPLACE8;
pavone@567 380 ea->base = opts->gen.context_reg;
pavone@571 381 ea->disp = reg_offset(op);
pavone@18 382 } else {
pavone@181 383 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
pavone@571 384 movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D);
pavone@181 385 } else {
pavone@571 386 mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size);
pavone@181 387 }
pavone@18 388 ea->mode = MODE_REG_DIRECT;
pavone@567 389 ea->base = opts->gen.scratch1;
pavone@181 390 //we're explicitly handling the areg dest here, so we exit immediately
pavone@567 391 return;
pavone@18 392 }
pavone@14 393 break;
pavone@18 394 case MODE_AREG_PREDEC:
pavone@571 395 if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
pavone@571 396 push_r(code, opts->gen.scratch1);
pavone@571 397 }
pavone@571 398 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1));
pavone@571 399 if (!dst) {
pavone@571 400 cycles(&opts->gen, PREDEC_PENALTY);
pavone@571 401 }
pavone@574 402 subi_areg(opts, dec_amount, op->params.regs.pri);
pavone@14 403 case MODE_AREG_INDIRECT:
pavone@447 404 case MODE_AREG_POSTINC:
pavone@574 405 areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1);
pavone@567 406 m68k_read_size(opts, inst->extra.size);
pavone@447 407
pavone@571 408 if (dst) {
pavone@686 409 if (inst->src.addr_mode == MODE_AREG_PREDEC) {
pavone@571 410 //restore src operand to opts->gen.scratch2
pavone@571 411 pop_r(code, opts->gen.scratch2);
pavone@686 412 } else {
pavone@571 413 //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later
pavone@574 414 areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2);
pavone@571 415 }
pavone@571 416 }
pavone@571 417
pavone@571 418 if (op->addr_mode == MODE_AREG_POSTINC) {
pavone@571 419 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1));
pavone@574 420 addi_areg(opts, inc_amount, op->params.regs.pri);
pavone@18 421 }
pavone@18 422 ea->mode = MODE_REG_DIRECT;
pavone@571 423 ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1;
pavone@14 424 break;
pavone@71 425 case MODE_AREG_DISPLACE:
pavone@567 426 cycles(&opts->gen, BUS);
pavone@574 427 calc_areg_displace(opts, op, opts->gen.scratch1);
pavone@571 428 if (dst) {
pavone@571 429 push_r(code, opts->gen.scratch1);
pavone@571 430 }
pavone@567 431 m68k_read_size(opts, inst->extra.size);
pavone@571 432 if (dst) {
pavone@571 433 pop_r(code, opts->gen.scratch2);
pavone@686 434 }
pavone@567 435
pavone@71 436 ea->mode = MODE_REG_DIRECT;
pavone@567 437 ea->base = opts->gen.scratch1;
pavone@71 438 break;
pavone@81 439 case MODE_AREG_INDEX_DISP8:
pavone@567 440 cycles(&opts->gen, 6);
pavone@574 441 calc_areg_index_disp8(opts, op, opts->gen.scratch1);
pavone@571 442 if (dst) {
pavone@571 443 push_r(code, opts->gen.scratch1);
pavone@81 444 }
pavone@567 445 m68k_read_size(opts, inst->extra.size);
pavone@571 446 if (dst) {
pavone@571 447 pop_r(code, opts->gen.scratch2);
pavone@686 448 }
pavone@567 449
pavone@97 450 ea->mode = MODE_REG_DIRECT;
pavone@567 451 ea->base = opts->gen.scratch1;
pavone@81 452 break;
pavone@71 453 case MODE_PC_DISPLACE:
pavone@567 454 cycles(&opts->gen, BUS);
pavone@571 455 mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D);
pavone@571 456 if (dst) {
pavone@571 457 push_r(code, opts->gen.scratch1);
pavone@686 458 }
pavone@567 459 m68k_read_size(opts, inst->extra.size);
pavone@571 460 if (dst) {
pavone@571 461 pop_r(code, opts->gen.scratch2);
pavone@571 462 }
pavone@567 463
pavone@71 464 ea->mode = MODE_REG_DIRECT;
pavone@567 465 ea->base = opts->gen.scratch1;
pavone@71 466 break;
pavone@81 467 case MODE_PC_INDEX_DISP8:
pavone@567 468 cycles(&opts->gen, 6);
pavone@567 469 mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
pavone@574 470 calc_index_disp8(opts, op, opts->gen.scratch1);
pavone@571 471 if (dst) {
pavone@571 472 push_r(code, opts->gen.scratch1);
pavone@686 473 }
pavone@567 474 m68k_read_size(opts, inst->extra.size);
pavone@571 475 if (dst) {
pavone@571 476 pop_r(code, opts->gen.scratch2);
pavone@686 477 }
pavone@567 478
pavone@96 479 ea->mode = MODE_REG_DIRECT;
pavone@567 480 ea->base = opts->gen.scratch1;
pavone@81 481 break;
pavone@54 482 case MODE_ABSOLUTE:
pavone@54 483 case MODE_ABSOLUTE_SHORT:
pavone@571 484 cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS);
pavone@571 485 mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D);
pavone@571 486 if (dst) {
pavone@571 487 push_r(code, opts->gen.scratch1);
pavone@686 488 }
pavone@567 489 m68k_read_size(opts, inst->extra.size);
pavone@571 490 if (dst) {
pavone@571 491 pop_r(code, opts->gen.scratch2);
pavone@571 492 }
pavone@567 493
pavone@54 494 ea->mode = MODE_REG_DIRECT;
pavone@567 495 ea->base = opts->gen.scratch1;
pavone@54 496 break;
pavone@18 497 case MODE_IMMEDIATE:
pavone@61 498 case MODE_IMMEDIATE_WORD:
pavone@18 499 if (inst->variant != VAR_QUICK) {
pavone@571 500 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS);
pavone@18 501 }
pavone@18 502 ea->mode = MODE_IMMED;
pavone@571 503 ea->disp = op->params.immed;
pavone@571 504 //sign extend value when the destination is an address register
pavone@216 505 if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
pavone@216 506 ea->disp |= 0xFFFF0000;
pavone@216 507 }
pavone@567 508 return;
pavone@18 509 default:
pavone@151 510 m68k_disasm(inst, disasm_buf);
pavone@792 511 fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
pavone@14 512 }
pavone@571 513 if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
pavone@181 514 if (ea->mode == MODE_REG_DIRECT) {
pavone@567 515 movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D);
pavone@181 516 } else {
pavone@567 517 movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D);
pavone@181 518 ea->mode = MODE_REG_DIRECT;
pavone@181 519 }
pavone@567 520 ea->base = opts->gen.scratch1;
pavone@181 521 }
pavone@18 522 }
pavone@18 523
pavone@687 524 void check_user_mode_swap_ssp_usp(m68k_options *opts)
pavone@687 525 {
pavone@687 526 code_info * code = &opts->gen.code;
pavone@687 527 //Check if we've switched to user mode and swap stack pointers if needed
pavone@687 528 bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@687 529 code_ptr end_off = code->cur + 1;
pavone@687 530 jcc(code, CC_C, code->cur + 2);
pavone@687 531 swap_ssp_usp(opts);
pavone@687 532 *end_off = code->cur - (end_off + 1);
pavone@687 533 }
pavone@687 534
pavone@569 535 void translate_m68k_move(m68k_options * opts, m68kinst * inst)
pavone@18 536 {
pavone@567 537 code_info *code = &opts->gen.code;
pavone@99 538 int8_t reg, flags_reg, sec_reg;
pavone@18 539 uint8_t dir = 0;
pavone@18 540 int32_t offset;
pavone@18 541 int32_t inc_amount, dec_amount;
pavone@582 542 host_ea src;
pavone@571 543 translate_m68k_op(inst, &src, opts, 0);
pavone@18 544 reg = native_reg(&(inst->dst), opts);
pavone@447 545
pavone@216 546 if (inst->dst.addr_mode != MODE_AREG) {
pavone@216 547 if (src.mode == MODE_REG_DIRECT) {
pavone@216 548 flags_reg = src.base;
pavone@18 549 } else {
pavone@216 550 if (reg >= 0) {
pavone@216 551 flags_reg = reg;
pavone@128 552 } else {
pavone@216 553 if(src.mode == MODE_REG_DISPLACE8) {
pavone@567 554 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@216 555 } else {
pavone@567 556 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@216 557 }
pavone@216 558 src.mode = MODE_REG_DIRECT;
pavone@567 559 flags_reg = src.base = opts->gen.scratch1;
pavone@128 560 }
pavone@18 561 }
pavone@18 562 }
pavone@181 563 uint8_t size = inst->extra.size;
pavone@18 564 switch(inst->dst.addr_mode)
pavone@18 565 {
pavone@181 566 case MODE_AREG:
pavone@181 567 size = OPSIZE_LONG;
pavone@18 568 case MODE_REG:
pavone@18 569 if (reg >= 0) {
pavone@18 570 if (src.mode == MODE_REG_DIRECT) {
pavone@567 571 mov_rr(code, src.base, reg, size);
pavone@18 572 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 573 mov_rdispr(code, src.base, src.disp, reg, size);
pavone@18 574 } else {
pavone@567 575 mov_ir(code, src.disp, reg, size);
pavone@18 576 }
pavone@18 577 } else if(src.mode == MODE_REG_DIRECT) {
pavone@567 578 mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
pavone@18 579 } else {
pavone@567 580 mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
pavone@18 581 }
pavone@18 582 break;
pavone@18 583 case MODE_AREG_PREDEC:
pavone@182 584 dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
pavone@18 585 case MODE_AREG_INDIRECT:
pavone@18 586 case MODE_AREG_POSTINC:
pavone@18 587 if (src.mode == MODE_REG_DIRECT) {
pavone@567 588 if (src.base != opts->gen.scratch1) {
pavone@567 589 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@18 590 }
pavone@18 591 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 592 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@18 593 } else {
pavone@567 594 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@18 595 }
pavone@610 596 if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
pavone@610 597 subi_areg(opts, dec_amount, inst->dst.params.regs.pri);
pavone@610 598 }
pavone@610 599 areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
pavone@18 600 break;
pavone@71 601 case MODE_AREG_DISPLACE:
pavone@567 602 cycles(&opts->gen, BUS);
pavone@574 603 calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
pavone@71 604 if (src.mode == MODE_REG_DIRECT) {
pavone@567 605 if (src.base != opts->gen.scratch1) {
pavone@567 606 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@71 607 }
pavone@71 608 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 609 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@71 610 } else {
pavone@567 611 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@71 612 }
pavone@71 613 break;
pavone@99 614 case MODE_AREG_INDEX_DISP8:
pavone@567 615 cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
pavone@574 616 //calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used
pavone@574 617 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
pavone@574 618 push_r(code, opts->gen.scratch1);
pavone@99 619 }
pavone@574 620 calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
pavone@574 621 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
pavone@574 622 pop_r(code, opts->gen.scratch1);
pavone@99 623 }
pavone@184 624 if (src.mode == MODE_REG_DIRECT) {
pavone@567 625 if (src.base != opts->gen.scratch1) {
pavone@567 626 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@184 627 }
pavone@184 628 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 629 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@184 630 } else {
pavone@567 631 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@184 632 }
pavone@99 633 break;
pavone@71 634 case MODE_PC_DISPLACE:
pavone@567 635 cycles(&opts->gen, BUS);
pavone@567 636 mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D);
pavone@71 637 if (src.mode == MODE_REG_DIRECT) {
pavone@567 638 if (src.base != opts->gen.scratch1) {
pavone@567 639 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@71 640 }
pavone@71 641 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 642 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@71 643 } else {
pavone@567 644 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@71 645 }
pavone@71 646 break;
pavone@196 647 case MODE_PC_INDEX_DISP8:
pavone@567 648 cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
pavone@567 649 mov_ir(code, inst->address, opts->gen.scratch2, SZ_D);
pavone@574 650 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
pavone@574 651 push_r(code, opts->gen.scratch1);
pavone@689 652 }
pavone@574 653 calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
pavone@574 654 if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
pavone@574 655 pop_r(code, opts->gen.scratch1);
pavone@196 656 }
pavone@196 657 if (src.mode == MODE_REG_DIRECT) {
pavone@567 658 if (src.base != opts->gen.scratch1) {
pavone@567 659 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@196 660 }
pavone@196 661 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 662 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@196 663 } else {
pavone@567 664 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@196 665 }
pavone@196 666 break;
pavone@54 667 case MODE_ABSOLUTE:
pavone@54 668 case MODE_ABSOLUTE_SHORT:
pavone@54 669 if (src.mode == MODE_REG_DIRECT) {
pavone@567 670 if (src.base != opts->gen.scratch1) {
pavone@567 671 mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
pavone@54 672 }
pavone@54 673 } else if (src.mode == MODE_REG_DISPLACE8) {
pavone@567 674 mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@54 675 } else {
pavone@567 676 mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
pavone@54 677 }
pavone@54 678 if (inst->dst.addr_mode == MODE_ABSOLUTE) {
pavone@567 679 cycles(&opts->gen, BUS*2);
pavone@54 680 } else {
pavone@567 681 cycles(&opts->gen, BUS);
pavone@54 682 }
pavone@567 683 mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D);
pavone@54 684 break;
pavone@18 685 default:
pavone@151 686 m68k_disasm(inst, disasm_buf);
pavone@792 687 fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
pavone@18 688 }
pavone@18 689
pavone@576 690 if (inst->dst.addr_mode != MODE_AREG) {
pavone@576 691 cmp_ir(code, 0, flags_reg, inst->extra.size);
pavone@576 692 update_flags(opts, N|Z|V0|C0);
pavone@689 693 }
pavone@576 694 if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
pavone@979 695 m68k_write_size(opts, inst->extra.size, inst->dst.addr_mode == MODE_AREG_PREDEC);
pavone@576 696 if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
pavone@576 697 inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
pavone@576 698 addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
pavone@686 699 }
pavone@686 700 }
pavone@576 701
pavone@18 702 //add cycles for prefetch
pavone@567 703 cycles(&opts->gen, BUS);
pavone@18 704 }
pavone@18 705
pavone@569 706 void translate_m68k_clr(m68k_options * opts, m68kinst * inst)
pavone@52 707 {
pavone@567 708 code_info *code = &opts->gen.code;
pavone@576 709 update_flags(opts, N0|V0|C0|Z1);
pavone@92 710 int8_t reg = native_reg(&(inst->dst), opts);
pavone@52 711 if (reg >= 0) {
pavone@567 712 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4));
pavone@567 713 xor_rr(code, reg, reg, inst->extra.size);
pavone@567 714 return;
pavone@52 715 }
pavone@582 716 host_ea dst_op;
pavone@576 717 //TODO: fix timing
pavone@571 718 translate_m68k_op(inst, &dst_op, opts, 1);
pavone@92 719 if (dst_op.mode == MODE_REG_DIRECT) {
pavone@567 720 xor_rr(code, dst_op.base, dst_op.base, inst->extra.size);
pavone@92 721 } else {
pavone@567 722 mov_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size);
pavone@52 723 }
pavone@567 724 m68k_save_result(inst, opts);
pavone@52 725 }
pavone@52 726
pavone@569 727 void translate_m68k_ext(m68k_options * opts, m68kinst * inst)
pavone@93 728 {
pavone@567 729 code_info *code = &opts->gen.code;
pavone@582 730 host_ea dst_op;
pavone@93 731 uint8_t dst_size = inst->extra.size;
pavone@93 732 inst->extra.size--;
pavone@571 733 translate_m68k_op(inst, &dst_op, opts, 1);
pavone@93 734 if (dst_op.mode == MODE_REG_DIRECT) {
pavone@567 735 movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size);
pavone@567 736 cmp_ir(code, 0, dst_op.base, dst_size);
pavone@93 737 } else {
pavone@567 738 movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size);
pavone@567 739 cmp_ir(code, 0, opts->gen.scratch1, dst_size);
pavone@567 740 mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size);
pavone@93 741 }
pavone@93 742 inst->extra.size = dst_size;
pavone@576 743 update_flags(opts, N|V0|C0|Z);
pavone@93 744 //M68K EXT only operates on registers so no need for a call to save result here
pavone@93 745 }
pavone@93 746
pavone@569 747 uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc)
pavone@18 748 {
pavone@686 749 uint8_t cond = CC_NZ;
pavone@567 750 switch (cc)
pavone@686 751 {
pavone@686 752 case COND_HIGH:
pavone@686 753 cond = CC_Z;
pavone@686 754 case COND_LOW_SAME:
pavone@567 755 flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
pavone@567 756 or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1);
pavone@686 757 break;
pavone@686 758 case COND_CARRY_CLR:
pavone@686 759 cond = CC_Z;
pavone@686 760 case COND_CARRY_SET:
pavone@567 761 check_flag(opts, FLAG_C);
pavone@686 762 break;
pavone@686 763 case COND_NOT_EQ:
pavone@686 764 cond = CC_Z;
pavone@686 765 case COND_EQ:
pavone@567 766 check_flag(opts, FLAG_Z);
pavone@686 767 break;
pavone@686 768 case COND_OVERF_CLR:
pavone@686 769 cond = CC_Z;
pavone@686 770 case COND_OVERF_SET:
pavone@567 771 check_flag(opts, FLAG_V);
pavone@686 772 break;
pavone@686 773 case COND_PLUS:
pavone@686 774 cond = CC_Z;
pavone@686 775 case COND_MINUS:
pavone@567 776 check_flag(opts, FLAG_N);
pavone@686 777 break;
pavone@686 778 case COND_GREATER_EQ:
pavone@686 779 cond = CC_Z;
pavone@686 780 case COND_LESS:
pavone@567 781 cmp_flags(opts, FLAG_N, FLAG_V);
pavone@686 782 break;
pavone@686 783 case COND_GREATER:
pavone@686 784 cond = CC_Z;
pavone@686 785 case COND_LESS_EQ:
pavone@567 786 flag_to_reg(opts, FLAG_V, opts->gen.scratch1);
pavone@567 787 xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1);
pavone@567 788 or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
pavone@686 789 break;
pavone@686 790 }
pavone@567 791 return cond;
pavone@567 792 }
pavone@567 793
pavone@569 794 void translate_m68k_bcc(m68k_options * opts, m68kinst * inst)
pavone@567 795 {
pavone@567 796 code_info *code = &opts->gen.code;
pavone@567 797 cycles(&opts->gen, 10);//TODO: Adjust this for branch not taken case
pavone@18 798 int32_t disp = inst->src.params.immed;
pavone@46 799 uint32_t after = inst->address + 2;
pavone@18 800 if (inst->extra.cond == COND_TRUE) {
pavone@574 801 jump_m68k_abs(opts, after + disp);
pavone@18 802 } else {
pavone@726 803 code_ptr dest_addr = get_native_address(opts, after + disp);
pavone@567 804 uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
pavone@567 805 if (!dest_addr) {
pavone@567 806 opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 2);
pavone@567 807 //dummy address to be replaced later, make sure it generates a 4-byte displacement
pavone@567 808 dest_addr = code->cur + 256;
pavone@18 809 }
pavone@567 810 jcc(code, cond, dest_addr);
pavone@18 811 }
pavone@18 812 }
pavone@18 813
pavone@569 814 void translate_m68k_scc(m68k_options * opts, m68kinst * inst)
pavone@112 815 {
pavone@567 816 code_info *code = &opts->gen.code;
pavone@112 817 uint8_t cond = inst->extra.cond;
pavone@582 818 host_ea dst_op;
pavone@112 819 inst->extra.size = OPSIZE_BYTE;
pavone@571 820 translate_m68k_op(inst, &dst_op, opts, 1);
pavone@112 821 if (cond == COND_TRUE || cond == COND_FALSE) {
pavone@112 822 if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
pavone@567 823 cycles(&opts->gen, 6);
pavone@112 824 } else {
pavone@567 825 cycles(&opts->gen, BUS);
pavone@112 826 }
pavone@112 827 if (dst_op.mode == MODE_REG_DIRECT) {
pavone@567 828 mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B);
pavone@112 829 } else {
pavone@567 830 mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B);
pavone@112 831 }
pavone@112 832 } else {
pavone@567 833 uint8_t cc = m68k_eval_cond(opts, cond);
pavone@567 834 check_alloc_code(code, 6*MAX_INST_LEN);
pavone@567 835 code_ptr true_off = code->cur + 1;
pavone@567 836 jcc(code, cc, code->cur+2);
pavone@567 837 cycles(&opts->gen, BUS);
pavone@567 838 if (dst_op.mode == MODE_REG_DIRECT) {
pavone@567 839 mov_ir(code, 0, dst_op.base, SZ_B);
pavone@567 840 } else {
pavone@567 841 mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
pavone@112 842 }
pavone@567 843 code_ptr end_off = code->cur+1;
pavone@567 844 jmp(code, code->cur+2);
pavone@567 845 *true_off = code->cur - (true_off+1);
pavone@567 846 cycles(&opts->gen, 6);
pavone@179 847 if (dst_op.mode == MODE_REG_DIRECT) {
pavone@567 848 mov_ir(code, 0xFF, dst_op.base, SZ_B);
pavone@112 849 } else {
pavone@567 850 mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B);
pavone@112 851 }
pavone@567 852 *end_off = code->cur - (end_off+1);
pavone@112 853 }
pavone@567 854 m68k_save_result(inst, opts);
pavone@112 855 }
pavone@112 856
pavone@569 857 void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst)
pavone@46 858 {
pavone@567 859 code_info *code = &opts->gen.code;
pavone@46 860 //best case duration
pavone@567 861 cycles(&opts->gen, 10);
pavone@558 862 code_ptr skip_loc = NULL;
pavone@46 863 //TODO: Check if COND_TRUE technically valid here even though
pavone@46 864 //it's basically a slow NOP
pavone@46 865 if (inst->extra.cond != COND_FALSE) {
pavone@567 866 uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
pavone@567 867 check_alloc_code(code, 6*MAX_INST_LEN);
pavone@567 868 skip_loc = code->cur + 1;
pavone@567 869 jcc(code, cond, code->cur + 2);
pavone@46 870 }
pavone@46 871 if (opts->dregs[inst->dst.params.regs.pri] >= 0) {
pavone@567 872 sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
pavone@567 873 cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
pavone@46 874 } else {
pavone@567 875 sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
pavone@567 876 cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
pavone@46 877 }
pavone@567 878 code_ptr loop_end_loc = code->cur + 1;
pavone@567 879 jcc(code, CC_Z, code->cur + 2);
pavone@46 880 uint32_t after = inst->address + 2;
pavone@574 881 jump_m68k_abs(opts, after + inst->src.params.immed);
pavone@567 882 *loop_end_loc = code->cur - (loop_end_loc+1);
pavone@46 883 if (skip_loc) {
pavone@567 884 cycles(&opts->gen, 2);
pavone@567 885 *skip_loc = code->cur - (skip_loc+1);
pavone@567 886 cycles(&opts->gen, 2);
pavone@46 887 } else {
pavone@567 888 cycles(&opts->gen, 4);
pavone@46 889 }
pavone@46 890 }
pavone@46 891
pavone@569 892 void translate_m68k_movep(m68k_options * opts, m68kinst * inst)
pavone@172 893 {
pavone@567 894 code_info *code = &opts->gen.code;
pavone@172 895 int8_t reg;
pavone@567 896 cycles(&opts->gen, BUS*2);
pavone@172 897 if (inst->src.addr_mode == MODE_REG) {
pavone@574 898 calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
pavone@172 899 reg = native_reg(&(inst->src), opts);
pavone@172 900 if (inst->extra.size == OPSIZE_LONG) {
pavone@172 901 if (reg >= 0) {
pavone@567 902 mov_rr(code, reg, opts->gen.scratch1, SZ_D);
pavone@567 903 shr_ir(code, 24, opts->gen.scratch1, SZ_D);
pavone@567 904 push_r(code, opts->gen.scratch2);
pavone@567 905 call(code, opts->write_8);
pavone@567 906 pop_r(code, opts->gen.scratch2);
pavone@567 907 mov_rr(code, reg, opts->gen.scratch1, SZ_D);
pavone@567 908 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
pavone@447 909
pavone@172 910 } else {
pavone@567 911 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B);
pavone@567 912 push_r(code, opts->gen.scratch2);
pavone@567 913 call(code, opts->write_8);
pavone@567 914 pop_r(code, opts->gen.scratch2);
pavone@567 915 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B);
pavone@172 916 }
pavone@567 917 add_ir(code, 2, opts->gen.scratch2, SZ_D);
pavone@567 918 push_r(code, opts->gen.scratch2);
pavone@567 919 call(code, opts->write_8);
pavone@567 920 pop_r(code, opts->gen.scratch2);
pavone@567 921 add_ir(code, 2, opts->gen.scratch2, SZ_D);
pavone@172 922 }
pavone@172 923 if (reg >= 0) {
pavone@567 924 mov_rr(code, reg, opts->gen.scratch1, SZ_W);
pavone@567 925 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
pavone@567 926 push_r(code, opts->gen.scratch2);
pavone@567 927 call(code, opts->write_8);
pavone@567 928 pop_r(code, opts->gen.scratch2);
pavone@567 929 mov_rr(code, reg, opts->gen.scratch1, SZ_W);
pavone@172 930 } else {
pavone@567 931 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B);
pavone@567 932 push_r(code, opts->gen.scratch2);
pavone@567 933 call(code, opts->write_8);
pavone@567 934 pop_r(code, opts->gen.scratch2);
pavone@567 935 mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B);
pavone@172 936 }
pavone@567 937 add_ir(code, 2, opts->gen.scratch2, SZ_D);
pavone@567 938 call(code, opts->write_8);
pavone@172 939 } else {
pavone@574 940 calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
pavone@172 941 reg = native_reg(&(inst->dst), opts);
pavone@172 942 if (inst->extra.size == OPSIZE_LONG) {
pavone@172 943 if (reg >= 0) {
pavone@567 944 push_r(code, opts->gen.scratch1);
pavone@567 945 call(code, opts->read_8);
pavone@567 946 shl_ir(code, 24, opts->gen.scratch1, SZ_D);
pavone@567 947 mov_rr(code, opts->gen.scratch1, reg, SZ_D);
pavone@567 948 pop_r(code, opts->gen.scratch1);
pavone@567 949 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@567 950 push_r(code, opts->gen.scratch1);
pavone@567 951 call(code, opts->read_8);
pavone@567 952 shl_ir(code, 16, opts->gen.scratch1, SZ_D);
pavone@567 953 or_rr(code, opts->gen.scratch1, reg, SZ_D);
pavone@172 954 } else {
pavone@567 955 push_r(code, opts->gen.scratch1);
pavone@567 956 call(code, opts->read_8);
pavone@567 957 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B);
pavone@567 958 pop_r(code, opts->gen.scratch1);
pavone@567 959 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@567 960 push_r(code, opts->gen.scratch1);
pavone@567 961 call(code, opts->read_8);
pavone@567 962 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B);
pavone@172 963 }
pavone@567 964 pop_r(code, opts->gen.scratch1);
pavone@567 965 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@172 966 }
pavone@567 967 push_r(code, opts->gen.scratch1);
pavone@567 968 call(code, opts->read_8);
pavone@172 969 if (reg >= 0) {
pavone@447 970
pavone@567 971 shl_ir(code, 8, opts->gen.scratch1, SZ_W);
pavone@567 972 mov_rr(code, opts->gen.scratch1, reg, SZ_W);
pavone@567 973 pop_r(code, opts->gen.scratch1);
pavone@567 974 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@567 975 call(code, opts->read_8);
pavone@567 976 mov_rr(code, opts->gen.scratch1, reg, SZ_B);
pavone@172 977 } else {
pavone@567 978 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B);
pavone@567 979 pop_r(code, opts->gen.scratch1);
pavone@567 980 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@567 981 call(code, opts->read_8);
pavone@567 982 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B);
pavone@172 983 }
pavone@172 984 }
pavone@172 985 }
pavone@172 986
pavone@567 987 typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
pavone@567 988 typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
pavone@567 989 typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size);
pavone@567 990 typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
pavone@51 991
pavone@582 992 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)
pavone@51 993 {
pavone@567 994 code_info *code = &opts->gen.code;
pavone@558 995 code_ptr end_off = NULL;
pavone@558 996 code_ptr nz_off = NULL;
pavone@558 997 code_ptr z_off = NULL;
pavone@51 998 if (inst->src.addr_mode == MODE_UNUSED) {
pavone@567 999 cycles(&opts->gen, BUS);
pavone@51 1000 //Memory shift
pavone@567 1001 shift_ir(code, 1, dst_op->base, SZ_W);
pavone@51 1002 } else {
pavone@51 1003 if (src_op->mode == MODE_IMMED) {
pavone@667 1004 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp);
pavone@207 1005 if (src_op->disp != 1 && inst->op == M68K_ASL) {
pavone@567 1006 set_flag(opts, 0, FLAG_V);
pavone@207 1007 for (int i = 0; i < src_op->disp; i++) {
pavone@207 1008 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1009 shift_ir(code, 1, dst_op->base, inst->extra.size);
pavone@207 1010 } else {
pavone@567 1011 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1012 }
pavone@567 1013 check_alloc_code(code, 2*MAX_INST_LEN);
pavone@567 1014 code_ptr after_flag_set = code->cur + 1;
pavone@567 1015 jcc(code, CC_NO, code->cur + 2);
pavone@567 1016 set_flag(opts, 1, FLAG_V);
pavone@567 1017 *after_flag_set = code->cur - (after_flag_set+1);
pavone@207 1018 }
pavone@51 1019 } else {
pavone@207 1020 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1021 shift_ir(code, src_op->disp, dst_op->base, inst->extra.size);
pavone@207 1022 } else {
pavone@567 1023 shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1024 }
pavone@567 1025 set_flag_cond(opts, CC_O, FLAG_V);
pavone@51 1026 }
pavone@51 1027 } else {
pavone@667 1028 cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6);
pavone@51 1029 if (src_op->base != RCX) {
pavone@51 1030 if (src_op->mode == MODE_REG_DIRECT) {
pavone@567 1031 mov_rr(code, src_op->base, RCX, SZ_B);
pavone@51 1032 } else {
pavone@567 1033 mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B);
pavone@51 1034 }
pavone@447 1035
pavone@51 1036 }
pavone@567 1037 and_ir(code, 63, RCX, SZ_D);
pavone@567 1038 check_alloc_code(code, 7*MAX_INST_LEN);
pavone@567 1039 nz_off = code->cur + 1;
pavone@567 1040 jcc(code, CC_NZ, code->cur + 2);
pavone@207 1041 //Flag behavior for shift count of 0 is different for x86 than 68K
pavone@207 1042 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1043 cmp_ir(code, 0, dst_op->base, inst->extra.size);
pavone@207 1044 } else {
pavone@567 1045 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1046 }
pavone@567 1047 set_flag_cond(opts, CC_Z, FLAG_Z);
pavone@567 1048 set_flag_cond(opts, CC_S, FLAG_N);
pavone@567 1049 set_flag(opts, 0, FLAG_C);
pavone@207 1050 //For other instructions, this flag will be set below
pavone@207 1051 if (inst->op == M68K_ASL) {
pavone@567 1052 set_flag(opts, 0, FLAG_V);
pavone@207 1053 }
pavone@567 1054 z_off = code->cur + 1;
pavone@567 1055 jmp(code, code->cur + 2);
pavone@567 1056 *nz_off = code->cur - (nz_off + 1);
pavone@51 1057 //add 2 cycles for every bit shifted
pavone@667 1058 mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
pavone@667 1059 imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
pavone@667 1060 add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
pavone@207 1061 if (inst->op == M68K_ASL) {
pavone@207 1062 //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
pavone@207 1063 //Easiest way to deal with this is to shift one bit at a time
pavone@567 1064 set_flag(opts, 0, FLAG_V);
pavone@567 1065 check_alloc_code(code, 5*MAX_INST_LEN);
pavone@567 1066 code_ptr loop_start = code->cur;
pavone@51 1067 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1068 shift_ir(code, 1, dst_op->base, inst->extra.size);
pavone@51 1069 } else {
pavone@567 1070 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
pavone@51 1071 }
pavone@567 1072 code_ptr after_flag_set = code->cur + 1;
pavone@567 1073 jcc(code, CC_NO, code->cur + 2);
pavone@567 1074 set_flag(opts, 1, FLAG_V);
pavone@567 1075 *after_flag_set = code->cur - (after_flag_set+1);
pavone@567 1076 loop(code, loop_start);
pavone@207 1077 } else {
pavone@207 1078 //x86 shifts modulo 32 for operand sizes less than 64-bits
pavone@207 1079 //but M68K shifts modulo 64, so we need to check for large shifts here
pavone@567 1080 cmp_ir(code, 32, RCX, SZ_B);
pavone@567 1081 check_alloc_code(code, 14*MAX_INST_LEN);
pavone@567 1082 code_ptr norm_shift_off = code->cur + 1;
pavone@567 1083 jcc(code, CC_L, code->cur + 2);
pavone@207 1084 if (special) {
pavone@558 1085 code_ptr after_flag_set = NULL;
pavone@207 1086 if (inst->extra.size == OPSIZE_LONG) {
pavone@567 1087 code_ptr neq_32_off = code->cur + 1;
pavone@567 1088 jcc(code, CC_NZ, code->cur + 2);
pavone@447 1089
pavone@207 1090 //set the carry bit to the lsb
pavone@207 1091 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1092 special(code, 1, dst_op->base, SZ_D);
pavone@207 1093 } else {
pavone@567 1094 special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D);
pavone@207 1095 }
pavone@567 1096 set_flag_cond(opts, CC_C, FLAG_C);
pavone@567 1097 after_flag_set = code->cur + 1;
pavone@567 1098 jmp(code, code->cur + 2);
pavone@567 1099 *neq_32_off = code->cur - (neq_32_off+1);
pavone@207 1100 }
pavone@567 1101 set_flag(opts, 0, FLAG_C);
pavone@546 1102 if (after_flag_set) {
pavone@567 1103 *after_flag_set = code->cur - (after_flag_set+1);
pavone@546 1104 }
pavone@567 1105 set_flag(opts, 1, FLAG_Z);
pavone@567 1106 set_flag(opts, 0, FLAG_N);
pavone@207 1107 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1108 xor_rr(code, dst_op->base, dst_op->base, inst->extra.size);
pavone@207 1109 } else {
pavone@567 1110 mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1111 }
pavone@207 1112 } else {
pavone@207 1113 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1114 shift_ir(code, 31, dst_op->base, inst->extra.size);
pavone@567 1115 shift_ir(code, 1, dst_op->base, inst->extra.size);
pavone@207 1116 } else {
pavone@567 1117 shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size);
pavone@567 1118 shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1119 }
pavone@447 1120
pavone@207 1121 }
pavone@567 1122 end_off = code->cur + 1;
pavone@567 1123 jmp(code, code->cur + 2);
pavone@567 1124 *norm_shift_off = code->cur - (norm_shift_off+1);
pavone@207 1125 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@567 1126 shift_clr(code, dst_op->base, inst->extra.size);
pavone@207 1127 } else {
pavone@567 1128 shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size);
pavone@207 1129 }
pavone@51 1130 }
pavone@51 1131 }
pavone@447 1132
pavone@51 1133 }
pavone@51 1134 if (!special && end_off) {
pavone@567 1135 *end_off = code->cur - (end_off + 1);
pavone@51 1136 }
pavone@583 1137 update_flags(opts, C|Z|N);
pavone@51 1138 if (special && end_off) {
pavone@567 1139 *end_off = code->cur - (end_off + 1);
pavone@51 1140 }
pavone@51 1141 //set X flag to same as C flag
pavone@546 1142 if (opts->flag_regs[FLAG_C] >= 0) {
pavone@567 1143 flag_to_flag(opts, FLAG_C, FLAG_X);
pavone@546 1144 } else {
pavone@567 1145 set_flag_cond(opts, CC_C, FLAG_X);
pavone@546 1146 }
pavone@207 1147 if (z_off) {
pavone@567 1148 *z_off = code->cur - (z_off + 1);
pavone@207 1149 }
pavone@219 1150 if (inst->op != M68K_ASL) {
pavone@567 1151 set_flag(opts, 0, FLAG_V);
pavone@207 1152 }
pavone@51 1153 if (inst->src.addr_mode == MODE_UNUSED) {
pavone@567 1154 m68k_save_result(inst, opts);
pavone@51 1155 }
pavone@51 1156 }
pavone@51 1157
pavone@577 1158 void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size)
pavone@577 1159 {
pavone@577 1160 switch (inst->op)
pavone@577 1161 {
pavone@577 1162 case M68K_ADD: add_ir(code, val, dst, size); break;
pavone@577 1163 case M68K_ADDX: adc_ir(code, val, dst, size); break;
pavone@577 1164 case M68K_AND: and_ir(code, val, dst, size); break;
pavone@581 1165 case M68K_BTST: bt_ir(code, val, dst, size); break;
pavone@581 1166 case M68K_BSET: bts_ir(code, val, dst, size); break;
pavone@581 1167 case M68K_BCLR: btr_ir(code, val, dst, size); break;
pavone@581 1168 case M68K_BCHG: btc_ir(code, val, dst, size); break;
pavone@582 1169 case M68K_CMP: cmp_ir(code, val, dst, size); break;
pavone@577 1170 case M68K_EOR: xor_ir(code, val, dst, size); break;
pavone@577 1171 case M68K_OR: or_ir(code, val, dst, size); break;
pavone@577 1172 case M68K_ROL: rol_ir(code, val, dst, size); break;
pavone@577 1173 case M68K_ROR: ror_ir(code, val, dst, size); break;
pavone@577 1174 case M68K_ROXL: rcl_ir(code, val, dst, size); break;
pavone@577 1175 case M68K_ROXR: rcr_ir(code, val, dst, size); break;
pavone@577 1176 case M68K_SUB: sub_ir(code, val, dst, size); break;
pavone@577 1177 case M68K_SUBX: sbb_ir(code, val, dst, size); break;
pavone@577 1178 }
pavone@577 1179 }
pavone@577 1180
pavone@577 1181 void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
pavone@577 1182 {
pavone@577 1183 switch (inst->op)
pavone@577 1184 {
pavone@577 1185 case M68K_ADD: add_irdisp(code, val, dst, disp, size); break;
pavone@577 1186 case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break;
pavone@577 1187 case M68K_AND: and_irdisp(code, val, dst, disp, size); break;
pavone@581 1188 case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break;
pavone@581 1189 case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break;
pavone@581 1190 case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break;
pavone@581 1191 case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break;
pavone@582 1192 case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break;
pavone@577 1193 case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break;
pavone@577 1194 case M68K_OR: or_irdisp(code, val, dst, disp, size); break;
pavone@577 1195 case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break;
pavone@577 1196 case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break;
pavone@577 1197 case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break;
pavone@577 1198 case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break;
pavone@577 1199 case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break;
pavone@577 1200 case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break;
pavone@577 1201 }
pavone@686 1202 }
pavone@577 1203
pavone@577 1204 void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size)
pavone@577 1205 {
pavone@577 1206 switch (inst->op)
pavone@577 1207 {
pavone@577 1208 case M68K_ADD: add_rr(code, src, dst, size); break;
pavone@577 1209 case M68K_ADDX: adc_rr(code, src, dst, size); break;
pavone@577 1210 case M68K_AND: and_rr(code, src, dst, size); break;
pavone@581 1211 case M68K_BTST: bt_rr(code, src, dst, size); break;
pavone@581 1212 case M68K_BSET: bts_rr(code, src, dst, size); break;
pavone@581 1213 case M68K_BCLR: btr_rr(code, src, dst, size); break;
pavone@581 1214 case M68K_BCHG: btc_rr(code, src, dst, size); break;
pavone@582 1215 case M68K_CMP: cmp_rr(code, src, dst, size); break;
pavone@577 1216 case M68K_EOR: xor_rr(code, src, dst, size); break;
pavone@577 1217 case M68K_OR: or_rr(code, src, dst, size); break;
pavone@577 1218 case M68K_SUB: sub_rr(code, src, dst, size); break;
pavone@577 1219 case M68K_SUBX: sbb_rr(code, src, dst, size); break;
pavone@577 1220 }
pavone@686 1221 }
pavone@577 1222
pavone@577 1223 void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size)
pavone@577 1224 {
pavone@558 1225 switch(inst->op)
pavone@577 1226 {
pavone@577 1227 case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break;
pavone@577 1228 case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break;
pavone@577 1229 case M68K_AND: and_rrdisp(code, src, dst, disp, size); break;
pavone@581 1230 case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break;
pavone@581 1231 case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break;
pavone@581 1232 case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break;
pavone@581 1233 case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break;
pavone@582 1234 case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break;
pavone@577 1235 case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break;
pavone@577 1236 case M68K_OR: or_rrdisp(code, src, dst, disp, size); break;
pavone@577 1237 case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break;
pavone@577 1238 case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break;
pavone@686 1239 }
pavone@686 1240 }
pavone@577 1241
pavone@577 1242 void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size)
pavone@577 1243 {
pavone@577 1244 switch (inst->op)
pavone@577 1245 {
pavone@577 1246 case M68K_ADD: add_rdispr(code, src, disp, dst, size); break;
pavone@577 1247 case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break;
pavone@577 1248 case M68K_AND: and_rdispr(code, src, disp, dst, size); break;
pavone@582 1249 case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break;
pavone@577 1250 case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break;
pavone@577 1251 case M68K_OR: or_rdispr(code, src, disp, dst, size); break;
pavone@577 1252 case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break;
pavone@577 1253 case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break;
pavone@686 1254 }
pavone@686 1255 }
pavone@577 1256
pavone@582 1257 void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op)
pavone@577 1258 {
pavone@577 1259 code_info *code = &opts->gen.code;
pavone@577 1260 cycles(&opts->gen, BUS);
pavone@577 1261 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
pavone@577 1262 flag_to_carry(opts, FLAG_X);
pavone@686 1263 }
pavone@577 1264 uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
pavone@577 1265 if (src_op->mode == MODE_REG_DIRECT) {
pavone@577 1266 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@577 1267 op_rr(code, inst, src_op->base, dst_op->base, size);
pavone@686 1268 } else {
pavone@577 1269 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
pavone@686 1270 }
pavone@577 1271 } else if (src_op->mode == MODE_REG_DISPLACE8) {
pavone@577 1272 op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size);
pavone@686 1273 } else {
pavone@577 1274 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@577 1275 op_ir(code, inst, src_op->disp, dst_op->base, size);
pavone@686 1276 } else {
pavone@577 1277 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size);
pavone@577 1278 }
pavone@686 1279 }
pavone@580 1280 if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) {
pavone@577 1281 update_flags(opts, flag_mask);
pavone@577 1282 if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
pavone@577 1283 check_alloc_code(code, 2*MAX_INST_LEN);
pavone@577 1284 code_ptr after_flag_set = code->cur + 1;
pavone@577 1285 jcc(code, CC_Z, code->cur + 2);
pavone@577 1286 set_flag(opts, 0, FLAG_Z);
pavone@577 1287 *after_flag_set = code->cur - (after_flag_set+1);
pavone@577 1288 }
pavone@686 1289 }
pavone@580 1290 if (inst->op != M68K_CMP) {
pavone@580 1291 m68k_save_result(inst, opts);
pavone@580 1292 }
pavone@580 1293 }
pavone@580 1294
pavone@580 1295 void translate_m68k_cmp(m68k_options * opts, m68kinst * inst)
pavone@580 1296 {
pavone@580 1297 code_info *code = &opts->gen.code;
pavone@580 1298 uint8_t size = inst->extra.size;
pavone@582 1299 host_ea src_op, dst_op;
pavone@580 1300 translate_m68k_op(inst, &src_op, opts, 0);
pavone@580 1301 if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
pavone@580 1302 push_r(code, opts->gen.scratch1);
pavone@580 1303 translate_m68k_op(inst, &dst_op, opts, 1);
pavone@580 1304 pop_r(code, opts->gen.scratch2);
pavone@580 1305 src_op.base = opts->gen.scratch2;
pavone@686 1306 } else {
pavone@580 1307 translate_m68k_op(inst, &dst_op, opts, 1);
pavone@580 1308 if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) {
pavone@580 1309 size = OPSIZE_LONG;
pavone@686 1310 }
pavone@580 1311 }
pavone@580 1312 translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op);
pavone@577 1313 }
pavone@577 1314
pavone@837 1315 void translate_m68k_tas(m68k_options *opts, m68kinst *inst)
pavone@837 1316 {
pavone@837 1317 code_info *code = &opts->gen.code;
pavone@837 1318 host_ea op;
pavone@837 1319 translate_m68k_op(inst, &op, opts, 1);
pavone@837 1320 if (op.mode == MODE_REG_DIRECT) {
pavone@837 1321 cmp_ir(code, 0, op.base, SZ_B);
pavone@837 1322 } else {
pavone@837 1323 cmp_irdisp(code, 0, op.base, op.disp, SZ_B);
pavone@837 1324 }
pavone@837 1325 update_flags(opts, N|Z|V0|C0);
pavone@837 1326 if (inst->dst.addr_mode == MODE_REG) {
pavone@837 1327 cycles(&opts->gen, BUS);
pavone@837 1328 if (op.mode == MODE_REG_DIRECT) {
pavone@837 1329 bts_ir(code, 7, op.base, SZ_B);
pavone@837 1330 } else {
pavone@837 1331 bts_irdisp(code, 7, op.base, op.disp, SZ_B);
pavone@837 1332 }
pavone@837 1333 } else {
pavone@837 1334 if (opts->gen.flags & M68K_OPT_BROKEN_READ_MODIFY) {
pavone@837 1335 //2 cycles for processing
pavone@837 1336 //4 for failed writeback
pavone@837 1337 //4 for prefetch
pavone@837 1338 cycles(&opts->gen, BUS * 2 + 2);
pavone@837 1339 } else {
pavone@837 1340 cycles(&opts->gen, 2);
pavone@837 1341 bts_ir(code, 7, op.base, SZ_B);
pavone@837 1342 m68k_save_result(inst, opts);
pavone@837 1343 cycles(&opts->gen, BUS);
pavone@837 1344 }
pavone@837 1345 }
pavone@837 1346 }
pavone@837 1347
pavone@577 1348 void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size)
pavone@577 1349 {
pavone@577 1350 switch(inst->op)
pavone@577 1351 {
pavone@577 1352 case M68K_NEG: neg_r(code, dst, size); break;
pavone@577 1353 case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break;
pavone@577 1354 case M68K_ROL: rol_clr(code, dst, size); break;
pavone@577 1355 case M68K_ROR: ror_clr(code, dst, size); break;
pavone@577 1356 case M68K_ROXL: rcl_clr(code, dst, size); break;
pavone@577 1357 case M68K_ROXR: rcr_clr(code, dst, size); break;
pavone@578 1358 case M68K_SWAP: rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break;
pavone@577 1359 case M68K_TST: cmp_ir(code, 0, dst, size); break;
pavone@577 1360 }
pavone@577 1361 }
pavone@577 1362
pavone@577 1363 void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size)
pavone@577 1364 {
pavone@577 1365 switch(inst->op)
pavone@577 1366 {
pavone@577 1367 case M68K_NEG: neg_rdisp(code, dst, disp, size); break;
pavone@577 1368 case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break;
pavone@577 1369 case M68K_ROL: rol_clrdisp(code, dst, disp, size); break;
pavone@577 1370 case M68K_ROR: ror_clrdisp(code, dst, disp, size); break;
pavone@577 1371 case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break;
pavone@577 1372 case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break;
pavone@578 1373 case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break;
pavone@577 1374 case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break;
pavone@577 1375 }
pavone@577 1376 }
pavone@577 1377
pavone@582 1378 void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op)
pavone@577 1379 {
pavone@577 1380 code_info *code = &opts->gen.code;
pavone@577 1381 cycles(&opts->gen, BUS);
pavone@577 1382 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@577 1383 op_r(code, inst, dst_op->base, inst->extra.size);
pavone@686 1384 } else {
pavone@577 1385 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1386 }
pavone@577 1387 update_flags(opts, flag_mask);
pavone@577 1388 m68k_save_result(inst, opts);
pavone@686 1389 }
pavone@577 1390
pavone@582 1391 void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@14 1392 {
pavone@567 1393 code_info *code = &opts->gen.code;
pavone@834 1394 if (inst->op == M68K_NBCD) {
pavone@834 1395 if (dst_op->base != opts->gen.scratch2) {
pavone@834 1396 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@834 1397 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_B);
pavone@834 1398 } else {
pavone@834 1399 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_B);
pavone@834 1400 }
pavone@208 1401 }
pavone@834 1402 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B);
pavone@834 1403 } else {
pavone@834 1404 if (src_op->base != opts->gen.scratch2) {
pavone@834 1405 if (src_op->mode == MODE_REG_DIRECT) {
pavone@834 1406 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
pavone@834 1407 } else {
pavone@834 1408 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
pavone@834 1409 }
pavone@834 1410 }
pavone@834 1411 if (dst_op->base != opts->gen.scratch1) {
pavone@834 1412 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@834 1413 mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B);
pavone@834 1414 } else {
pavone@834 1415 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B);
pavone@834 1416 }
pavone@686 1417 }
pavone@18 1418 }
pavone@612 1419 uint8_t other_reg;
pavone@612 1420 //WARNING: This may need adjustment if register assignments change
pavone@612 1421 if (opts->gen.scratch2 > RBX) {
pavone@612 1422 other_reg = RAX;
pavone@612 1423 xchg_rr(code, opts->gen.scratch2, RAX, SZ_D);
pavone@686 1424 } else {
pavone@612 1425 other_reg = opts->gen.scratch2;
pavone@612 1426 }
pavone@612 1427 mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@612 1428 mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B);
pavone@612 1429 and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@612 1430 and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B);
pavone@833 1431 //do op on low nibble so we can determine if an adjustment is necessary
pavone@582 1432 flag_to_carry(opts, FLAG_X);
pavone@582 1433 if (inst->op == M68K_ABCD) {
pavone@612 1434 adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@686 1435 } else {
pavone@612 1436 sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@686 1437 }
pavone@612 1438 cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@833 1439 mov_ir(code, 0xA0, other_reg + (AH-RAX), SZ_B);
pavone@612 1440 code_ptr no_adjust = code->cur+1;
pavone@612 1441 //add correction factor if necessary
pavone@612 1442 jcc(code, CC_B, no_adjust);
pavone@833 1443 mov_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@833 1444 mov_ir(code, inst->op == M68K_ABCD ? 0x9A : 0xA6, other_reg + (AH-RAX), SZ_B);
pavone@833 1445 code_ptr after_adjust = code->cur+1;
pavone@833 1446 jmp(code, after_adjust);
pavone@833 1447
pavone@833 1448 *no_adjust = code->cur - (no_adjust+1);
pavone@833 1449 xor_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@833 1450 *after_adjust = code->cur - (after_adjust+1);
pavone@833 1451
pavone@833 1452 //do op on full byte
pavone@833 1453 flag_to_carry(opts, FLAG_X);
pavone@612 1454 if (inst->op == M68K_ABCD) {
pavone@833 1455 adc_rr(code, other_reg, opts->gen.scratch1, SZ_B);
pavone@612 1456 } else {
pavone@833 1457 sbb_rr(code, other_reg, opts->gen.scratch1, SZ_B);
pavone@686 1458 }
pavone@612 1459 set_flag(opts, 0, FLAG_C);
pavone@833 1460 //determine if we need a correction on the upper nibble
pavone@612 1461 code_ptr def_adjust = code->cur+1;
pavone@612 1462 jcc(code, CC_C, def_adjust);
pavone@833 1463 cmp_rr(code, other_reg + (AH-RAX), opts->gen.scratch1, SZ_B);
pavone@612 1464 no_adjust = code->cur+1;
pavone@612 1465 jcc(code, CC_B, no_adjust);
pavone@612 1466 *def_adjust = code->cur - (def_adjust + 1);
pavone@612 1467 set_flag(opts, 1, FLAG_C);
pavone@833 1468 or_ir(code, 0x60, opts->gen.scratch1 + (AH-RAX), SZ_B);
pavone@833 1469 *no_adjust = code->cur - (no_adjust+1);
pavone@612 1470 if (inst->op == M68K_ABCD) {
pavone@833 1471 add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
pavone@612 1472 } else {
pavone@833 1473 sub_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
pavone@686 1474 }
pavone@833 1475 code_ptr no_ensure_carry = code->cur+1;
pavone@833 1476 jcc(code, CC_NC, no_ensure_carry);
pavone@833 1477 set_flag(opts, 1, FLAG_C);
pavone@833 1478 *no_ensure_carry = code->cur - (no_ensure_carry+1);
pavone@833 1479 //restore RAX if necessary
pavone@833 1480 if (opts->gen.scratch2 > RBX) {
pavone@833 1481 mov_rr(code, opts->gen.scratch2, RAX, SZ_D);
pavone@833 1482 }
pavone@833 1483 //V flag is set based on the result of the addition/subtraction of the
pavone@612 1484 //result and the correction factor
pavone@612 1485 set_flag_cond(opts, CC_O, FLAG_V);
pavone@833 1486
pavone@612 1487 flag_to_flag(opts, FLAG_C, FLAG_X);
pavone@653 1488
pavone@582 1489 cmp_ir(code, 0, opts->gen.scratch1, SZ_B);
pavone@612 1490 set_flag_cond(opts, CC_S, FLAG_N);
pavone@733 1491 code_ptr no_setz = code->cur+1;
pavone@733 1492 jcc(code, CC_Z, no_setz);
pavone@582 1493 set_flag(opts, 0, FLAG_Z);
pavone@733 1494 *no_setz = code->cur - (no_setz + 1);
pavone@582 1495 if (dst_op->base != opts->gen.scratch1) {
pavone@582 1496 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1497 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B);
pavone@582 1498 } else {
pavone@582 1499 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B);
pavone@582 1500 }
pavone@686 1501 }
pavone@582 1502 m68k_save_result(inst, opts);
pavone@686 1503 }
pavone@582 1504
pavone@582 1505 void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1506 {
pavone@582 1507 translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp);
pavone@686 1508 }
pavone@582 1509
pavone@582 1510 void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1511 {
pavone@582 1512 translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL);
pavone@686 1513 }
pavone@582 1514
pavone@582 1515 void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1516 {
pavone@582 1517 translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp);
pavone@582 1518 }
pavone@582 1519
pavone@582 1520 void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1521 {
pavone@582 1522 code_info *code = &opts->gen.code;
pavone@582 1523 cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : (
pavone@558 1524 inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
pavone@686 1525 );
pavone@582 1526 if (src_op->mode == MODE_IMMED) {
pavone@686 1527 if (inst->extra.size == OPSIZE_BYTE) {
pavone@582 1528 src_op->disp &= 0x7;
pavone@686 1529 }
pavone@582 1530 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1531 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
pavone@686 1532 } else {
pavone@582 1533 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1534 }
pavone@686 1535 } else {
pavone@582 1536 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)) {
pavone@582 1537 if (dst_op->base == opts->gen.scratch1) {
pavone@582 1538 push_r(code, opts->gen.scratch2);
pavone@582 1539 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1540 mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
pavone@582 1541 } else {
pavone@582 1542 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
pavone@582 1543 }
pavone@582 1544 src_op->base = opts->gen.scratch2;
pavone@194 1545 } else {
pavone@582 1546 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1547 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
pavone@582 1548 } else {
pavone@582 1549 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
pavone@582 1550 }
pavone@582 1551 src_op->base = opts->gen.scratch1;
pavone@558 1552 }
pavone@194 1553 }
pavone@558 1554 uint8_t size = inst->extra.size;
pavone@582 1555 if (dst_op->mode == MODE_REG_DISPLACE8) {
pavone@582 1556 if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) {
pavone@582 1557 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1558 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D);
pavone@686 1559 } else {
pavone@582 1560 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
pavone@582 1561 src_op->mode = MODE_REG_DIRECT;
pavone@686 1562 }
pavone@682 1563 src_op->base = opts->gen.scratch1;
pavone@686 1564 }
pavone@686 1565 //b### with register destination is modulo 32
pavone@686 1566 //x86 with a memory destination isn't modulo anything
pavone@686 1567 //so use an and here to force the value to be modulo 32
pavone@682 1568 and_ir(code, 31, opts->gen.scratch1, SZ_D);
pavone@686 1569 } else if(inst->dst.addr_mode != MODE_REG) {
pavone@686 1570 //b### with memory destination is modulo 8
pavone@686 1571 //x86-64 doesn't support 8-bit bit operations
pavone@686 1572 //so we fake it by forcing the bit number to be modulo 8
pavone@682 1573 and_ir(code, 7, src_op->base, SZ_D);
pavone@686 1574 size = SZ_D;
pavone@686 1575 }
pavone@976 1576 if (dst_op->mode == MODE_IMMED) {
pavone@976 1577 dst_op->base = src_op->base == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
pavone@976 1578 mov_ir(code, dst_op->disp, dst_op->base, SZ_B);
pavone@976 1579 dst_op->mode = MODE_REG_DIRECT;
pavone@976 1580 }
pavone@582 1581 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1582 op_rr(code, inst, src_op->base, dst_op->base, size);
pavone@686 1583 } else {
pavone@582 1584 op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
pavone@686 1585 }
pavone@582 1586 if (src_op->base == opts->gen.scratch2) {
pavone@582 1587 pop_r(code, opts->gen.scratch2);
pavone@194 1588 }
pavone@686 1589 }
pavone@686 1590 //x86 sets the carry flag to the value of the bit tested
pavone@686 1591 //68K sets the zero flag to the complement of the bit tested
pavone@582 1592 set_flag_cond(opts, CC_NC, FLAG_Z);
pavone@686 1593 if (inst->op != M68K_BTST) {
pavone@567 1594 m68k_save_result(inst, opts);
pavone@686 1595 }
pavone@582 1596 }
pavone@582 1597
pavone@582 1598 void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@558 1599 {
pavone@582 1600 code_info *code = &opts->gen.code;
pavone@582 1601 cycles(&opts->gen, 6);
pavone@582 1602 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1603 cmp_ir(code, 0, dst_op->base, inst->extra.size);
pavone@686 1604 } else {
pavone@582 1605 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1606 }
pavone@686 1607 uint32_t isize;
pavone@686 1608 switch(inst->src.addr_mode)
pavone@686 1609 {
pavone@686 1610 case MODE_AREG_DISPLACE:
pavone@686 1611 case MODE_AREG_INDEX_DISP8:
pavone@686 1612 case MODE_ABSOLUTE_SHORT:
pavone@686 1613 case MODE_PC_INDEX_DISP8:
pavone@686 1614 case MODE_PC_DISPLACE:
pavone@686 1615 case MODE_IMMEDIATE:
pavone@686 1616 isize = 4;
pavone@686 1617 break;
pavone@686 1618 case MODE_ABSOLUTE:
pavone@686 1619 isize = 6;
pavone@686 1620 break;
pavone@686 1621 default:
pavone@686 1622 isize = 2;
pavone@686 1623 }
pavone@582 1624 //make sure we won't start a new chunk in the middle of these branches
pavone@582 1625 check_alloc_code(code, MAX_INST_LEN * 11);
pavone@582 1626 code_ptr passed = code->cur + 1;
pavone@582 1627 jcc(code, CC_GE, code->cur + 2);
pavone@582 1628 set_flag(opts, 1, FLAG_N);
pavone@582 1629 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
pavone@582 1630 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
pavone@582 1631 jmp(code, opts->trap);
pavone@582 1632 *passed = code->cur - (passed+1);
pavone@582 1633 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1634 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1635 cmp_rr(code, src_op->base, dst_op->base, inst->extra.size);
pavone@582 1636 } else if(src_op->mode == MODE_REG_DISPLACE8) {
pavone@582 1637 cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size);
pavone@686 1638 } else {
pavone@582 1639 cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size);
pavone@686 1640 }
pavone@582 1641 } else if(dst_op->mode == MODE_REG_DISPLACE8) {
pavone@582 1642 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1643 cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1644 } else {
pavone@582 1645 cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
pavone@73 1646 }
pavone@686 1647 }
pavone@582 1648 passed = code->cur + 1;
pavone@582 1649 jcc(code, CC_LE, code->cur + 2);
pavone@582 1650 set_flag(opts, 0, FLAG_N);
pavone@582 1651 mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
pavone@582 1652 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
pavone@582 1653 jmp(code, opts->trap);
pavone@582 1654 *passed = code->cur - (passed+1);
pavone@582 1655 cycles(&opts->gen, 4);
pavone@686 1656 }
pavone@582 1657
pavone@582 1658 void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@686 1659 {
pavone@582 1660 code_info *code = &opts->gen.code;
pavone@582 1661 check_alloc_code(code, MAX_NATIVE_SIZE);
pavone@686 1662 //TODO: cycle exact division
pavone@582 1663 cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140);
pavone@582 1664 set_flag(opts, 0, FLAG_C);
pavone@582 1665 push_r(code, RDX);
pavone@582 1666 push_r(code, RAX);
pavone@894 1667 uint32_t tmp_stack_off = code->stack_off;
pavone@582 1668 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1669 mov_rr(code, dst_op->base, RAX, SZ_D);
pavone@686 1670 } else {
pavone@582 1671 mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D);
pavone@686 1672 }
pavone@582 1673 if (src_op->mode == MODE_IMMED) {
pavone@582 1674 mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D);
pavone@582 1675 } else if (src_op->mode == MODE_REG_DIRECT) {
pavone@686 1676 if (inst->op == M68K_DIVS) {
pavone@582 1677 movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D);
pavone@686 1678 } else {
pavone@582 1679 movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D);
pavone@686 1680 }
pavone@682 1681 } else if (src_op->mode == MODE_REG_DISPLACE8) {
pavone@686 1682 if (inst->op == M68K_DIVS) {
pavone@682 1683 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
pavone@686 1684 } else {
pavone@682 1685 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
pavone@73 1686 }
pavone@686 1687 }
pavone@611 1688 uint32_t isize = 2;
pavone@611 1689 switch(inst->src.addr_mode)
pavone@611 1690 {
pavone@611 1691 case MODE_AREG_DISPLACE:
pavone@611 1692 case MODE_AREG_INDEX_DISP8:
pavone@611 1693 case MODE_ABSOLUTE_SHORT:
pavone@611 1694 case MODE_PC_INDEX_DISP8:
pavone@611 1695 case MODE_IMMEDIATE:
pavone@653 1696 isize = 4;
pavone@611 1697 break;
pavone@611 1698 case MODE_ABSOLUTE:
pavone@611 1699 isize = 6;
pavone@611 1700 break;
pavone@611 1701 }
pavone@582 1702 cmp_ir(code, 0, opts->gen.scratch2, SZ_D);
pavone@582 1703 check_alloc_code(code, 6*MAX_INST_LEN);
pavone@582 1704 code_ptr not_zero = code->cur + 1;
pavone@582 1705 jcc(code, CC_NZ, code->cur + 2);
pavone@582 1706 pop_r(code, RAX);
pavone@582 1707 pop_r(code, RDX);
pavone@582 1708 mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D);
pavone@611 1709 mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
pavone@582 1710 jmp(code, opts->trap);
pavone@894 1711
pavone@894 1712 code->stack_off = tmp_stack_off;
pavone@582 1713 *not_zero = code->cur - (not_zero+1);
pavone@686 1714 if (inst->op == M68K_DIVS) {
pavone@582 1715 cdq(code);
pavone@686 1716 } else {
pavone@582 1717 xor_rr(code, RDX, RDX, SZ_D);
pavone@686 1718 }
pavone@686 1719 if (inst->op == M68K_DIVS) {
pavone@582 1720 idiv_r(code, opts->gen.scratch2, SZ_D);
pavone@686 1721 } else {
pavone@582 1722 div_r(code, opts->gen.scratch2, SZ_D);
pavone@686 1723 }
pavone@582 1724 code_ptr skip_sec_check, norm_off;
pavone@686 1725 if (inst->op == M68K_DIVS) {
pavone@582 1726 cmp_ir(code, 0x8000, RAX, SZ_D);
pavone@582 1727 skip_sec_check = code->cur + 1;
pavone@582 1728 jcc(code, CC_GE, code->cur + 2);
pavone@582 1729 cmp_ir(code, -0x8000, RAX, SZ_D);
pavone@582 1730 norm_off = code->cur + 1;
pavone@582 1731 jcc(code, CC_L, code->cur + 2);
pavone@686 1732 } else {
pavone@582 1733 cmp_ir(code, 0x10000, RAX, SZ_D);
pavone@582 1734 norm_off = code->cur + 1;
pavone@582 1735 jcc(code, CC_NC, code->cur + 2);
pavone@686 1736 }
pavone@582 1737 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1738 mov_rr(code, RDX, dst_op->base, SZ_W);
pavone@582 1739 shl_ir(code, 16, dst_op->base, SZ_D);
pavone@582 1740 mov_rr(code, RAX, dst_op->base, SZ_W);
pavone@686 1741 } else {
pavone@582 1742 mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W);
pavone@582 1743 shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D);
pavone@582 1744 mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W);
pavone@686 1745 }
pavone@582 1746 cmp_ir(code, 0, RAX, SZ_W);
pavone@582 1747 pop_r(code, RAX);
pavone@732 1748 if (dst_op->base == RDX) {
pavone@732 1749 update_flags(opts, V0|Z|N);
pavone@732 1750 add_ir(code, sizeof(void *), RSP, SZ_D);
pavone@732 1751 } else {
pavone@732 1752 pop_r(code, RDX);
pavone@732 1753 update_flags(opts, V0|Z|N);
pavone@732 1754 }
pavone@582 1755 code_ptr end_off = code->cur + 1;
pavone@582 1756 jmp(code, code->cur + 2);
pavone@894 1757 code->stack_off = tmp_stack_off;
pavone@582 1758 *norm_off = code->cur - (norm_off + 1);
pavone@686 1759 if (inst->op == M68K_DIVS) {
pavone@582 1760 *skip_sec_check = code->cur - (skip_sec_check+1);
pavone@686 1761 }
pavone@582 1762 pop_r(code, RAX);
pavone@582 1763 pop_r(code, RDX);
pavone@582 1764 set_flag(opts, 1, FLAG_V);
pavone@582 1765 *end_off = code->cur - (end_off + 1);
pavone@686 1766 }
pavone@582 1767
pavone@582 1768 void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1769 {
pavone@582 1770 code_info *code = &opts->gen.code;
pavone@582 1771 cycles(&opts->gen, 6);
pavone@582 1772 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1773 mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
pavone@582 1774 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1775 mov_rr(code, src_op->base, dst_op->base, SZ_D);
pavone@582 1776 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
pavone@686 1777 } else {
pavone@582 1778 mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D);
pavone@582 1779 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
pavone@686 1780 }
pavone@686 1781 } else {
pavone@582 1782 mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
pavone@582 1783 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1784 mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D);
pavone@582 1785 mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
pavone@686 1786 } else {
pavone@582 1787 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
pavone@582 1788 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
pavone@582 1789 mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
pavone@73 1790 }
pavone@686 1791 }
pavone@686 1792 }
pavone@582 1793
pavone@582 1794 void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1795 {
pavone@582 1796 code_info *code = &opts->gen.code;
pavone@582 1797 cycles(&opts->gen, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter
pavone@582 1798 if (src_op->mode == MODE_IMMED) {
pavone@582 1799 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);
pavone@582 1800 } else if (src_op->mode == MODE_REG_DIRECT) {
pavone@686 1801 if (inst->op == M68K_MULS) {
pavone@582 1802 movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
pavone@686 1803 } else {
pavone@682 1804 movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
pavone@686 1805 }
pavone@686 1806 } else {
pavone@686 1807 if (inst->op == M68K_MULS) {
pavone@686 1808 movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
pavone@61 1809 } else {
pavone@682 1810 movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
pavone@128 1811 }
pavone@686 1812 }
pavone@582 1813 uint8_t dst_reg;
pavone@582 1814 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1815 dst_reg = dst_op->base;
pavone@686 1816 if (inst->op == M68K_MULS) {
pavone@582 1817 movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
pavone@686 1818 } else {
pavone@682 1819 movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
pavone@686 1820 }
pavone@686 1821 } else {
pavone@686 1822 dst_reg = opts->gen.scratch2;
pavone@686 1823 if (inst->op == M68K_MULS) {
pavone@686 1824 movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
pavone@226 1825 } else {
pavone@682 1826 movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
pavone@226 1827 }
pavone@686 1828 }
pavone@582 1829 imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D);
pavone@582 1830 if (dst_op->mode == MODE_REG_DISPLACE8) {
pavone@582 1831 mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D);
pavone@686 1832 }
pavone@582 1833 cmp_ir(code, 0, dst_reg, SZ_D);
pavone@582 1834 update_flags(opts, N|Z|V0|C0);
pavone@686 1835 }
pavone@447 1836
pavone@582 1837 void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1838 {
pavone@582 1839 code_info *code = &opts->gen.code;
pavone@582 1840 cycles(&opts->gen, BUS);
pavone@582 1841 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1842 if (dst_op->base == opts->gen.scratch1) {
pavone@582 1843 push_r(code, opts->gen.scratch2);
pavone@582 1844 xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size);
pavone@582 1845 flag_to_carry(opts, FLAG_X);
pavone@582 1846 sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size);
pavone@582 1847 mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size);
pavone@582 1848 pop_r(code, opts->gen.scratch2);
pavone@173 1849 } else {
pavone@567 1850 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
pavone@567 1851 flag_to_carry(opts, FLAG_X);
pavone@582 1852 sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size);
pavone@582 1853 mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size);
pavone@173 1854 }
pavone@686 1855 } else {
pavone@582 1856 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
pavone@582 1857 flag_to_carry(opts, FLAG_X);
pavone@582 1858 sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size);
pavone@582 1859 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1860 }
pavone@582 1861 set_flag_cond(opts, CC_C, FLAG_C);
pavone@582 1862 code_ptr after_flag_set = code->cur + 1;
pavone@582 1863 jcc(code, CC_Z, code->cur + 2);
pavone@582 1864 set_flag(opts, 0, FLAG_Z);
pavone@582 1865 *after_flag_set = code->cur - (after_flag_set+1);
pavone@582 1866 set_flag_cond(opts, CC_S, FLAG_N);
pavone@582 1867 set_flag_cond(opts, CC_O, FLAG_V);
pavone@686 1868 if (opts->flag_regs[FLAG_C] >= 0) {
pavone@582 1869 flag_to_flag(opts, FLAG_C, FLAG_X);
pavone@686 1870 } else {
pavone@582 1871 set_flag_cond(opts, CC_C, FLAG_X);
pavone@686 1872 }
pavone@582 1873 m68k_save_result(inst, opts);
pavone@686 1874 }
pavone@582 1875
pavone@582 1876 void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 1877 {
pavone@582 1878 code_info *code = &opts->gen.code;
pavone@582 1879 int32_t init_flags = C|V0;
pavone@686 1880 if (inst->src.addr_mode == MODE_UNUSED) {
pavone@582 1881 cycles(&opts->gen, BUS);
pavone@686 1882 //Memory rotate
pavone@582 1883 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
pavone@582 1884 flag_to_carry(opts, FLAG_X);
pavone@582 1885 init_flags |= X;
pavone@546 1886 }
pavone@582 1887 op_ir(code, inst, 1, dst_op->base, inst->extra.size);
pavone@582 1888 update_flags(opts, init_flags);
pavone@582 1889 cmp_ir(code, 0, dst_op->base, inst->extra.size);
pavone@582 1890 update_flags(opts, Z|N);
pavone@567 1891 m68k_save_result(inst, opts);
pavone@686 1892 } else {
pavone@582 1893 if (src_op->mode == MODE_IMMED) {
pavone@582 1894 cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2);
pavone@577 1895 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
pavone@577 1896 flag_to_carry(opts, FLAG_X);
pavone@577 1897 init_flags |= X;
pavone@122 1898 }
pavone@582 1899 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1900 op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
pavone@686 1901 } else {
pavone@686 1902 op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1903 }
pavone@686 1904 update_flags(opts, init_flags);
pavone@682 1905 } else {
pavone@582 1906 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 1907 if (src_op->base != opts->gen.scratch1) {
pavone@582 1908 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
pavone@686 1909 }
pavone@122 1910 } else {
pavone@582 1911 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
pavone@686 1912 }
pavone@582 1913 and_ir(code, 63, opts->gen.scratch1, SZ_D);
pavone@582 1914 code_ptr zero_off = code->cur + 1;
pavone@582 1915 jcc(code, CC_Z, code->cur + 2);
pavone@667 1916 //add 2 cycles for every bit shifted
pavone@667 1917 mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
pavone@667 1918 imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
pavone@667 1919 add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
pavone@582 1920 cmp_ir(code, 32, opts->gen.scratch1, SZ_B);
pavone@582 1921 code_ptr norm_off = code->cur + 1;
pavone@582 1922 jcc(code, CC_L, code->cur + 2);
pavone@582 1923 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
pavone@582 1924 flag_to_carry(opts, FLAG_X);
pavone@582 1925 init_flags |= X;
pavone@686 1926 } else {
pavone@582 1927 sub_ir(code, 32, opts->gen.scratch1, SZ_B);
pavone@686 1928 }
pavone@582 1929 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1930 op_ir(code, inst, 31, dst_op->base, inst->extra.size);
pavone@582 1931 op_ir(code, inst, 1, dst_op->base, inst->extra.size);
pavone@686 1932 } else {
pavone@582 1933 op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size);
pavone@582 1934 op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1935 }
pavone@577 1936
pavone@582 1937 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
pavone@582 1938 set_flag_cond(opts, CC_C, FLAG_X);
pavone@582 1939 sub_ir(code, 32, opts->gen.scratch1, SZ_B);
pavone@582 1940 *norm_off = code->cur - (norm_off+1);
pavone@582 1941 flag_to_carry(opts, FLAG_X);
pavone@686 1942 } else {
pavone@582 1943 *norm_off = code->cur - (norm_off+1);
pavone@686 1944 }
pavone@582 1945 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1946 op_r(code, inst, dst_op->base, inst->extra.size);
pavone@686 1947 } else {
pavone@582 1948 op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1949 }
pavone@582 1950 update_flags(opts, init_flags);
pavone@582 1951 code_ptr end_off = code->cur + 1;
pavone@582 1952 jmp(code, code->cur + 2);
pavone@582 1953 *zero_off = code->cur - (zero_off+1);
pavone@582 1954 if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
pavone@582 1955 //Carry flag is set to X flag when count is 0, this is different from ROR/ROL
pavone@582 1956 flag_to_flag(opts, FLAG_X, FLAG_C);
pavone@686 1957 } else {
pavone@582 1958 set_flag(opts, 0, FLAG_C);
pavone@686 1959 }
pavone@582 1960 *end_off = code->cur - (end_off+1);
pavone@686 1961 }
pavone@582 1962 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 1963 cmp_ir(code, 0, dst_op->base, inst->extra.size);
pavone@686 1964 } else {
pavone@582 1965 cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
pavone@686 1966 }
pavone@682 1967 update_flags(opts, Z|N);
pavone@686 1968 }
pavone@686 1969 }
pavone@582 1970
pavone@582 1971 #define BIT_SUPERVISOR 5
pavone@582 1972
pavone@990 1973 void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst)
pavone@990 1974 {
pavone@990 1975 code_info *code = &opts->gen.code;
pavone@990 1976 //check supervisor bit in SR and trap if not in supervisor mode
pavone@990 1977 bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@990 1978 code_ptr in_sup_mode = code->cur + 1;
pavone@990 1979 jcc(code, CC_C, code->cur + 2);
pavone@990 1980
pavone@990 1981 ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2);
pavone@990 1982 ldi_native(opts, inst->address, opts->gen.scratch1);
pavone@990 1983 jmp(code, opts->trap);
pavone@990 1984
pavone@990 1985 *in_sup_mode = code->cur - (in_sup_mode + 1);
pavone@990 1986 }
pavone@990 1987
pavone@584 1988 void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst)
pavone@582 1989 {
pavone@582 1990 code_info *code = &opts->gen.code;
pavone@990 1991 if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
pavone@990 1992 m68k_trap_if_not_supervisor(opts, inst);
pavone@990 1993 }
pavone@582 1994 cycles(&opts->gen, 20);
pavone@582 1995 uint32_t flag_mask = 0;
pavone@584 1996 uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1;
pavone@584 1997 for (int i = 0; i < 5; i++)
pavone@584 1998 {
pavone@757 1999 if ((base_flag == X0) ^ ((inst->src.params.immed & 1 << i) > 0))
pavone@584 2000 {
pavone@584 2001 flag_mask |= base_flag << ((4 - i) * 3);
pavone@686 2002 }
pavone@686 2003 }
pavone@582 2004 update_flags(opts, flag_mask);
pavone@584 2005 if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
pavone@584 2006 if (inst->op == M68K_ANDI_SR) {
pavone@584 2007 and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@686 2008 } else {
pavone@584 2009 or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@686 2010 }
pavone@605 2011 if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) {
pavone@446 2012 //leave supervisor mode
pavone@574 2013 swap_ssp_usp(opts);
pavone@686 2014 }
pavone@584 2015 if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700)
pavone@584 2016 || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) {
pavone@846 2017 if (inst->op == M68K_ANDI_SR) {
pavone@846 2018 //set int pending flag in case we trigger an interrupt as a result of the mask change
pavone@996 2019 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@846 2020 }
pavone@582 2021 call(code, opts->do_sync);
pavone@686 2022 }
pavone@686 2023 }
pavone@686 2024 }
pavone@582 2025
pavone@582 2026 void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst)
pavone@582 2027 {
pavone@582 2028 code_info *code = &opts->gen.code;
pavone@990 2029 if (inst->op == M68K_EORI_SR) {
pavone@990 2030 m68k_trap_if_not_supervisor(opts, inst);
pavone@990 2031 }
pavone@582 2032 cycles(&opts->gen, 20);
pavone@582 2033 if (inst->src.params.immed & 0x1) {
pavone@582 2034 xor_flag(opts, 1, FLAG_C);
pavone@686 2035 }
pavone@582 2036 if (inst->src.params.immed & 0x2) {
pavone@582 2037 xor_flag(opts, 1, FLAG_V);
pavone@686 2038 }
pavone@582 2039 if (inst->src.params.immed & 0x4) {
pavone@582 2040 xor_flag(opts, 1, FLAG_Z);
pavone@686 2041 }
pavone@582 2042 if (inst->src.params.immed & 0x8) {
pavone@582 2043 xor_flag(opts, 1, FLAG_N);
pavone@686 2044 }
pavone@582 2045 if (inst->src.params.immed & 0x10) {
pavone@582 2046 xor_flag(opts, 1, FLAG_X);
pavone@686 2047 }
pavone@846 2048 if (inst->op == M68K_EORI_SR) {
pavone@582 2049 xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@582 2050 if (inst->src.params.immed & 0x700) {
pavone@846 2051 //set int pending flag in case we trigger an interrupt as a result of the mask change
pavone@996 2052 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@582 2053 call(code, opts->do_sync);
pavone@686 2054 }
pavone@686 2055 }
pavone@686 2056 }
pavone@582 2057
pavone@586 2058 void set_all_flags(m68k_options *opts, uint8_t flags)
pavone@586 2059 {
pavone@586 2060 uint32_t flag_mask = flags & 0x10 ? X1 : X0;
pavone@586 2061 flag_mask |= flags & 0x8 ? N1 : N0;
pavone@586 2062 flag_mask |= flags & 0x4 ? Z1 : Z0;
pavone@586 2063 flag_mask |= flags & 0x2 ? V1 : V0;
pavone@586 2064 flag_mask |= flags & 0x1 ? C1 : C0;
pavone@586 2065 update_flags(opts, flag_mask);
pavone@686 2066 }
pavone@586 2067
pavone@582 2068 void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 2069 {
pavone@582 2070 code_info *code = &opts->gen.code;
pavone@990 2071 if (inst->op == M68K_MOVE_SR) {
pavone@990 2072 m68k_trap_if_not_supervisor(opts, inst);
pavone@990 2073 }
pavone@582 2074 if (src_op->mode == MODE_IMMED) {
pavone@586 2075 set_all_flags(opts, src_op->disp);
pavone@582 2076 if (inst->op == M68K_MOVE_SR) {
pavone@582 2077 mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@582 2078 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
pavone@582 2079 //leave supervisor mode
pavone@585 2080 swap_ssp_usp(opts);
pavone@686 2081 }
pavone@846 2082 if (((src_op->disp >> 8) & 7) < 7) {
pavone@846 2083 //set int pending flag in case we trigger an interrupt as a result of the mask change
pavone@996 2084 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@846 2085 }
pavone@686 2086 call(code, opts->do_sync);
pavone@682 2087 }
pavone@582 2088 cycles(&opts->gen, 12);
pavone@686 2089 } else {
pavone@582 2090 if (src_op->base != opts->gen.scratch1) {
pavone@582 2091 if (src_op->mode == MODE_REG_DIRECT) {
pavone@582 2092 mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W);
pavone@582 2093 } else {
pavone@582 2094 mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W);
pavone@582 2095 }
pavone@582 2096 }
pavone@698 2097 if (inst->op == M68K_MOVE_SR) {
pavone@698 2098 call(code, opts->set_sr);
pavone@698 2099 call(code, opts->do_sync);
pavone@698 2100 } else {
pavone@698 2101 call(code, opts->set_ccr);
pavone@698 2102 }
pavone@582 2103 cycles(&opts->gen, 12);
pavone@686 2104 }
pavone@686 2105 }
pavone@582 2106
pavone@582 2107 void translate_m68k_stop(m68k_options *opts, m68kinst *inst)
pavone@582 2108 {
pavone@990 2109 m68k_trap_if_not_supervisor(opts, inst);
pavone@686 2110 //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
pavone@686 2111 //possibly even 12 since that's how long MOVE to SR takes
pavone@582 2112 //On further thought prefetch + the fact that this stops the CPU may make
pavone@582 2113 //Motorola's accounting make sense here
pavone@582 2114 code_info *code = &opts->gen.code;
pavone@582 2115 cycles(&opts->gen, BUS*2);
pavone@586 2116 set_all_flags(opts, inst->src.params.immed);
pavone@582 2117 mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@686 2118 if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
pavone@686 2119 //leave supervisor mode
pavone@582 2120 swap_ssp_usp(opts);
pavone@686 2121 }
pavone@582 2122 code_ptr loop_top = code->cur;
pavone@985 2123 call(code, opts->do_sync);
pavone@985 2124 cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
pavone@985 2125 code_ptr normal_cycle_up = code->cur + 1;
pavone@985 2126 jcc(code, CC_A, code->cur + 2);
pavone@985 2127 cycles(&opts->gen, BUS);
pavone@985 2128 code_ptr after_cycle_up = code->cur + 1;
pavone@985 2129 jmp(code, code->cur + 2);
pavone@985 2130 *normal_cycle_up = code->cur - (normal_cycle_up + 1);
pavone@985 2131 mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
pavone@985 2132 *after_cycle_up = code->cur - (after_cycle_up+1);
pavone@985 2133 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
pavone@582 2134 jcc(code, CC_C, loop_top);
pavone@985 2135 //set int pending flag so interrupt fires immediately after stop is done
pavone@996 2136 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@686 2137 }
pavone@582 2138
pavone@839 2139 void translate_m68k_trapv(m68k_options *opts, m68kinst *inst)
pavone@839 2140 {
pavone@839 2141 code_info *code = &opts->gen.code;
pavone@839 2142 cycles(&opts->gen, BUS);
pavone@839 2143 flag_to_carry(opts, FLAG_V);
pavone@839 2144 code_ptr no_trap = code->cur + 1;
pavone@839 2145 jcc(code, CC_NC, no_trap);
pavone@839 2146 ldi_native(opts, VECTOR_TRAPV, opts->gen.scratch2);
pavone@839 2147 ldi_native(opts, inst->address+2, opts->gen.scratch1);
pavone@839 2148 jmp(code, opts->trap);
pavone@839 2149 *no_trap = code->cur - (no_trap + 1);
pavone@839 2150 }
pavone@839 2151
pavone@987 2152 void translate_m68k_odd(m68k_options *opts, m68kinst *inst)
pavone@987 2153 {
pavone@987 2154 code_info *code = &opts->gen.code;
pavone@987 2155 //swap USP and SSP if not already in supervisor mode
pavone@987 2156 check_user_mode_swap_ssp_usp(opts);
pavone@987 2157 //save PC
pavone@987 2158 subi_areg(opts, 4, 7);
pavone@987 2159 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2160 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
pavone@987 2161 call(code, opts->write_32_lowfirst);
pavone@987 2162 //save status register
pavone@987 2163 subi_areg(opts, 2, 7);
pavone@987 2164 call(code, opts->get_sr);
pavone@987 2165 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2166 call(code, opts->write_16);
pavone@987 2167 //save instruction register
pavone@987 2168 subi_areg(opts, 2, 7);
pavone@989 2169 //calculate IR
pavone@989 2170 push_r(code, opts->gen.context_reg);
pavone@989 2171 call(code, opts->gen.save_context);
pavone@989 2172 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
pavone@989 2173 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
pavone@989 2174 pop_r(code, opts->gen.context_reg);
pavone@989 2175 push_r(code, RAX); //save it for use in the "info" word
pavone@989 2176 call(code, opts->gen.load_context);
pavone@989 2177 //write it to the stack
pavone@987 2178 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2179 call(code, opts->write_16);
pavone@987 2180 //save access address
pavone@987 2181 subi_areg(opts, 4, 7);
pavone@987 2182 mov_ir(code, inst->address, opts->gen.scratch1, SZ_D);
pavone@987 2183 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2184 call(code, opts->write_32_lowfirst);
pavone@987 2185 //save FC, I/N and R/W word'
pavone@987 2186 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
pavone@987 2187 //FC3 is basically the same as the supervisor bit
pavone@987 2188 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
pavone@987 2189 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
pavone@987 2190 and_ir(code, 4, opts->gen.scratch1, SZ_B);
pavone@987 2191 //set FC1 to one to indicate instruction fetch, and R/W to indicate read
pavone@987 2192 or_ir(code, 0x12, opts->gen.scratch1, SZ_B);
pavone@989 2193 //set undefined bits to IR value
pavone@989 2194 pop_r(code, opts->gen.scratch2);
pavone@989 2195 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
pavone@989 2196 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
pavone@987 2197 subi_areg(opts, 2, 7);
pavone@987 2198 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2199 call(code, opts->write_16);
pavone@987 2200 //set supervisor bit
pavone@987 2201 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@987 2202 //load vector address
pavone@987 2203 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
pavone@987 2204 call(code, opts->read_32);
pavone@987 2205 call(code, opts->native_addr_and_sync);
pavone@987 2206 cycles(&opts->gen, 18);
pavone@987 2207 jmp_r(code, opts->gen.scratch1);
pavone@987 2208 }
pavone@987 2209
pavone@582 2210 void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
pavone@582 2211 {
pavone@582 2212 code_info *code = &opts->gen.code;
pavone@582 2213 call(code, opts->get_sr);
pavone@582 2214 if (dst_op->mode == MODE_REG_DIRECT) {
pavone@582 2215 mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W);
pavone@686 2216 } else {
pavone@582 2217 mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W);
pavone@686 2218 }
pavone@582 2219 m68k_save_result(inst, opts);
pavone@582 2220 }
pavone@582 2221
pavone@570 2222 void translate_out_of_bounds(code_info *code)
pavone@319 2223 {
pavone@570 2224 xor_rr(code, RDI, RDI, SZ_D);
pavone@656 2225 call_args(code, (code_ptr)exit, 1, RDI);
pavone@319 2226 }
pavone@319 2227
pavone@981 2228 void m68k_set_last_prefetch(m68k_options *opts, uint32_t address)
pavone@981 2229 {
pavone@981 2230 mov_irdisp(&opts->gen.code, address, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), SZ_D);
pavone@981 2231 }
pavone@981 2232
pavone@587 2233 void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst)
pavone@193 2234 {
pavone@587 2235 if (next_inst == old_end && next_inst - code->cur < 2) {
pavone@587 2236 while (code->cur < old_end) {
pavone@587 2237 *(code->cur++) = 0x90; //NOP
pavone@686 2238 }
pavone@686 2239 } else {
pavone@587 2240 jmp(code, next_inst);
pavone@193 2241 }
pavone@193 2242 }
pavone@193 2243
pavone@193 2244 m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context)
pavone@193 2245 {
pavone@985 2246 m68k_options * options = context->options;
pavone@985 2247 //TODO: Modify gen_mem_fun so that it passes the raw address instead of the masked one, then remove the OR below
pavone@985 2248 uint32_t inst_start = get_instruction_start(options, context->native_code_map, address | 0xE00000);
pavone@193 2249 if (inst_start) {
pavone@567 2250 code_info *code = &options->gen.code;
pavone@726 2251 code_ptr dst = get_native_address(context->options, inst_start);
pavone@902 2252 code_info orig = {dst, dst + 128, 0};
pavone@567 2253 mov_ir(&orig, inst_start, options->gen.scratch2, SZ_D);
pavone@567 2254
pavone@543 2255 if (!options->retrans_stub) {
pavone@567 2256 options->retrans_stub = code->cur;
pavone@567 2257 call(code, options->gen.save_context);
pavone@567 2258 push_r(code, options->gen.context_reg);
pavone@656 2259 call_args(code,(code_ptr)m68k_retranslate_inst, 2, options->gen.scratch2, options->gen.context_reg);
pavone@567 2260 pop_r(code, options->gen.context_reg);
pavone@567 2261 mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
pavone@567 2262 call(code, options->gen.load_context);
pavone@567 2263 jmp_r(code, options->gen.scratch1);
pavone@686 2264 }
pavone@567 2265 jmp(&orig, options->retrans_stub);
pavone@193 2266 }
pavone@193 2267 return context;
pavone@193 2268 }
pavone@193 2269
pavone@558 2270 void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_handler)
pavone@184 2271 {
pavone@558 2272 static code_ptr bp_stub = NULL;
pavone@569 2273 m68k_options * opts = context->options;
pavone@567 2274 code_info native;
pavone@567 2275 native.cur = get_native_address_trans(context, address);
pavone@567 2276 native.last = native.cur + 128;
pavone@908 2277 native.stack_off = 0;
pavone@567 2278 code_ptr start_native = native.cur;
pavone@567 2279 mov_ir(&native, address, opts->gen.scratch1, SZ_D);
pavone@184 2280 if (!bp_stub) {
pavone@567 2281 code_info *code = &opts->gen.code;
pavone@654 2282 check_code_prologue(code);
pavone@567 2283 bp_stub = code->cur;
pavone@567 2284 call(&native, bp_stub);
pavone@447 2285
pavone@908 2286 uint32_t tmp_stack_off = code->stack_off;
pavone@184 2287 //Calculate length of prologue
pavone@567 2288 check_cycles_int(&opts->gen, address);
pavone@567 2289 int check_int_size = code->cur-bp_stub;
pavone@567 2290 code->cur = bp_stub;
pavone@908 2291 code->stack_off = tmp_stack_off;
pavone@447 2292
pavone@184 2293 //Save context and call breakpoint handler
pavone@567 2294 call(code, opts->gen.save_context);
pavone@567 2295 push_r(code, opts->gen.scratch1);
pavone@657 2296 call_args_abi(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1);
pavone@567 2297 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
pavone@184 2298 //Restore context
pavone@567 2299 call(code, opts->gen.load_context);
pavone@567 2300 pop_r(code, opts->gen.scratch1);
pavone@184 2301 //do prologue stuff
pavone@567 2302 cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
pavone@567 2303 code_ptr jmp_off = code->cur + 1;
pavone@567 2304 jcc(code, CC_NC, code->cur + 7);
pavone@567 2305 call(code, opts->gen.handle_cycle_limit_int);
pavone@567 2306 *jmp_off = code->cur - (jmp_off+1);
pavone@184 2307 //jump back to body of translated instruction
pavone@567 2308 pop_r(code, opts->gen.scratch1);
pavone@567 2309 add_ir(code, check_int_size - (native.cur-start_native), opts->gen.scratch1, SZ_PTR);
pavone@567 2310 jmp_r(code, opts->gen.scratch1);
pavone@908 2311 code->stack_off = tmp_stack_off;
pavone@184 2312 } else {
pavone@567 2313 call(&native, bp_stub);
pavone@184 2314 }
pavone@184 2315 }
pavone@184 2316
pavone@667 2317 void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider)
pavone@18 2318 {
pavone@440 2319 memset(opts, 0, sizeof(*opts));
pavone@653 2320 opts->gen.memmap = memmap;
pavone@653 2321 opts->gen.memmap_chunks = num_chunks;
pavone@589 2322 opts->gen.address_size = SZ_D;
pavone@589 2323 opts->gen.address_mask = 0xFFFFFF;
pavone@596 2324 opts->gen.byte_swap = 1;
pavone@589 2325 opts->gen.max_address = 0x1000000;
pavone@589 2326 opts->gen.bus_cycles = BUS;
pavone@667 2327 opts->gen.clock_divider = clock_divider;
pavone@589 2328 opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers);
pavone@589 2329 opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags);
pavone@620 2330 opts->gen.ram_flags_shift = 11;
pavone@18 2331 for (int i = 0; i < 8; i++)
pavone@567 2332 {
pavone@18 2333 opts->dregs[i] = opts->aregs[i] = -1;
pavone@567 2334 }
pavone@548 2335 #ifdef X86_64
pavone@18 2336 opts->dregs[0] = R10;
pavone@18 2337 opts->dregs[1] = R11;
pavone@18 2338 opts->dregs[2] = R12;
pavone@423 2339 opts->dregs[3] = R8;
pavone@18 2340 opts->aregs[0] = R13;
pavone@18 2341 opts->aregs[1] = R14;
pavone@423 2342 opts->aregs[2] = R9;
pavone@18 2343 opts->aregs[7] = R15;
pavone@539 2344
pavone@539 2345 opts->flag_regs[0] = -1;
pavone@539 2346 opts->flag_regs[1] = RBX;
pavone@539 2347 opts->flag_regs[2] = RDX;
pavone@539 2348 opts->flag_regs[3] = BH;
pavone@539 2349 opts->flag_regs[4] = DH;
pavone@567 2350
pavone@567 2351 opts->gen.scratch2 = RDI;
pavone@548 2352 #else
pavone@548 2353 opts->dregs[0] = RDX;
pavone@548 2354 opts->aregs[7] = RDI;
pavone@548 2355
pavone@548 2356 for (int i = 0; i < 5; i++)
pavone@567 2357 {
pavone@548 2358 opts->flag_regs[i] = -1;
pavone@567 2359 }
pavone@567 2360 opts->gen.scratch2 = RBX;
pavone@548 2361 #endif
pavone@567 2362 opts->gen.context_reg = RSI;
pavone@567 2363 opts->gen.cycles = RAX;
pavone@567 2364 opts->gen.limit = RBP;
pavone@567 2365 opts->gen.scratch1 = RCX;
pavone@987 2366 opts->gen.align_error_mask = 1;
pavone@548 2367
pavone@548 2368
pavone@558 2369 opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
pavone@558 2370 memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
pavone@558 2371 opts->gen.deferred = NULL;
pavone@690 2372
pavone@690 2373 uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&opts->gen) / 1024;
pavone@690 2374 opts->gen.ram_inst_sizes = malloc(inst_size_size);
pavone@690 2375 memset(opts->gen.ram_inst_sizes, 0, inst_size_size);
pavone@447 2376
pavone@567 2377 code_info *code = &opts->gen.code;
pavone@567 2378 init_code_info(code);
pavone@539 2379
pavone@567 2380 opts->gen.save_context = code->cur;
pavone@539 2381 for (int i = 0; i < 5; i++)
pavone@539 2382 if (opts->flag_regs[i] >= 0) {
pavone@567 2383 mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B);
pavone@539 2384 }
pavone@539 2385 for (int i = 0; i < 8; i++)
pavone@539 2386 {
pavone@539 2387 if (opts->dregs[i] >= 0) {
pavone@567 2388 mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D);
pavone@539 2389 }
pavone@539 2390 if (opts->aregs[i] >= 0) {
pavone@567 2391 mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D);
pavone@539 2392 }
pavone@539 2393 }
pavone@567 2394 mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
pavone@567 2395 retn(code);
pavone@539 2396
pavone@567 2397 opts->gen.load_context = code->cur;
pavone@539 2398 for (int i = 0; i < 5; i++)
pavone@690 2399 {
pavone@539 2400 if (opts->flag_regs[i] >= 0) {
pavone@567 2401 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B);
pavone@539 2402 }
pavone@690 2403 }
pavone@539 2404 for (int i = 0; i < 8; i++)
pavone@539 2405 {
pavone@539 2406 if (opts->dregs[i] >= 0) {
pavone@567 2407 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D);
pavone@539 2408 }
pavone@539 2409 if (opts->aregs[i] >= 0) {
pavone@567 2410 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D);
pavone@539 2411 }
pavone@539 2412 }
pavone@656 2413 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), opts->gen.cycles, SZ_D);
pavone@656 2414 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), opts->gen.limit, SZ_D);
pavone@567 2415 retn(code);
pavone@539 2416
pavone@567 2417 opts->start_context = (start_fun)code->cur;
pavone@665 2418 save_callee_save_regs(code);
pavone@550 2419 #ifdef X86_64
pavone@567 2420 if (opts->gen.scratch2 != RDI) {
pavone@567 2421 mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR);
pavone@548 2422 }
pavone@550 2423 #else
pavone@567 2424 mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D);
pavone@567 2425 mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D);
pavone@550 2426 #endif
pavone@567 2427 call(code, opts->gen.load_context);
pavone@567 2428 call_r(code, opts->gen.scratch2);
pavone@567 2429 call(code, opts->gen.save_context);
pavone@665 2430 restore_callee_save_regs(code);
pavone@567 2431 retn(code);
pavone@540 2432
pavone@567 2433 opts->native_addr = code->cur;
pavone@567 2434 call(code, opts->gen.save_context);
pavone@567 2435 push_r(code, opts->gen.context_reg);
pavone@656 2436 call_args(code, (code_ptr)get_native_address_trans, 2, opts->gen.context_reg, opts->gen.scratch1);
pavone@567 2437 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
pavone@567 2438 pop_r(code, opts->gen.context_reg);
pavone@567 2439 call(code, opts->gen.load_context);
pavone@567 2440 retn(code);
pavone@544 2441
pavone@567 2442 opts->native_addr_and_sync = code->cur;
pavone@567 2443 call(code, opts->gen.save_context);
pavone@567 2444 push_r(code, opts->gen.scratch1);
pavone@667 2445
pavone@656 2446 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
pavone@656 2447 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
pavone@567 2448 pop_r(code, RSI); //restore saved address from opts->gen.scratch1
pavone@567 2449 push_r(code, RAX); //save context pointer for later
pavone@656 2450 call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI);
pavone@567 2451 mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
pavone@567 2452 pop_r(code, opts->gen.context_reg);
pavone@567 2453 call(code, opts->gen.load_context);
pavone@567 2454 retn(code);
pavone@544 2455
pavone@567 2456 opts->gen.handle_cycle_limit = code->cur;
pavone@656 2457 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
pavone@567 2458 code_ptr skip_sync = code->cur + 1;
pavone@567 2459 jcc(code, CC_C, code->cur + 2);
pavone@567 2460 opts->do_sync = code->cur;
pavone@567 2461 push_r(code, opts->gen.scratch1);
pavone@567 2462 push_r(code, opts->gen.scratch2);
pavone@567 2463 call(code, opts->gen.save_context);
pavone@656 2464 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
pavone@656 2465 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
pavone@567 2466 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
pavone@567 2467 call(code, opts->gen.load_context);
pavone@567 2468 pop_r(code, opts->gen.scratch2);
pavone@567 2469 pop_r(code, opts->gen.scratch1);
pavone@567 2470 *skip_sync = code->cur - (skip_sync+1);
pavone@567 2471 retn(code);
pavone@539 2472
pavone@590 2473 opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write;
pavone@987 2474
pavone@987 2475 check_alloc_code(code, 256);
pavone@987 2476 opts->gen.handle_align_error_write = code->cur;
pavone@987 2477 code->cur += 256;
pavone@987 2478 check_alloc_code(code, 256);
pavone@987 2479 opts->gen.handle_align_error_read = code->cur;
pavone@987 2480 code->cur += 256;
pavone@987 2481
pavone@590 2482 opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL);
pavone@590 2483 opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL);
pavone@590 2484 opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL);
pavone@590 2485 opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL);
pavone@447 2486
pavone@567 2487 opts->read_32 = code->cur;
pavone@567 2488 push_r(code, opts->gen.scratch1);
pavone@567 2489 call(code, opts->read_16);
pavone@567 2490 mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W);
pavone@567 2491 pop_r(code, opts->gen.scratch1);
pavone@567 2492 push_r(code, opts->gen.scratch2);
pavone@567 2493 add_ir(code, 2, opts->gen.scratch1, SZ_D);
pavone@567 2494 call(code, opts->read_16);
pavone@567 2495 pop_r(code, opts->gen.scratch2);
pavone@567 2496 movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D);
pavone@567 2497 shl_ir(code, 16, opts->gen.scratch2, SZ_D);
pavone@567 2498 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
pavone@567 2499 retn(code);
pavone@447 2500
pavone@567 2501 opts->write_32_lowfirst = code->cur;
pavone@567 2502 push_r(code, opts->gen.scratch2);
pavone@567 2503 push_r(code, opts->gen.scratch1);
pavone@567 2504 add_ir(code, 2, opts->gen.scratch2, SZ_D);
pavone@567 2505 call(code, opts->write_16);
pavone@567 2506 pop_r(code, opts->gen.scratch1);
pavone@567 2507 pop_r(code, opts->gen.scratch2);
pavone@567 2508 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
pavone@567 2509 jmp(code, opts->write_16);
pavone@447 2510
pavone@567 2511 opts->write_32_highfirst = code->cur;
pavone@567 2512 push_r(code, opts->gen.scratch1);
pavone@567 2513 push_r(code, opts->gen.scratch2);
pavone@567 2514 shr_ir(code, 16, opts->gen.scratch1, SZ_D);
pavone@567 2515 call(code, opts->write_16);
pavone@567 2516 pop_r(code, opts->gen.scratch2);
pavone@567 2517 pop_r(code, opts->gen.scratch1);
pavone@567 2518 add_ir(code, 2, opts->gen.scratch2, SZ_D);
pavone@567 2519 jmp(code, opts->write_16);
pavone@447 2520
pavone@567 2521 opts->get_sr = code->cur;
pavone@567 2522 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
pavone@567 2523 shl_ir(code, 8, opts->gen.scratch1, SZ_W);
pavone@547 2524 if (opts->flag_regs[FLAG_X] >= 0) {
pavone@567 2525 mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B);
pavone@547 2526 } else {
pavone@547 2527 int8_t offset = offsetof(m68k_context, flags);
pavone@547 2528 if (offset) {
pavone@567 2529 mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B);
pavone@547 2530 } else {
pavone@567 2531 mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B);
pavone@547 2532 }
pavone@547 2533 }
pavone@547 2534 for (int flag = FLAG_N; flag <= FLAG_C; flag++)
pavone@547 2535 {
pavone@567 2536 shl_ir(code, 1, opts->gen.scratch1, SZ_B);
pavone@547 2537 if (opts->flag_regs[flag] >= 0) {
pavone@567 2538 or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B);
pavone@547 2539 } else {
pavone@567 2540 or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B);
pavone@547 2541 }
pavone@547 2542 }
pavone@567 2543 retn(code);
pavone@547 2544
pavone@567 2545 opts->set_sr = code->cur;
pavone@547 2546 for (int flag = FLAG_C; flag >= FLAG_X; flag--)
pavone@547 2547 {
pavone@567 2548 rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
pavone@547 2549 if (opts->flag_regs[flag] >= 0) {
pavone@567 2550 setcc_r(code, CC_C, opts->flag_regs[flag]);
pavone@547 2551 } else {
pavone@547 2552 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@547 2553 if (offset) {
pavone@567 2554 setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
pavone@547 2555 } else {
pavone@567 2556 setcc_rind(code, CC_C, opts->gen.context_reg);
pavone@547 2557 }
pavone@547 2558 }
pavone@547 2559 }
pavone@567 2560 shr_ir(code, 8, opts->gen.scratch1, SZ_W);
pavone@567 2561 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@846 2562 //set int pending flag in case we trigger an interrupt as a result of the mask change
pavone@996 2563 mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@567 2564 retn(code);
pavone@547 2565
pavone@567 2566 opts->set_ccr = code->cur;
pavone@547 2567 for (int flag = FLAG_C; flag >= FLAG_X; flag--)
pavone@547 2568 {
pavone@567 2569 rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
pavone@547 2570 if (opts->flag_regs[flag] >= 0) {
pavone@567 2571 setcc_r(code, CC_C, opts->flag_regs[flag]);
pavone@547 2572 } else {
pavone@547 2573 int8_t offset = offsetof(m68k_context, flags) + flag;
pavone@547 2574 if (offset) {
pavone@567 2575 setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
pavone@547 2576 } else {
pavone@567 2577 setcc_rind(code, CC_C, opts->gen.context_reg);
pavone@547 2578 }
pavone@547 2579 }
pavone@547 2580 }
pavone@567 2581 retn(code);
pavone@987 2582
pavone@987 2583 code_info tmp_code = *code;
pavone@987 2584 code->cur = opts->gen.handle_align_error_write;
pavone@987 2585 code->last = code->cur + 256;
pavone@987 2586 //unwind the stack one functinon call
pavone@987 2587 add_ir(code, 16, RSP, SZ_PTR);
pavone@987 2588 //save address that triggered error so we can write it to the 68K stack at the appropriate place
pavone@987 2589 push_r(code, opts->gen.scratch2);
pavone@987 2590 //swap USP and SSP if not already in supervisor mode
pavone@987 2591 check_user_mode_swap_ssp_usp(opts);
pavone@987 2592 //save PC
pavone@987 2593 subi_areg(opts, 4, 7);
pavone@987 2594 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2595 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
pavone@987 2596 call(code, opts->write_32_lowfirst);
pavone@987 2597 //save status register
pavone@987 2598 subi_areg(opts, 2, 7);
pavone@987 2599 call(code, opts->get_sr);
pavone@987 2600 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2601 call(code, opts->write_16);
pavone@987 2602 //save instruction register
pavone@987 2603 subi_areg(opts, 2, 7);
pavone@989 2604 //calculate IR
pavone@989 2605 push_r(code, opts->gen.context_reg);
pavone@989 2606 call(code, opts->gen.save_context);
pavone@989 2607 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
pavone@989 2608 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
pavone@989 2609 pop_r(code, opts->gen.context_reg);
pavone@989 2610 pop_r(code, opts->gen.scratch2); //access address
pavone@989 2611 push_r(code, RAX); //save it for use in the "info" word
pavone@989 2612 push_r(code, opts->gen.scratch2); //access address
pavone@989 2613 call(code, opts->gen.load_context);
pavone@989 2614 //write it to the stack
pavone@987 2615 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2616 call(code, opts->write_16);
pavone@987 2617 //save access address
pavone@987 2618 subi_areg(opts, 4, 7);
pavone@987 2619 pop_r(code, opts->gen.scratch1);
pavone@987 2620 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2621 call(code, opts->write_32_lowfirst);
pavone@987 2622 //save FC, I/N and R/W word'
pavone@987 2623 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
pavone@987 2624 //FC3 is basically the same as the supervisor bit
pavone@987 2625 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
pavone@987 2626 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
pavone@987 2627 and_ir(code, 4, opts->gen.scratch1, SZ_B);
pavone@987 2628 //set FC0 to one to indicate data access
pavone@987 2629 or_ir(code, 1, opts->gen.scratch1, SZ_B);
pavone@989 2630 //set undefined bits to IR value
pavone@989 2631 pop_r(code, opts->gen.scratch2);
pavone@989 2632 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
pavone@989 2633 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
pavone@987 2634 subi_areg(opts, 2, 7);
pavone@987 2635 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2636 call(code, opts->write_16);
pavone@987 2637 //set supervisor bit
pavone@987 2638 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@987 2639 //load vector address
pavone@987 2640 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
pavone@987 2641 call(code, opts->read_32);
pavone@987 2642 call(code, opts->native_addr_and_sync);
pavone@987 2643 cycles(&opts->gen, 18);
pavone@987 2644 jmp_r(code, opts->gen.scratch1);
pavone@987 2645
pavone@987 2646 code->cur = opts->gen.handle_align_error_read;
pavone@987 2647 code->last = code->cur + 256;
pavone@987 2648 //unwind the stack one functinon call
pavone@987 2649 add_ir(code, 16, RSP, SZ_PTR);
pavone@987 2650 //save address that triggered error so we can write it to the 68K stack at the appropriate place
pavone@987 2651 push_r(code, opts->gen.scratch1);
pavone@987 2652 //swap USP and SSP if not already in supervisor mode
pavone@987 2653 check_user_mode_swap_ssp_usp(opts);
pavone@987 2654 //save PC
pavone@987 2655 subi_areg(opts, 4, 7);
pavone@987 2656 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2657 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
pavone@987 2658 call(code, opts->write_32_lowfirst);
pavone@987 2659 //save status register
pavone@987 2660 subi_areg(opts, 2, 7);
pavone@987 2661 call(code, opts->get_sr);
pavone@987 2662 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2663 call(code, opts->write_16);
pavone@987 2664 //save instruction register
pavone@987 2665 subi_areg(opts, 2, 7);
pavone@989 2666 //calculate IR
pavone@989 2667 push_r(code, opts->gen.context_reg);
pavone@989 2668 call(code, opts->gen.save_context);
pavone@989 2669 call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
pavone@989 2670 mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
pavone@989 2671 pop_r(code, opts->gen.context_reg);
pavone@989 2672 pop_r(code, opts->gen.scratch2); //access address
pavone@989 2673 push_r(code, RAX); //save it for use in the "info" word
pavone@989 2674 push_r(code, opts->gen.scratch2); //access address
pavone@989 2675 call(code, opts->gen.load_context);
pavone@989 2676 //write it to the stack
pavone@987 2677 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2678 call(code, opts->write_16);
pavone@987 2679 //save access address
pavone@987 2680 subi_areg(opts, 4, 7);
pavone@987 2681 pop_r(code, opts->gen.scratch1);
pavone@987 2682 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2683 call(code, opts->write_32_lowfirst);
pavone@987 2684 //save FC, I/N and R/W word'
pavone@987 2685 xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
pavone@987 2686 //FC3 is basically the same as the supervisor bit
pavone@987 2687 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
pavone@987 2688 shr_ir(code, 3, opts->gen.scratch1, SZ_B);
pavone@987 2689 and_ir(code, 4, opts->gen.scratch1, SZ_B);
pavone@987 2690 //set FC0 to one to indicate data access, and R/W to indicate read
pavone@987 2691 or_ir(code, 0x11, opts->gen.scratch1, SZ_B);
pavone@989 2692 //set undefined bits to IR value
pavone@989 2693 pop_r(code, opts->gen.scratch2);
pavone@989 2694 and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
pavone@989 2695 or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
pavone@987 2696 subi_areg(opts, 2, 7);
pavone@987 2697 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@987 2698 call(code, opts->write_16);
pavone@987 2699 //set supervisor bit
pavone@987 2700 or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
pavone@987 2701 //load vector address
pavone@987 2702 mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
pavone@987 2703 call(code, opts->read_32);
pavone@987 2704 call(code, opts->native_addr_and_sync);
pavone@987 2705 cycles(&opts->gen, 18);
pavone@987 2706 jmp_r(code, opts->gen.scratch1);
pavone@987 2707
pavone@987 2708 *code = tmp_code;
pavone@547 2709
pavone@567 2710 opts->gen.handle_cycle_limit_int = code->cur;
pavone@902 2711 //calculate stack adjust size
pavone@902 2712 add_ir(code, 16-sizeof(void*), RSP, SZ_PTR);
pavone@902 2713 uint32_t adjust_size = code->cur - opts->gen.handle_cycle_limit_int;
pavone@902 2714 code->cur = opts->gen.handle_cycle_limit_int;
pavone@908 2715
pavone@656 2716 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
pavone@567 2717 code_ptr do_int = code->cur + 1;
pavone@567 2718 jcc(code, CC_NC, code->cur + 2);
pavone@656 2719 cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
pavone@567 2720 skip_sync = code->cur + 1;
pavone@567 2721 jcc(code, CC_C, code->cur + 2);
pavone@567 2722 call(code, opts->gen.save_context);
pavone@656 2723 call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
pavone@567 2724 mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
pavone@567 2725 jmp(code, opts->gen.load_context);
pavone@567 2726 *skip_sync = code->cur - (skip_sync+1);
pavone@872 2727 cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, should_return), SZ_B);
pavone@872 2728 code_ptr do_ret = code->cur + 1;
pavone@872 2729 jcc(code, CC_NZ, do_ret);
pavone@567 2730 retn(code);
pavone@872 2731 *do_ret = code->cur - (do_ret+1);
pavone@894 2732 uint32_t tmp_stack_off = code->stack_off;
pavone@894 2733 //fetch return address and adjust RSP
pavone@872 2734 pop_r(code, opts->gen.scratch1);
pavone@894 2735 add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
pavone@902 2736 add_ir(code, adjust_size, opts->gen.scratch1, SZ_PTR);
pavone@894 2737 //save return address for restoring later
pavone@883 2738 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
pavone@872 2739 retn(code);
pavone@894 2740 code->stack_off = tmp_stack_off;
pavone@567 2741 *do_int = code->cur - (do_int+1);
pavone@846 2742 //implement 1 instruction latency
pavone@846 2743 cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@846 2744 do_int = code->cur + 1;
pavone@846 2745 jcc(code, CC_NZ, do_int);
pavone@996 2746 //store current interrupt number so it doesn't change before we start processing the vector
pavone@996 2747 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
pavone@996 2748 mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@846 2749 retn(code);
pavone@846 2750 *do_int = code->cur - (do_int + 1);
pavone@996 2751 //Check if int_pending has an actual interrupt priority in it
pavone@996 2752 cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@996 2753 code_ptr already_int_num = code->cur + 1;
pavone@996 2754 jcc(code, CC_NZ, already_int_num);
pavone@996 2755
pavone@996 2756 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B);
pavone@996 2757 mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
pavone@996 2758
pavone@996 2759 *already_int_num = code->cur - (already_int_num + 1);
pavone@847 2760 //save PC as stored in scratch1 for later
pavone@847 2761 push_r(code, opts->gen.scratch1);
pavone@347 2762 //set target cycle to sync cycle
pavone@656 2763 mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D);
pavone@347 2764 //swap USP and SSP if not already in supervisor mode
pavone@687 2765 check_user_mode_swap_ssp_usp(opts);
pavone@347 2766 //save status register
pavone@847 2767 subi_areg(opts, 6, 7);
pavone@567 2768 call(code, opts->get_sr);
pavone@847 2769 //6 cycles before SR gets saved
pavone@847 2770 cycles(&opts->gen, 6);
pavone@847 2771 //save SR to stack
pavone@574 2772 areg_to_native(opts, 7, opts->gen.scratch2);
pavone@567 2773 call(code, opts->write_16);
pavone@847 2774 //interrupt ack cycle