aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfp.h18
-rw-r--r--arch/arm/vfp/vfpdouble.c50
-rw-r--r--arch/arm/vfp/vfphw.S10
-rw-r--r--arch/arm/vfp/vfpmodule.c4
-rw-r--r--arch/arm/vfp/vfpsingle.c55
5 files changed, 82 insertions, 55 deletions
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 4b97950984e9..96fdf30f6a3b 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -156,7 +156,7 @@ struct vfp_single {
156}; 156};
157 157
158extern s32 vfp_get_float(unsigned int reg); 158extern s32 vfp_get_float(unsigned int reg);
159extern void vfp_put_float(unsigned int reg, s32 val); 159extern void vfp_put_float(s32 val, unsigned int reg);
160 160
161/* 161/*
162 * VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa 162 * VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
@@ -267,7 +267,7 @@ struct vfp_double {
267 */ 267 */
268#define VFP_REG_ZERO 16 268#define VFP_REG_ZERO 16
269extern u64 vfp_get_double(unsigned int reg); 269extern u64 vfp_get_double(unsigned int reg);
270extern void vfp_put_double(unsigned int reg, u64 val); 270extern void vfp_put_double(u64 val, unsigned int reg);
271 271
272#define VFP_DOUBLE_MANTISSA_BITS (52) 272#define VFP_DOUBLE_MANTISSA_BITS (52)
273#define VFP_DOUBLE_EXPONENT_BITS (11) 273#define VFP_DOUBLE_EXPONENT_BITS (11)
@@ -341,15 +341,17 @@ static inline int vfp_double_type(struct vfp_double *s)
341 341
342u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); 342u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
343 343
344/*
345 * System registers
346 */
347extern u32 vfp_get_sys(unsigned int reg);
348extern void vfp_put_sys(unsigned int reg, u32 val);
349
350u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); 344u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
351 345
352/* 346/*
353 * A special flag to tell the normalisation code not to normalise. 347 * A special flag to tell the normalisation code not to normalise.
354 */ 348 */
355#define VFP_NAN_FLAG 0x100 349#define VFP_NAN_FLAG 0x100
350
351/*
352 * A bit pattern used to indicate the initial (unset) value of the
353 * exception mask, in case nothing handles an instruction. This
354 * doesn't include the NAN flag, which get masked out before
355 * we check for an error.
356 */
357#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index 009038c8113e..add48e36c2dc 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -195,7 +195,7 @@ u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exce
195 s64 d = vfp_double_pack(vd); 195 s64 d = vfp_double_pack(vd);
196 pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, 196 pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
197 dd, d, exceptions); 197 dd, d, exceptions);
198 vfp_put_double(dd, d); 198 vfp_put_double(d, dd);
199 } 199 }
200 return exceptions; 200 return exceptions;
201} 201}
@@ -250,19 +250,19 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
250 */ 250 */
251static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr) 251static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr)
252{ 252{
253 vfp_put_double(dd, vfp_double_packed_abs(vfp_get_double(dm))); 253 vfp_put_double(vfp_double_packed_abs(vfp_get_double(dm)), dd);
254 return 0; 254 return 0;
255} 255}
256 256
257static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr) 257static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr)
258{ 258{
259 vfp_put_double(dd, vfp_get_double(dm)); 259 vfp_put_double(vfp_get_double(dm), dd);
260 return 0; 260 return 0;
261} 261}
262 262
263static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr) 263static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr)
264{ 264{
265 vfp_put_double(dd, vfp_double_packed_negate(vfp_get_double(dm))); 265 vfp_put_double(vfp_double_packed_negate(vfp_get_double(dm)), dd);
266 return 0; 266 return 0;
267} 267}
268 268
@@ -287,7 +287,7 @@ static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr)
287 vdp = &vfp_double_default_qnan; 287 vdp = &vfp_double_default_qnan;
288 ret = FPSCR_IOC; 288 ret = FPSCR_IOC;
289 } 289 }
290 vfp_put_double(dd, vfp_double_pack(vdp)); 290 vfp_put_double(vfp_double_pack(vdp), dd);
291 return ret; 291 return ret;
292 } 292 }
293 293
@@ -465,7 +465,7 @@ static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
465 */ 465 */
466 if (tm & (VFP_INFINITY|VFP_NAN)) { 466 if (tm & (VFP_INFINITY|VFP_NAN)) {
467 vsd.exponent = 255; 467 vsd.exponent = 255;
468 if (tm & VFP_NAN) 468 if (tm == VFP_QNAN)
469 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; 469 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
470 goto pack_nan; 470 goto pack_nan;
471 } else if (tm & VFP_ZERO) 471 } else if (tm & VFP_ZERO)
@@ -476,7 +476,7 @@ static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
476 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fcvts"); 476 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fcvts");
477 477
478 pack_nan: 478 pack_nan:
479 vfp_put_float(sd, vfp_single_pack(&vsd)); 479 vfp_put_float(vfp_single_pack(&vsd), sd);
480 return exceptions; 480 return exceptions;
481} 481}
482 482
@@ -573,7 +573,7 @@ static u32 vfp_double_ftoui(int sd, int unused, int dm, u32 fpscr)
573 573
574 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); 574 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
575 575
576 vfp_put_float(sd, d); 576 vfp_put_float(d, sd);
577 577
578 return exceptions; 578 return exceptions;
579} 579}
@@ -648,7 +648,7 @@ static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr)
648 648
649 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); 649 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
650 650
651 vfp_put_float(sd, (s32)d); 651 vfp_put_float((s32)d, sd);
652 652
653 return exceptions; 653 return exceptions;
654} 654}
@@ -1084,7 +1084,7 @@ static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
1084 vdn_nan: 1084 vdn_nan:
1085 exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); 1085 exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1086 pack: 1086 pack:
1087 vfp_put_double(dd, vfp_double_pack(&vdd)); 1087 vfp_put_double(vfp_double_pack(&vdd), dd);
1088 return exceptions; 1088 return exceptions;
1089 1089
1090 vdm_nan: 1090 vdm_nan:
@@ -1104,7 +1104,7 @@ static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
1104 goto pack; 1104 goto pack;
1105 1105
1106 invalid: 1106 invalid:
1107 vfp_put_double(dd, vfp_double_pack(&vfp_double_default_qnan)); 1107 vfp_put_double(vfp_double_pack(&vfp_double_default_qnan), dd);
1108 return FPSCR_IOC; 1108 return FPSCR_IOC;
1109} 1109}
1110 1110
@@ -1127,7 +1127,7 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1127{ 1127{
1128 u32 op = inst & FOP_MASK; 1128 u32 op = inst & FOP_MASK;
1129 u32 exceptions = 0; 1129 u32 exceptions = 0;
1130 unsigned int dd = vfp_get_dd(inst); 1130 unsigned int dest;
1131 unsigned int dn = vfp_get_dn(inst); 1131 unsigned int dn = vfp_get_dn(inst);
1132 unsigned int dm = vfp_get_dm(inst); 1132 unsigned int dm = vfp_get_dm(inst);
1133 unsigned int vecitr, veclen, vecstride; 1133 unsigned int vecitr, veclen, vecstride;
@@ -1137,10 +1137,20 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1137 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2; 1137 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2;
1138 1138
1139 /* 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 /*
1140 * If destination bank is zero, vector length is always '1'. 1150 * If destination bank is zero, vector length is always '1'.
1141 * ARM DDI0100F C5.1.3, C5.3.2. 1151 * ARM DDI0100F C5.1.3, C5.3.2.
1142 */ 1152 */
1143 if (FREG_BANK(dd) == 0) 1153 if (FREG_BANK(dest) == 0)
1144 veclen = 0; 1154 veclen = 0;
1145 1155
1146 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, 1156 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
@@ -1153,16 +1163,20 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1153 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { 1163 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1154 u32 except; 1164 u32 except;
1155 1165
1156 if (op == FOP_EXT) 1166 if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
1167 pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n",
1168 vecitr >> FPSCR_LENGTH_BIT,
1169 dest, dn, dm);
1170 else if (op == FOP_EXT)
1157 pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n", 1171 pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n",
1158 vecitr >> FPSCR_LENGTH_BIT, 1172 vecitr >> FPSCR_LENGTH_BIT,
1159 dd, dn, dm); 1173 dest, dn, dm);
1160 else 1174 else
1161 pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n", 1175 pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n",
1162 vecitr >> FPSCR_LENGTH_BIT, 1176 vecitr >> FPSCR_LENGTH_BIT,
1163 dd, dn, FOP_TO_IDX(op), dm); 1177 dest, dn, FOP_TO_IDX(op), dm);
1164 1178
1165 except = fop(dd, dn, dm, fpscr); 1179 except = fop(dest, dn, dm, fpscr);
1166 pr_debug("VFP: itr%d: exceptions=%08x\n", 1180 pr_debug("VFP: itr%d: exceptions=%08x\n",
1167 vecitr >> FPSCR_LENGTH_BIT, except); 1181 vecitr >> FPSCR_LENGTH_BIT, except);
1168 1182
@@ -1180,7 +1194,7 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1180 * we encounter an exception. We continue. 1194 * we encounter an exception. We continue.
1181 */ 1195 */
1182 1196
1183 dd = FREG_BANK(dd) + ((FREG_IDX(dd) + vecstride) & 6); 1197 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 6);
1184 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6); 1198 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6);
1185 if (FREG_BANK(dm) != 0) 1199 if (FREG_BANK(dm) != 0)
1186 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 6); 1200 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 6);
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index eb683cd77163..e51e6679c402 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -178,12 +178,12 @@ vfp_get_float:
178 178
179 .globl vfp_put_float 179 .globl vfp_put_float
180vfp_put_float: 180vfp_put_float:
181 add pc, pc, r0, lsl #3 181 add pc, pc, r1, lsl #3
182 mov r0, r0 182 mov r0, r0
183 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 183 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
184 mcr p10, 0, r1, c\dr, c0, 0 @ fmsr r0, s0 184 mcr p10, 0, r0, c\dr, c0, 0 @ fmsr r0, s0
185 mov pc, lr 185 mov pc, lr
186 mcr p10, 0, r1, c\dr, c0, 4 @ fmsr r0, s1 186 mcr p10, 0, r0, c\dr, c0, 4 @ fmsr r0, s1
187 mov pc, lr 187 mov pc, lr
188 .endr 188 .endr
189 189
@@ -203,9 +203,9 @@ vfp_get_double:
203 203
204 .globl vfp_put_double 204 .globl vfp_put_double
205vfp_put_double: 205vfp_put_double:
206 add pc, pc, r0, lsl #3 206 add pc, pc, r2, lsl #3
207 mov r0, r0 207 mov r0, r0
208 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 208 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
209 fmdrr d\dr, r1, r2 209 fmdrr d\dr, r0, r1
210 mov pc, lr 210 mov pc, lr
211 .endr 211 .endr
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 9d265d5e748c..4178f6cc3d37 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -131,7 +131,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
131 131
132 pr_debug("VFP: raising exceptions %08x\n", exceptions); 132 pr_debug("VFP: raising exceptions %08x\n", exceptions);
133 133
134 if (exceptions == (u32)-1) { 134 if (exceptions == VFP_EXCEPTION_ERROR) {
135 vfp_panic("unhandled bounce"); 135 vfp_panic("unhandled bounce");
136 vfp_raise_sigfpe(0, regs); 136 vfp_raise_sigfpe(0, regs);
137 return; 137 return;
@@ -170,7 +170,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
170 */ 170 */
171static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs) 171static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
172{ 172{
173 u32 exceptions = (u32)-1; 173 u32 exceptions = VFP_EXCEPTION_ERROR;
174 174
175 pr_debug("VFP: emulate: INST=0x%08x SCR=0x%08x\n", inst, fpscr); 175 pr_debug("VFP: emulate: INST=0x%08x SCR=0x%08x\n", inst, fpscr);
176 176
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index dae2c2f46052..8f6c179cafbe 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -200,7 +200,7 @@ u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exce
200 s32 d = vfp_single_pack(vs); 200 s32 d = vfp_single_pack(vs);
201 pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, 201 pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
202 sd, d, exceptions); 202 sd, d, exceptions);
203 vfp_put_float(sd, d); 203 vfp_put_float(d, sd);
204 } 204 }
205 205
206 return exceptions; 206 return exceptions;
@@ -257,19 +257,19 @@ vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
257 */ 257 */
258static u32 vfp_single_fabs(int sd, int unused, s32 m, u32 fpscr) 258static u32 vfp_single_fabs(int sd, int unused, s32 m, u32 fpscr)
259{ 259{
260 vfp_put_float(sd, vfp_single_packed_abs(m)); 260 vfp_put_float(vfp_single_packed_abs(m), sd);
261 return 0; 261 return 0;
262} 262}
263 263
264static u32 vfp_single_fcpy(int sd, int unused, s32 m, u32 fpscr) 264static u32 vfp_single_fcpy(int sd, int unused, s32 m, u32 fpscr)
265{ 265{
266 vfp_put_float(sd, m); 266 vfp_put_float(m, sd);
267 return 0; 267 return 0;
268} 268}
269 269
270static u32 vfp_single_fneg(int sd, int unused, s32 m, u32 fpscr) 270static u32 vfp_single_fneg(int sd, int unused, s32 m, u32 fpscr)
271{ 271{
272 vfp_put_float(sd, vfp_single_packed_negate(m)); 272 vfp_put_float(vfp_single_packed_negate(m), sd);
273 return 0; 273 return 0;
274} 274}
275 275
@@ -333,7 +333,7 @@ static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
333 vsp = &vfp_single_default_qnan; 333 vsp = &vfp_single_default_qnan;
334 ret = FPSCR_IOC; 334 ret = FPSCR_IOC;
335 } 335 }
336 vfp_put_float(sd, vfp_single_pack(vsp)); 336 vfp_put_float(vfp_single_pack(vsp), sd);
337 return ret; 337 return ret;
338 } 338 }
339 339
@@ -506,7 +506,7 @@ static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr)
506 */ 506 */
507 if (tm & (VFP_INFINITY|VFP_NAN)) { 507 if (tm & (VFP_INFINITY|VFP_NAN)) {
508 vdd.exponent = 2047; 508 vdd.exponent = 2047;
509 if (tm & VFP_NAN) 509 if (tm == VFP_QNAN)
510 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; 510 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
511 goto pack_nan; 511 goto pack_nan;
512 } else if (tm & VFP_ZERO) 512 } else if (tm & VFP_ZERO)
@@ -514,14 +514,10 @@ static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr)
514 else 514 else
515 vdd.exponent = vsm.exponent + (1023 - 127); 515 vdd.exponent = vsm.exponent + (1023 - 127);
516 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"); 517 return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd");
522 518
523 pack_nan: 519 pack_nan:
524 vfp_put_double(dd, vfp_double_pack(&vdd)); 520 vfp_put_double(vfp_double_pack(&vdd), dd);
525 return exceptions; 521 return exceptions;
526} 522}
527 523
@@ -617,7 +613,7 @@ static u32 vfp_single_ftoui(int sd, int unused, s32 m, u32 fpscr)
617 613
618 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); 614 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
619 615
620 vfp_put_float(sd, d); 616 vfp_put_float(d, sd);
621 617
622 return exceptions; 618 return exceptions;
623} 619}
@@ -696,7 +692,7 @@ static u32 vfp_single_ftosi(int sd, int unused, s32 m, u32 fpscr)
696 692
697 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); 693 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
698 694
699 vfp_put_float(sd, (s32)d); 695 vfp_put_float((s32)d, sd);
700 696
701 return exceptions; 697 return exceptions;
702} 698}
@@ -1131,7 +1127,7 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
1131 vsn_nan: 1127 vsn_nan:
1132 exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); 1128 exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
1133 pack: 1129 pack:
1134 vfp_put_float(sd, vfp_single_pack(&vsd)); 1130 vfp_put_float(vfp_single_pack(&vsd), sd);
1135 return exceptions; 1131 return exceptions;
1136 1132
1137 vsm_nan: 1133 vsm_nan:
@@ -1151,7 +1147,7 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
1151 goto pack; 1147 goto pack;
1152 1148
1153 invalid: 1149 invalid:
1154 vfp_put_float(sd, vfp_single_pack(&vfp_single_default_qnan)); 1150 vfp_put_float(vfp_single_pack(&vfp_single_default_qnan), sd);
1155 return FPSCR_IOC; 1151 return FPSCR_IOC;
1156} 1152}
1157 1153
@@ -1174,7 +1170,7 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1174{ 1170{
1175 u32 op = inst & FOP_MASK; 1171 u32 op = inst & FOP_MASK;
1176 u32 exceptions = 0; 1172 u32 exceptions = 0;
1177 unsigned int sd = vfp_get_sd(inst); 1173 unsigned int dest;
1178 unsigned int sn = vfp_get_sn(inst); 1174 unsigned int sn = vfp_get_sn(inst);
1179 unsigned int sm = vfp_get_sm(inst); 1175 unsigned int sm = vfp_get_sm(inst);
1180 unsigned int vecitr, veclen, vecstride; 1176 unsigned int vecitr, veclen, vecstride;
@@ -1184,10 +1180,22 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1184 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); 1180 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1185 1181
1186 /* 1182 /*
1183 * fcvtsd takes a dN register number as destination, not sN.
1184 * Technically, if bit 0 of dd is set, this is an invalid
1185 * instruction. However, we ignore this for efficiency.
1186 * It also only operates on scalars.
1187 */
1188 if ((inst & FEXT_MASK) == FEXT_FCVT) {
1189 veclen = 0;
1190 dest = vfp_get_dd(inst);
1191 } else
1192 dest = vfp_get_sd(inst);
1193
1194 /*
1187 * If destination bank is zero, vector length is always '1'. 1195 * If destination bank is zero, vector length is always '1'.
1188 * ARM DDI0100F C5.1.3, C5.3.2. 1196 * ARM DDI0100F C5.1.3, C5.3.2.
1189 */ 1197 */
1190 if (FREG_BANK(sd) == 0) 1198 if (FREG_BANK(dest) == 0)
1191 veclen = 0; 1199 veclen = 0;
1192 1200
1193 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, 1201 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
@@ -1201,15 +1209,18 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1201 s32 m = vfp_get_float(sm); 1209 s32 m = vfp_get_float(sm);
1202 u32 except; 1210 u32 except;
1203 1211
1204 if (op == FOP_EXT) 1212 if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
1213 pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n",
1214 vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
1215 else if (op == FOP_EXT)
1205 pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n", 1216 pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n",
1206 vecitr >> FPSCR_LENGTH_BIT, sd, sn, sm, m); 1217 vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
1207 else 1218 else
1208 pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n", 1219 pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n",
1209 vecitr >> FPSCR_LENGTH_BIT, sd, sn, 1220 vecitr >> FPSCR_LENGTH_BIT, dest, sn,
1210 FOP_TO_IDX(op), sm, m); 1221 FOP_TO_IDX(op), sm, m);
1211 1222
1212 except = fop(sd, sn, m, fpscr); 1223 except = fop(dest, sn, m, fpscr);
1213 pr_debug("VFP: itr%d: exceptions=%08x\n", 1224 pr_debug("VFP: itr%d: exceptions=%08x\n",
1214 vecitr >> FPSCR_LENGTH_BIT, except); 1225 vecitr >> FPSCR_LENGTH_BIT, except);
1215 1226
@@ -1227,7 +1238,7 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1227 * we encounter an exception. We continue. 1238 * we encounter an exception. We continue.
1228 */ 1239 */
1229 1240
1230 sd = FREG_BANK(sd) + ((FREG_IDX(sd) + vecstride) & 7); 1241 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
1231 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); 1242 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
1232 if (FREG_BANK(sm) != 0) 1243 if (FREG_BANK(sm) != 0)
1233 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); 1244 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);