diff options
author | Gen FUKATSU <fukatsu.gen@jp.panasonic.com> | 2006-09-21 09:08:24 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-09-25 05:34:06 -0400 |
commit | 4cc9bd2eaa1063c68341c1c00e66660adcfdf254 (patch) | |
tree | 3ee6d9f6b2075d4a5e340d2a3370f9e068aab723 /arch/arm/vfp/vfpdouble.c | |
parent | f8c440b209581809c5c8acac599410f23597a7b8 (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>
Diffstat (limited to 'arch/arm/vfp/vfpdouble.c')
-rw-r--r-- | arch/arm/vfp/vfpdouble.c | 72 |
1 files changed, 36 insertions, 36 deletions
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 | ||
662 | static u32 (* const fop_extfns[32])(int dd, int unused, int dm, u32 fpscr) = { | 662 | static 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 | ||
1111 | static u32 (* const fop_fns[16])(int dd, int dn, int dm, u32 fpscr) = { | 1111 | static 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 | ||