aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGen FUKATSU <fukatsu.gen@jp.panasonic.com>2006-09-21 09:08:24 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-09-25 05:34:06 -0400
commit4cc9bd2eaa1063c68341c1c00e66660adcfdf254 (patch)
tree3ee6d9f6b2075d4a5e340d2a3370f9e068aab723
parentf8c440b209581809c5c8acac599410f23597a7b8 (diff)
[ARM] 3789/4: Fix VFP emulation to ignore VECITR for scalar instruction
VECITR in Floating-Point Exception register indicates the number of remaining short vector iterations after a potential exception was detected. In case of exception caused by scalar instructions, VECITR is NOT updated. Therefore emulation for VFP must ignore VECITR field and treat "veclen" as zero when recognizing scalar instructing. Signed-off-by: Gen Fukatsu <fukatsu.gen@jp.panasonic.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/vfp/vfp.h11
-rw-r--r--arch/arm/vfp/vfpdouble.c72
-rw-r--r--arch/arm/vfp/vfpsingle.c70
3 files changed, 82 insertions, 71 deletions
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 96fdf30f6a3b..19ace2e37789 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -355,3 +355,14 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
355 * we check for an error. 355 * we check for an error.
356 */ 356 */
357#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) 357#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
358
359/*
360 * A flag to tell vfp instruction type
361 */
362#define OP_SCALAR (1 << 0)
363#define OP_SD (1 << 1)
364
365struct op {
366 u32 (* const fn)(int dd, int dn, int dm, u32 fpscr);
367 u32 flags;
368};
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index add48e36c2dc..e19a4f7620de 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -659,22 +659,22 @@ static u32 vfp_double_ftosiz(int dd, int unused, int dm, u32 fpscr)
659} 659}
660 660
661 661
662static u32 (* const fop_extfns[32])(int dd, int unused, int dm, u32 fpscr) = { 662static struct op fops_ext[32] = {
663 [FEXT_TO_IDX(FEXT_FCPY)] = vfp_double_fcpy, 663 [FEXT_TO_IDX(FEXT_FCPY)] = {vfp_double_fcpy, 0},
664 [FEXT_TO_IDX(FEXT_FABS)] = vfp_double_fabs, 664 [FEXT_TO_IDX(FEXT_FABS)] = {vfp_double_fabs, 0},
665 [FEXT_TO_IDX(FEXT_FNEG)] = vfp_double_fneg, 665 [FEXT_TO_IDX(FEXT_FNEG)] = {vfp_double_fneg, 0},
666 [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_double_fsqrt, 666 [FEXT_TO_IDX(FEXT_FSQRT)] = {vfp_double_fsqrt, 0},
667 [FEXT_TO_IDX(FEXT_FCMP)] = vfp_double_fcmp, 667 [FEXT_TO_IDX(FEXT_FCMP)] = {vfp_double_fcmp, OP_SCALAR},
668 [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_double_fcmpe, 668 [FEXT_TO_IDX(FEXT_FCMPE)] = {vfp_double_fcmpe, OP_SCALAR},
669 [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_double_fcmpz, 669 [FEXT_TO_IDX(FEXT_FCMPZ)] = {vfp_double_fcmpz, OP_SCALAR},
670 [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_double_fcmpez, 670 [FEXT_TO_IDX(FEXT_FCMPEZ)] = {vfp_double_fcmpez, OP_SCALAR},
671 [FEXT_TO_IDX(FEXT_FCVT)] = vfp_double_fcvts, 671 [FEXT_TO_IDX(FEXT_FCVT)] = {vfp_double_fcvts, (OP_SD|OP_SCALAR)},
672 [FEXT_TO_IDX(FEXT_FUITO)] = vfp_double_fuito, 672 [FEXT_TO_IDX(FEXT_FUITO)] = {vfp_double_fuito, OP_SCALAR},
673 [FEXT_TO_IDX(FEXT_FSITO)] = vfp_double_fsito, 673 [FEXT_TO_IDX(FEXT_FSITO)] = {vfp_double_fsito, OP_SCALAR},
674 [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_double_ftoui, 674 [FEXT_TO_IDX(FEXT_FTOUI)] = {vfp_double_ftoui, (OP_SD|OP_SCALAR)},
675 [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_double_ftouiz, 675 [FEXT_TO_IDX(FEXT_FTOUIZ)] = {vfp_double_ftouiz, (OP_SD|OP_SCALAR)},
676 [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_double_ftosi, 676 [FEXT_TO_IDX(FEXT_FTOSI)] = {vfp_double_ftosi, (OP_SD|OP_SCALAR)},
677 [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_double_ftosiz, 677 [FEXT_TO_IDX(FEXT_FTOSIZ)] = {vfp_double_ftosiz, (OP_SD|OP_SCALAR)},
678}; 678};
679 679
680 680
@@ -1108,16 +1108,16 @@ static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
1108 return FPSCR_IOC; 1108 return FPSCR_IOC;
1109} 1109}
1110 1110
1111static u32 (* const fop_fns[16])(int dd, int dn, int dm, u32 fpscr) = { 1111static struct op fops[16] = {
1112 [FOP_TO_IDX(FOP_FMAC)] = vfp_double_fmac, 1112 [FOP_TO_IDX(FOP_FMAC)] = {vfp_double_fmac, 0},
1113 [FOP_TO_IDX(FOP_FNMAC)] = vfp_double_fnmac, 1113 [FOP_TO_IDX(FOP_FNMAC)] = {vfp_double_fnmac, 0},
1114 [FOP_TO_IDX(FOP_FMSC)] = vfp_double_fmsc, 1114 [FOP_TO_IDX(FOP_FMSC)] = {vfp_double_fmsc, 0},
1115 [FOP_TO_IDX(FOP_FNMSC)] = vfp_double_fnmsc, 1115 [FOP_TO_IDX(FOP_FNMSC)] = {vfp_double_fnmsc, 0},
1116 [FOP_TO_IDX(FOP_FMUL)] = vfp_double_fmul, 1116 [FOP_TO_IDX(FOP_FMUL)] = {vfp_double_fmul, 0},
1117 [FOP_TO_IDX(FOP_FNMUL)] = vfp_double_fnmul, 1117 [FOP_TO_IDX(FOP_FNMUL)] = {vfp_double_fnmul, 0},
1118 [FOP_TO_IDX(FOP_FADD)] = vfp_double_fadd, 1118 [FOP_TO_IDX(FOP_FADD)] = {vfp_double_fadd, 0},
1119 [FOP_TO_IDX(FOP_FSUB)] = vfp_double_fsub, 1119 [FOP_TO_IDX(FOP_FSUB)] = {vfp_double_fsub, 0},
1120 [FOP_TO_IDX(FOP_FDIV)] = vfp_double_fdiv, 1120 [FOP_TO_IDX(FOP_FDIV)] = {vfp_double_fdiv, 0},
1121}; 1121};
1122 1122
1123#define FREG_BANK(x) ((x) & 0x0c) 1123#define FREG_BANK(x) ((x) & 0x0c)
@@ -1131,39 +1131,39 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
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;
1134 u32 (*fop)(int, int, s32, u32); 1134 struct op *fop;
1135 1135
1136 veclen = fpscr & FPSCR_LENGTH_MASK;
1137 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2; 1136 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2;
1138 1137
1138 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1139 /* 1139 /*
1140 * fcvtds takes an sN register number as destination, not dN. 1140 * fcvtds takes an sN register number as destination, not dN.
1141 * It also always operates on scalars. 1141 * It also always operates on scalars.
1142 */ 1142 */
1143 if ((inst & FEXT_MASK) == FEXT_FCVT) { 1143 if (fop->flags & OP_SD)
1144 veclen = 0;
1145 dest = vfp_get_sd(inst); 1144 dest = vfp_get_sd(inst);
1146 } else 1145 else
1147 dest = vfp_get_dd(inst); 1146 dest = vfp_get_dd(inst);
1148 1147
1149 /* 1148 /*
1150 * If destination bank is zero, vector length is always '1'. 1149 * If destination bank is zero, vector length is always '1'.
1151 * ARM DDI0100F C5.1.3, C5.3.2. 1150 * ARM DDI0100F C5.1.3, C5.3.2.
1152 */ 1151 */
1153 if (FREG_BANK(dest) == 0) 1152 if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1154 veclen = 0; 1153 veclen = 0;
1154 else
1155 veclen = fpscr & FPSCR_LENGTH_MASK;
1155 1156
1156 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, 1157 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1157 (veclen >> FPSCR_LENGTH_BIT) + 1); 1158 (veclen >> FPSCR_LENGTH_BIT) + 1);
1158 1159
1159 fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)]; 1160 if (!fop->fn)
1160 if (!fop)
1161 goto invalid; 1161 goto invalid;
1162 1162
1163 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { 1163 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1164 u32 except; 1164 u32 except;
1165 1165
1166 if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT) 1166 if (op == FOP_EXT && (fop->flags & OP_SD))
1167 pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n", 1167 pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n",
1168 vecitr >> FPSCR_LENGTH_BIT, 1168 vecitr >> FPSCR_LENGTH_BIT,
1169 dest, dn, dm); 1169 dest, dn, dm);
@@ -1176,7 +1176,7 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1176 vecitr >> FPSCR_LENGTH_BIT, 1176 vecitr >> FPSCR_LENGTH_BIT,
1177 dest, dn, FOP_TO_IDX(op), dm); 1177 dest, dn, FOP_TO_IDX(op), dm);
1178 1178
1179 except = fop(dest, dn, dm, fpscr); 1179 except = fop->fn(dest, dn, dm, fpscr);
1180 pr_debug("VFP: itr%d: exceptions=%08x\n", 1180 pr_debug("VFP: itr%d: exceptions=%08x\n",
1181 vecitr >> FPSCR_LENGTH_BIT, except); 1181 vecitr >> FPSCR_LENGTH_BIT, except);
1182 1182
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index 8f6c179cafbe..4f717d72eb6b 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -702,22 +702,22 @@ static u32 vfp_single_ftosiz(int sd, int unused, s32 m, u32 fpscr)
702 return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO); 702 return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO);
703} 703}
704 704
705static u32 (* const fop_extfns[32])(int sd, int unused, s32 m, u32 fpscr) = { 705static struct op fops_ext[32] = {
706 [FEXT_TO_IDX(FEXT_FCPY)] = vfp_single_fcpy, 706 [FEXT_TO_IDX(FEXT_FCPY)] = {vfp_single_fcpy, 0},
707 [FEXT_TO_IDX(FEXT_FABS)] = vfp_single_fabs, 707 [FEXT_TO_IDX(FEXT_FABS)] = {vfp_single_fabs, 0},
708 [FEXT_TO_IDX(FEXT_FNEG)] = vfp_single_fneg, 708 [FEXT_TO_IDX(FEXT_FNEG)] = {vfp_single_fneg, 0},
709 [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_single_fsqrt, 709 [FEXT_TO_IDX(FEXT_FSQRT)] = {vfp_single_fsqrt, 0},
710 [FEXT_TO_IDX(FEXT_FCMP)] = vfp_single_fcmp, 710 [FEXT_TO_IDX(FEXT_FCMP)] = {vfp_single_fcmp, OP_SCALAR},
711 [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_single_fcmpe, 711 [FEXT_TO_IDX(FEXT_FCMPE)] = {vfp_single_fcmpe, OP_SCALAR},
712 [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_single_fcmpz, 712 [FEXT_TO_IDX(FEXT_FCMPZ)] = {vfp_single_fcmpz, OP_SCALAR},
713 [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_single_fcmpez, 713 [FEXT_TO_IDX(FEXT_FCMPEZ)] = {vfp_single_fcmpez, OP_SCALAR},
714 [FEXT_TO_IDX(FEXT_FCVT)] = vfp_single_fcvtd, 714 [FEXT_TO_IDX(FEXT_FCVT)] = {vfp_single_fcvtd, (OP_SD|OP_SCALAR)},
715 [FEXT_TO_IDX(FEXT_FUITO)] = vfp_single_fuito, 715 [FEXT_TO_IDX(FEXT_FUITO)] = {vfp_single_fuito, OP_SCALAR},
716 [FEXT_TO_IDX(FEXT_FSITO)] = vfp_single_fsito, 716 [FEXT_TO_IDX(FEXT_FSITO)] = {vfp_single_fsito, OP_SCALAR},
717 [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_single_ftoui, 717 [FEXT_TO_IDX(FEXT_FTOUI)] = {vfp_single_ftoui, OP_SCALAR},
718 [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_single_ftouiz, 718 [FEXT_TO_IDX(FEXT_FTOUIZ)] = {vfp_single_ftouiz, OP_SCALAR},
719 [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_single_ftosi, 719 [FEXT_TO_IDX(FEXT_FTOSI)] = {vfp_single_ftosi, OP_SCALAR},
720 [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_single_ftosiz, 720 [FEXT_TO_IDX(FEXT_FTOSIZ)] = {vfp_single_ftosiz, OP_SCALAR},
721}; 721};
722 722
723 723
@@ -1151,16 +1151,16 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
1151 return FPSCR_IOC; 1151 return FPSCR_IOC;
1152} 1152}
1153 1153
1154static u32 (* const fop_fns[16])(int sd, int sn, s32 m, u32 fpscr) = { 1154static struct op fops[16] = {
1155 [FOP_TO_IDX(FOP_FMAC)] = vfp_single_fmac, 1155 [FOP_TO_IDX(FOP_FMAC)] = {vfp_single_fmac, 0},
1156 [FOP_TO_IDX(FOP_FNMAC)] = vfp_single_fnmac, 1156 [FOP_TO_IDX(FOP_FNMAC)] = {vfp_single_fnmac, 0},
1157 [FOP_TO_IDX(FOP_FMSC)] = vfp_single_fmsc, 1157 [FOP_TO_IDX(FOP_FMSC)] = {vfp_single_fmsc, 0},
1158 [FOP_TO_IDX(FOP_FNMSC)] = vfp_single_fnmsc, 1158 [FOP_TO_IDX(FOP_FNMSC)] = {vfp_single_fnmsc, 0},
1159 [FOP_TO_IDX(FOP_FMUL)] = vfp_single_fmul, 1159 [FOP_TO_IDX(FOP_FMUL)] = {vfp_single_fmul, 0},
1160 [FOP_TO_IDX(FOP_FNMUL)] = vfp_single_fnmul, 1160 [FOP_TO_IDX(FOP_FNMUL)] = {vfp_single_fnmul, 0},
1161 [FOP_TO_IDX(FOP_FADD)] = vfp_single_fadd, 1161 [FOP_TO_IDX(FOP_FADD)] = {vfp_single_fadd, 0},
1162 [FOP_TO_IDX(FOP_FSUB)] = vfp_single_fsub, 1162 [FOP_TO_IDX(FOP_FSUB)] = {vfp_single_fsub, 0},
1163 [FOP_TO_IDX(FOP_FDIV)] = vfp_single_fdiv, 1163 [FOP_TO_IDX(FOP_FDIV)] = {vfp_single_fdiv, 0},
1164}; 1164};
1165 1165
1166#define FREG_BANK(x) ((x) & 0x18) 1166#define FREG_BANK(x) ((x) & 0x18)
@@ -1174,19 +1174,18 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1174 unsigned int sn = vfp_get_sn(inst); 1174 unsigned int sn = vfp_get_sn(inst);
1175 unsigned int sm = vfp_get_sm(inst); 1175 unsigned int sm = vfp_get_sm(inst);
1176 unsigned int vecitr, veclen, vecstride; 1176 unsigned int vecitr, veclen, vecstride;
1177 u32 (*fop)(int, int, s32, u32); 1177 struct op *fop;
1178 1178
1179 veclen = fpscr & FPSCR_LENGTH_MASK;
1180 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); 1179 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1181 1180
1181 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1182 /* 1182 /*
1183 * fcvtsd takes a dN register number as destination, not sN. 1183 * fcvtsd takes a dN register number as destination, not sN.
1184 * Technically, if bit 0 of dd is set, this is an invalid 1184 * Technically, if bit 0 of dd is set, this is an invalid
1185 * instruction. However, we ignore this for efficiency. 1185 * instruction. However, we ignore this for efficiency.
1186 * It also only operates on scalars. 1186 * It also only operates on scalars.
1187 */ 1187 */
1188 if ((inst & FEXT_MASK) == FEXT_FCVT) { 1188 if (fop->flags & OP_SD) {
1189 veclen = 0;
1190 dest = vfp_get_dd(inst); 1189 dest = vfp_get_dd(inst);
1191 } else 1190 } else
1192 dest = vfp_get_sd(inst); 1191 dest = vfp_get_sd(inst);
@@ -1195,21 +1194,22 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1195 * If destination bank is zero, vector length is always '1'. 1194 * If destination bank is zero, vector length is always '1'.
1196 * ARM DDI0100F C5.1.3, C5.3.2. 1195 * ARM DDI0100F C5.1.3, C5.3.2.
1197 */ 1196 */
1198 if (FREG_BANK(dest) == 0) 1197 if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1199 veclen = 0; 1198 veclen = 0;
1199 else
1200 veclen = fpscr & FPSCR_LENGTH_MASK;
1200 1201
1201 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, 1202 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1202 (veclen >> FPSCR_LENGTH_BIT) + 1); 1203 (veclen >> FPSCR_LENGTH_BIT) + 1);
1203 1204
1204 fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)]; 1205 if (!fop->fn)
1205 if (!fop)
1206 goto invalid; 1206 goto invalid;
1207 1207
1208 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { 1208 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1209 s32 m = vfp_get_float(sm); 1209 s32 m = vfp_get_float(sm);
1210 u32 except; 1210 u32 except;
1211 1211
1212 if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT) 1212 if (op == FOP_EXT && (fop->flags & OP_SD))
1213 pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n", 1213 pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n",
1214 vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m); 1214 vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
1215 else if (op == FOP_EXT) 1215 else if (op == FOP_EXT)
@@ -1220,7 +1220,7 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1220 vecitr >> FPSCR_LENGTH_BIT, dest, sn, 1220 vecitr >> FPSCR_LENGTH_BIT, dest, sn,
1221 FOP_TO_IDX(op), sm, m); 1221 FOP_TO_IDX(op), sm, m);
1222 1222
1223 except = fop(dest, sn, m, fpscr); 1223 except = fop->fn(dest, sn, m, fpscr);
1224 pr_debug("VFP: itr%d: exceptions=%08x\n", 1224 pr_debug("VFP: itr%d: exceptions=%08x\n",
1225 vecitr >> FPSCR_LENGTH_BIT, except); 1225 vecitr >> FPSCR_LENGTH_BIT, except);
1226 1226