[ARM] 3749/3: Correct VFP single/double conversion emulation

Patch from Daniel Jacobowitz

The fcvtsd/fcvtds emulation was left behind when the numbering of double
precision registers was changed from 0-30 to 0-15. Both conversion
instructions were writing their results to the wrong register. Also,
the conversion instructions should stop after the first element even
if a vector length is specified.

Signed-off-by: Daniel Jacobowitz <dan@codesourcery.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by Daniel Jacobowitz and committed by Russell King c29ecac1 7c6f2514

+43 -18
+21 -7
arch/arm/vfp/vfpdouble.c
··· 1127 { 1128 u32 op = inst & FOP_MASK; 1129 u32 exceptions = 0; 1130 - unsigned int dd = vfp_get_dd(inst); 1131 unsigned int dn = vfp_get_dn(inst); 1132 unsigned int dm = vfp_get_dm(inst); 1133 unsigned int vecitr, veclen, vecstride; ··· 1137 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2; 1138 1139 /* 1140 * If destination bank is zero, vector length is always '1'. 1141 * ARM DDI0100F C5.1.3, C5.3.2. 1142 */ 1143 - if (FREG_BANK(dd) == 0) 1144 veclen = 0; 1145 1146 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, ··· 1163 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { 1164 u32 except; 1165 1166 - if (op == FOP_EXT) 1167 pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n", 1168 vecitr >> FPSCR_LENGTH_BIT, 1169 - dd, dn, dm); 1170 else 1171 pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n", 1172 vecitr >> FPSCR_LENGTH_BIT, 1173 - dd, dn, FOP_TO_IDX(op), dm); 1174 1175 - except = fop(dd, dn, dm, fpscr); 1176 pr_debug("VFP: itr%d: exceptions=%08x\n", 1177 vecitr >> FPSCR_LENGTH_BIT, except); 1178 ··· 1194 * we encounter an exception. We continue. 1195 */ 1196 1197 - dd = FREG_BANK(dd) + ((FREG_IDX(dd) + vecstride) & 6); 1198 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6); 1199 if (FREG_BANK(dm) != 0) 1200 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 6);
··· 1127 { 1128 u32 op = inst & FOP_MASK; 1129 u32 exceptions = 0; 1130 + unsigned int dest; 1131 unsigned int dn = vfp_get_dn(inst); 1132 unsigned int dm = vfp_get_dm(inst); 1133 unsigned int vecitr, veclen, vecstride; ··· 1137 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2; 1138 1139 /* 1140 + * fcvtds takes an sN register number as destination, not dN. 1141 + * It also always operates on scalars. 1142 + */ 1143 + if ((inst & FEXT_MASK) == FEXT_FCVT) { 1144 + veclen = 0; 1145 + dest = vfp_get_sd(inst); 1146 + } else 1147 + dest = vfp_get_dd(inst); 1148 + 1149 + /* 1150 * If destination bank is zero, vector length is always '1'. 1151 * ARM DDI0100F C5.1.3, C5.3.2. 1152 */ 1153 + if (FREG_BANK(dest) == 0) 1154 veclen = 0; 1155 1156 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, ··· 1153 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { 1154 u32 except; 1155 1156 + if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT) 1157 + pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n", 1158 + vecitr >> FPSCR_LENGTH_BIT, 1159 + dest, dn, dm); 1160 + else if (op == FOP_EXT) 1161 pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n", 1162 vecitr >> FPSCR_LENGTH_BIT, 1163 + dest, dn, dm); 1164 else 1165 pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n", 1166 vecitr >> FPSCR_LENGTH_BIT, 1167 + dest, dn, FOP_TO_IDX(op), dm); 1168 1169 + except = fop(dest, dn, dm, fpscr); 1170 pr_debug("VFP: itr%d: exceptions=%08x\n", 1171 vecitr >> FPSCR_LENGTH_BIT, except); 1172 ··· 1180 * we encounter an exception. We continue. 1181 */ 1182 1183 + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 6); 1184 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6); 1185 if (FREG_BANK(dm) != 0) 1186 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 6);
+22 -11
arch/arm/vfp/vfpsingle.c
··· 514 else 515 vdd.exponent = vsm.exponent + (1023 - 127); 516 517 - /* 518 - * Technically, if bit 0 of dd is set, this is an invalid 519 - * instruction. However, we ignore this for efficiency. 520 - */ 521 return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd"); 522 523 pack_nan: ··· 1170 { 1171 u32 op = inst & FOP_MASK; 1172 u32 exceptions = 0; 1173 - unsigned int sd = vfp_get_sd(inst); 1174 unsigned int sn = vfp_get_sn(inst); 1175 unsigned int sm = vfp_get_sm(inst); 1176 unsigned int vecitr, veclen, vecstride; ··· 1180 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); 1181 1182 /* 1183 * If destination bank is zero, vector length is always '1'. 1184 * ARM DDI0100F C5.1.3, C5.3.2. 1185 */ 1186 - if (FREG_BANK(sd) == 0) 1187 veclen = 0; 1188 1189 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, ··· 1209 s32 m = vfp_get_float(sm); 1210 u32 except; 1211 1212 - if (op == FOP_EXT) 1213 pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n", 1214 - vecitr >> FPSCR_LENGTH_BIT, sd, sn, sm, m); 1215 else 1216 pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n", 1217 - vecitr >> FPSCR_LENGTH_BIT, sd, sn, 1218 FOP_TO_IDX(op), sm, m); 1219 1220 - except = fop(sd, sn, m, fpscr); 1221 pr_debug("VFP: itr%d: exceptions=%08x\n", 1222 vecitr >> FPSCR_LENGTH_BIT, except); 1223 ··· 1238 * we encounter an exception. We continue. 1239 */ 1240 1241 - sd = FREG_BANK(sd) + ((FREG_IDX(sd) + vecstride) & 7); 1242 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); 1243 if (FREG_BANK(sm) != 0) 1244 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
··· 514 else 515 vdd.exponent = vsm.exponent + (1023 - 127); 516 517 return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd"); 518 519 pack_nan: ··· 1174 { 1175 u32 op = inst & FOP_MASK; 1176 u32 exceptions = 0; 1177 + unsigned int dest; 1178 unsigned int sn = vfp_get_sn(inst); 1179 unsigned int sm = vfp_get_sm(inst); 1180 unsigned int vecitr, veclen, vecstride; ··· 1184 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); 1185 1186 /* 1187 + * fcvtsd takes a dN register number as destination, not sN. 1188 + * Technically, if bit 0 of dd is set, this is an invalid 1189 + * instruction. However, we ignore this for efficiency. 1190 + * It also only operates on scalars. 1191 + */ 1192 + if ((inst & FEXT_MASK) == FEXT_FCVT) { 1193 + veclen = 0; 1194 + dest = vfp_get_dd(inst); 1195 + } else 1196 + dest = vfp_get_sd(inst); 1197 + 1198 + /* 1199 * If destination bank is zero, vector length is always '1'. 1200 * ARM DDI0100F C5.1.3, C5.3.2. 1201 */ 1202 + if (FREG_BANK(dest) == 0) 1203 veclen = 0; 1204 1205 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, ··· 1201 s32 m = vfp_get_float(sm); 1202 u32 except; 1203 1204 + if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT) 1205 + pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n", 1206 + vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m); 1207 + else if (op == FOP_EXT) 1208 pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n", 1209 + vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m); 1210 else 1211 pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n", 1212 + vecitr >> FPSCR_LENGTH_BIT, dest, sn, 1213 FOP_TO_IDX(op), sm, m); 1214 1215 + except = fop(dest, sn, m, fpscr); 1216 pr_debug("VFP: itr%d: exceptions=%08x\n", 1217 vecitr >> FPSCR_LENGTH_BIT, except); 1218 ··· 1227 * we encounter an exception. We continue. 1228 */ 1229 1230 + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); 1231 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); 1232 if (FREG_BANK(sm) != 0) 1233 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);