+/* V850E2R FPU functions */
+/*
+ sim_fpu_status_invalid_snan = 1, -V--- (sim spec.)
+ sim_fpu_status_invalid_qnan = 2, ----- (sim spec.)
+ sim_fpu_status_invalid_isi = 4, (inf - inf) -V---
+ sim_fpu_status_invalid_idi = 8, (inf / inf) -V---
+ sim_fpu_status_invalid_zdz = 16, (0 / 0) -V---
+ sim_fpu_status_invalid_imz = 32, (inf * 0) -V---
+ sim_fpu_status_invalid_cvi = 64, convert to integer -V---
+ sim_fpu_status_invalid_div0 = 128, (X / 0) --Z--
+ sim_fpu_status_invalid_cmp = 256, compare ----- (sim spec.)
+ sim_fpu_status_invalid_sqrt = 512, -V---
+ sim_fpu_status_rounded = 1024, I----
+ sim_fpu_status_inexact = 2048, I---- (sim spec.)
+ sim_fpu_status_overflow = 4096, I--O-
+ sim_fpu_status_underflow = 8192, I---U
+ sim_fpu_status_denorm = 16384, ----U (sim spec.)
+*/
+
+void
+update_fpsr (SIM_DESC sd, sim_fpu_status status, unsigned int mask, unsigned int double_op_p)
+{
+ unsigned int fpsr = FPSR & mask;
+
+ unsigned int flags = 0;
+
+ if (fpsr & FPSR_XEI
+ && ((status & (sim_fpu_status_rounded
+ | sim_fpu_status_overflow
+ | sim_fpu_status_inexact))
+ || (status & sim_fpu_status_underflow
+ && (fpsr & (FPSR_XEU | FPSR_XEI)) == 0
+ && fpsr & FPSR_FS)))
+ {
+ flags |= FPSR_XCI | FPSR_XPI;
+ }
+
+ if (fpsr & FPSR_XEV
+ && (status & (sim_fpu_status_invalid_isi
+ | sim_fpu_status_invalid_imz
+ | sim_fpu_status_invalid_zdz
+ | sim_fpu_status_invalid_idi
+ | sim_fpu_status_invalid_cvi
+ | sim_fpu_status_invalid_sqrt
+ | sim_fpu_status_invalid_snan)))
+ {
+ flags |= FPSR_XCV | FPSR_XPV;
+ }
+
+ if (fpsr & FPSR_XEZ
+ && (status & sim_fpu_status_invalid_div0))
+ {
+ flags |= FPSR_XCV | FPSR_XPV;
+ }
+
+ if (fpsr & FPSR_XEO
+ && (status & sim_fpu_status_overflow))
+ {
+ flags |= FPSR_XCO | FPSR_XPO;
+ }
+
+ if (((fpsr & FPSR_XEU) || (fpsr & FPSR_FS) == 0)
+ && (status & (sim_fpu_status_underflow
+ | sim_fpu_status_denorm)))
+ {
+ flags |= FPSR_XCU | FPSR_XPU;
+ }
+
+ if (flags)
+ {
+ FPSR &= ~FPSR_XC;
+ FPSR |= flags;
+
+ SignalExceptionFPE (sd, double_op_p);
+ }
+}
+
+/* Exception. */
+
+void
+SignalException (SIM_DESC sd)
+{
+ if (MPM & MPM_AUE)
+ {
+ PSW = PSW & ~(PSW_NPV | PSW_DMP | PSW_IMP);
+ }
+}
+
+void
+SignalExceptionFPE (SIM_DESC sd, unsigned int double_op_p)
+{
+ if (((PSW & (PSW_NP|PSW_ID)) == 0)
+ || !(FPSR & (double_op_p ? FPSR_DEM : FPSR_SEM)))
+ {
+ EIPC = PC;
+ EIPSW = PSW;
+ EIIC = (FPSR & (double_op_p ? FPSR_DEM : FPSR_SEM))
+ ? 0x71 : 0x72;
+ PSW |= (PSW_EP | PSW_ID);
+ PC = 0x70;
+
+ SignalException (sd);
+ }
+}
+
+void
+check_invalid_snan (SIM_DESC sd, sim_fpu_status status, unsigned int double_op_p)
+{
+ if ((FPSR & FPSR_XEI)
+ && (status & sim_fpu_status_invalid_snan))
+ {
+ FPSR &= ~FPSR_XC;
+ FPSR |= FPSR_XCV;
+ FPSR |= FPSR_XPV;
+ SignalExceptionFPE (sd, double_op_p);
+ }
+}
+
+int
+v850_float_compare (SIM_DESC sd, int cmp, sim_fpu wop1, sim_fpu wop2, int double_op_p)
+{
+ int result = -1;
+
+ if (sim_fpu_is_nan (&wop1) || sim_fpu_is_nan (&wop2))
+ {
+ if (cmp & 0x8)
+ {
+ if (FPSR & FPSR_XEV)
+ {
+ FPSR |= FPSR_XCV | FPSR_XPV;
+ SignalExceptionFPE (sd, double_op_p);
+ }
+ }
+
+ switch (cmp)
+ {
+ case FPU_CMP_F:
+ result = 0;
+ break;
+ case FPU_CMP_UN:
+ result = 1;
+ break;
+ case FPU_CMP_EQ:
+ result = 0;
+ break;
+ case FPU_CMP_UEQ:
+ result = 1;
+ break;
+ case FPU_CMP_OLT:
+ result = 0;
+ break;
+ case FPU_CMP_ULT:
+ result = 1;
+ break;
+ case FPU_CMP_OLE:
+ result = 0;
+ break;
+ case FPU_CMP_ULE:
+ result = 1;
+ break;
+ case FPU_CMP_SF:
+ result = 0;
+ break;
+ case FPU_CMP_NGLE:
+ result = 1;
+ break;
+ case FPU_CMP_SEQ:
+ result = 0;
+ break;
+ case FPU_CMP_NGL:
+ result = 1;
+ break;
+ case FPU_CMP_LT:
+ result = 0;
+ break;
+ case FPU_CMP_NGE:
+ result = 1;
+ break;
+ case FPU_CMP_LE:
+ result = 0;
+ break;
+ case FPU_CMP_NGT:
+ result = 1;
+ break;
+ default:
+ abort ();
+ }
+ }
+ else if (sim_fpu_is_infinity (&wop1) && sim_fpu_is_infinity (&wop2)
+ && sim_fpu_sign (&wop1) == sim_fpu_sign (&wop2))
+ {
+ switch (cmp)
+ {
+ case FPU_CMP_F:
+ result = 0;
+ break;
+ case FPU_CMP_UN:
+ result = 0;
+ break;
+ case FPU_CMP_EQ:
+ result = 1;
+ break;
+ case FPU_CMP_UEQ:
+ result = 1;
+ break;
+ case FPU_CMP_OLT:
+ result = 0;
+ break;
+ case FPU_CMP_ULT:
+ result = 0;
+ break;
+ case FPU_CMP_OLE:
+ result = 1;
+ break;
+ case FPU_CMP_ULE:
+ result = 1;
+ break;
+ case FPU_CMP_SF:
+ result = 0;
+ break;
+ case FPU_CMP_NGLE:
+ result = 0;
+ break;
+ case FPU_CMP_SEQ:
+ result = 1;
+ break;
+ case FPU_CMP_NGL:
+ result = 1;
+ break;
+ case FPU_CMP_LT:
+ result = 0;
+ break;
+ case FPU_CMP_NGE:
+ result = 0;
+ break;
+ case FPU_CMP_LE:
+ result = 1;
+ break;
+ case FPU_CMP_NGT:
+ result = 1;
+ break;
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ int gt = 0,lt = 0,eq = 0, status;
+
+ status = sim_fpu_cmp (&wop1, &wop2);
+
+ switch (status)
+ {
+ case SIM_FPU_IS_SNAN:
+ case SIM_FPU_IS_QNAN:
+ abort ();
+ break;
+
+ case SIM_FPU_IS_NINF:
+ lt = 1;
+ break;
+ case SIM_FPU_IS_PINF:
+ gt = 1;
+ break;
+ case SIM_FPU_IS_NNUMBER:
+ lt = 1;
+ break;
+ case SIM_FPU_IS_PNUMBER:
+ gt = 1;
+ break;
+ case SIM_FPU_IS_NDENORM:
+ lt = 1;
+ break;
+ case SIM_FPU_IS_PDENORM:
+ gt = 1;
+ break;
+ case SIM_FPU_IS_NZERO:
+ case SIM_FPU_IS_PZERO:
+ eq = 1;
+ break;
+ }
+
+ switch (cmp)
+ {
+ case FPU_CMP_F:
+ result = 0;
+ break;
+ case FPU_CMP_UN:
+ result = 0;
+ break;
+ case FPU_CMP_EQ:
+ result = eq;
+ break;
+ case FPU_CMP_UEQ:
+ result = eq;
+ break;
+ case FPU_CMP_OLT:
+ result = lt;
+ break;
+ case FPU_CMP_ULT:
+ result = lt;
+ break;
+ case FPU_CMP_OLE:
+ result = lt || eq;
+ break;
+ case FPU_CMP_ULE:
+ result = lt || eq;
+ break;
+ case FPU_CMP_SF:
+ result = 0;
+ break;
+ case FPU_CMP_NGLE:
+ result = 0;
+ break;
+ case FPU_CMP_SEQ:
+ result = eq;
+ break;
+ case FPU_CMP_NGL:
+ result = eq;
+ break;
+ case FPU_CMP_LT:
+ result = lt;
+ break;
+ case FPU_CMP_NGE:
+ result = lt;
+ break;
+ case FPU_CMP_LE:
+ result = lt || eq;
+ break;
+ case FPU_CMP_NGT:
+ result = lt || eq;
+ break;
+ }
+ }
+
+ ASSERT (result != -1);
+ return result;
+}
+
+void
+v850_div (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p, unsigned int *op3p)
+{
+ signed long int quotient;
+ signed long int remainder;
+ signed long int divide_by;
+ signed long int divide_this;
+ bfd_boolean overflow = FALSE;
+
+ /* Compute the result. */
+ divide_by = op0;
+ divide_this = op1;
+
+ if (divide_by == 0 || (divide_by == -1 && divide_this == (1 << 31)))
+ {
+ overflow = TRUE;
+ divide_by = 1;
+ }
+
+ quotient = divide_this / divide_by;
+ remainder = divide_this % divide_by;
+
+ /* Set condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV);
+
+ if (overflow) PSW |= PSW_OV;
+ if (quotient == 0) PSW |= PSW_Z;
+ if (quotient < 0) PSW |= PSW_S;
+
+ *op2p = quotient;
+ *op3p = remainder;
+}
+
+void
+v850_divu (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p, unsigned int *op3p)
+{
+ unsigned long int quotient;
+ unsigned long int remainder;
+ unsigned long int divide_by;
+ unsigned long int divide_this;
+ bfd_boolean overflow = FALSE;
+
+ /* Compute the result. */
+
+ divide_by = op0;
+ divide_this = op1;
+
+ if (divide_by == 0)
+ {
+ overflow = TRUE;
+ divide_by = 1;
+ }
+
+ quotient = divide_this / divide_by;
+ remainder = divide_this % divide_by;
+
+ /* Set condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV);
+
+ if (overflow) PSW |= PSW_OV;
+ if (quotient == 0) PSW |= PSW_Z;
+ if (quotient & 0x80000000) PSW |= PSW_S;
+
+ *op2p = quotient;
+ *op3p = remainder;
+}
+
+void
+v850_sar (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p)
+{
+ unsigned int result, z, s, cy;
+
+ op0 &= 0x1f;
+ result = (signed)op1 >> op0;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = (op1 & (1 << (op0 - 1)));
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV | PSW_CY);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0));
+
+ *op2p = result;
+}
+
+void
+v850_shl (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p)
+{
+ unsigned int result, z, s, cy;
+
+ op0 &= 0x1f;
+ result = op1 << op0;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = (op1 & (1 << (32 - op0)));
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV | PSW_CY);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0));
+
+ *op2p = result;
+}
+
+void
+v850_rotl (SIM_DESC sd, unsigned int amount, unsigned int src, unsigned int * dest)
+{
+ unsigned int result, z, s, cy;
+
+ amount &= 0x1f;
+ result = src << amount;
+ result |= src >> (32 - amount);
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = ! (result & 1);
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV | PSW_CY);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0));
+
+ * dest = result;
+}
+
+void
+v850_bins (SIM_DESC sd, unsigned int source, unsigned int lsb, unsigned int msb,
+ unsigned int * dest)
+{
+ unsigned int mask;
+ unsigned int result, pos, width;
+ unsigned int z, s;
+
+ pos = lsb;
+ width = (msb - lsb) + 1;
+
+ mask = ~ (-(1 << width));
+ source &= mask;
+ mask <<= pos;
+ result = (* dest) & ~ mask;
+ result |= source << pos;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = result & 0x80000000;
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV );
+ PSW |= (z ? PSW_Z : 0) | (s ? PSW_S : 0);
+
+ * dest = result;
+}
+
+void
+v850_shr (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p)
+{
+ unsigned int result, z, s, cy;
+
+ op0 &= 0x1f;
+ result = op1 >> op0;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = (op1 & (1 << (op0 - 1)));
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_OV | PSW_CY);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0));
+
+ *op2p = result;
+}
+
+void
+v850_satadd (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p)
+{
+ unsigned int result, z, s, cy, ov, sat;
+
+ result = op0 + op1;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = (result < op0 || result < op1);
+ ov = ((op0 & 0x80000000) == (op1 & 0x80000000)
+ && (op0 & 0x80000000) != (result & 0x80000000));
+ sat = ov;
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_CY | PSW_OV);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0) | (ov ? PSW_OV : 0)
+ | (sat ? PSW_SAT : 0));
+
+ /* Handle saturated results. */
+ if (sat && s)
+ {
+ result = 0x7fffffff;
+ PSW &= ~PSW_S;
+ }
+ else if (sat)
+ {
+ result = 0x80000000;
+ PSW |= PSW_S;
+ }
+
+ *op2p = result;
+}
+
+void
+v850_satsub (SIM_DESC sd, unsigned int op0, unsigned int op1, unsigned int *op2p)
+{
+ unsigned int result, z, s, cy, ov, sat;
+
+ /* Compute the result. */
+ result = op1 - op0;
+
+ /* Compute the condition codes. */
+ z = (result == 0);
+ s = (result & 0x80000000);
+ cy = (op1 < op0);
+ ov = ((op1 & 0x80000000) != (op0 & 0x80000000)
+ && (op1 & 0x80000000) != (result & 0x80000000));
+ sat = ov;
+
+ /* Store the result and condition codes. */
+ PSW &= ~(PSW_Z | PSW_S | PSW_CY | PSW_OV);
+ PSW |= ((z ? PSW_Z : 0) | (s ? PSW_S : 0)
+ | (cy ? PSW_CY : 0) | (ov ? PSW_OV : 0)
+ | (sat ? PSW_SAT : 0));
+
+ /* Handle saturated results. */
+ if (sat && s)
+ {
+ result = 0x7fffffff;
+ PSW &= ~PSW_S;
+ }
+ else if (sat)
+ {
+ result = 0x80000000;
+ PSW |= PSW_S;
+ }
+
+ *op2p = result;
+}
+
+unsigned32
+load_data_mem (SIM_DESC sd,
+ SIM_ADDR addr,
+ int len)
+{
+ uint32 data;
+
+ switch (len)
+ {
+ case 1:
+ data = sim_core_read_unaligned_1 (STATE_CPU (sd, 0),
+ PC, read_map, addr);
+ break;
+ case 2:
+ data = sim_core_read_unaligned_2 (STATE_CPU (sd, 0),
+ PC, read_map, addr);
+ break;
+ case 4:
+ data = sim_core_read_unaligned_4 (STATE_CPU (sd, 0),
+ PC, read_map, addr);
+ break;
+ default:
+ abort ();
+ }
+ return data;
+}
+
+void
+store_data_mem (SIM_DESC sd,
+ SIM_ADDR addr,
+ int len,
+ unsigned32 data)
+{
+ switch (len)
+ {
+ case 1:
+ store_mem (addr, 1, data);
+ break;
+ case 2:
+ store_mem (addr, 2, data);
+ break;
+ case 4:
+ store_mem (addr, 4, data);
+ break;
+ default:
+ abort ();
+ }
+}
+
+int
+mpu_load_mem_test (SIM_DESC sd, unsigned int addr, int size, int base_reg)
+{
+ int result = 1;
+
+ if (PSW & PSW_DMP)
+ {
+ if (IPE0 && addr >= IPA2ADDR (IPA0L) && addr <= IPA2ADDR (IPA0L) && IPR0)
+ {
+ /* text area */
+ }
+ else if (IPE1 && addr >= IPA2ADDR (IPA1L) && addr <= IPA2ADDR (IPA1L) && IPR1)
+ {
+ /* text area */
+ }
+ else if (IPE2 && addr >= IPA2ADDR (IPA2L) && addr <= IPA2ADDR (IPA2L) && IPR2)
+ {
+ /* text area */
+ }
+ else if (IPE3 && addr >= IPA2ADDR (IPA3L) && addr <= IPA2ADDR (IPA3L) && IPR3)
+ {
+ /* text area */
+ }
+ else if (addr >= PPA2ADDR (PPA & ~PPM) && addr <= DPA2ADDR (PPA | PPM))
+ {
+ /* preifarallel area */
+ }
+ else if (addr >= PPA2ADDR (SPAL) && addr <= DPA2ADDR (SPAU))
+ {
+ /* stack area */
+ }
+ else if (DPE0 && addr >= DPA2ADDR (DPA0L) && addr <= DPA2ADDR (DPA0L) && DPR0
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE1 && addr >= DPA2ADDR (DPA1L) && addr <= DPA2ADDR (DPA1L) && DPR1
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE2 && addr >= DPA2ADDR (DPA2L) && addr <= DPA2ADDR (DPA2L) && DPR2
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE3 && addr >= DPA2ADDR (DPA3L) && addr <= DPA2ADDR (DPA3L) && DPR3
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else
+ {
+ VMECR &= ~(VMECR_VMW | VMECR_VMX);
+ VMECR |= VMECR_VMR;
+ VMADR = addr;
+ VMTID = TID;
+ FEIC = 0x431;
+
+ PC = 0x30;
+
+ SignalException (sd);
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+int
+mpu_store_mem_test (SIM_DESC sd, unsigned int addr, int size, int base_reg)
+{
+ int result = 1;
+
+ if (PSW & PSW_DMP)
+ {
+ if (addr >= PPA2ADDR (PPA & ~PPM) && addr <= DPA2ADDR (PPA | PPM))
+ {
+ /* preifarallel area */
+ }
+ else if (addr >= PPA2ADDR (SPAL) && addr <= DPA2ADDR (SPAU))
+ {
+ /* stack area */
+ }
+ else if (DPE0 && addr >= DPA2ADDR (DPA0L) && addr <= DPA2ADDR (DPA0L) && DPW0
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE1 && addr >= DPA2ADDR (DPA1L) && addr <= DPA2ADDR (DPA1L) && DPW1
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE2 && addr >= DPA2ADDR (DPA2L) && addr <= DPA2ADDR (DPA2L) && DPW2
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else if (DPE3 && addr >= DPA2ADDR (DPA3L) && addr <= DPA2ADDR (DPA3L) && DPW3
+ && ((SPAL & SPAL_SPS) ? base_reg == SP_REGNO : 1))
+ {
+ /* data area */
+ }
+ else
+ {
+ if (addr >= PPA2ADDR (PPA & ~PPM) && addr <= DPA2ADDR (PPA | PPM))
+ {
+ FEIC = 0x432;
+ VPTID = TID;
+ VPADR = PC;
+#ifdef NOT_YET
+ VIP_PP;
+ VPECR;
+#endif
+ }
+ else
+ {
+ FEIC = 0x431;
+ VMTID = TID;
+ VMADR = VMECR;
+ VMECR &= ~(VMECR_VMW | VMECR_VMX);
+ VMECR |= VMECR_VMR;
+ PC = 0x30;
+ }
+ result = 0;
+ }
+ }
+
+ return result;
+}
+