]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5e/fpa.c
cwfs: fix listen filedescriptor leaks
[plan9front.git] / sys / src / cmd / 5e / fpa.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <bio.h>
5 #include <mach.h>
6 #include "dat.h"
7 #include "fns.h"
8
9 void
10 resetfpa(void)
11 {
12         int i;
13         
14         P->FPSR = 0x81000000;
15         for(i = 0; i < 8; i++)
16                 P->F[i] = 0;
17 }
18
19 void
20 fpatransfer(u32int instr)
21 {
22         enum {
23                 fP = 1<<24,
24                 fU = 1<<23,
25                 fT1 = 1<<22,
26                 fW = 1<<21,
27                 fL = 1<<20,
28                 fT0 = 1<<15,
29         };
30
31         long double *Fd;
32         u32int *Rn, addr;
33         int off;
34         void *targ;
35         Segment *seg;
36
37         Rn = P->R + ((instr >> 16) & 15);
38         Fd = P->F + ((instr >> 12) & 7);
39         if(Rn == P->R + 15)
40                 invalid(instr);
41         off = (instr & 255) * 4;
42         if(!(instr  & fU))
43                 off = -off;
44         addr = *Rn;
45         if(instr & fP)
46                 addr += off;
47         targ = vaddr(addr, 8, &seg);
48         switch(instr & (fT0 | fT1 | fL)) {
49         case 0: *(float *) targ = *Fd; break;
50         case fL: *Fd = *(float *) targ; break;
51         case fT0: *(double *) targ = *Fd; break;
52         case fT0 | fL: *Fd = *(double *) targ; break;
53         default: invalid(instr);
54         }
55         segunlock(seg);
56         if(!(instr & fP))
57                 addr += off;
58         if(instr & fW)
59                 *Rn = addr;
60 }
61
62 static long double
63 fpasecop(u32int instr)
64 {
65         switch(instr & 15) {
66         case 8: return 0.0; break;
67         case 9: return 1.0; break;
68         case 10: return 2.0; break;
69         case 11: return 3.0; break;
70         case 12: return 4.0; break;
71         case 13: return 5.0; break;
72         case 14: return 0.5; break;
73         case 15: return 10.0; break;
74         }
75         return P->F[instr & 7];
76 }
77
78 void
79 fpaoperation(u32int instr)
80 {
81         long double *Fn, *Fd, op, op2, res;
82         int prec, opc;
83         
84         Fn = P->F + ((instr >> 16) & 7);
85         Fd = P->F + ((instr >> 12) & 7);
86         op2 = fpasecop(instr);
87         op = *Fn;
88         prec = ((instr >> 7) & 1) | ((instr >> 18) & 2);
89         opc = ((instr >> 20) & 15) | ((instr >> 11) & 16);
90         switch(opc) {
91         case 0: res = op + op2; break;
92         case 1: res = op * op2; break;
93         case 2: res = op - op2; break;
94         case 3: res = op2 - op; break;
95         case 4: res = op / op2; break;
96         case 5: res = op2 / op; break;
97         case 16: res = op2; break;
98         case 17: res = - op2; break;
99         case 18: res = fabs(op2); break;
100         case 19: res = (vlong) op2; break;
101         case 20: res = sqrt(op2); break;
102         default: sysfatal("unimplemented FPA operation %#x @ %8ux", opc, P->R[15] - 4);
103         return;
104         }
105         switch(prec) {
106         case 0: *Fd = (float) res; break;
107         case 1: *Fd = (double) res; break;
108         case 2: *Fd = res; break;
109         default: invalid(instr);
110         }
111 }
112
113 void
114 fparegtransfer(u32int instr)
115 {
116         u32int *Rd;
117         long tmp;
118         long double *Fn, op, op2;
119         
120         Rd = P->R + ((instr >> 12) & 15);
121         Fn = P->F + ((instr >> 16) & 7);
122         op = fpasecop(instr);
123         if(Rd == P->R + 15) {
124                 op2 = *Fn;
125                 switch((instr >> 21) & 7) {
126                 case 4: break;
127                 case 5: op = - op; break;
128                 default: invalid(instr);
129                 }
130                 if(op2 < op)
131                         P->CPSR = (P->CPSR & ~FLAGS) | flN;
132                 else if(op2 >= op) {
133                         P->CPSR = (P->CPSR & ~FLAGS) | flC;
134                         if(op2 == op)
135                                 P->CPSR |= flZ;
136                 } else
137                         P->CPSR = (P->CPSR & ~FLAGS) | flV;
138                 return;
139         }
140         if(instr & (1<<3))
141                 invalid(instr);
142         switch((instr >> 20) & 15) {
143         case 0: *Fn = *(long *) Rd; break;
144         case 1: tmp = op; *Rd = tmp; break;
145         case 2: P->FPSR = *Rd; break;
146         case 3: *Rd = P->FPSR; break;
147         default: invalid(instr);
148         }
149 }