Ver código fonte

waterDataStatisticsCrossAssociation memoryOperation.c 朱涛 commit at 2021-04-25

朱涛 4 anos atrás
pai
commit
6e85bb9ae9

+ 144 - 0
waterDataStatisticsCrossAssociation/dataSharedMemory/memoryOperation.c

@@ -1058,3 +1058,147 @@ static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
 	if (tm & VFP_DENORMAL)
 		vfp_double_normalise_denormal(&vdm);
 
+	/*
+	 * Ok, we have two numbers, we can perform division.
+	 */
+	vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
+	vdm.significand <<= 1;
+	if (vdm.significand <= (2 * vdn.significand)) {
+		vdn.significand >>= 1;
+		vdd.exponent++;
+	}
+	vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
+	if ((vdd.significand & 0x1ff) <= 2) {
+		u64 termh, terml, remh, reml;
+		mul64to128(&termh, &terml, vdm.significand, vdd.significand);
+		sub128(&remh, &reml, vdn.significand, 0, termh, terml);
+		while ((s64)remh < 0) {
+			vdd.significand -= 1;
+			add128(&remh, &reml, remh, reml, 0, vdm.significand);
+		}
+		vdd.significand |= (reml != 0);
+	}
+	return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fdiv");
+
+ vdn_nan:
+	exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
+ pack:
+	vfp_put_double(vfp_double_pack(&vdd), dd);
+	return exceptions;
+
+ vdm_nan:
+	exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
+	goto pack;
+
+ zero:
+	vdd.exponent = 0;
+	vdd.significand = 0;
+	goto pack;
+
+ divzero:
+	exceptions = FPSCR_DZC;
+ infinity:
+	vdd.exponent = 2047;
+	vdd.significand = 0;
+	goto pack;
+
+ invalid:
+	vfp_put_double(vfp_double_pack(&vfp_double_default_qnan), dd);
+	return FPSCR_IOC;
+}
+
+static struct op fops[16] = {
+	[FOP_TO_IDX(FOP_FMAC)]	= { vfp_double_fmac,  0 },
+	[FOP_TO_IDX(FOP_FNMAC)]	= { vfp_double_fnmac, 0 },
+	[FOP_TO_IDX(FOP_FMSC)]	= { vfp_double_fmsc,  0 },
+	[FOP_TO_IDX(FOP_FNMSC)]	= { vfp_double_fnmsc, 0 },
+	[FOP_TO_IDX(FOP_FMUL)]	= { vfp_double_fmul,  0 },
+	[FOP_TO_IDX(FOP_FNMUL)]	= { vfp_double_fnmul, 0 },
+	[FOP_TO_IDX(FOP_FADD)]	= { vfp_double_fadd,  0 },
+	[FOP_TO_IDX(FOP_FSUB)]	= { vfp_double_fsub,  0 },
+	[FOP_TO_IDX(FOP_FDIV)]	= { vfp_double_fdiv,  0 },
+};
+
+#define FREG_BANK(x)	((x) & 0x0c)
+#define FREG_IDX(x)	((x) & 3)
+
+u32 vfp_double_cpdo(u32 inst, u32 fpscr)
+{
+	u32 op = inst & FOP_MASK;
+	u32 exceptions = 0;
+	unsigned int dest;
+	unsigned int dn = vfp_get_dn(inst);
+	unsigned int dm;
+	unsigned int vecitr, veclen, vecstride;
+	struct op *fop;
+
+	vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
+
+	fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
+	/*
+	 * fcvtds takes an sN register number as destination, not dN.
+	 * It also always operates on scalars.
+	 */
+	if (fop->flags & OP_SD)
+		dest = vfp_get_sd(inst);
+	else
+		dest = vfp_get_dd(inst);
+
+	/*
+	 * f[us]ito takes a sN operand, not a dN operand.
+	 */
+	if (fop->flags & OP_SM)
+		dm = vfp_get_sm(inst);
+	else
+		dm = vfp_get_dm(inst);
+
+	/*
+	 * If destination bank is zero, vector length is always '1'.
+	 * ARM DDI0100F C5.1.3, C5.3.2.
+	 */
+	if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
+		veclen = 0;
+	else
+		veclen = fpscr & FPSCR_LENGTH_MASK;
+
+	pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+		 (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+	if (!fop->fn)
+		goto invalid;
+
+	for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+		u32 except;
+		char type;
+
+		type = fop->flags & OP_SD ? 's' : 'd';
+		if (op == FOP_EXT)
+			pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
+				 vecitr >> FPSCR_LENGTH_BIT,
+				 type, dest, dn, dm);
+		else
+			pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
+				 vecitr >> FPSCR_LENGTH_BIT,
+				 type, dest, dn, FOP_TO_IDX(op), dm);
+
+		except = fop->fn(dest, dn, dm, fpscr);
+		pr_debug("VFP: itr%d: exceptions=%08x\n",
+			 vecitr >> FPSCR_LENGTH_BIT, except);
+
+		exceptions |= except;
+
+		/*
+		 * CHECK: It appears to be undefined whether we stop when
+		 * we encounter an exception.  We continue.
+		 */
+		dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
+		dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
+		if (FREG_BANK(dm) != 0)
+			dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
+	}
+	return exceptions;
+
+ invalid:
+	return ~0;
+}