1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #define Extern extern
6 #include "mips.h"
7
8 void unimp(ulong);
9 void Ifcmp(ulong);
10 void Ifdiv(ulong);
11 void Ifmul(ulong);
12 void Ifadd(ulong);
13 void Ifsub(ulong);
14 void Ifmov(ulong);
15 void Icvtd(ulong);
16 void Icvtw(ulong);
17 void Icvts(ulong);
18 void Ifabs(ulong);
19 void Ifneg(ulong);
20
21 Inst cop1[] = {
22 { Ifadd, "add.f", Ifloat },
23 { Ifsub, "sub.f", Ifloat },
24 { Ifmul, "mul.f", Ifloat },
25 { Ifdiv, "div.f", Ifloat },
26 { unimp, "", },
27 { Ifabs, "abs.f", Ifloat },
28 { Ifmov, "mov.f", Ifloat },
29 { Ifneg, "neg.f", Ifloat },
30 { unimp, "", },
31 { unimp, "", },
32 { unimp, "", },
33 { unimp, "", },
34 { unimp, "", },
35 { unimp, "", },
36 { unimp, "", },
37 { unimp, "", },
38 { unimp, "", },
39 { unimp, "", },
40 { unimp, "", },
41 { unimp, "", },
42 { unimp, "", },
43 { unimp, "", },
44 { unimp, "", },
45 { unimp, "", },
46 { unimp, "", },
47 { unimp, "", },
48 { unimp, "", },
49 { unimp, "", },
50 { unimp, "", },
51 { unimp, "", },
52 { unimp, "", },
53 { unimp, "", },
54 { Icvts, "cvt.s", Ifloat },
55 { Icvtd, "cvt.d", Ifloat },
56 { unimp, "", },
57 { unimp, "", },
58 { Icvtw, "cvt.w", Ifloat },
59 { unimp, "", },
60 { unimp, "", },
61 { unimp, "", },
62 { unimp, "", },
63 { unimp, "", },
64 { unimp, "", },
65 { unimp, "", },
66 { unimp, "", },
67 { unimp, "", },
68 { unimp, "", },
69 { unimp, "", },
70 { Ifcmp, "c.f", Ifloat },
71 { Ifcmp, "c.un", Ifloat },
72 { Ifcmp, "c.eq", Ifloat },
73 { Ifcmp, "c.ueq", Ifloat },
74 { Ifcmp, "c.olt", Ifloat },
75 { Ifcmp, "c.ult", Ifloat },
76 { Ifcmp, "c.ole", Ifloat },
77 { Ifcmp, "c.ule", Ifloat },
78 { Ifcmp, "c,sf", Ifloat },
79 { Ifcmp, "c.ngle",Ifloat },
80 { Ifcmp, "c.seq", Ifloat },
81 { Ifcmp, "c.ngl", Ifloat },
82 { Ifcmp, "c.lt", Ifloat },
83 { Ifcmp, "c.nge", Ifloat },
84 { Ifcmp, "c.le", Ifloat },
85 { Ifcmp, "c.ngt", Ifloat },
86 { 0 }
87 };
88
89 void
unimp(ulong inst)90 unimp(ulong inst)
91 {
92 print("op %ld\n", inst&0x3f);
93 Bprint(bioout, "Unimplemented floating point Trap IR %.8lux\n", inst);
94 longjmp(errjmp, 0);
95 }
96
97 void
inval(ulong inst)98 inval(ulong inst)
99 {
100 Bprint(bioout, "Invalid Operation Exception IR %.8lux\n", inst);
101 longjmp(errjmp, 0);
102 }
103
104 void
ifmt(int r)105 ifmt(int r)
106 {
107 Bprint(bioout, "Invalid Floating Data Format f%d pc 0x%lux\n", r, reg.pc);
108 longjmp(errjmp, 0);
109 }
110
111 void
floatop(int dst,int s1,int s2)112 floatop(int dst, int s1, int s2)
113 {
114 if(reg.ft[s1] == FPd && s1 != 24)
115 ifmt(s1);
116 if(reg.ft[s2] == FPd && s2 != 24)
117 ifmt(s2);
118 reg.ft[dst] = FPs;
119 }
120
121 void
doubop(int dst,int s1,int s2)122 doubop(int dst, int s1, int s2)
123 {
124 ulong l;
125
126 if(reg.ft[s1] != FPd) {
127 if(reg.ft[s1] == FPs && s1 != 24)
128 ifmt(s1);
129 l = reg.di[s1];
130 reg.di[s1] = reg.di[s1+1];
131 reg.di[s1+1] = l;
132 reg.ft[s1] = FPd;
133 }
134 if(reg.ft[s2] != FPd) {
135 if(reg.ft[s2] == FPs && s2 != 24)
136 ifmt(s2);
137 l = reg.di[s2];
138 reg.di[s2] = reg.di[s2+1];
139 reg.di[s2+1] = l;
140 reg.ft[s2] = FPd;
141 }
142 reg.ft[dst] = FPd;
143 }
144
145 void
Iswc1(ulong inst)146 Iswc1(ulong inst)
147 {
148 int off;
149 ulong l;
150 int rt, rb, ert;
151
152 Getrbrt(rb, rt, inst);
153 off = (short)(inst&0xffff);
154
155 if(trace)
156 itrace("swc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off);
157
158 ert = rt&~1;
159 if(reg.ft[ert] == FPd) {
160 l = reg.di[ert];
161 reg.di[ert] = reg.di[ert+1];
162 reg.di[ert+1] = l;
163 reg.ft[ert] = FPmemory;
164 }
165 putmem_w(reg.r[rb]+off, reg.di[rt]);
166 }
167
168 void
Ifsub(ulong ir)169 Ifsub(ulong ir)
170 {
171 char fmt;
172 int fs, ft, fd;
173
174 Getf3(fs, ft, fd, ir);
175
176 switch((ir>>21)&0xf) {
177 default:
178 unimp(ir);
179 case 0: /* single */
180 fmt = 's';
181 floatop(fd, fs, ft);
182 reg.fl[fd] = reg.fl[fs] - reg.fl[ft];
183 break;
184 case 1: /* double */
185 fmt = 'd';
186 doubop(fd, fs, ft);
187 reg.fd[fd>>1] = reg.fd[fs>>1] - reg.fd[ft>>1];
188 break;
189 case 4:
190 fmt = 'w';
191 reg.di[fd] = reg.di[fs] - reg.di[ft];
192 break;
193 }
194 if(trace)
195 itrace("sub.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
196 }
197
198 void
Ifmov(ulong ir)199 Ifmov(ulong ir)
200 {
201 char fmt;
202 int fs, fd;
203
204 Getf2(fs, fd, ir);
205
206 switch((ir>>21)&0xf) {
207 default:
208 unimp(ir);
209 case 0: /* single */
210 fmt = 's';
211 reg.fl[fd] = reg.fl[fs];
212 reg.ft[fd] = reg.ft[fs];
213 break;
214 case 1: /* double */
215 fmt = 'd';
216 reg.fd[fd>>1] = reg.fd[fs>>1];
217 reg.ft[fd] = reg.ft[fs];
218 break;
219 case 4:
220 fmt = 'w';
221 reg.di[fd] = reg.di[fs];
222 reg.ft[fd] = reg.ft[fs];
223 break;
224 }
225 if(trace)
226 itrace("mov.%c\tf%d,f%d", fmt, fd, fs);
227 }
228
229 void
Ifabs(ulong ir)230 Ifabs(ulong ir)
231 {
232 char fmt;
233 int fs, fd;
234
235 Getf2(fs, fd, ir);
236
237 switch((ir>>21)&0xf) {
238 default:
239 unimp(ir);
240 case 0: /* single */
241 fmt = 's';
242 floatop(fd, fs, fs);
243 if(reg.fl[fs] < 0.0)
244 reg.fl[fd] = -reg.fl[fs];
245 else
246 reg.fl[fd] = reg.fl[fs];
247 break;
248 case 1: /* double */
249 fmt = 'd';
250 doubop(fd, fs, fs);
251 if(reg.fd[fs>>1] < 0.0)
252 reg.fd[fd>>1] = -reg.fd[fs>>1];
253 else
254 reg.fd[fd>>1] = reg.fd[fs>>1];
255 break;
256 case 4:
257 fmt = 'w';
258 if((long)reg.di[fs] < 0)
259 reg.di[fd] = -reg.di[fs];
260 else
261 reg.di[fd] = reg.di[fs];
262 break;
263 }
264 if(trace)
265 itrace("abs.%c\tf%d,f%d", fmt, fd, fs);
266 }
267
268 void
Ifneg(ulong ir)269 Ifneg(ulong ir)
270 {
271 char fmt;
272 int fs, fd;
273
274 Getf2(fs, fd, ir);
275
276 switch((ir>>21)&0xf) {
277 default:
278 unimp(ir);
279 case 0: /* single */
280 fmt = 's';
281 floatop(fd, fs, fs);
282 reg.fl[fd] = -reg.fl[fs];
283 break;
284 case 1: /* double */
285 fmt = 'd';
286 doubop(fd, fs, fs);
287 reg.fd[fd>>1] = -reg.fd[fs>>1];
288 break;
289 case 4:
290 fmt = 'w';
291 reg.di[fd] = -reg.di[fs];
292 break;
293 }
294 if(trace)
295 itrace("neg.%c\tf%d,f%d", fmt, fd, fs);
296 }
297
298 void
Icvtd(ulong ir)299 Icvtd(ulong ir)
300 {
301 char fmt;
302 int fs, fd;
303
304 Getf2(fs, fd, ir);
305
306 switch((ir>>21)&0xf) {
307 default:
308 unimp(ir);
309 case 0: /* single */
310 fmt = 's';
311 floatop(fs, fs, fs);
312 reg.fd[fd>>1] = reg.fl[fs];
313 reg.ft[fd] = FPd;
314 break;
315 case 1: /* double */
316 fmt = 'd';
317 doubop(fd, fs, fs);
318 reg.fd[fd>>1] = reg.fd[fs>>1];
319 break;
320 case 4:
321 fmt = 'w';
322 reg.fd[fd>>1] = (long)reg.di[fs];
323 reg.ft[fd] = FPd;
324 break;
325 }
326 if(trace)
327 itrace("cvt.d.%c\tf%d,f%d", fmt, fd, fs);
328 }
329
330 void
Icvts(ulong ir)331 Icvts(ulong ir)
332 {
333 char fmt;
334 int fs, fd;
335
336 Getf2(fs, fd, ir);
337
338 switch((ir>>21)&0xf) {
339 default:
340 unimp(ir);
341 case 0: /* single */
342 fmt = 's';
343 floatop(fd, fs, fs);
344 reg.fl[fd] = reg.fl[fs];
345 break;
346 case 1: /* double */
347 fmt = 'd';
348 doubop(fs, fs, fs);
349 reg.fl[fd] = reg.fd[fs>>1];
350 reg.ft[fd] = FPs;
351 break;
352 case 4:
353 fmt = 'w';
354 reg.fl[fd] = (long)reg.di[fs];
355 reg.ft[fd] = FPs;
356 break;
357 }
358 if(trace)
359 itrace("cvt.s.%c\tf%d,f%d", fmt, fd, fs);
360 }
361
362 void
Icvtw(ulong ir)363 Icvtw(ulong ir)
364 {
365 long v;
366 char fmt;
367 int fs, fd;
368
369 Getf2(fs, fd, ir);
370
371 switch((ir>>21)&0xf) {
372 default:
373 unimp(ir);
374 case 0: /* single */
375 fmt = 's';
376 floatop(fs, fs, fs);
377 v = reg.fl[fs];
378 break;
379 case 1: /* double */
380 fmt = 'd';
381 doubop(fs, fs, fs);
382 v = reg.fd[fs>>1];
383 break;
384 case 4:
385 fmt = 'w';
386 v = reg.di[fs];
387 break;
388 }
389 reg.di[fd] = v;
390 reg.ft[fd] = FPmemory;
391 if(trace)
392 itrace("cvt.w.%c\tf%d,f%d", fmt, fd, fs);
393 }
394
395 void
Ifadd(ulong ir)396 Ifadd(ulong ir)
397 {
398 char fmt;
399 int fs, ft, fd;
400
401 Getf3(fs, ft, fd, ir);
402
403 switch((ir>>21)&0xf) {
404 default:
405 unimp(ir);
406 case 0: /* single */
407 fmt = 's';
408 floatop(fd, fs, ft);
409 reg.fl[fd] = reg.fl[fs] + reg.fl[ft];
410 break;
411 case 1: /* double */
412 fmt = 'd';
413 doubop(fd, fs, ft);
414 reg.fd[fd>>1] = reg.fd[fs>>1] + reg.fd[ft>>1];
415 break;
416 case 4:
417 fmt = 'w';
418 reg.di[fd] = reg.di[fs] + reg.di[ft];
419 break;
420 }
421 if(trace)
422 itrace("add.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
423 }
424
425 void
Ifmul(ulong ir)426 Ifmul(ulong ir)
427 {
428 char fmt;
429 int fs, ft, fd;
430
431 Getf3(fs, ft, fd, ir);
432
433 switch((ir>>21)&0xf) {
434 default:
435 unimp(ir);
436 case 0: /* single */
437 fmt = 's';
438 floatop(fd, fs, ft);
439 reg.fl[fd] = reg.fl[fs] * reg.fl[ft];
440 break;
441 case 1: /* double */
442 fmt = 'd';
443 doubop(fd, fs, ft);
444 reg.fd[fd>>1] = reg.fd[fs>>1] * reg.fd[ft>>1];
445 break;
446 case 4:
447 fmt = 'w';
448 reg.di[fd] = reg.di[fs] * reg.di[ft];
449 break;
450 }
451 if(trace)
452 itrace("mul.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
453 }
454
455 void
Ifdiv(ulong ir)456 Ifdiv(ulong ir)
457 {
458 char fmt;
459 int fs, ft, fd;
460
461 Getf3(fs, ft, fd, ir);
462
463 switch((ir>>21)&0xf) {
464 default:
465 unimp(ir);
466 case 0: /* single */
467 fmt = 's';
468 floatop(fd, fs, ft);
469 reg.fl[fd] = reg.fl[fs] / reg.fl[ft];
470 break;
471 case 1: /* double */
472 fmt = 'd';
473 doubop(fd, fs, ft);
474 reg.fd[fd>>1] = reg.fd[fs>>1] / reg.fd[ft>>1];
475 break;
476 case 4:
477 fmt = 'w';
478 reg.di[fd] = reg.di[fs] / reg.di[ft];
479 break;
480 }
481 if(trace)
482 itrace("div.%c\tf%d,f%d,f%d", fmt, fd, fs, ft);
483 }
484
485 void
Ilwc1(ulong inst)486 Ilwc1(ulong inst)
487 {
488 int rt, rb;
489 int off;
490
491 Getrbrt(rb, rt, inst);
492 off = (short)(inst&0xffff);
493
494 if(trace)
495 itrace("lwc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off);
496
497 reg.di[rt] = getmem_w(reg.r[rb]+off);
498 reg.ft[rt] = FPmemory;
499 }
500
501 void
Ibcfbct(ulong inst)502 Ibcfbct(ulong inst)
503 {
504 int takeit;
505 int off;
506 ulong npc;
507
508 off = (short)(inst&0xffff);
509
510 takeit = 0;
511 npc = reg.pc + (off<<2) + 4;
512 if(inst&(1<<16)) {
513 if(trace)
514 itrace("bc1t\t0x%lux", npc);
515
516 if(reg.fpsr&FP_CBIT)
517 takeit = 1;
518 }
519 else {
520 if(trace)
521 itrace("bc1f\t0x%lux", npc);
522
523 if((reg.fpsr&FP_CBIT) == 0)
524 takeit = 1;
525 }
526
527 if(takeit) {
528 /* Do the delay slot */
529 reg.ir = ifetch(reg.pc+4);
530 Statbra();
531 Iexec(reg.ir);
532 reg.pc = npc-4;
533 }
534 }
535
536 void
Imtct(ulong ir)537 Imtct(ulong ir)
538 {
539 int rt, fs;
540
541 SpecialGetrtrd(rt, fs, ir);
542 if(ir&(1<<22)) { /* CT */
543 if(trace)
544 itrace("ctc1\tr%d,f%d", rt, fs);
545 }
546 else { /* MT */
547 if(trace)
548 itrace("mtc1\tr%d,f%d", rt, fs);
549
550 reg.di[fs] = reg.r[rt];
551 reg.ft[fs] = FPmemory;
552 }
553 }
554
555 void
Imfcf(ulong ir)556 Imfcf(ulong ir)
557 {
558 int rt, fs;
559
560 SpecialGetrtrd(rt, fs, ir);
561 if(ir&(1<<22)) { /* CF */
562 if(trace)
563 itrace("cfc1\tr%d,f%d", rt, fs);
564 }
565 else { /* MF */
566 if(trace)
567 itrace("mfc1\tr%d,f%d", rt, fs);
568
569 reg.r[rt] = reg.di[fs];
570 }
571 }
572
573 void
Icop1(ulong ir)574 Icop1(ulong ir)
575 {
576 Inst *i;
577
578 switch((ir>>23)&7) {
579 case 0:
580 Imfcf(ir);
581 break;
582 case 1:
583 Imtct(ir);
584 break;
585 case 2:
586 case 3:
587 Ibcfbct(ir);
588 break;
589 case 4:
590 case 5:
591 case 6:
592 case 7:
593 i = &cop1[ir&0x3f];
594 i->count++;
595 (*i->func)(ir);
596 }
597 }
598
599 void
Ifcmp(ulong ir)600 Ifcmp(ulong ir)
601 {
602 char fmt;
603 int fc;
604 int ft, fs;
605
606 SpecialGetrtrd(ft, fs, ir);
607
608 SET(fc);
609 switch((ir>>21)&0xf) {
610 default:
611 unimp(ir);
612 case 0: /* single */
613 fmt = 's';
614 floatop(fs, fs, ft);
615 if(isNaN(reg.fl[fs]) || isNaN(reg.fl[ft])) {
616 fc = FP_U;
617 break;
618 }
619 if(reg.fl[fs] == reg.fl[ft]) {
620 fc = FP_E;
621 break;
622 }
623 if(reg.fl[fs] < reg.fl[ft]) {
624 fc = FP_L;
625 break;
626 }
627 if(reg.fl[fs] > reg.fl[ft]) {
628 fc = FP_G;
629 break;
630 }
631 print("vi: bad in fcmp");
632 break;
633 case 1: /* double */
634 fmt = 'd';
635 doubop(fs, fs, ft);
636 if(isNaN(reg.fd[fs>>1]) || isNaN(reg.fd[ft>>1])) {
637 fc = FP_U;
638 break;
639 }
640 if(reg.fd[fs>>1] == reg.fd[ft>>1]) {
641 fc = FP_E;
642 break;
643 }
644 if(reg.fd[fs>>1] < reg.fd[ft>>1]) {
645 fc = FP_L;
646 break;
647 }
648 if(reg.fd[fs>>1] > reg.fd[ft>>1]) {
649 fc = FP_G;
650 break;
651 }
652 print("vi: bad in fcmp");
653 break;
654 case 4:
655 fmt = 'w';
656 if(reg.di[fs] == reg.di[ft]) {
657 fc = FP_E;
658 break;
659 }
660 if(reg.di[fs] < reg.di[ft]) {
661 fc = FP_L;
662 break;
663 }
664 if(reg.di[fs] > reg.di[ft]) {
665 fc = FP_G;
666 break;
667 }
668 break;
669 }
670
671 reg.fpsr &= ~FP_CBIT;
672 switch(ir&0xf) {
673 case 0:
674 if(trace)
675 itrace("c.f.%c\tf%d,f%d", fmt, fs, ft);
676 break;
677 case 1:
678 if(trace)
679 itrace("c.un.%c\tf%d,f%d", fmt, fs, ft);
680 if(fc == FP_U)
681 reg.fpsr |= FP_CBIT;
682 break;
683 case 2:
684 if(trace)
685 itrace("c.eq.%c\tf%d,f%d", fmt, fs, ft);
686 if(fc == FP_E)
687 reg.fpsr |= FP_CBIT;
688 break;
689 case 3:
690 if(trace)
691 itrace("c.ueq.%c\tf%d,f%d", fmt, fs, ft);
692 if(fc == FP_E || fc == FP_U)
693 reg.fpsr |= FP_CBIT;
694 break;
695 case 4:
696 if(trace)
697 itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft);
698 if(fc == FP_L)
699 reg.fpsr |= FP_CBIT;
700 break;
701 case 5:
702 if(trace)
703 itrace("c.ult.%c\tf%d,f%d", fmt, fs, ft);
704 if(fc == FP_L || fc == FP_U)
705 reg.fpsr |= FP_CBIT;
706 break;
707 case 6:
708 if(trace)
709 itrace("c.le.%c\tf%d,f%d", fmt, fs, ft);
710 if(fc == FP_E || fc == FP_L)
711 reg.fpsr |= FP_CBIT;
712 break;
713 case 7:
714 if(trace)
715 itrace("c.ule.%c\tf%d,f%d", fmt, fs, ft);
716 if(fc == FP_E || fc == FP_L || fc == FP_U)
717 reg.fpsr |= FP_CBIT;
718 break;
719 case 8:
720 if(trace)
721 itrace("c.sf.%c\tf%d,f%d", fmt, fs, ft);
722 if(fc == FP_U)
723 inval(ir);
724 break;
725 case 9:
726 if(trace)
727 itrace("c.ngle.%c\tf%d,f%d", fmt, fs, ft);
728 if(fc == FP_U) {
729 reg.fpsr |= FP_CBIT;
730 inval(ir);
731 }
732 break;
733 case 10:
734 if(trace)
735 itrace("c.seq.%c\tf%d,f%d", fmt, fs, ft);
736 if(fc == FP_E)
737 reg.fpsr |= FP_CBIT;
738 if(fc == FP_U)
739 inval(ir);
740 break;
741 case 11:
742 if(trace)
743 itrace("c.ngl.%c\tf%d,f%d", fmt, fs, ft);
744 if(fc == FP_E || fc == FP_U)
745 reg.fpsr |= FP_CBIT;
746 if(fc == FP_U)
747 inval(ir);
748 break;
749 case 12:
750 if(trace)
751 itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft);
752 if(fc == FP_L)
753 reg.fpsr |= FP_CBIT;
754 if(fc == FP_U)
755 inval(ir);
756 break;
757 case 13:
758 if(trace)
759 itrace("c.nge.%c\tf%d,f%d", fmt, fs, ft);
760 if(fc == FP_L || fc == FP_U)
761 reg.fpsr |= FP_CBIT;
762 if(fc == FP_U)
763 inval(ir);
764 break;
765 case 14:
766 if(trace)
767 itrace("c.le.%c\tf%d,f%d", fmt, fs, ft);
768 if(fc == FP_E || fc == FP_L)
769 reg.fpsr |= FP_CBIT;
770 if(fc == FP_U)
771 inval(ir);
772 break;
773 case 15:
774 if(trace)
775 itrace("c.ngt.%c\tf%d,f%d", fmt, fs, ft);
776 if(fc == FP_E || fc == FP_L || fc == FP_U)
777 reg.fpsr |= FP_CBIT;
778 if(fc == FP_U)
779 inval(ir);
780 break;
781 }
782 USED(fmt);
783 }
784