free_cond(&c);
}
-DISAS_INSN(scc)
-{
- DisasCompare c;
- int cond;
- TCGv reg, tmp;
-
- cond = (insn >> 8) & 0xf;
- gen_cc_cond(&c, s, cond);
-
- tmp = tcg_temp_new();
- tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
- free_cond(&c);
-
- reg = DREG(insn, 0);
- tcg_gen_neg_i32(tmp, tmp);
- tcg_gen_deposit_i32(reg, reg, tmp, 0, 8);
- tcg_temp_free(tmp);
-}
-
/* Force a TB lookup after an instruction that changes the CPU state. */
static void gen_lookup_tb(DisasContext *s)
{
s->is_jmp = DISAS_TB_JUMP;
}
+DISAS_INSN(scc)
+{
+ DisasCompare c;
+ int cond;
+ TCGv tmp;
+
+ cond = (insn >> 8) & 0xf;
+ gen_cc_cond(&c, s, cond);
+
+ tmp = tcg_temp_new();
+ tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2);
+ free_cond(&c);
+
+ tcg_gen_neg_i32(tmp, tmp);
+ DEST_EA(env, insn, OS_BYTE, tmp, NULL);
+ tcg_temp_free(tmp);
+}
+
+DISAS_INSN(dbcc)
+{
+ TCGLabel *l1;
+ TCGv reg;
+ TCGv tmp;
+ int16_t offset;
+ uint32_t base;
+
+ reg = DREG(insn, 0);
+ base = s->pc;
+ offset = (int16_t)read_im16(env, s);
+ l1 = gen_new_label();
+ gen_jmpcc(s, (insn >> 8) & 0xf, l1);
+
+ tmp = tcg_temp_new();
+ tcg_gen_ext16s_i32(tmp, reg);
+ tcg_gen_addi_i32(tmp, tmp, -1);
+ gen_partset_reg(OS_WORD, reg, tmp);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
+ gen_jmp_tb(s, 1, base + offset);
+ gen_set_label(l1);
+ gen_jmp_tb(s, 0, s->pc);
+}
+
DISAS_INSN(undef_mac)
{
gen_exception(s, s->pc - 2, EXCP_LINEA);
DISAS_INSN(negx)
{
- TCGv reg;
+ TCGv z;
+ TCGv src;
+ TCGv addr;
+ int opsize;
- gen_flush_flags(s);
- reg = DREG(insn, 0);
- gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg);
+ opsize = insn_opsize(insn);
+ SRC_EA(env, src, opsize, 1, &addr);
+
+ gen_flush_flags(s); /* compute old Z */
+
+ /* Perform substract with borrow.
+ * (X, N) = -(src + X);
+ */
+
+ z = tcg_const_i32(0);
+ tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
+ tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
+ tcg_temp_free(z);
+ gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
+
+ tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
+
+ /* Compute signed-overflow for negation. The normal formula for
+ * subtraction is (res ^ src) & (src ^ dest), but with dest==0
+ * this simplies to res & src.
+ */
+
+ tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, src);
+
+ /* Copy the rest of the results into place. */
+ tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
+ tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
+
+ set_cc_op(s, CC_OP_FLAGS);
+
+ /* result is in QREG_CC_N */
+
+ DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
}
DISAS_INSN(lea)
DISAS_INSN(not)
{
- TCGv reg;
+ TCGv src1;
+ TCGv dest;
+ TCGv addr;
+ int opsize;
- reg = DREG(insn, 0);
- tcg_gen_not_i32(reg, reg);
- gen_logic_cc(s, reg, OS_LONG);
+ opsize = insn_opsize(insn);
+ SRC_EA(env, src1, opsize, 1, &addr);
+ dest = tcg_temp_new();
+ tcg_gen_not_i32(dest, src1);
+ DEST_EA(env, insn, opsize, dest, &addr);
+ gen_logic_cc(s, dest, opsize);
}
DISAS_INSN(swap)
tcg_gen_sub_i32(reg, reg, src);
}
-DISAS_INSN(subx)
+static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
{
- TCGv reg;
+ TCGv tmp;
+
+ gen_flush_flags(s); /* compute old Z */
+
+ /* Perform substract with borrow.
+ * (X, N) = dest - (src + X);
+ */
+
+ tmp = tcg_const_i32(0);
+ tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
+ tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
+ gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
+ tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1);
+
+ /* Compute signed-overflow for substract. */
+
+ tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, dest);
+ tcg_gen_xor_i32(tmp, dest, src);
+ tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, tmp);
+ tcg_temp_free(tmp);
+
+ /* Copy the rest of the results into place. */
+ tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
+ tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
+
+ set_cc_op(s, CC_OP_FLAGS);
+
+ /* result is in QREG_CC_N */
+}
+
+DISAS_INSN(subx_reg)
+{
+ TCGv dest;
TCGv src;
+ int opsize;
- gen_flush_flags(s);
- reg = DREG(insn, 9);
- src = DREG(insn, 0);
- gen_helper_subx_cc(reg, cpu_env, reg, src);
+ opsize = insn_opsize(insn);
+
+ src = gen_extend(DREG(insn, 0), opsize, 1);
+ dest = gen_extend(DREG(insn, 9), opsize, 1);
+
+ gen_subx(s, src, dest, opsize);
+
+ gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
+}
+
+DISAS_INSN(subx_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv dest;
+ TCGv addr_dest;
+ int opsize;
+
+ opsize = insn_opsize(insn);
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, opsize);
+ src = gen_load(s, opsize, addr_src, 1);
+
+ addr_dest = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_dest, addr_dest, opsize);
+ dest = gen_load(s, opsize, addr_dest, 1);
+
+ gen_subx(s, src, dest, opsize);
+
+ gen_store(s, opsize, addr_dest, QREG_CC_N);
}
DISAS_INSN(mov3q)
tcg_gen_add_i32(reg, reg, src);
}
-DISAS_INSN(addx)
+static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
{
- TCGv reg;
+ TCGv tmp;
+
+ gen_flush_flags(s); /* compute old Z */
+
+ /* Perform addition with carry.
+ * (X, N) = src + dest + X;
+ */
+
+ tmp = tcg_const_i32(0);
+ tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
+ tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
+ gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1);
+
+ /* Compute signed-overflow for addition. */
+
+ tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src);
+ tcg_gen_xor_i32(tmp, dest, src);
+ tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, tmp);
+ tcg_temp_free(tmp);
+
+ /* Copy the rest of the results into place. */
+ tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
+ tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X);
+
+ set_cc_op(s, CC_OP_FLAGS);
+
+ /* result is in QREG_CC_N */
+}
+
+DISAS_INSN(addx_reg)
+{
+ TCGv dest;
TCGv src;
+ int opsize;
- gen_flush_flags(s);
- reg = DREG(insn, 9);
- src = DREG(insn, 0);
- gen_helper_addx_cc(reg, cpu_env, reg, src);
+ opsize = insn_opsize(insn);
+
+ dest = gen_extend(DREG(insn, 9), opsize, 1);
+ src = gen_extend(DREG(insn, 0), opsize, 1);
+
+ gen_addx(s, src, dest, opsize);
+
+ gen_partset_reg(opsize, DREG(insn, 9), QREG_CC_N);
+}
+
+DISAS_INSN(addx_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv dest;
+ TCGv addr_dest;
+ int opsize;
+
+ opsize = insn_opsize(insn);
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
+ src = gen_load(s, opsize, addr_src, 1);
+
+ addr_dest = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
+ dest = gen_load(s, opsize, addr_dest, 1);
+
+ gen_addx(s, src, dest, opsize);
+
+ gen_store(s, opsize, addr_dest, QREG_CC_N);
}
/* TODO: This could be implemented without helper functions. */
BASE(move, 3000, f000);
INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
INSN(negx, 4080, fff8, CF_ISA_A);
+ INSN(negx, 4000, ff00, M68000);
+ INSN(undef, 40c0, ffc0, M68000);
INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
INSN(move_from_sr, 40c0, ffc0, M68000);
BASE(lea, 41c0, f1c0);
INSN(jump, 4ec0, ffc0, M68000);
INSN(addsubq, 5000, f080, M68000);
INSN(addsubq, 5080, f0c0, M68000);
- INSN(scc, 50c0, f0f8, CF_ISA_A);
+ INSN(scc, 50c0, f0f8, CF_ISA_A); /* Scc.B Dx */
+ INSN(scc, 50c0, f0c0, M68000); /* Scc.B <EA> */
+ INSN(dbcc, 50c8, f0f8, M68000);
INSN(addsubq, 5080, f1c0, CF_ISA_A);
INSN(tpf, 51f8, fff8, CF_ISA_A);
BASE(or, 8000, f000);
BASE(divw, 80c0, f0c0);
BASE(addsub, 9000, f000);
- INSN(subx, 9180, f1f8, CF_ISA_A);
+ INSN(undef, 90c0, f0c0, CF_ISA_A);
+ INSN(subx_reg, 9180, f1f8, CF_ISA_A);
+ INSN(subx_reg, 9100, f138, M68000);
+ INSN(subx_mem, 9108, f138, M68000);
INSN(suba, 91c0, f1c0, CF_ISA_A);
BASE(undef_mac, a000, f000);
INSN(exg_da, c188, f1f8, M68000);
BASE(mulw, c0c0, f0c0);
BASE(addsub, d000, f000);
- INSN(addx, d180, f1f8, CF_ISA_A);
+ INSN(undef, d0c0, f0c0, CF_ISA_A);
+ INSN(addx_reg, d180, f1f8, CF_ISA_A);
+ INSN(addx_reg, d100, f138, M68000);
+ INSN(addx_mem, d108, f138, M68000);
INSN(adda, d1c0, f1c0, CF_ISA_A);
INSN(adda, d0c0, f0c0, M68000);
INSN(shift_im, e080, f0f0, CF_ISA_A);