Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/powerpc/booke/spe.c
39536 views
1
/*-
2
* Copyright (C) 1996 Wolfgang Solfrank.
3
* Copyright (C) 1996 TooLs GmbH.
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* 3. All advertising materials mentioning features or use of this software
15
* must display the following acknowledgement:
16
* This product includes software developed by TooLs GmbH.
17
* 4. The name of TooLs GmbH may not be used to endorse or promote products
18
* derived from this software without specific prior written permission.
19
*
20
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
*
31
* $NetBSD: fpu.c,v 1.5 2001/07/22 11:29:46 wiz Exp $
32
*/
33
34
#include <sys/param.h>
35
#include <sys/proc.h>
36
#include <sys/systm.h>
37
#include <sys/limits.h>
38
39
#include <machine/altivec.h>
40
#include <machine/fpu.h>
41
#include <machine/ieeefp.h>
42
#include <machine/pcb.h>
43
#include <machine/psl.h>
44
45
#include <powerpc/fpu/fpu_arith.h>
46
#include <powerpc/fpu/fpu_emu.h>
47
#include <powerpc/fpu/fpu_extern.h>
48
49
void spe_handle_fpdata(struct trapframe *);
50
void spe_handle_fpround(struct trapframe *);
51
static int spe_emu_instr(uint32_t, struct fpemu *, struct fpn **, uint32_t *);
52
53
static void
54
save_vec_int(struct thread *td)
55
{
56
int msr;
57
struct pcb *pcb;
58
59
pcb = td->td_pcb;
60
61
/*
62
* Temporarily re-enable the vector unit during the save
63
*/
64
msr = mfmsr();
65
mtmsr(msr | PSL_VEC);
66
67
/*
68
* Save the vector registers and SPEFSCR to the PCB
69
*/
70
#define EVSTDW(n) __asm ("evstdw %1,0(%0)" \
71
:: "b"(pcb->pcb_vec.vr[n]), "n"(n));
72
EVSTDW(0); EVSTDW(1); EVSTDW(2); EVSTDW(3);
73
EVSTDW(4); EVSTDW(5); EVSTDW(6); EVSTDW(7);
74
EVSTDW(8); EVSTDW(9); EVSTDW(10); EVSTDW(11);
75
EVSTDW(12); EVSTDW(13); EVSTDW(14); EVSTDW(15);
76
EVSTDW(16); EVSTDW(17); EVSTDW(18); EVSTDW(19);
77
EVSTDW(20); EVSTDW(21); EVSTDW(22); EVSTDW(23);
78
EVSTDW(24); EVSTDW(25); EVSTDW(26); EVSTDW(27);
79
EVSTDW(28); EVSTDW(29); EVSTDW(30); EVSTDW(31);
80
#undef EVSTDW
81
82
__asm ( "evxor 0,0,0\n"
83
"evmwumiaa 0,0,0\n"
84
"evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.spare[0]));
85
pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
86
87
/*
88
* Disable vector unit again
89
*/
90
isync();
91
mtmsr(msr);
92
93
}
94
95
void
96
enable_vec(struct thread *td)
97
{
98
int msr;
99
struct pcb *pcb;
100
struct trapframe *tf;
101
102
pcb = td->td_pcb;
103
tf = trapframe(td);
104
105
/*
106
* Save the thread's SPE CPU number, and set the CPU's current
107
* vector thread
108
*/
109
td->td_pcb->pcb_veccpu = PCPU_GET(cpuid);
110
PCPU_SET(vecthread, td);
111
112
/*
113
* Enable the vector unit for when the thread returns from the
114
* exception. If this is the first time the unit has been used by
115
* the thread, initialise the vector registers and VSCR to 0, and
116
* set the flag to indicate that the vector unit is in use.
117
*/
118
tf->srr1 |= PSL_VEC;
119
if (!(pcb->pcb_flags & PCB_VEC)) {
120
memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
121
pcb->pcb_flags |= PCB_VEC;
122
pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
123
}
124
125
/*
126
* Temporarily enable the vector unit so the registers
127
* can be restored.
128
*/
129
msr = mfmsr();
130
mtmsr(msr | PSL_VEC);
131
132
/* Restore SPEFSCR and ACC. Use %r0 as the scratch for ACC. */
133
mtspr(SPR_SPEFSCR, pcb->pcb_vec.vscr);
134
__asm __volatile("isync;evldd 0, 0(%0); evmra 0,0\n"
135
:: "b"(&pcb->pcb_vec.spare[0]));
136
137
/*
138
* The lower half of each register will be restored on trap return. Use
139
* %r0 as a scratch register, and restore it last.
140
*/
141
#define EVLDW(n) __asm __volatile("evldw 0, 0(%0); evmergehilo "#n",0,"#n \
142
:: "b"(&pcb->pcb_vec.vr[n]));
143
EVLDW(1); EVLDW(2); EVLDW(3); EVLDW(4);
144
EVLDW(5); EVLDW(6); EVLDW(7); EVLDW(8);
145
EVLDW(9); EVLDW(10); EVLDW(11); EVLDW(12);
146
EVLDW(13); EVLDW(14); EVLDW(15); EVLDW(16);
147
EVLDW(17); EVLDW(18); EVLDW(19); EVLDW(20);
148
EVLDW(21); EVLDW(22); EVLDW(23); EVLDW(24);
149
EVLDW(25); EVLDW(26); EVLDW(27); EVLDW(28);
150
EVLDW(29); EVLDW(30); EVLDW(31); EVLDW(0);
151
#undef EVLDW
152
153
isync();
154
mtmsr(msr);
155
}
156
157
void
158
save_vec(struct thread *td)
159
{
160
struct pcb *pcb;
161
162
pcb = td->td_pcb;
163
164
save_vec_int(td);
165
166
/*
167
* Clear the current vec thread and pcb's CPU id
168
* XXX should this be left clear to allow lazy save/restore ?
169
*/
170
pcb->pcb_veccpu = INT_MAX;
171
PCPU_SET(vecthread, NULL);
172
}
173
174
/*
175
* Save SPE state without dropping ownership. This will only save state if
176
* the current vector-thread is `td'. This is used for taking core dumps, so
177
* don't leak kernel information; overwrite the low words of each vector with
178
* their real value, taken from the thread's trap frame, unconditionally.
179
*/
180
void
181
save_vec_nodrop(struct thread *td)
182
{
183
struct pcb *pcb;
184
int i;
185
186
if (td == PCPU_GET(vecthread))
187
save_vec_int(td);
188
189
pcb = td->td_pcb;
190
191
for (i = 0; i < 32; i++) {
192
pcb->pcb_vec.vr[i][1] =
193
td->td_frame ? td->td_frame->fixreg[i] : 0;
194
}
195
}
196
197
#define SPE_INST_MASK 0x31f
198
#define EADD 0x200
199
#define ESUB 0x201
200
#define EABS 0x204
201
#define ENABS 0x205
202
#define ENEG 0x206
203
#define EMUL 0x208
204
#define EDIV 0x209
205
#define ECMPGT 0x20c
206
#define ECMPLT 0x20d
207
#define ECMPEQ 0x20e
208
#define ECFUI 0x210
209
#define ECFSI 0x211
210
#define ECTUI 0x214
211
#define ECTSI 0x215
212
#define ECTUF 0x216
213
#define ECTSF 0x217
214
#define ECTUIZ 0x218
215
#define ECTSIZ 0x21a
216
217
#define SPE 0x4
218
#define SPFP 0x6
219
#define DPFP 0x7
220
221
#define SPE_OPC 4
222
#define OPC_SHIFT 26
223
224
#define EVFSADD 0x280
225
#define EVFSSUB 0x281
226
#define EVFSABS 0x284
227
#define EVFSNABS 0x285
228
#define EVFSNEG 0x286
229
#define EVFSMUL 0x288
230
#define EVFSDIV 0x289
231
#define EVFSCMPGT 0x28c
232
#define EVFSCMPLT 0x28d
233
#define EVFSCMPEQ 0x28e
234
#define EVFSCFUI 0x290
235
#define EVFSCFSI 0x291
236
#define EVFSCTUI 0x294
237
#define EVFSCTSI 0x295
238
#define EVFSCTUF 0x296
239
#define EVFSCTSF 0x297
240
#define EVFSCTUIZ 0x298
241
#define EVFSCTSIZ 0x29a
242
243
#define EFSADD 0x2c0
244
#define EFSSUB 0x2c1
245
#define EFSABS 0x2c4
246
#define EFSNABS 0x2c5
247
#define EFSNEG 0x2c6
248
#define EFSMUL 0x2c8
249
#define EFSDIV 0x2c9
250
#define EFSCMPGT 0x2cc
251
#define EFSCMPLT 0x2cd
252
#define EFSCMPEQ 0x2ce
253
#define EFSCFD 0x2cf
254
#define EFSCFUI 0x2d0
255
#define EFSCFSI 0x2d1
256
#define EFSCTUI 0x2d4
257
#define EFSCTSI 0x2d5
258
#define EFSCTUF 0x2d6
259
#define EFSCTSF 0x2d7
260
#define EFSCTUIZ 0x2d8
261
#define EFSCTSIZ 0x2da
262
263
#define EFDADD 0x2e0
264
#define EFDSUB 0x2e1
265
#define EFDABS 0x2e4
266
#define EFDNABS 0x2e5
267
#define EFDNEG 0x2e6
268
#define EFDMUL 0x2e8
269
#define EFDDIV 0x2e9
270
#define EFDCMPGT 0x2ec
271
#define EFDCMPLT 0x2ed
272
#define EFDCMPEQ 0x2ee
273
#define EFDCFS 0x2ef
274
#define EFDCFUI 0x2f0
275
#define EFDCFSI 0x2f1
276
#define EFDCTUI 0x2f4
277
#define EFDCTSI 0x2f5
278
#define EFDCTUF 0x2f6
279
#define EFDCTSF 0x2f7
280
#define EFDCTUIZ 0x2f8
281
#define EFDCTSIZ 0x2fa
282
283
enum {
284
NONE,
285
SINGLE,
286
DOUBLE,
287
VECTOR,
288
};
289
290
static uint32_t fpscr_to_spefscr(uint32_t fpscr)
291
{
292
uint32_t spefscr;
293
294
spefscr = 0;
295
296
if (fpscr & FPSCR_VX)
297
spefscr |= SPEFSCR_FINV;
298
if (fpscr & FPSCR_OX)
299
spefscr |= SPEFSCR_FOVF;
300
if (fpscr & FPSCR_UX)
301
spefscr |= SPEFSCR_FUNF;
302
if (fpscr & FPSCR_ZX)
303
spefscr |= SPEFSCR_FDBZ;
304
if (fpscr & FPSCR_XX)
305
spefscr |= SPEFSCR_FX;
306
307
return (spefscr);
308
}
309
310
/* Sign is 0 for unsigned, 1 for signed. */
311
static int
312
spe_to_int(struct fpemu *fpemu, struct fpn *fpn, uint32_t *val, int sign)
313
{
314
uint32_t res[2];
315
316
res[0] = fpu_ftox(fpemu, fpn, res);
317
if (res[0] != UINT_MAX && res[0] != 0)
318
fpemu->fe_cx |= FPSCR_OX;
319
else if (sign == 0 && res[0] != 0)
320
fpemu->fe_cx |= FPSCR_UX;
321
else
322
*val = res[1];
323
324
return (0);
325
}
326
327
/* Masked instruction */
328
/*
329
* For compare instructions, returns 1 if success, 0 if not. For all others,
330
* returns -1, or -2 if no result needs recorded.
331
*/
332
static int
333
spe_emu_instr(uint32_t instr, struct fpemu *fpemu,
334
struct fpn **result, uint32_t *iresult)
335
{
336
switch (instr & SPE_INST_MASK) {
337
case EABS:
338
case ENABS:
339
case ENEG:
340
/* Taken care of elsewhere. */
341
break;
342
case ECTUIZ:
343
fpemu->fe_cx &= ~FPSCR_RN;
344
fpemu->fe_cx |= FP_RZ;
345
case ECTUI:
346
spe_to_int(fpemu, &fpemu->fe_f2, iresult, 0);
347
return (-1);
348
case ECTSIZ:
349
fpemu->fe_cx &= ~FPSCR_RN;
350
fpemu->fe_cx |= FP_RZ;
351
case ECTSI:
352
spe_to_int(fpemu, &fpemu->fe_f2, iresult, 1);
353
return (-1);
354
case EADD:
355
*result = fpu_add(fpemu);
356
break;
357
case ESUB:
358
*result = fpu_sub(fpemu);
359
break;
360
case EMUL:
361
*result = fpu_mul(fpemu);
362
break;
363
case EDIV:
364
*result = fpu_div(fpemu);
365
break;
366
case ECMPGT:
367
fpu_compare(fpemu, 0);
368
if (fpemu->fe_cx & FPSCR_FG)
369
return (1);
370
return (0);
371
case ECMPLT:
372
fpu_compare(fpemu, 0);
373
if (fpemu->fe_cx & FPSCR_FL)
374
return (1);
375
return (0);
376
case ECMPEQ:
377
fpu_compare(fpemu, 0);
378
if (fpemu->fe_cx & FPSCR_FE)
379
return (1);
380
return (0);
381
default:
382
printf("Unknown instruction %x\n", instr);
383
}
384
385
return (-1);
386
}
387
388
static int
389
spe_explode(struct fpemu *fe, struct fpn *fp, uint32_t type,
390
uint32_t hi, uint32_t lo)
391
{
392
uint32_t s;
393
394
fp->fp_sign = hi >> 31;
395
fp->fp_sticky = 0;
396
switch (type) {
397
case SINGLE:
398
s = fpu_stof(fp, hi);
399
break;
400
401
case DOUBLE:
402
s = fpu_dtof(fp, hi, lo);
403
break;
404
}
405
406
if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
407
/*
408
* Input is a signalling NaN. All operations that return
409
* an input NaN operand put it through a ``NaN conversion'',
410
* which basically just means ``turn on the quiet bit''.
411
* We do this here so that all NaNs internally look quiet
412
* (we can tell signalling ones by their class).
413
*/
414
fp->fp_mant[0] |= FP_QUIETBIT;
415
fe->fe_cx = FPSCR_VXSNAN; /* assert invalid operand */
416
s = FPC_SNAN;
417
}
418
fp->fp_class = s;
419
420
return (0);
421
}
422
423
/*
424
* Save the high word of a 64-bit GPR for manipulation in the exception handler.
425
*/
426
static uint32_t
427
spe_save_reg_high(int reg)
428
{
429
uint32_t vec[2];
430
#define EVSTDW(n) case n: __asm __volatile ("evstdw %1,0(%0)" \
431
:: "b"(vec), "n"(n) : "memory"); break;
432
switch (reg) {
433
EVSTDW(0); EVSTDW(1); EVSTDW(2); EVSTDW(3);
434
EVSTDW(4); EVSTDW(5); EVSTDW(6); EVSTDW(7);
435
EVSTDW(8); EVSTDW(9); EVSTDW(10); EVSTDW(11);
436
EVSTDW(12); EVSTDW(13); EVSTDW(14); EVSTDW(15);
437
EVSTDW(16); EVSTDW(17); EVSTDW(18); EVSTDW(19);
438
EVSTDW(20); EVSTDW(21); EVSTDW(22); EVSTDW(23);
439
EVSTDW(24); EVSTDW(25); EVSTDW(26); EVSTDW(27);
440
EVSTDW(28); EVSTDW(29); EVSTDW(30); EVSTDW(31);
441
}
442
#undef EVSTDW
443
444
return (vec[0]);
445
}
446
447
/*
448
* Load the given value into the high word of the requested register.
449
*/
450
static void
451
spe_load_reg_high(int reg, uint32_t val)
452
{
453
#define EVLDW(n) case n: __asm __volatile("evmergelo "#n",%0,"#n \
454
:: "r"(val)); break;
455
switch (reg) {
456
EVLDW(1); EVLDW(2); EVLDW(3); EVLDW(4);
457
EVLDW(5); EVLDW(6); EVLDW(7); EVLDW(8);
458
EVLDW(9); EVLDW(10); EVLDW(11); EVLDW(12);
459
EVLDW(13); EVLDW(14); EVLDW(15); EVLDW(16);
460
EVLDW(17); EVLDW(18); EVLDW(19); EVLDW(20);
461
EVLDW(21); EVLDW(22); EVLDW(23); EVLDW(24);
462
EVLDW(25); EVLDW(26); EVLDW(27); EVLDW(28);
463
EVLDW(29); EVLDW(30); EVLDW(31); EVLDW(0);
464
}
465
#undef EVLDW
466
467
}
468
469
void
470
spe_handle_fpdata(struct trapframe *frame)
471
{
472
struct fpemu fpemu;
473
struct fpn *result;
474
uint32_t instr, instr_sec_op;
475
uint32_t cr_shift, ra, rb, rd, src;
476
uint32_t high, low, res, tmp; /* For vector operations. */
477
uint32_t spefscr = 0;
478
uint32_t ftod_res[2];
479
int width; /* Single, Double, Vector, Integer */
480
int err;
481
uint32_t msr;
482
483
err = fueword32((void *)frame->srr0, &instr);
484
485
if (err != 0)
486
return;
487
/* Fault. */;
488
489
if ((instr >> OPC_SHIFT) != SPE_OPC)
490
return;
491
492
msr = mfmsr();
493
/*
494
* 'cr' field is the upper 3 bits of rd. Magically, since a) rd is 5
495
* bits, b) each 'cr' field is 4 bits, and c) Only the 'GT' bit is
496
* modified for most compare operations, the full value of rd can be
497
* used as a shift value.
498
*/
499
rd = (instr >> 21) & 0x1f;
500
ra = (instr >> 16) & 0x1f;
501
rb = (instr >> 11) & 0x1f;
502
src = (instr >> 5) & 0x7;
503
cr_shift = 28 - (rd & 0x1f);
504
505
instr_sec_op = (instr & 0x7ff);
506
507
memset(&fpemu, 0, sizeof(fpemu));
508
509
width = NONE;
510
switch (src) {
511
case SPE:
512
mtmsr(msr | PSL_VEC);
513
switch (instr_sec_op) {
514
case EVFSABS:
515
high = spe_save_reg_high(ra) & ~(1U << 31);
516
frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
517
spe_load_reg_high(rd, high);
518
break;
519
case EVFSNABS:
520
high = spe_save_reg_high(ra) | (1U << 31);
521
frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
522
spe_load_reg_high(rd, high);
523
break;
524
case EVFSNEG:
525
high = spe_save_reg_high(ra) ^ (1U << 31);
526
frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
527
spe_load_reg_high(rd, high);
528
break;
529
default:
530
/* High word */
531
spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
532
spe_save_reg_high(ra), 0);
533
spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
534
spe_save_reg_high(rb), 0);
535
high = spe_emu_instr(instr_sec_op, &fpemu, &result,
536
&tmp);
537
538
if (high < 0)
539
spe_load_reg_high(rd, tmp);
540
541
spefscr = fpscr_to_spefscr(fpemu.fe_cx) << 16;
542
/* Clear the fpemu to start over on the lower bits. */
543
memset(&fpemu, 0, sizeof(fpemu));
544
545
/* Now low word */
546
spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
547
frame->fixreg[ra], 0);
548
spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
549
frame->fixreg[rb], 0);
550
spefscr |= fpscr_to_spefscr(fpemu.fe_cx);
551
low = spe_emu_instr(instr_sec_op, &fpemu, &result,
552
&frame->fixreg[rd]);
553
if (instr_sec_op == EVFSCMPEQ ||
554
instr_sec_op == EVFSCMPGT ||
555
instr_sec_op == EVFSCMPLT) {
556
res = (high << 3) | (low << 2) |
557
((high | low) << 1) | (high & low);
558
width = NONE;
559
} else
560
width = VECTOR;
561
break;
562
}
563
goto end;
564
565
case SPFP:
566
switch (instr_sec_op) {
567
case EFSABS:
568
frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
569
break;
570
case EFSNABS:
571
frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
572
break;
573
case EFSNEG:
574
frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
575
break;
576
case EFSCFD:
577
mtmsr(msr | PSL_VEC);
578
spe_explode(&fpemu, &fpemu.fe_f3, DOUBLE,
579
spe_save_reg_high(rb), frame->fixreg[rb]);
580
result = &fpemu.fe_f3;
581
width = SINGLE;
582
break;
583
default:
584
spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
585
frame->fixreg[ra], 0);
586
spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
587
frame->fixreg[rb], 0);
588
width = SINGLE;
589
}
590
break;
591
case DPFP:
592
mtmsr(msr | PSL_VEC);
593
switch (instr_sec_op) {
594
case EFDABS:
595
high = spe_save_reg_high(ra) & ~(1U << 31);
596
frame->fixreg[rd] = frame->fixreg[ra];
597
spe_load_reg_high(rd, high);
598
break;
599
case EFDNABS:
600
high = spe_save_reg_high(ra) | (1U << 31);
601
frame->fixreg[rd] = frame->fixreg[ra];
602
spe_load_reg_high(rd, high);
603
break;
604
case EFDNEG:
605
high = spe_save_reg_high(ra) ^ (1U << 31);
606
frame->fixreg[rd] = frame->fixreg[ra];
607
spe_load_reg_high(rd, high);
608
break;
609
case EFDCFS:
610
spe_explode(&fpemu, &fpemu.fe_f3, SINGLE,
611
frame->fixreg[rb], 0);
612
result = &fpemu.fe_f3;
613
width = DOUBLE;
614
break;
615
default:
616
spe_explode(&fpemu, &fpemu.fe_f1, DOUBLE,
617
spe_save_reg_high(ra), frame->fixreg[ra]);
618
spe_explode(&fpemu, &fpemu.fe_f2, DOUBLE,
619
spe_save_reg_high(rb), frame->fixreg[rb]);
620
width = DOUBLE;
621
}
622
break;
623
}
624
switch (instr_sec_op) {
625
case EFDCFS:
626
case EFSCFD:
627
/* Already handled. */
628
break;
629
default:
630
res = spe_emu_instr(instr_sec_op, &fpemu, &result,
631
&frame->fixreg[rd]);
632
if (res != -1)
633
res <<= 2;
634
break;
635
}
636
637
switch (instr_sec_op & SPE_INST_MASK) {
638
case ECMPEQ:
639
case ECMPGT:
640
case ECMPLT:
641
frame->cr &= ~(0xf << cr_shift);
642
frame->cr |= (res << cr_shift);
643
break;
644
case ECTUI:
645
case ECTUIZ:
646
case ECTSI:
647
case ECTSIZ:
648
break;
649
default:
650
switch (width) {
651
case NONE:
652
case VECTOR:
653
break;
654
case SINGLE:
655
frame->fixreg[rd] = fpu_ftos(&fpemu, result);
656
break;
657
case DOUBLE:
658
spe_load_reg_high(rd, fpu_ftod(&fpemu, result, ftod_res));
659
frame->fixreg[rd] = ftod_res[1];
660
break;
661
default:
662
panic("Unknown storage width %d", width);
663
break;
664
}
665
}
666
667
end:
668
spefscr |= (mfspr(SPR_SPEFSCR) & ~SPEFSCR_FINVS);
669
mtspr(SPR_SPEFSCR, spefscr);
670
frame->srr0 += 4;
671
mtmsr(msr);
672
673
return;
674
}
675
676
void
677
spe_handle_fpround(struct trapframe *frame)
678
{
679
680
/*
681
* Punt fpround exceptions for now. This leaves the truncated result in
682
* the register. We'll deal with overflow/underflow later.
683
*/
684
return;
685
}
686
687