#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
#include "d10v_sim.h"
#include "simops.h"
OP_CONSTANT4,
OP_MEMREF,
OP_MEMREF2,
+ OP_MEMREF3,
OP_POSTDEC,
OP_POSTINC,
OP_PREDEC,
PSW_MASK = (PSW_SM_BIT
| PSW_EA_BIT
| PSW_DB_BIT
- | PSW_DM_BIT
| PSW_IE_BIT
| PSW_RP_BIT
| PSW_MD_BIT
| PSW_F0_BIT
| PSW_F1_BIT
| PSW_C_BIT),
+ /* The following bits in the PSW _can't_ be set by instructions such
+ as mvtc. */
+ PSW_HW_MASK = (PSW_MASK | PSW_DM_BIT)
};
reg_t
-move_to_cr (int cr, reg_t mask, reg_t val)
+move_to_cr (int cr, reg_t mask, reg_t val, int psw_hw_p)
{
/* A MASK bit is set when the corresponding bit in the CR should
be left alone */
switch (cr)
{
case PSW_CR:
- val &= PSW_MASK;
+ if (psw_hw_p)
+ val &= PSW_HW_MASK;
+ else
+ val &= PSW_MASK;
if ((mask & PSW_SM_BIT) == 0)
{
- int new_sm = (val & PSW_SM_BIT) != 0;
- SET_HELD_SP (PSW_SM, GPR (SP_IDX)); /* save old SP */
- if (PSW_SM != new_sm)
- SET_GPR (SP_IDX, HELD_SP (new_sm)); /* restore new SP */
+ int new_psw_sm = (val & PSW_SM_BIT) != 0;
+ /* save old SP */
+ SET_HELD_SP (PSW_SM, GPR (SP_IDX));
+ if (PSW_SM != new_psw_sm)
+ /* restore new SP */
+ SET_GPR (SP_IDX, HELD_SP (new_psw_sm));
}
if ((mask & (PSW_ST_BIT | PSW_FX_BIT)) == 0)
{
break;
case BPSW_CR:
case DPSW_CR:
- val &= PSW_MASK;
+ /* Just like PSW, mask things like DM out. */
+ if (psw_hw_p)
+ val &= PSW_HW_MASK;
+ else
+ val &= PSW_MASK;
break;
case MOD_S_CR:
case MOD_E_CR:
filename = (const char *)0;
functionname = (const char *)0;
linenumber = 0;
- if (bfd_find_nearest_line (prog_bfd, text, (struct symbol_cache_entry **)0, byte_pc - text_start,
+ if (bfd_find_nearest_line (prog_bfd, text, (struct bfd_symbol **)0, byte_pc - text_start,
&filename, &functionname, &linenumber))
{
p = buf;
comma = ",";
break;
+ case OP_MEMREF3:
+ sprintf (p, "%s@%d", comma, OP[i]);
+ p += strlen (p);
+ comma = ",";
+ break;
+
case OP_POSTINC:
sprintf (p, "%s@r%d+", comma, OP[i]);
p += strlen (p);
(uint16) GPR (OP[i]));
break;
+ case OP_MEMREF3:
+ (*d10v_callback->printf_filtered) (d10v_callback, "%*s0x%.4x", SIZE_VALUES-6, "", (uint16) OP[i]);
+ break;
+
case OP_DREG:
tmp = (long)((((uint32) GPR (OP[i])) << 16) | ((uint32) GPR (OP[i] + 1)));
(*d10v_callback->printf_filtered) (d10v_callback, "%*s0x%.8lx", SIZE_VALUES-10, "", tmp);
trace_output_flag ();
}
+/* cpfg */
+void
+OP_4E0F ()
+{
+ uint8 val;
+
+ trace_input ("cpfg", OP_FLAG_OUTPUT, OP_FLAG, OP_VOID);
+
+ if (OP[1] == 0)
+ val = PSW_F0;
+ else if (OP[1] == 1)
+ val = PSW_F1;
+ else
+ val = PSW_C;
+ if (OP[0] == 0)
+ SET_PSW_F0 (val);
+ else
+ SET_PSW_F1 (val);
+
+ trace_output_flag ();
+}
+
/* dbt */
void
OP_5F20 ()
trace_input ("dbt", OP_VOID, OP_VOID, OP_VOID);
SET_DPC (PC + 1);
SET_DPSW (PSW);
- SET_PSW (PSW_DM_BIT | (PSW & (PSW_F0_BIT | PSW_F1_BIT | PSW_C_BIT)));
+ SET_HW_PSW (PSW_DM_BIT | (PSW & (PSW_F0_BIT | PSW_F1_BIT | PSW_C_BIT)));
JMP (DBT_VECTOR_START);
trace_output_void ();
}
OP_30000000 ()
{
uint16 tmp;
+ uint16 addr = OP[1] + GPR (OP[2]);
trace_input ("ld", OP_REG_OUTPUT, OP_MEMREF2, OP_VOID);
- tmp = RW (OP[1] + GPR (OP[2]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RW (addr);
SET_GPR (OP[0], tmp);
trace_output_16 (tmp);
}
OP_6401 ()
{
uint16 tmp;
+ uint16 addr = GPR (OP[1]);
trace_input ("ld", OP_REG_OUTPUT, OP_POSTDEC, OP_VOID);
- tmp = RW (GPR (OP[1]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RW (addr);
SET_GPR (OP[0], tmp);
if (OP[0] != OP[1])
INC_ADDR (OP[1], -2);
OP_6001 ()
{
uint16 tmp;
+ uint16 addr = GPR (OP[1]);
trace_input ("ld", OP_REG_OUTPUT, OP_POSTINC, OP_VOID);
- tmp = RW (GPR (OP[1]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RW (addr);
SET_GPR (OP[0], tmp);
if (OP[0] != OP[1])
INC_ADDR (OP[1], 2);
OP_6000 ()
{
uint16 tmp;
+ uint16 addr = GPR (OP[1]);
trace_input ("ld", OP_REG_OUTPUT, OP_MEMREF, OP_VOID);
- tmp = RW (GPR (OP[1]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RW (addr);
+ SET_GPR (OP[0], tmp);
+ trace_output_16 (tmp);
+}
+
+/* ld */
+void
+OP_32010000 ()
+{
+ uint16 tmp;
+ uint16 addr = OP[1];
+ trace_input ("ld", OP_REG_OUTPUT, OP_MEMREF3, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RW (addr);
SET_GPR (OP[0], tmp);
trace_output_16 (tmp);
}
OP_31000000 ()
{
int32 tmp;
- uint16 addr = GPR (OP[2]);
+ uint16 addr = OP[1] + GPR (OP[2]);
trace_input ("ld2w", OP_REG_OUTPUT, OP_MEMREF2, OP_VOID);
- tmp = RLW (OP[1] + addr);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RLW (addr);
SET_GPR32 (OP[0], tmp);
trace_output_32 (tmp);
}
uint16 addr = GPR (OP[1]);
int32 tmp;
trace_input ("ld2w", OP_REG_OUTPUT, OP_POSTDEC, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
tmp = RLW (addr);
SET_GPR32 (OP[0], tmp);
- INC_ADDR (OP[1], -4);
+ if (OP[0] != OP[1] && ((OP[0] + 1) != OP[1]))
+ INC_ADDR (OP[1], -4);
trace_output_32 (tmp);
}
int32 tmp;
uint16 addr = GPR (OP[1]);
trace_input ("ld2w", OP_REG_OUTPUT, OP_POSTINC, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
tmp = RLW (addr);
SET_GPR32 (OP[0], tmp);
- INC_ADDR (OP[1], 4);
+ if (OP[0] != OP[1] && ((OP[0] + 1) != OP[1]))
+ INC_ADDR (OP[1], 4);
trace_output_32 (tmp);
}
uint16 addr = GPR (OP[1]);
int32 tmp;
trace_input ("ld2w", OP_REG_OUTPUT, OP_MEMREF, OP_VOID);
- tmp = RLW (addr + 0);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RLW (addr);
+ SET_GPR32 (OP[0], tmp);
+ trace_output_32 (tmp);
+}
+
+/* ld2w */
+void
+OP_33010000 ()
+{
+ int32 tmp;
+ uint16 addr = OP[1];
+ trace_input ("ld2w", OP_REG_OUTPUT, OP_MEMREF3, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ tmp = RLW (addr);
SET_GPR32 (OP[0], tmp);
trace_output_32 (tmp);
}
OP_4400 ()
{
int16 tmp;
- trace_input ("mf0f", OP_REG_OUTPUT, OP_REG, OP_VOID);
+ trace_input ("mvf0f", OP_REG_OUTPUT, OP_REG, OP_VOID);
if (PSW_F0 == 0)
{
tmp = GPR (OP[1]);
OP_4401 ()
{
int16 tmp;
- trace_input ("mf0t", OP_REG_OUTPUT, OP_REG, OP_VOID);
+ trace_input ("mvf0t", OP_REG_OUTPUT, OP_REG, OP_VOID);
if (PSW_F0)
{
tmp = GPR (OP[1]);
trace_output_void ();
}
+/* sac */
+void OP_5209 ()
+{
+ int64 tmp;
+
+ trace_input ("sac", OP_REG_OUTPUT, OP_ACCUM, OP_VOID);
+
+ tmp = SEXT40(ACC (OP[1]));
+
+ SET_PSW_F1 (PSW_F0);
+
+ if (tmp > SEXT40(MAX32))
+ {
+ tmp = (MAX32);
+ SET_PSW_F0 (1);
+ }
+ else if (tmp < SEXT40(MIN32))
+ {
+ tmp = 0x80000000;
+ SET_PSW_F0 (1);
+ }
+ else
+ {
+ tmp = (tmp & MASK32);
+ SET_PSW_F0 (0);
+ }
+
+ SET_GPR32 (OP[0], tmp);
+
+ trace_output_40 (tmp);
+}
+
+/* sachi */
+void
+OP_4209 ()
+{
+ int64 tmp;
+
+ trace_input ("sachi", OP_REG_OUTPUT, OP_ACCUM, OP_VOID);
+
+ tmp = SEXT40(ACC (OP[1]));
+
+ SET_PSW_F1 (PSW_F0);
+
+ if (tmp > SEXT40(MAX32))
+ {
+ tmp = 0x7fff;
+ SET_PSW_F0 (1);
+ }
+ else if (tmp < SEXT40(MIN32))
+ {
+ tmp = 0x8000;
+ SET_PSW_F0 (1);
+ }
+ else
+ {
+ tmp >>= 16;
+ SET_PSW_F0 (0);
+ }
+
+ SET_GPR (OP[0], tmp);
+
+ trace_output_16 (OP[0]);
+}
+
/* sadd */
void
OP_1223 ()
trace_output_16 (tmp);
}
+/* slae */
+void
+OP_3220 ()
+{
+ int64 tmp;
+ int16 reg;
+
+ trace_input ("slae", OP_ACCUM, OP_REG, OP_VOID);
+
+ reg = SEXT16 (GPR (OP[1]));
+
+ if (reg >= 17 || reg <= -17)
+ {
+ (*d10v_callback->printf_filtered) (d10v_callback, "ERROR: shift value %d too large.\n", reg);
+ State.exception = SIGILL;
+ return;
+ }
+
+ tmp = SEXT40 (ACC (OP[0]));
+
+ if (PSW_ST && (tmp < SEXT40 (MIN32) || tmp > SEXT40 (MAX32)))
+ {
+ (*d10v_callback->printf_filtered) (d10v_callback, "ERROR: accumulator value 0x%.2x%.8lx out of range\n", ((int)(tmp >> 32) & 0xff), ((unsigned long) tmp) & 0xffffffff);
+ State.exception = SIGILL;
+ return;
+ }
+
+ if (reg >= 0 && reg <= 16)
+ {
+ tmp = SEXT56 ((SEXT56 (tmp)) << (GPR (OP[1])));
+ if (PSW_ST)
+ {
+ if (tmp > SEXT40(MAX32))
+ tmp = (MAX32);
+ else if (tmp < SEXT40(MIN32))
+ tmp = (MIN32);
+ else
+ tmp = (tmp & MASK40);
+ }
+ else
+ tmp = (tmp & MASK40);
+ }
+ else
+ {
+ tmp = (SEXT40 (ACC (OP[0]))) >> (-GPR (OP[1]));
+ }
+
+ SET_ACC(OP[0], tmp);
+
+ trace_output_40(tmp);
+}
+
/* sleep */
void
OP_5FC0 ()
OP_460B ()
{
int16 tmp;
- trace_input ("slx", OP_REG, OP_FLAG, OP_VOID);
+ trace_input ("slx", OP_REG, OP_VOID, OP_VOID);
tmp = ((GPR (OP[0]) << 1) | PSW_F0);
SET_GPR (OP[0], tmp);
trace_output_16 (tmp);
OP_4609 ()
{
uint16 tmp;
- trace_input ("srx", OP_REG, OP_FLAG, OP_VOID);
+ trace_input ("srx", OP_REG, OP_VOID, OP_VOID);
tmp = PSW_F0 << 15;
tmp = ((GPR (OP[0]) >> 1) | tmp);
SET_GPR (OP[0], tmp);
void
OP_34000000 ()
{
+ uint16 addr = OP[1] + GPR (OP[2]);
trace_input ("st", OP_REG, OP_MEMREF2, OP_VOID);
- SW (OP[1] + GPR (OP[2]), GPR (OP[0]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr, GPR (OP[0]));
trace_output_void ();
}
void
OP_6800 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st", OP_REG, OP_MEMREF, OP_VOID);
- SW (GPR (OP[1]), GPR (OP[0]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr, GPR (OP[0]));
trace_output_void ();
}
/* st */
+/* st Rsrc1,@-SP */
void
OP_6C1F ()
{
State.exception = SIGILL;
return;
}
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
SW (addr, GPR (OP[0]));
SET_GPR (OP[1], addr);
trace_output_void ();
void
OP_6801 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st", OP_REG, OP_POSTINC, OP_VOID);
- SW (GPR (OP[1]), GPR (OP[0]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr, GPR (OP[0]));
INC_ADDR (OP[1], 2);
trace_output_void ();
}
void
OP_6C01 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st", OP_REG, OP_POSTDEC, OP_VOID);
if ( OP[1] == 15 )
{
State.exception = SIGILL;
return;
}
- SW (GPR (OP[1]), GPR (OP[0]));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr, GPR (OP[0]));
INC_ADDR (OP[1], -2);
trace_output_void ();
}
+/* st */
+void
+OP_36010000 ()
+{
+ uint16 addr = OP[1];
+ trace_input ("st", OP_REG, OP_MEMREF3, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr, GPR (OP[0]));
+ trace_output_void ();
+}
+
/* st2w */
void
OP_35000000 ()
{
+ uint16 addr = GPR (OP[2])+ OP[1];
trace_input ("st2w", OP_DREG, OP_MEMREF2, OP_VOID);
- SW (GPR (OP[2])+ OP[1] + 0, GPR (OP[0] + 0));
- SW (GPR (OP[2])+ OP[1] + 2, GPR (OP[0] + 1));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr + 0, GPR (OP[0] + 0));
+ SW (addr + 2, GPR (OP[0] + 1));
trace_output_void ();
}
void
OP_6A00 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st2w", OP_DREG, OP_MEMREF, OP_VOID);
- SW (GPR (OP[1]) + 0, GPR (OP[0] + 0));
- SW (GPR (OP[1]) + 2, GPR (OP[0] + 1));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr + 0, GPR (OP[0] + 0));
+ SW (addr + 2, GPR (OP[0] + 1));
trace_output_void ();
}
State.exception = SIGILL;
return;
}
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
SW (addr + 0, GPR (OP[0] + 0));
SW (addr + 2, GPR (OP[0] + 1));
SET_GPR (OP[1], addr);
void
OP_6A01 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st2w", OP_DREG, OP_POSTINC, OP_VOID);
- SW (GPR (OP[1]) + 0, GPR (OP[0] + 0));
- SW (GPR (OP[1]) + 2, GPR (OP[0] + 1));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr + 0, GPR (OP[0] + 0));
+ SW (addr + 2, GPR (OP[0] + 1));
INC_ADDR (OP[1], 4);
trace_output_void ();
}
void
OP_6E01 ()
{
+ uint16 addr = GPR (OP[1]);
trace_input ("st2w", OP_DREG, OP_POSTDEC, OP_VOID);
if ( OP[1] == 15 )
{
State.exception = SIGILL;
return;
}
- SW (GPR (OP[1]) + 0, GPR (OP[0] + 0));
- SW (GPR (OP[1]) + 2, GPR (OP[0] + 1));
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr + 0, GPR (OP[0] + 0));
+ SW (addr + 2, GPR (OP[0] + 1));
INC_ADDR (OP[1], -4);
trace_output_void ();
}
+/* st2w */
+void
+OP_37010000 ()
+{
+ uint16 addr = OP[1];
+ trace_input ("st2w", OP_DREG, OP_MEMREF3, OP_VOID);
+ if ((addr & 1))
+ {
+ State.exception = SIG_D10V_BUS;
+ State.pc_changed = 1; /* Don't increment the PC. */
+ trace_output_void ();
+ return;
+ }
+ SW (addr + 0, GPR (OP[0] + 0));
+ SW (addr + 2, GPR (OP[0] + 1));
+ trace_output_void ();
+}
+
/* stb */
void
OP_3C000000 ()
trace_output_void ();
break;
+#ifdef TARGET_SYS_stat
case TARGET_SYS_stat:
trace_input ("<stat>", OP_R0, OP_R1, OP_VOID);
/* stat system call */
}
trace_output_16 (result);
break;
+#endif
case TARGET_SYS_chown:
trace_input ("<chown>", OP_R0, OP_R1, OP_R2);
SET_GPR (OP[0], tmp);
trace_output_16 (tmp);
}
-