/* Simulator for Analog Devices Blackfin processors.
- Copyright (C) 2005-2011 Free Software Foundation, Inc.
+ Copyright (C) 2005-2016 Free Software Foundation, Inc.
Contributed by Analog Devices, Inc.
This file is part of simulators.
cec_exception (cpu, VEC_ILGAL_I);
}
+static __attribute__ ((noreturn)) void
+illegal_instruction_or_combination (SIM_CPU *cpu)
+{
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+ else
+ illegal_instruction (cpu);
+}
+
static __attribute__ ((noreturn)) void
unhandled_instruction (SIM_CPU *cpu, const char *insn)
{
x <<= constant_formats[cf].scale;
if (constant_formats[cf].decimal)
- {
- if (constant_formats[cf].leading)
- {
- char ps[10];
- sprintf (ps, "%%%ii", constant_formats[cf].leading);
- sprintf (buf, ps, x);
- }
- else
- sprintf (buf, "%i", x);
- }
+ sprintf (buf, "%*i", constant_formats[cf].leading, x);
else
{
if (constant_formats[cf].issigned && x < 0)
val |= sgn;
SET_ASTATREG (an, val >> (size - 1));
SET_ASTATREG (az, val == 0);
- /* XXX: Need to check ASTAT[v] behavior here. */
- SET_ASTATREG (v, 0);
+ if (size != 40)
+ SET_ASTATREG (v, 0);
return val;
}
}
SET_ASTATREG (an, val >> (size - 1));
SET_ASTATREG (az, val == 0);
- SET_ASTATREG (v, 0);
+ if (size != 40)
+ SET_ASTATREG (v, 0);
return val;
}
static bu64
-lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate)
+lshift (SIM_CPU *cpu, bu64 val, int cnt, int size, bool saturate, bool overflow)
{
- int i, j, real_cnt = cnt > size ? size : cnt;
+ int v_i, real_cnt = cnt > size ? size : cnt;
bu64 sgn = ~((val >> (size - 1)) - 1);
int mask_cnt = size - 1;
- bu64 masked, new_val = val, tmp;
+ bu64 masked, new_val = val;
bu64 mask = ~0;
mask <<= mask_cnt;
However, it's a little more complex than looking at sign bits, we need
to see if we are shifting the sign information away... */
- tmp = val & ((~mask << 1) | 1);
-
- j = 0;
- for (i = 1; i <= real_cnt && saturate; i++)
- {
- if ((tmp & ((bu64)1 << (size - 1))) !=
- (((val >> mask_cnt) & 0x1) << mask_cnt))
- j++;
- tmp <<= 1;
- }
- saturate &= (!sgn && (new_val & (1 << mask_cnt)))
- || (sgn && !(new_val & (1 << mask_cnt)));
+ if (((val << cnt) >> size) == 0
+ || (((val << cnt) >> size) == ~(~0 << cnt)
+ && ((new_val >> (size - 1)) & 0x1)))
+ v_i = 0;
+ else
+ v_i = 1;
switch (size)
{
case 16:
- if (j || (saturate && (new_val & mask)))
- new_val = sgn == 0 ? 0x7fff : 0x8000, saturate = 1;
new_val &= 0xFFFF;
+ if (saturate && (v_i || ((val >> (size - 1)) != (new_val >> (size - 1)))))
+ {
+ new_val = (val >> (size - 1)) == 0 ? 0x7fff : 0x8000;
+ v_i = 1;
+ }
break;
case 32:
new_val &= 0xFFFFFFFF;
masked &= 0xFFFFFFFF;
- if (j || (saturate && ((sgn != masked) || (!sgn && new_val == 0))))
- new_val = sgn == 0 ? 0x7fffffff : 0x80000000, saturate = 1;
+ sgn &= 0xFFFFFFFF;
+ if (saturate
+ && (v_i
+ || (sgn != masked)
+ || (!sgn && new_val == 0 && val != 0)))
+ {
+ new_val = sgn == 0 ? 0x7fffffff : 0x80000000;
+ v_i = 1;
+ }
break;
case 40:
new_val &= 0xFFFFFFFFFFull;
SET_ASTATREG (an, new_val >> (size - 1));
SET_ASTATREG (az, new_val == 0);
- SET_ASTATREG (v, !!(saturate || j));
- if (saturate || j)
- SET_ASTATREG (vs, 1);
+ if (size != 40)
+ {
+ SET_ASTATREG (v, overflow && v_i);
+ if (overflow && v_i)
+ SET_ASTATREG (vs, 1);
+ }
+
return new_val;
}
}
val1 = val;
- if (mmod == 0 || mmod == M_IS || mmod == M_T || mmod == M_S2RND
- || mmod == M_ISS2 || mmod == M_IH || (MM && mmod == M_FU))
+ /* In signed modes, sign extend. */
+ if (is_macmod_signed (mmod) || MM)
val1 |= -(val1 & 0x80000000);
if (*psat)
*v = 1;
return -((bs64)1 << 39);
}
- else if ((bs64)val >= ((bs64)1 << 39) - 1)
+ else if ((bs64)val > ((bs64)1 << 39) - 1)
{
*v = 1;
return ((bu64)1 << 39) - 1;
case M_IS:
return saturate_s32 (res, overflow);
case M_IU:
+ if (MM)
+ return saturate_s32 (res, overflow);
return saturate_u32 (res, overflow);
case M_FU:
if (MM)
{
case 0:
case M_W32:
- return saturate_s16 (rnd16 (res), overflow);
case M_IH:
- return saturate_s32 (rnd16 (res), overflow) & 0xFFFF;
+ return saturate_s16 (rnd16 (res), overflow);
case M_IS:
return saturate_s16 (res, overflow);
case M_FU:
case M_T:
return saturate_s16 (trunc16 (res), overflow);
case M_TFU:
+ if (MM)
+ return saturate_s16 (trunc16 (res), overflow);
return saturate_u16 (trunc16 (res), overflow);
case M_S2RND:
bu32 sat = 0, tsat, ret;
/* Sign extend accumulator if necessary, otherwise unsigned. */
- if (mmod == 0 || mmod == M_T || mmod == M_IS || mmod == M_ISS2
- || mmod == M_S2RND || mmod == M_IH || mmod == M_W32)
+ if (is_macmod_signed (mmod) || MM)
acc = get_extended_acc (cpu, which);
else
acc = get_unextended_acc (cpu, which);
- if (MM && (mmod == M_T || mmod == M_IS || mmod == M_ISS2
- || mmod == M_S2RND || mmod == M_IH || mmod == M_W32))
- acc |= -(acc & 0x80000000);
-
if (op != 3)
{
bu8 sgn0 = (acc >> 31) & 1;
+ bu8 sgn40 = (acc >> 39) & 1;
+ bu40 nosat_acc;
+
/* This can't saturate, so we don't keep track of the sat flag. */
bu64 res = decode_multfunc (cpu, h0, h1, src0, src1, mmod,
MM, &tsat);
break;
}
+ nosat_acc = acc;
/* Saturate. */
switch (mmod)
{
acc = 0x7fffffffffull, sat = 1;
break;
case M_TFU:
- if (!MM && acc > 0xFFFFFFFFFFull)
- acc = 0x0, sat = 1;
- if (MM && acc > 0xFFFFFFFF)
- acc &= 0xFFFFFFFF;
+ if (MM)
+ {
+ if ((bs64)acc < -((bs64)1 << 39))
+ acc = -((bu64)1 << 39), sat = 1;
+ if ((bs64)acc > 0x7FFFFFFFFFll)
+ acc = 0x7FFFFFFFFFull, sat = 1;
+ }
+ else
+ {
+ if ((bs64)acc < 0)
+ acc = 0, sat = 1;
+ if ((bs64)acc > 0xFFFFFFFFFFull)
+ acc = 0xFFFFFFFFFFull, sat = 1;
+ }
break;
case M_IU:
- if (acc & 0x8000000000000000ull)
- acc = 0x0, sat = 1;
- if (acc > 0xFFFFFFFFFFull)
- acc &= 0xFFFFFFFFFFull, sat = 1;
- if (MM && acc > 0xFFFFFFFF)
- acc &= 0xFFFFFFFF;
- if (acc & 0x80000000)
- acc |= 0xffffffff00000000ull;
- break;
- case M_FU:
- if (!MM && (bs64)acc < 0)
+ if (!MM && acc & 0x8000000000000000ull)
acc = 0x0, sat = 1;
- if (MM && (bs64)acc < -((bs64)1 << 39))
- acc = -((bu64)1 << 39), sat = 1;
- if (!MM && (bs64)acc > (bs64)0xFFFFFFFFFFll)
+ if (!MM && acc > 0xFFFFFFFFFFull)
acc = 0xFFFFFFFFFFull, sat = 1;
if (MM && acc > 0xFFFFFFFFFFull)
acc &= 0xFFFFFFFFFFull;
- if (MM && acc & 0x80000000)
- acc |= 0xffffffff00000000ull;
+ if (acc & 0x8000000000ull)
+ acc |= 0xffffff0000000000ull;
+ break;
+ case M_FU:
+ if (MM)
+ {
+ if ((bs64)acc < -((bs64)1 << 39))
+ acc = -((bu64)1 << 39), sat = 1;
+ if ((bs64)acc > 0x7FFFFFFFFFll)
+ acc = 0x7FFFFFFFFFull, sat = 1;
+ else if (acc & 0x8000000000ull)
+ acc |= 0xffffff0000000000ull;
+ }
+ else
+ {
+ if ((bs64)acc < 0)
+ acc = 0x0, sat = 1;
+ else if ((bs64)acc > (bs64)0xFFFFFFFFFFll)
+ acc = 0xFFFFFFFFFFull, sat = 1;
+ }
break;
case M_IH:
if ((bs64)acc < -0x80000000ll)
acc = -0x80000000ull, sat = 1;
- else if ((bs64)acc >= 0x7fffffffll)
+ else if ((bs64)acc > 0x7fffffffll)
acc = 0x7fffffffull, sat = 1;
break;
case M_W32:
- if (sgn0 && (sgn0 != ((acc >> 31) & 1))
- && (((acc >> 32) & 0xFF) == 0xff))
- acc = 0x80000000;
+ /* check max negative value */
+ if (sgn40 && ((acc >> 31) != 0x1ffffffff)
+ && ((acc >> 31) != 0x0))
+ acc = 0x80000000, sat = 1;
+ if (!sat && !sgn40 && ((acc >> 31) != 0x0)
+ && ((acc >> 31) != 0x1ffffffff))
+ acc = 0x7FFFFFFF, sat = 1;
acc &= 0xffffffff;
if (acc & 0x80000000)
acc |= 0xffffffff00000000ull;
+ if (tsat)
+ sat = 1;
break;
default:
illegal_instruction (cpu);
STORE (ASTATREG (av[which]), sat);
if (sat)
STORE (ASTATREG (avs[which]), sat);
+
+ /* Figure out the overflow bit. */
+ if (sat)
+ {
+ if (fullword)
+ *overflow = 1;
+ else
+ ret = extract_mult (cpu, nosat_acc, mmod, MM, fullword, overflow);
+ }
}
ret = extract_mult (cpu, acc, mmod, MM, fullword, overflow);
for (i = 1; i >= 0; --i)
if (LCREG (i) > 1 && pc == LBREG (i))
{
- TRACE_BRANCH (cpu, pc, LTREG (i), i, "Hardware loop %i", i);
+ BFIN_TRACE_BRANCH (cpu, pc, LTREG (i), i, "Hardware loop %i", i);
return LTREG (i);
}
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "RTS;");
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "RTS");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "RTS");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
CYCLE_DELAY = 5;
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "RTI;");
/* Do not do IFETCH_CHECK here -- LSB has special meaning. */
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_return (cpu, -1);
CYCLE_DELAY = 5;
TRACE_INSN (cpu, "RTX;");
/* XXX: Not sure if this is what the hardware does. */
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_return (cpu, IVG_EVX);
CYCLE_DELAY = 5;
TRACE_INSN (cpu, "RTN;");
/* XXX: Not sure if this is what the hardware does. */
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_return (cpu, IVG_NMI);
CYCLE_DELAY = 5;
{
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "RTE;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_return (cpu, IVG_EMU);
CYCLE_DELAY = 5;
in user mode, it's a NOP ... */
TRACE_INSN (cpu, "IDLE;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
/* Timewarp ! */
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_sync);
/* Just NOP it. */
TRACE_INSN (cpu, "CSYNC;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
CYCLE_DELAY = 10;
}
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_sync);
/* Just NOP it. */
TRACE_INSN (cpu, "SSYNC;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
/* Really 10+, but no model info for this. */
{
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
TRACE_INSN (cpu, "EMUEXCPT;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_exception (cpu, VEC_SIM_TRAP);
}
{
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
TRACE_INSN (cpu, "CLI R%i;", poprnd);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (poprnd, cec_cli (cpu));
}
{
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
TRACE_INSN (cpu, "STI R%i;", poprnd);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_sti (cpu, DREG (poprnd));
CYCLE_DELAY = 3;
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "JUMP (%s);", get_preg_name (poprnd));
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (Preg)");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (Preg)");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
PROFILE_BRANCH_TAKEN (cpu);
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "CALL (%s);", get_preg_name (poprnd));
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (Preg)");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (Preg)");
/* If we're at the end of a hardware loop, RETS is going to be
the top of the loop rather than the next instruction. */
SET_RETSREG (hwloop_get_next_pc (cpu, pc, 2));
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "CALL (PC + %s);", get_preg_name (poprnd));
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (PC + Preg)");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL (PC + Preg)");
SET_RETSREG (hwloop_get_next_pc (cpu, pc, 2));
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_branch);
TRACE_INSN (cpu, "JUMP (PC + %s);", get_preg_name (poprnd));
IFETCH_CHECK (newpc);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (PC + Preg)");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP (PC + Preg)");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
PROFILE_BRANCH_TAKEN (cpu);
int raise = uimm4 (poprnd);
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
TRACE_INSN (cpu, "RAISE %s;", uimm4_str (raise));
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_require_supervisor (cpu);
if (raise == IVG_IVHW)
int excpt = uimm4 (poprnd);
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_cec);
TRACE_INSN (cpu, "EXCPT %s;", uimm4_str (excpt));
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
cec_exception (cpu, excpt);
CYCLE_DELAY = 3;
bu8 byte;
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ProgCtrl_atomic);
TRACE_INSN (cpu, "TESTSET (%s);", get_preg_name (poprnd));
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
byte = GET_WORD (addr);
SET_CCREG (byte == 0);
CYCLE_DELAY = 2;
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
TRACE_EXTRACT (cpu, "%s: a:%i op:%i reg:%i", __func__, a, op, reg);
TRACE_INSN (cpu, "%s [%s%s];", sinsn[op], get_preg_name (reg), a ? "++" : "");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
/* None of these can be part of a parallel instruction. */
illegal_instruction_combination (cpu);
/* Can't push/pop reserved registers */
if (reg_is_reserved (grp, reg))
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
if (W == 0)
{
/* Dreg and Preg are not supported by this instruction. */
if (grp == 0 || grp == 1)
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
TRACE_INSN (cpu, "%s = [SP++];", reg_name);
/* Can't pop USP while in userspace. */
- if (INSN_LEN == 8 || (grp == 7 && reg == 0 && cec_is_user_mode(cpu)))
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE
+ || (grp == 7 && reg == 0 && cec_is_user_mode(cpu)))
illegal_instruction_combination (cpu);
/* XXX: The valid register check is in reg_write(), so we might
incorrectly do a GET_LONG() here ... */
else
{
TRACE_INSN (cpu, "[--SP] = %s;", reg_name);
- /* Can't push SP. */
- if (INSN_LEN == 8 || (grp == 1 && reg == 6))
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
sp -= 4;
TRACE_EXTRACT (cpu, "%s: d:%i p:%i W:%i dr:%i pr:%i",
__func__, d, p, W, dr, pr);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if ((d == 0 && p == 0) || (p && imm5 (pr) > 5)
|| (d && !p && pr) || (p && !d && dr))
illegal_instruction (cpu);
TRACE_INSN (cpu, "IF %sCC %s = %s;", T ? "" : "! ",
get_allreg_name (d, dst),
get_allreg_name (s, src));
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
if (cond)
bs64 diff = acc0 - acc1;
if (x != 0 || y != 0)
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
if (opc == 5 && I == 0 && G == 0)
{
TRACE_INSN (cpu, "CC = A0 == A1;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG (acc0 == acc1);
}
else if (opc == 6 && I == 0 && G == 0)
{
TRACE_INSN (cpu, "CC = A0 < A1");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG (acc0 < acc1);
}
else if (opc == 7 && I == 0 && G == 0)
{
TRACE_INSN (cpu, "CC = A0 <= A1");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG (acc0 <= acc1);
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
SET_ASTATREG (az, diff == 0);
SET_ASTATREG (an, diff < 0);
TRACE_INSN (cpu, "CC = %c%i %s %c%i%s;", s, x, op, d, y, sign);
}
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
SET_CCREG (cc);
/* Pointer compares only touch CC. */
if (!G)
if (op == 0)
{
TRACE_INSN (cpu, "R%i = CC;", reg);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (reg, CCREG);
}
else if (op == 1)
{
TRACE_INSN (cpu, "CC = R%i;", reg);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG (DREG (reg) != 0);
}
else if (op == 3 && reg == 0)
{
TRACE_INSN (cpu, "CC = !CC;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG (!CCREG);
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
TRACE_INSN (cpu, "%s %s= %s;", D ? astat_names[cbit] : "CC",
op_names[op], D ? "CC" : astat_names[cbit]);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
/* CC = CC; is invalid. */
if (cbit == 5)
illegal_instruction (cpu);
- if (INSN_LEN == 8)
- illegal_instruction_combination (cpu);
-
pval = !!(ASTAT & (1 << cbit));
if (D == 0)
switch (op)
TRACE_INSN (cpu, "IF %sCC JUMP %#x%s;", T ? "" : "! ",
pcrel, B ? " (bp)" : "");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
if (cond)
{
bu32 newpc = pc + pcrel;
- TRACE_BRANCH (cpu, pc, newpc, -1, "Conditional JUMP");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "Conditional JUMP");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
PROFILE_BRANCH_TAKEN (cpu);
TRACE_INSN (cpu, "JUMP.S %#x;", pcrel);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.S");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.S");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
TRACE_INSN (cpu, "%s = %s;", dstreg_name, srcreg_name);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
/* Reserved slots cannot be a src/dst. */
if (reg_is_reserved (gs, src) || reg_is_reserved (gd, dst))
goto invalid_move;
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_ALU2op);
TRACE_EXTRACT (cpu, "%s: opc:%i src:%i dst:%i", __func__, opc, src, dst);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if (opc == 0)
{
TRACE_INSN (cpu, "R%i >>>= R%i;", dst, src);
else if (opc == 2)
{
TRACE_INSN (cpu, "R%i <<= R%i;", dst, src);
- SET_DREG (dst, lshift (cpu, DREG (dst), DREG (src), 32, 0));
+ SET_DREG (dst, lshift (cpu, DREG (dst), DREG (src), 32, 0, 0));
}
else if (opc == 3)
{
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_PTR2op);
TRACE_EXTRACT (cpu, "%s: opc:%i src:%i dst:%i", __func__, opc, src, dst);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if (opc == 0)
{
TRACE_INSN (cpu, "%s -= %s", dst_name, src_name);
if (opc == 0)
{
TRACE_INSN (cpu, "CC = ! BITTST (R%i, %s);", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG ((~DREG (dst) >> uimm) & 1);
}
else if (opc == 1)
{
TRACE_INSN (cpu, "CC = BITTST (R%i, %s);", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_CCREG ((DREG (dst) >> uimm) & 1);
}
else if (opc == 2)
{
TRACE_INSN (cpu, "BITSET (R%i, %s);", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (dst, DREG (dst) | (1 << uimm));
setflags_logical (cpu, DREG (dst));
else if (opc == 3)
{
TRACE_INSN (cpu, "BITTGL (R%i, %s);", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (dst, DREG (dst) ^ (1 << uimm));
setflags_logical (cpu, DREG (dst));
else if (opc == 4)
{
TRACE_INSN (cpu, "BITCLR (R%i, %s);", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (dst, DREG (dst) & ~(1 << uimm));
setflags_logical (cpu, DREG (dst));
else if (opc == 5)
{
TRACE_INSN (cpu, "R%i >>>= %s;", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (dst, ashiftrt (cpu, DREG (dst), uimm, 32));
}
else if (opc == 6)
{
TRACE_INSN (cpu, "R%i >>= %s;", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_DREG (dst, lshiftrt (cpu, DREG (dst), uimm, 32));
}
else if (opc == 7)
{
TRACE_INSN (cpu, "R%i <<= %s;", dst, uimm_str);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
- SET_DREG (dst, lshift (cpu, DREG (dst), uimm, 32, 0));
+ SET_DREG (dst, lshift (cpu, DREG (dst), uimm, 32, 0, 0));
}
}
TRACE_EXTRACT (cpu, "%s: opc:%i dst:%i src1:%i src0:%i",
__func__, opc, dst, src1, src0);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if (opc == 0)
{
TRACE_INSN (cpu, "R%i = R%i + R%i;", dst, src0, src1);
TRACE_EXTRACT (cpu, "%s: op:%i src:%i dst:%i", __func__, op, src, dst);
TRACE_DECODE (cpu, "%s: imm7:%#x", __func__, imm);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if (op == 0)
{
TRACE_INSN (cpu, "R%i = %s (X);", dst, imm7_str (imm));
TRACE_EXTRACT (cpu, "%s: op:%i src:%i dst:%i", __func__, op, src, dst);
TRACE_DECODE (cpu, "%s: imm:%#x", __func__, imm);
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
+ illegal_instruction_combination (cpu);
+
if (op == 0)
{
TRACE_INSN (cpu, "%s = %s;", dst_name, imm7_str (imm));
TRACE_EXTRACT (cpu, "%s: W:%i aop:%i reg:%i idx:%i ptr:%i",
__func__, W, aop, reg, idx, ptr);
+ if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_combination (cpu);
+
if (aop == 1 && W == 0 && idx == ptr)
{
TRACE_INSN (cpu, "R%i.L = W[%s];", reg, ptr_name);
STORE (PREG (ptr), addr + PREG (idx));
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_dagMODim);
TRACE_EXTRACT (cpu, "%s: br:%i op:%i m:%i i:%i", __func__, br, op, m, i);
+ if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_combination (cpu);
+
if (op == 0 && br == 1)
{
TRACE_INSN (cpu, "I%i += M%i (BREV);", i, m);
dagsub (cpu, i, MREG (m));
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
PROFILE_COUNT_INSN (cpu, pc, BFIN_INSN_dagMODik);
TRACE_EXTRACT (cpu, "%s: op:%i i:%i", __func__, op, i);
+ if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_combination (cpu);
+
if (op == 0)
{
TRACE_INSN (cpu, "I%i += 2;", i);
dagsub (cpu, i, 4);
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
PUT_LONG (addr, DREG (reg));
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
static void
int aop = ((iw0 >> LDST_aop_bits) & LDST_aop_mask);
int reg = ((iw0 >> LDST_reg_bits) & LDST_reg_mask);
int ptr = ((iw0 >> LDST_ptr_bits) & LDST_ptr_mask);
- const char * const posts[] = { "++", "--", "" };
+ const char * const posts[] = { "++", "--", "", "<INV>" };
const char *post = posts[aop];
const char *ptr_name = get_preg_name (ptr);
TRACE_EXTRACT (cpu, "%s: sz:%i W:%i aop:%i Z:%i ptr:%i reg:%i",
__func__, sz, W, aop, Z, ptr, reg);
- if (aop == 3)
- illegal_instruction (cpu);
+ if (aop == 3 || PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_or_combination (cpu);
if (W == 0)
{
SET_DREG (reg, (bs32) (bs8) GET_BYTE (PREG (ptr)));
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
else
{
PUT_BYTE (PREG (ptr), DREG (reg));
}
else
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
if (aop == 0)
W, offset, grp, reg);
TRACE_DECODE (cpu, "%s: negimm5s4:%#x", __func__, imm);
+ if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_or_combination (cpu);
+
if (W == 0)
{
TRACE_INSN (cpu, "%s = [FP + %s];", reg_name, imm_str);
TRACE_DECODE (cpu, "%s: uimm4s4/uimm4s2:%#x", __func__, imm);
+ if (PARALLEL_GROUP == BFIN_PARALLEL_GROUP2)
+ illegal_instruction_combination (cpu);
+
if (W == 1 && op == 2)
illegal_instruction (cpu);
if (reg > 7)
illegal_instruction (cpu);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
if (rop == 0)
TRACE_EXTRACT (cpu, "%s: Z:%i H:%i S:%i grp:%i reg:%i hword:%#x",
__func__, Z, H, S, grp, reg, hword);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
if (S == 1)
TRACE_INSN (cpu, "%s %#x;", S ? "CALL" : "JUMP.L", pcrel);
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
if (S == 1)
{
- TRACE_BRANCH (cpu, pc, newpc, -1, "CALL");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "CALL");
SET_RETSREG (hwloop_get_next_pc (cpu, pc, 4));
}
else
- TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.L");
+ BFIN_TRACE_BRANCH (cpu, pc, newpc, -1, "JUMP.L");
SET_PCREG (newpc);
BFIN_CPU_STATE.did_jump = true;
int size = uimm16s4 (framesize);
sp = SPREG;
TRACE_INSN (cpu, "LINK %s;", uimm16s4_str (framesize));
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
sp -= 4;
PUT_LONG (sp, RETSREG);
/* Restore SP from FP. */
sp = FPREG;
TRACE_INSN (cpu, "UNLINK;");
- if (INSN_LEN == 8)
+ if (PARALLEL_GROUP != BFIN_PARALLEL_NONE)
illegal_instruction_combination (cpu);
SET_FPREG (GET_LONG (sp));
sp += 4;
int h01 = ((iw1 >> DSP32Mac_h01_bits) & DSP32Mac_h01_mask);
bu32 res = DREG (dst);
- bu32 v_i = 0, zero = 0, n_1 = 0, n_0 = 0;
+ bu32 v_0 = 0, v_1 = 0, zero = 0, n_1 = 0, n_0 = 0;
static const char * const ops[] = { "=", "+=", "-=" };
char _buf[128], *buf = _buf;
if (w1 == 1 || op1 != 3)
{
bu32 res1 = decode_macfunc (cpu, 1, op1, h01, h11, src0,
- src1, mmod, MM, P, &v_i, &n_1);
+ src1, mmod, MM, P, &v_1, &n_1);
if (w1)
buf += sprintf (buf, P ? "R%i" : "R%i.H", dst + P);
res = REG_H_L (res1 << 16, res);
}
}
+ else
+ v_1 = 0;
if (w0 == 1 || op0 != 3)
{
if (w0 == 1 || op0 != 3)
{
bu32 res0 = decode_macfunc (cpu, 0, op0, h00, h10, src0,
- src1, mmod, 0, P, &v_i, &n_0);
+ src1, mmod, 0, P, &v_0, &n_0);
if (w0)
buf += sprintf (buf, P ? "R%i" : "R%i.L", dst);
res = REG_H_L (res, res0);
}
}
+ else
+ v_0 = 0;
}
TRACE_INSN (cpu, "%s%s;", _buf, mac_optmode (mmod, _MM));
if (!P && (w0 || w1))
{
STORE (DREG (dst), res);
- SET_ASTATREG (v, v_i);
- if (v_i)
- SET_ASTATREG (vs, v_i);
+ SET_ASTATREG (v, v_0 | v_1);
+ if (v_0 || v_1)
+ SET_ASTATREG (vs, 1);
}
else if (P)
{
- SET_ASTATREG (v, v_i);
- if (v_i)
- SET_ASTATREG (vs, v_i);
+ SET_ASTATREG (v, v_0 | v_1);
+ if (v_0 || v_1)
+ SET_ASTATREG (vs, 1);
}
if ((w0 == 1 && op0 == 3) || (w1 == 1 && op1 == 3))
"dst1:%i src0:%i src1:%i",
__func__, M, HL, aopcde, aop, s, x, dst0, dst1, src0, src1);
- if ((aop == 0 || aop == 2) && aopcde == 9 && HL == 0 && s == 0)
+ if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 0 && HL == 0)
{
int a = aop >> 1;
TRACE_INSN (cpu, "A%i.L = R%i.L;", a, src0);
SET_AWREG (a, REG_H_L (AWREG (a), DREG (src0)));
}
- else if ((aop == 0 || aop == 2) && aopcde == 9 && HL == 1 && s == 0)
+ else if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 0 && HL == 1)
{
int a = aop >> 1;
TRACE_INSN (cpu, "A%i.H = R%i.H;", a, src0);
SET_AWREG (a, REG_H_L (DREG (src0), AWREG (a)));
}
- else if ((aop == 1 || aop == 0) && aopcde == 5)
+ else if ((aop == 1 || aop == 0) && aopcde == 5 && x == 0 && s == 0)
{
bs32 val0 = DREG (src0);
bs32 val1 = DREG (src1);
/* If subtract, just invert and add one. */
if (aop & 0x1)
- val1 = ~val1 + 1;
+ {
+ if (val1 == 0x80000000)
+ val1 = 0x7FFFFFFF;
+ else
+ val1 = ~val1 + 1;
+ }
/* Get the sign bits, since we need them later. */
sBit1 = !!(val0 & 0x80000000);
if (ovX)
SET_ASTATREG (vs, ovX);
}
- else if ((aop == 2 || aop == 3) && aopcde == 5)
+ else if ((aop == 2 || aop == 3) && aopcde == 5 && x == 1 && s == 0)
{
bs32 val0 = DREG (src0);
bs32 val1 = DREG (src1);
SET_ASTATREG (an, res & 0x8000);
SET_ASTATREG (v, 0);
}
- else if (aopcde == 2 || aopcde == 3)
+ else if ((aopcde == 2 || aopcde == 3) && x == 0)
{
bu32 s1, s2, val, ac0_i = 0, v_i = 0;
SET_ASTATREG (ac0, ac0_i);
SET_ASTATREG (v, v_i);
+ if (v_i)
+ SET_ASTATREG (vs, v_i);
+
if (HL)
SET_DREG_H (dst0, val << 16);
else
SET_ASTATREG (an, val & 0x8000);
SET_ASTATREG (az, val == 0);
}
- else if ((aop == 0 || aop == 2) && aopcde == 9 && s == 1)
+ else if ((aop == 0 || aop == 2) && aopcde == 9 && x == 0 && s == 1 && HL == 0)
{
int a = aop >> 1;
TRACE_INSN (cpu, "A%i = R%i;", a, src0);
SET_AREG32 (a, DREG (src0));
}
- else if ((aop == 1 || aop == 3) && aopcde == 9 && s == 0)
+ else if ((aop == 1 || aop == 3) && aopcde == 9 && x == 0 && s == 0 && HL == 0)
{
int a = aop >> 1;
TRACE_INSN (cpu, "A%i.X = R%i.L;", a, src0);
SET_AXREG (a, (bs8)DREG (src0));
}
- else if (aop == 3 && aopcde == 11 && (s == 0 || s == 1))
+ else if (aop == 3 && aopcde == 11 && x == 0 && HL == 0)
{
bu64 acc0 = get_extended_acc (cpu, 0);
bu64 acc1 = get_extended_acc (cpu, 1);
if (sat)
STORE (ASTATREG (av0s), sat);
}
- else if ((aop == 0 || aop == 1) && aopcde == 22)
+ else if ((aop == 0 || aop == 1) && aopcde == 22 && x == 0)
{
bu32 s0, s0L, s0H, s1, s1L, s1H;
bu32 tmp0, tmp1, i;
src0 + 1, src0, src1 + 1, src1, opts[HL + (aop << 1)],
s ? ", r" : "");
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
s0L = DREG (src0);
s0H = DREG (src0 + 1);
s1L = DREG (src1);
((s0 >> 8) & 0xff) + ((s0 >> 0) & 0xff) + i) >> 2) & 0xff;
tmp1 = ((((s1 >> 24) & 0xff) + ((s1 >> 16) & 0xff) +
((s0 >> 24) & 0xff) + ((s0 >> 16) & 0xff) + i) >> 2) & 0xff;
- SET_DREG (dst0, (tmp1 << (16 + (HL * 8))) | (tmp0 << (HL * 8)));
+ STORE (DREG (dst0), (tmp1 << (16 + (HL * 8))) | (tmp0 << (HL * 8)));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if ((aop == 0 || aop == 1) && s == 0 && aopcde == 8)
+ else if ((aop == 0 || aop == 1) && aopcde == 8 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "A%i = 0;", aop);
SET_AREG (aop, 0);
}
- else if (aop == 2 && s == 0 && aopcde == 8)
+ else if (aop == 2 && aopcde == 8 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "A1 = A0 = 0;");
SET_AREG (0, 0);
SET_AREG (1, 0);
}
- else if ((aop == 0 || aop == 1 || aop == 2) && s == 1 && aopcde == 8)
+ else if ((aop == 0 || aop == 1 || aop == 2) && s == 1 && aopcde == 8
+ && x == 0 && HL == 0)
{
bs40 acc0 = get_extended_acc (cpu, 0);
bs40 acc1 = get_extended_acc (cpu, 1);
SET_ASTATREG (az, (acc0 == 0) || (acc1 == 0));
SET_ASTATREG (an, ((acc0 >> 31) & 1) || ((acc1 >> 31) & 1));
}
- else if (aop == 3 && (s == 0 || s == 1) && aopcde == 8)
+ else if (aop == 3 && aopcde == 8 && x == 0 && HL == 0)
{
TRACE_INSN (cpu, "A%i = A%i;", s, !s);
SET_AXREG (s, AXREG (!s));
SET_AWREG (s, AWREG (!s));
}
- else if (aop == 3 && HL == 0 && aopcde == 16)
+ else if (aop == 3 && HL == 0 && aopcde == 16 && x == 0 && s == 0)
{
int i;
bu32 az;
SET_ASTATREG (az, az);
SET_ASTATREG (an, 0);
}
- else if (aop == 0 && aopcde == 23)
+ else if (aop == 0 && aopcde == 23 && x == 0)
{
bu32 s0, s0L, s0H, s1, s1L, s1H;
bs32 tmp0, tmp1;
src0 + 1, src0, src1 + 1, src1, HL ? "HI" : "LO",
s ? ", R" : "");
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
s0L = DREG (src0);
s0H = DREG (src0 + 1);
s1L = DREG (src1);
tmp0 = (bs32)(bs16)(s0 >> 0) + ((s1 >> ( 0 + (8 * !HL))) & 0xff);
tmp1 = (bs32)(bs16)(s0 >> 16) + ((s1 >> (16 + (8 * !HL))) & 0xff);
- SET_DREG (dst0, (CLAMP (tmp0, 0, 255) << ( 0 + (8 * HL))) |
- (CLAMP (tmp1, 0, 255) << (16 + (8 * HL))));
+ STORE (DREG (dst0), (CLAMP (tmp0, 0, 255) << ( 0 + (8 * HL))) |
+ (CLAMP (tmp1, 0, 255) << (16 + (8 * HL))));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if ((aop == 0 || aop == 1) && aopcde == 16)
+ else if ((aop == 0 || aop == 1) && aopcde == 16 && x == 0 && s == 0)
{
bu32 av;
bs40 acc;
SET_ASTATREG (az, acc == 0);
SET_ASTATREG (an, 0);
}
- else if (aop == 3 && aopcde == 12)
+ else if (aop == 3 && aopcde == 12 && x == 0 && s == 0)
{
bs32 res = DREG (src0);
bs32 ovX;
if (ovX)
SET_ASTATREG (vs, ovX);
}
- else if (aop == 3 && HL == 0 && aopcde == 15)
+ else if (aop == 3 && HL == 0 && aopcde == 15 && x == 0 && s == 0)
{
bu32 hi = (-(bs16)(DREG (src0) >> 16)) << 16;
bu32 lo = (-(bs16)(DREG (src0) & 0xFFFF)) & 0xFFFF;
SET_ASTATREG (ac1, ac1);
setflags_nz_2x16 (cpu, DREG (dst0));
}
- else if (aop == 3 && HL == 0 && aopcde == 14)
+ else if (aop == 3 && HL == 0 && aopcde == 14 && x == 0 && s == 0)
{
TRACE_INSN (cpu, "A1 = - A1 , A0 = - A0;");
SET_AREG (1, saturate_s40 (-get_extended_acc (cpu, 1)));
/* XXX: what ASTAT flags need updating ? */
}
- else if ((aop == 0 || aop == 1) && (HL == 0 || HL == 1) && aopcde == 14)
+ else if ((aop == 0 || aop == 1) && aopcde == 14 && x == 0 && s == 0)
{
bs40 src_acc = get_extended_acc (cpu, aop);
- int v = 0;
+ bu32 v = 0;
TRACE_INSN (cpu, "A%i = - A%i;", HL, aop);
SET_ASTATREG (av1s, 1);
}
}
- else if (aop == 0 && aopcde == 12)
+ else if (aop == 0 && aopcde == 12 && x == 0 && s == 0 && HL == 0)
{
bs16 tmp0_hi = DREG (src0) >> 16;
bs16 tmp0_lo = DREG (src0);
STORE (DREG (dst0), REG_H_L (tmp1_hi << 16, tmp1_hi));
}
- else if (aopcde == 0)
+ else if (aopcde == 0 && HL == 0)
{
bu32 s0 = DREG (src0);
bu32 s1 = DREG (src1);
else
SET_DREG (dst0, (t0 << 16) | t1);
}
- else if (aop == 1 && aopcde == 12)
+ else if (aop == 1 && aopcde == 12 && x == 0 && s == 0 && HL == 0)
{
- bu32 val0 = ((AWREG (0) >> 16) + (AWREG (0) & 0xFFFF)) & 0xFFFF;
- bu32 val1 = ((AWREG (1) >> 16) + (AWREG (1) & 0xFFFF)) & 0xFFFF;
+ bs32 val0 = (bs16)(AWREG (0) >> 16) + (bs16)AWREG (0);
+ bs32 val1 = (bs16)(AWREG (1) >> 16) + (bs16)AWREG (1);
TRACE_INSN (cpu, "R%i = A1.L + A1.H, R%i = A0.L + A0.H;", dst1, dst0);
if (dst0 == dst1)
illegal_instruction_combination (cpu);
- if (val0 & 0x8000)
- val0 |= 0xFFFF0000;
-
- if (val1 & 0x8000)
- val1 |= 0xFFFF0000;
-
SET_DREG (dst0, val0);
SET_DREG (dst1, val1);
- /* XXX: ASTAT ? */
}
- else if (aopcde == 1)
+ else if ((aop == 0 || aop == 2 || aop == 3) && aopcde == 1)
{
bu32 d0, d1;
bu32 x0, x1;
STORE (DREG (dst0), d0);
STORE (DREG (dst1), d1);
}
- else if ((aop == 0 || aop == 1 || aop == 2) && aopcde == 11)
+ else if ((aop == 0 || aop == 1 || aop == 2) && aopcde == 11 && x == 0)
{
bs40 acc0 = get_extended_acc (cpu, 0);
bs40 acc1 = get_extended_acc (cpu, 1);
bu32 carry = !!((bu40)~acc1 < (bu40)acc0);
if (aop == 0)
- TRACE_INSN (cpu, "R%i = (A0 += A1);", dst0);
+ {
+ if (s != 0 || HL != 0)
+ illegal_instruction (cpu);
+ TRACE_INSN (cpu, "R%i = (A0 += A1);", dst0);
+ }
else if (aop == 1)
- TRACE_INSN (cpu, "R%i.%c = (A0 += A1);", dst0, HL ? 'H' : 'L');
+ {
+ if (s != 0)
+ illegal_instruction (cpu);
+ TRACE_INSN (cpu, "R%i.%c = (A0 += A1);", dst0, HL ? 'H' : 'L');
+ }
else
- TRACE_INSN (cpu, "A0 += A1%s;", s ? " (W32)" : "");
+ {
+ if (HL != 0)
+ illegal_instruction (cpu);
+ TRACE_INSN (cpu, "A0 += A1%s;", s ? " (W32)" : "");
+ }
acc0 += acc1;
acc0 = saturate_s40_astat (acc0, &v);
STORE (ASTATREG (ac0_copy), carry);
}
}
- else if ((aop == 0 || aop == 1) && aopcde == 10)
+ else if ((aop == 0 || aop == 1) && aopcde == 10 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i.L = A%i.X;", dst0, aop);
SET_DREG_L (dst0, (bs8)AXREG (aop));
}
- else if (aop == 0 && aopcde == 4)
+ else if (aop == 0 && aopcde == 4 && x == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = R%i + R%i%s;", dst0, src0, src1, amod1 (s, x));
SET_DREG (dst0, add32 (cpu, DREG (src0), DREG (src1), 1, s));
}
- else if (aop == 1 && aopcde == 4)
+ else if (aop == 1 && aopcde == 4 && x == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = R%i - R%i%s;", dst0, src0, src1, amod1 (s, x));
SET_DREG (dst0, sub32 (cpu, DREG (src0), DREG (src1), 1, s, 0));
}
- else if (aop == 2 && aopcde == 4)
+ else if (aop == 2 && aopcde == 4 && x == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = R%i + R%i, R%i = R%i - R%i%s;",
dst1, src0, src1, dst0, src0, src1, amod1 (s, x));
STORE (DREG (dst1), add32 (cpu, DREG (src0), DREG (src1), 1, s));
STORE (DREG (dst0), sub32 (cpu, DREG (src0), DREG (src1), 1, s, 1));
}
- else if ((aop == 0 || aop == 1) && aopcde == 17)
+ else if ((aop == 0 || aop == 1) && aopcde == 17 && x == 0 && HL == 0)
{
bs40 acc0 = get_extended_acc (cpu, 0);
bs40 acc1 = get_extended_acc (cpu, 1);
else
SET_ASTATREG (ac0, !!((bu40)acc0 <= (bu40)acc1));
}
- else if (aop == 0 && aopcde == 18)
+ else if (aop == 0 && aopcde == 18 && x == 0 && HL == 0)
{
bu40 acc0 = get_extended_acc (cpu, 0);
bu40 acc1 = get_extended_acc (cpu, 1);
STORE (AXREG (0), 0);
STORE (AWREG (1), (s1H << 16) | (s1L & 0xFFFF));
STORE (AXREG (1), 0);
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aop == 3 && aopcde == 18)
+ else if (aop == 3 && aopcde == 18 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "DISALGNEXCPT");
DIS_ALGN_EXPT |= 1;
}
- else if ((aop == 0 || aop == 1) && aopcde == 20)
+ else if ((aop == 0 || aop == 1) && aopcde == 20 && x == 0 && HL == 0)
{
bu32 s0, s0L, s0H, s1, s1L, s1H;
const char * const opts[] = { "", " (R)", " (T)", " (T, R)" };
TRACE_INSN (cpu, "R%i = BYTEOP1P (R%i:%i, R%i:%i)%s;", dst0,
src0 + 1, src0, src1 + 1, src1, opts[s + (aop << 1)]);
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
s0L = DREG (src0);
s0H = DREG (src0 + 1);
s1L = DREG (src1);
s1 = algn (s1L, s1H, IREG (1) & 3);
}
- SET_DREG (dst0,
+ STORE (DREG (dst0),
(((((s0 >> 0) & 0xff) + ((s1 >> 0) & 0xff) + !aop) >> 1) << 0) |
(((((s0 >> 8) & 0xff) + ((s1 >> 8) & 0xff) + !aop) >> 1) << 8) |
(((((s0 >> 16) & 0xff) + ((s1 >> 16) & 0xff) + !aop) >> 1) << 16) |
(((((s0 >> 24) & 0xff) + ((s1 >> 24) & 0xff) + !aop) >> 1) << 24));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aop == 0 && aopcde == 21)
+ else if (aop == 0 && aopcde == 21 && x == 0 && HL == 0)
{
bu32 s0, s0L, s0H, s1, s1L, s1H;
TRACE_INSN (cpu, "(R%i, R%i) = BYTEOP16P (R%i:%i, R%i:%i)%s;", dst1, dst0,
src0 + 1, src0, src1 + 1, src1, s ? " (R)" : "");
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
if (dst0 == dst1)
illegal_instruction_combination (cpu);
s1 = algn (s1L, s1H, IREG (1) & 3);
}
- SET_DREG (dst0,
+ STORE (DREG (dst0),
((((s0 >> 0) & 0xff) + ((s1 >> 0) & 0xff)) << 0) |
((((s0 >> 8) & 0xff) + ((s1 >> 8) & 0xff)) << 16));
- SET_DREG (dst1,
+ STORE (DREG (dst1),
((((s0 >> 16) & 0xff) + ((s1 >> 16) & 0xff)) << 0) |
((((s0 >> 24) & 0xff) + ((s1 >> 24) & 0xff)) << 16));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aop == 1 && aopcde == 21)
+ else if (aop == 1 && aopcde == 21 && x == 0 && HL == 0)
{
bu32 s0, s0L, s0H, s1, s1L, s1H;
TRACE_INSN (cpu, "(R%i, R%i) = BYTEOP16M (R%i:%i, R%i:%i)%s;", dst1, dst0,
src0 + 1, src0, src1 + 1, src1, s ? " (R)" : "");
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
if (dst0 == dst1)
illegal_instruction_combination (cpu);
s1 = algn (s1L, s1H, IREG (1) & 3);
}
- SET_DREG (dst0,
+ STORE (DREG (dst0),
(((((s0 >> 0) & 0xff) - ((s1 >> 0) & 0xff)) << 0) & 0xffff) |
(((((s0 >> 8) & 0xff) - ((s1 >> 8) & 0xff)) << 16)));
- SET_DREG (dst1,
+ STORE (DREG (dst1),
(((((s0 >> 16) & 0xff) - ((s1 >> 16) & 0xff)) << 0) & 0xffff) |
(((((s0 >> 24) & 0xff) - ((s1 >> 24) & 0xff)) << 16)));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aop == 1 && aopcde == 7)
+ else if (aop == 1 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = MIN (R%i, R%i);", dst0, src0, src1);
SET_DREG (dst0, min32 (cpu, DREG (src0), DREG (src1)));
}
- else if (aop == 0 && aopcde == 7)
+ else if (aop == 0 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = MAX (R%i, R%i);", dst0, src0, src1);
SET_DREG (dst0, max32 (cpu, DREG (src0), DREG (src1)));
}
- else if (aop == 2 && aopcde == 7)
+ else if (aop == 2 && aopcde == 7 && x == 0 && s == 0 && HL == 0)
{
bu32 val = DREG (src0);
int v;
SET_ASTATREG (vs, 1);
setflags_nz (cpu, val);
}
- else if (aop == 3 && aopcde == 7)
+ else if (aop == 3 && aopcde == 7 && x == 0 && HL == 0)
{
bu32 val = DREG (src0);
- TRACE_INSN (cpu, "R%i = - R%i %s;", dst0, src0, amod1 (s, 0));
+ TRACE_INSN (cpu, "R%i = - R%i%s;", dst0, src0, amod1 (s, 0));
if (s && val == 0x80000000)
{
SET_ASTATREG (az, val == 0);
SET_ASTATREG (an, val & 0x80000000);
}
- else if (aop == 2 && aopcde == 6)
+ else if (aop == 2 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
{
bu32 in = DREG (src0);
bu32 hi = (in & 0x80000000 ? (bu32)-(bs16)(in >> 16) : in >> 16) << 16;
SET_ASTATREG (vs, 1);
setflags_nz_2x16 (cpu, DREG (dst0));
}
- else if (aop == 1 && aopcde == 6)
+ else if (aop == 1 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = MIN (R%i, R%i) (V);", dst0, src0, src1);
SET_DREG (dst0, min2x16 (cpu, DREG (src0), DREG (src1)));
}
- else if (aop == 0 && aopcde == 6)
+ else if (aop == 0 && aopcde == 6 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = MAX (R%i, R%i) (V);", dst0, src0, src1);
SET_DREG (dst0, max2x16 (cpu, DREG (src0), DREG (src1)));
}
- else if (aop == 0 && aopcde == 24)
+ else if (aop == 0 && aopcde == 24 && x == 0 && s == 0 && HL == 0)
{
TRACE_INSN (cpu, "R%i = BYTEPACK (R%i, R%i);", dst0, src0, src1);
- SET_DREG (dst0,
+ STORE (DREG (dst0),
(((DREG (src0) >> 0) & 0xff) << 0) |
(((DREG (src0) >> 16) & 0xff) << 8) |
(((DREG (src1) >> 0) & 0xff) << 16) |
(((DREG (src1) >> 16) & 0xff) << 24));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aop == 1 && aopcde == 24)
+ else if (aop == 1 && aopcde == 24 && x == 0 && HL == 0)
{
int order, lo, hi;
bu64 comb_src;
TRACE_INSN (cpu, "(R%i, R%i) = BYTEUNPACK R%i:%i%s;",
dst1, dst0, src0 + 1, src0, s ? " (R)" : "");
+ if ((src1 != 0 && src1 != 2) || (src0 != 0 && src0 != 2))
+ illegal_instruction (cpu);
+
if (dst0 == dst1)
illegal_instruction_combination (cpu);
byteb = (comb_src >> (8 + 8 * order));
bytec = (comb_src >> (16 + 8 * order));
byted = (comb_src >> (24 + 8 * order));
- SET_DREG (dst0, bytea | ((bu32)byteb << 16));
- SET_DREG (dst1, bytec | ((bu32)byted << 16));
+ STORE (DREG (dst0), bytea | ((bu32)byteb << 16));
+ STORE (DREG (dst1), bytec | ((bu32)byted << 16));
+
+ /* Implicit DISALGNEXCPT in parallel. */
+ DIS_ALGN_EXPT |= 1;
}
- else if (aopcde == 13)
+ else if (aopcde == 13 && HL == 0 && x == 0 && s == 0)
{
const char *searchmodes[] = { "GT", "GE", "LT", "LE" };
bool up_hi, up_lo;
TRACE_INSN (cpu, "(R%i, R%i) = SEARCH R%i (%s);",
dst1, dst0, src0, searchmodes[aop]);
+ /* XXX: The parallel version is a bit weird in its limits:
+
+ This instruction can be issued in parallel with the combination of one
+ 16-bit length load instruction to the P0 register and one 16-bit NOP.
+ No other instructions can be issued in parallel with the Vector Search
+ instruction. Note the following legal and illegal forms.
+ (r1, r0) = search r2 (LT) || r2 = [p0++p3]; // ILLEGAL
+ (r1, r0) = search r2 (LT) || r2 = [p0++]; // LEGAL
+ (r1, r0) = search r2 (LT) || r2 = [p0++]; // LEGAL
+
+ Unfortunately, our parallel insn state doesn't (currently) track enough
+ details to be able to check this. */
+
if (dst0 == dst1)
illegal_instruction_combination (cpu);
if (shft <= 0)
val = ashiftrt (cpu, val, -shft, 16);
else
- val = lshift (cpu, val, shft, 16, sop == 1);
+ {
+ int sgn = (val >> 15) & 0x1;
+
+ val = lshift (cpu, val, shft, 16, sop == 1, 1);
+ if (((val >> 15) & 0x1) != sgn)
+ {
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ }
if ((HLs & 2) == 0)
STORE (DREG (dst0), REG_H_L (DREG (dst0), val));
else if (sop == 0 && sopcde == 3 && (HLs == 0 || HLs == 1))
{
bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
- bu64 val = get_extended_acc (cpu, HLs);
+ bu64 acc = get_extended_acc (cpu, HLs);
+ bu64 val;
HLs = !!HLs;
TRACE_INSN (cpu, "A%i = ASHIFT A%i BY R%i.L;", HLs, HLs, src0);
- TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, val, shft);
+ TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, acc, shft);
if (shft <= 0)
- val = ashiftrt (cpu, val, -shft, 40);
+ val = ashiftrt (cpu, acc, -shft, 40);
else
- val = lshift (cpu, val, shft, 40, 0);
+ val = lshift (cpu, acc, shft, 40, 0, 0);
STORE (AXREG (HLs), (val >> 32) & 0xff);
STORE (AWREG (HLs), (val & 0xffffffff));
+ STORE (ASTATREG (av[HLs]), 0);
}
else if (sop == 1 && sopcde == 3 && (HLs == 0 || HLs == 1))
{
bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
+ bu64 acc = get_unextended_acc (cpu, HLs);
bu64 val;
HLs = !!HLs;
TRACE_INSN (cpu, "A%i = LSHIFT A%i BY R%i.L;", HLs, HLs, src0);
- val = get_extended_acc (cpu, HLs);
+ TRACE_DECODE (cpu, "A%i:%#"PRIx64" shift:%i", HLs, acc, shft);
if (shft <= 0)
- val = lshiftrt (cpu, val, -shft, 40);
+ val = lshiftrt (cpu, acc, -shft, 40);
else
- val = lshift (cpu, val, shft, 40, 0);
+ val = lshift (cpu, acc, shft, 40, 0, 0);
STORE (AXREG (HLs), (val >> 32) & 0xff);
STORE (AWREG (HLs), (val & 0xffffffff));
+ STORE (ASTATREG (av[HLs]), 0);
}
- else if ((sop == 0 || sop == 1) && sopcde == 1)
+ else if (HLs != 0)
+ /* All the insns after this point don't use HLs. */
+ illegal_instruction (cpu);
+ else if ((sop == 0 || sop == 1) && sopcde == 1 && HLs == 0)
{
bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
bu16 val0, val1;
}
else
{
- val0 = lshift (cpu, val0, shft, 16, sop == 1);
+ int sgn0 = (val0 >> 15) & 0x1;
+ int sgn1 = (val1 >> 15) & 0x1;
+
+ val0 = lshift (cpu, val0, shft, 16, sop == 1, 1);
astat = ASTAT;
- val1 = lshift (cpu, val1, shft, 16, sop == 1);
+ val1 = lshift (cpu, val1, shft, 16, sop == 1, 1);
+
+ if ((sgn0 != ((val0 >> 15) & 0x1)) || (sgn1 != ((val1 >> 15) & 0x1)))
+ {
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
}
SET_ASTAT (ASTAT | astat);
STORE (DREG (dst0), (val1 << 16) | val0);
STORE (DREG (dst0), ashiftrt (cpu, v, -shft, 32));
}
else
- STORE (DREG (dst0), lshift (cpu, v, shft, 32, sop == 1));
+ {
+ bu32 val = lshift (cpu, v, shft, 32, sop == 1, 1);
+
+ STORE (DREG (dst0), val);
+ if (((v >> 31) & 0x1) != ((val >> 31) & 0x1))
+ {
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ }
}
else if (sop == 3 && sopcde == 2)
{
if (shift)
SET_CCREG (cc);
}
- else if (sop == 2 && sopcde == 1)
+ else if (sop == 2 && sopcde == 1 && HLs == 0)
{
bs32 shft = (bs8)(DREG (src0) << 2) >> 2;
bu16 val0, val1;
}
else
{
- val0 = lshift (cpu, val0, shft, 16, 0);
+ val0 = lshift (cpu, val0, shft, 16, 0, 0);
astat = ASTAT;
- val1 = lshift (cpu, val1, shft, 16, 0);
+ val1 = lshift (cpu, val1, shft, 16, 0, 0);
}
SET_ASTAT (ASTAT | astat);
STORE (DREG (dst0), (val1 << 16) | val0);
sv0 >>= 16;
if (sop & 2)
sv1 >>= 16;
- SET_DREG (dst0, (sv1 << 16) | (sv0 & 0xFFFF));
+ STORE (DREG (dst0), (sv1 << 16) | (sv0 & 0xFFFF));
}
else if (sop == 0 && sopcde == 5)
{
acc = (acc >> 2) |
(((bu64)s0 & 1) << 38) |
(((bu64)s1 & 1) << 39);
- SET_DREG (src0, s0 >> 1);
- SET_DREG (src1, s1 >> 1);
+ STORE (DREG (src0), s0 >> 1);
+ STORE (DREG (src1), s1 >> 1);
SET_AREG (0, acc);
}
acc = (acc << 2) |
((s0 >> 31) & 1) |
((s1 >> 30) & 2);
- SET_DREG (src0, s0 << 1);
- SET_DREG (src1, s1 << 1);
+ STORE (DREG (src0), s0 << 1);
+ STORE (DREG (src1), s1 << 1);
SET_AREG (0, acc);
}
out = sL;
SET_AREG (0, acc0);
- SET_DREG (dst0, REG_H_L (DREG (dst0), out));
+ STORE (DREG (dst0), REG_H_L (DREG (dst0), out));
}
else if ((sop == 2 || sop == 3) && sopcde == 9)
{
out1 = s1L;
SET_AREG (0, acc0);
- SET_DREG (dst0, REG_H_L (out1 << 16, out0));
+ STORE (DREG (dst0), REG_H_L (out1 << 16, out0));
}
else if (sop == 0 && sopcde == 10)
{
bu32 v = DREG (src0);
bu32 x = DREG (src1);
bu32 mask = (1 << (v & 0x1f)) - 1;
+
TRACE_INSN (cpu, "R%i = EXTRACT (R%i, R%i.L) (Z);", dst0, src1, src0);
+
x >>= ((v >> 8) & 0x1f);
- SET_DREG (dst0, x & mask);
- setflags_logical (cpu, DREG (dst0));
+ x &= mask;
+ STORE (DREG (dst0), x);
+ setflags_logical (cpu, x);
}
else if (sop == 1 && sopcde == 10)
{
bu32 x = DREG (src1);
bu32 sgn = (1 << (v & 0x1f)) >> 1;
bu32 mask = (1 << (v & 0x1f)) - 1;
+
TRACE_INSN (cpu, "R%i = EXTRACT (R%i, R%i.L) (X);", dst0, src1, src0);
+
x >>= ((v >> 8) & 0x1f);
x &= mask;
if (x & sgn)
x |= ~mask;
- SET_DREG (dst0, x);
- setflags_logical (cpu, DREG (dst0));
+ STORE (DREG (dst0), x);
+ setflags_logical (cpu, x);
}
else if ((sop == 2 || sop == 3) && sopcde == 10)
{
bu32 fg = DREG (src0);
bu32 bg = DREG (src1);
bu32 len = fg & 0x1f;
- bu32 mask = (1 << MIN (16, len)) - 1;
+ bu32 mask = (1 << min (16, len)) - 1;
bu32 fgnd = (fg >> 16) & mask;
int shft = ((fg >> 8) & 0x1f);
mask <<= shft;
bg &= ~mask;
- SET_DREG (dst0, bg | fgnd);
- setflags_logical (cpu, DREG (dst0));
+ bg |= fgnd;
+ STORE (DREG (dst0), bg);
+ setflags_logical (cpu, bg);
}
else if (sop == 0 && sopcde == 11)
{
{
int shift = (sop + 1) * 8;
TRACE_INSN (cpu, "R%i = ALIGN%i (R%i, R%i);", dst0, shift, src1, src0);
- SET_DREG (dst0, (DREG (src1) << (32 - shift)) | (DREG (src0) >> shift));
+ STORE (DREG (dst0), (DREG (src1) << (32 - shift)) | (DREG (src0) >> shift));
}
else
illegal_instruction (cpu);
}
+static bu64
+sgn_extend (bu40 org, bu40 val, int size)
+{
+ bu64 ret = val;
+
+ if (org & (1ULL << (size - 1)))
+ {
+ /* We need to shift in to the MSB which is set. */
+ int n;
+
+ for (n = 40; n >= 0; n--)
+ if (ret & (1ULL << n))
+ break;
+ ret |= (-1ULL << n);
+ }
+ else
+ ret &= ~(-1ULL << 39);
+
+ return ret;
+}
static void
decode_dsp32shiftimm_0 (SIM_CPU *cpu, bu16 iw0, bu16 iw1)
{
TRACE_INSN (cpu, "R%i.%c = R%i.%c >>> %i;",
dst0, (HLs & 2) ? 'H' : 'L',
src1, (HLs & 1) ? 'H' : 'L', newimmag);
- result = ashiftrt (cpu, in, newimmag, 16);
+ if (newimmag > 16)
+ {
+ result = lshift (cpu, in, 16 - (newimmag & 0xF), 16, 0, 1);
+ if (((result >> 15) & 0x1) != ((in >> 15) & 0x1))
+ {
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ }
+ else
+ result = ashiftrt (cpu, in, newimmag, 16);
}
else if (sop == 1 && bit8 == 0)
{
TRACE_INSN (cpu, "R%i.%c = R%i.%c << %i (S);",
dst0, (HLs & 2) ? 'H' : 'L',
src1, (HLs & 1) ? 'H' : 'L', immag);
- result = lshift (cpu, in, immag, 16, 1);
+ result = lshift (cpu, in, immag, 16, 1, 1);
}
else if (sop == 1 && bit8)
{
TRACE_INSN (cpu, "R%i.%c = R%i.%c >>> %i (S);",
dst0, (HLs & 2) ? 'H' : 'L',
- src1, (HLs & 1) ? 'H' : 'L', immag);
- result = lshift (cpu, in, immag, 16, 1);
+ src1, (HLs & 1) ? 'H' : 'L', newimmag);
+ if (newimmag > 16)
+ {
+ int shift = 32 - newimmag;
+ bu16 inshift = in << shift;
+
+ if (((inshift & ~0xFFFF)
+ && ((inshift & ~0xFFFF) >> 16) != ~(~0 << shift))
+ || (inshift & 0x8000) != (in & 0x8000))
+ {
+ if (in & 0x8000)
+ result = 0x8000;
+ else
+ result = 0x7fff;
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ else
+ {
+ result = inshift;
+ SET_ASTATREG (v, 0);
+ }
+
+ SET_ASTATREG (az, !result);
+ SET_ASTATREG (an, !!(result & 0x8000));
+ }
+ else
+ {
+ result = ashiftrt (cpu, in, newimmag, 16);
+ result = sgn_extend (in, result, 16);
+ }
}
else if (sop == 2 && bit8)
{
TRACE_INSN (cpu, "R%i.%c = R%i.%c << %i;",
dst0, (HLs & 2) ? 'H' : 'L',
src1, (HLs & 1) ? 'H' : 'L', immag);
- result = lshift (cpu, in, immag, 16, 0);
+ result = lshift (cpu, in, immag, 16, 0, 1);
}
else
illegal_instruction (cpu);
if (shift)
SET_CCREG (cc);
}
- else if (sop == 0 && sopcde == 3 && bit8 == 1)
+ else if (sop == 0 && sopcde == 3 && bit8 == 1 && HLs < 2)
{
/* Arithmetic shift, so shift in sign bit copies. */
- bu64 acc;
+ bu64 acc, val;
int shift = uimm5 (newimmag);
- HLs = !!HLs;
TRACE_INSN (cpu, "A%i = A%i >>> %i;", HLs, HLs, shift);
acc = get_extended_acc (cpu, HLs);
- acc >>= shift;
+ val = acc >> shift;
+
/* Sign extend again. */
- if (acc & (1ULL << 39))
- acc |= -(1ULL << 39);
- else
- acc &= ~(-(1ULL << 39));
+ val = sgn_extend (acc, val, 40);
- STORE (AXREG (HLs), (acc >> 32) & 0xFF);
- STORE (AWREG (HLs), acc & 0xFFFFFFFF);
+ STORE (AXREG (HLs), (val >> 32) & 0xFF);
+ STORE (AWREG (HLs), val & 0xFFFFFFFF);
+ STORE (ASTATREG (an), !!(val & (1ULL << 39)));
+ STORE (ASTATREG (az), !val);
+ STORE (ASTATREG (av[HLs]), 0);
}
- else if ((sop == 0 && sopcde == 3 && bit8 == 0)
- || (sop == 1 && sopcde == 3))
+ else if (((sop == 0 && sopcde == 3 && bit8 == 0)
+ || (sop == 1 && sopcde == 3)) && HLs < 2)
{
bu64 acc;
int shiftup = uimm5 (immag);
int shiftdn = uimm5 (newimmag);
- HLs = !!HLs;
TRACE_INSN (cpu, "A%i = A%i %s %i;", HLs, HLs,
sop == 0 ? "<<" : ">>",
if (sop == 0)
acc <<= shiftup;
else
- acc >>= shiftdn;
+ {
+ if (shiftdn <= 32)
+ acc >>= shiftdn;
+ else
+ acc <<= 32 - (shiftdn & 0x1f);
+ }
SET_AREG (HLs, acc);
+ SET_ASTATREG (av[HLs], 0);
SET_ASTATREG (an, !!(acc & 0x8000000000ull));
- SET_ASTATREG (az, acc == 0);
+ SET_ASTATREG (az, (acc & 0xFFFFFFFFFF) == 0);
}
+ else if (HLs != 0)
+ /* All the insns after this point don't use HLs. */
+ illegal_instruction (cpu);
else if (sop == 1 && sopcde == 1 && bit8 == 0)
{
int count = imm5 (immag);
bu32 astat;
TRACE_INSN (cpu, "R%i = R%i << %i (V,S);", dst0, src1, count);
- val0 = lshift (cpu, val0, count, 16, 1);
- astat = ASTAT;
- val1 = lshift (cpu, val1, count, 16, 1);
+ if (count >= 0)
+ {
+ val0 = lshift (cpu, val0, count, 16, 1, 1);
+ astat = ASTAT;
+ val1 = lshift (cpu, val1, count, 16, 1, 1);
+ }
+ else
+ {
+ val0 = ashiftrt (cpu, val0, -count, 16);
+ astat = ASTAT;
+ val1 = ashiftrt (cpu, val1, -count, 16);
+ }
SET_ASTAT (ASTAT | astat);
STORE (DREG (dst0), (val0 << 16) | val1);
bu32 astat;
TRACE_INSN (cpu, "R%i = R%i << %i (V);", dst0, src1, count);
- val0 = lshift (cpu, val0, count, 16, 0);
+ val0 = lshift (cpu, val0, count, 16, 0, 1);
astat = ASTAT;
- val1 = lshift (cpu, val1, count, 16, 0);
+ val1 = lshift (cpu, val1, count, 16, 0, 1);
SET_ASTAT (ASTAT | astat);
STORE (DREG (dst0), val0 | (val1 << 16));
TRACE_INSN (cpu, "R%i = R%i >>> %i %s;", dst0, src1, count,
sop == 0 ? "(V)" : "(V,S)");
- val0 = ashiftrt (cpu, val0, count, 16);
- astat = ASTAT;
- val1 = ashiftrt (cpu, val1, count, 16);
+ if (count > 16)
+ {
+ int sgn0 = (val0 >> 15) & 0x1;
+ int sgn1 = (val1 >> 15) & 0x1;
+
+ val0 = lshift (cpu, val0, 16 - (count & 0xF), 16, 0, 1);
+ astat = ASTAT;
+ val1 = lshift (cpu, val1, 16 - (count & 0xF), 16, 0, 1);
+
+ if ((sgn0 != ((val0 >> 15) & 0x1)) || (sgn1 != ((val1 >> 15) & 0x1)))
+ {
+ SET_ASTATREG (v, 1);
+ SET_ASTATREG (vs, 1);
+ }
+ }
+ else
+ {
+ val0 = ashiftrt (cpu, val0, count, 16);
+ astat = ASTAT;
+ val1 = ashiftrt (cpu, val1, count, 16);
+ }
+
SET_ASTAT (ASTAT | astat);
STORE (DREG (dst0), REG_H_L (val1 << 16, val0));
int count = imm6 (immag);
TRACE_INSN (cpu, "R%i = R%i << %i (S);", dst0, src1, count);
- STORE (DREG (dst0), lshift (cpu, DREG (src1), count, 32, 1));
+
+ if (count < 0)
+ STORE (DREG (dst0), ashiftrt (cpu, DREG (src1), -count, 32));
+ else
+ STORE (DREG (dst0), lshift (cpu, DREG (src1), count, 32, 1, 1));
}
else if (sop == 2 && sopcde == 2)
{
TRACE_INSN (cpu, "R%i = R%i >> %i;", dst0, src1, count);
if (count < 0)
- STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0));
+ STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0, 1));
else
STORE (DREG (dst0), lshiftrt (cpu, DREG (src1), count, 32));
}
TRACE_INSN (cpu, "R%i = R%i >>> %i;", dst0, src1, count);
if (count < 0)
- STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0));
+ STORE (DREG (dst0), lshift (cpu, DREG (src1), -count, 32, 0, 1));
else
STORE (DREG (dst0), ashiftrt (cpu, DREG (src1), count, 32));
}
else
{
TRACE_EXTRACT (cpu, "%s: no matching 16-bit pattern", __func__);
- illegal_instruction (cpu);
+ illegal_instruction_or_combination (cpu);
}
return insn_len;
}
trace_prefix (sd, cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu),
NULL, 0, "|| %#"PRIx64, sim_events_time (sd));
insn_len = 8;
+ PARALLEL_GROUP = BFIN_PARALLEL_GROUP0;
}
else
insn_len = 4;
/* Only cache on first run through (in case of parallel insns). */
if (INSN_LEN == 0)
INSN_LEN = insn_len;
+ else
+ /* Once you're past the first slot, only 16bit insns are valid. */
+ illegal_instruction_combination (cpu);
if ((iw0 & 0xf7ff) == 0xc003 && (iw1 & 0xfe00) == 0x1800)
{
bu32 insn_len;
BFIN_CPU_STATE.n_stores = 0;
+ PARALLEL_GROUP = BFIN_PARALLEL_NONE;
DIS_ALGN_EXPT &= ~1;
CYCLE_DELAY = 1;
INSN_LEN = 0;
/* Proper display of multiple issue instructions. */
if (insn_len == 8)
{
+ PARALLEL_GROUP = BFIN_PARALLEL_GROUP1;
_interp_insn_bfin (cpu, pc + 4);
+ PARALLEL_GROUP = BFIN_PARALLEL_GROUP2;
_interp_insn_bfin (cpu, pc + 6);
}
for (i = 0; i < BFIN_CPU_STATE.n_stores; i++)