]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/fptrap.c
merge
[plan9front.git] / sys / src / 9 / sgi / fptrap.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "ureg.h"
7 #include        "io.h"
8 #include        "../port/error.h"
9
10 enum    /* op */
11 {
12         ABS =   5,
13         ADD =   0,
14         CVTD =  33,
15         CVTS =  32,
16         CVTW =  36,
17         DIV =   3,
18         MOV =   6,
19         MUL =   2,
20         NEG =   7,
21         SUB =   1,
22 };
23
24 static int      fpunimp(ulong);
25 static ulong    branch(Ureg*, ulong);
26
27 void
28 fptrap(Ureg *ur)
29 {
30         ulong iw, npc;
31
32         if((up->fpsave.fpstatus&(1<<17)) == 0)
33                 return;
34
35         if(ur->cause & (1<<31))
36                 iw = *(ulong*)(ur->pc+4);
37         else
38                 iw = *(ulong*)ur->pc;
39
40         if(fpunimp(iw) == 0)
41                 return;
42
43         if(ur->cause & (1<<31)){
44                 npc = branch(ur, up->fpsave.fpstatus);
45                 if(npc == 0)
46                         return;
47                 ur->pc = npc;
48         }
49         else
50                 ur->pc += 4;
51
52         up->fpsave.fpstatus &= ~(1<<17);
53 }
54
55 static void
56 unpack(FPsave *f, int fmt, int reg, int *sign, int *exp)
57 {
58         *sign = 1;
59         if(f->reg[reg] & 0x80000000)
60                 *sign = -1;
61
62         switch(fmt){
63         case 0:
64                 *exp = ((f->reg[reg]>>23)&0xFF) - ((1<<7)-2);
65                 break;
66         case 1:
67                 if(reg & 1)     /* shouldn't happen */
68                         reg &= ~1;
69                 *exp = ((f->reg[reg]>>20)&0x7FF) - ((1<<10)-2);
70                 break;
71         }
72 }
73
74 static void
75 zeroreg(FPsave *f, int fmt, int reg, int sign)
76 {
77         int size;
78
79         size = 0;
80         switch(fmt){
81         case 0:
82                 size = 4;
83                 break;
84         case 1:
85                 if(reg & 1)
86                         reg &= ~1;
87                 size = 8;
88                 break;
89         }
90         memset(&f->reg[reg], 0, size);
91         if(sign < 0)
92                 f->reg[reg] |= 0x80000000;
93 }
94
95 static int
96 fpunimp(ulong iw)
97 {
98         int ss, st, sd;
99         int es, et, ed;
100         int maxe, maxm;
101         ulong op, fmt, ft, fs, fd;
102
103         if((iw>>25) != 0x23)
104                 return 0;
105         op = iw & ((1<<6)-1);
106         fmt = (iw>>21) & ((1<<4)-1);
107         ft = (iw>>16) & ((1<<5)-1);
108         fs = (iw>>11) & ((1<<5)-1);
109         fd = (iw>>6) & ((1<<5)-1);
110         unpack(&up->fpsave, fmt, fs, &ss, &es);
111         unpack(&up->fpsave, fmt, ft, &st, &et);
112         ed = 0;
113         maxe = 0;
114         maxm = 0;
115         switch(fmt){
116         case 0:
117                 maxe = 1<<7;
118                 maxm = 24;
119                 break;
120         case 1:
121                 maxe = 1<<10;
122                 maxm = 53;
123                 break;
124         }
125         switch(op){
126         case ABS:
127                 up->fpsave.reg[fd] &= ~0x80000000;
128                 return 1;
129
130         case NEG:
131                 up->fpsave.reg[fd] ^= 0x80000000;
132                 return 1;
133
134         case SUB:
135                 st = -st;
136         case ADD:
137                 if(es<-(maxe-maxm) && et<-(maxe-maxm))
138                         ed = -maxe;
139                 if(es > et)
140                         sd = es;
141                 else
142                         sd = et;
143                 break;
144
145         case DIV:
146                 et = -et;
147         case MUL:
148                 sd = 1;
149                 if(ss != st)
150                         sd = -1;
151                 ed = es + et;
152                 break;
153
154         case CVTS:
155                 if(fmt != 1)
156                         return 0;
157                 fmt = 0;        /* convert FROM double TO single */
158                 maxe = 1<<7;
159                 ed = es;
160                 sd = ss;
161                 break;
162
163         default:        /* probably a compare */
164                 return 0;
165         }
166         if(ed <= -(maxe-5)){    /* guess: underflow */
167                 zeroreg(&up->fpsave, fmt, fd, sd);
168                 /* Set underflow exception and sticky */
169                 up->fpsave.fpstatus |= (1<<3)|(1<<13);
170                 return 1;
171         }
172         return 0;
173 }
174
175 static ulong
176 branch(Ureg *ur, ulong fcr31)
177 {
178         ulong iw, npc, rs, rt, rd, offset;
179
180         iw = *(ulong*)ur->pc;
181         rs = (iw>>21) & 0x1F;
182         if(rs)
183                 rs = *reg(ur, rs);
184         rt = (iw>>16) & 0x1F;
185         if(rt)
186                 rt = *reg(ur, rt);
187         offset = iw & ((1<<16)-1);
188         if(offset & (1<<15))    /* sign extend */
189                 offset |= ~((1<<16)-1);
190         offset <<= 2;
191         /*
192          * Integer unit jumps first
193          */
194         switch(iw>>26){
195         case 0:                 /* SPECIAL: JR or JALR */
196                 switch(iw&0x3F){
197                 case 0x09:      /* JALR */
198                         rd = (iw>>11) & 0x1F;
199                         if(rd)
200                                 *reg(ur, rd) = ur->pc+8;
201                         /* fall through */
202                 case 0x08:      /* JR */
203                         return rs;
204                 default:
205                         return 0;
206                 }
207         case 1:                 /* BCOND */
208                 switch((iw>>16) & 0x1F){
209                 case 0x10:      /* BLTZAL */
210                         ur->r31 = ur->pc + 8;
211                         /* fall through */
212                 case 0x00:      /* BLTZ */
213                         if((long)rs < 0)
214                                 return ur->pc+4 + offset;
215                         return ur->pc + 8;
216                 case 0x11:      /* BGEZAL */
217                         ur->r31 = ur->pc + 8;
218                         /* fall through */
219                 case 0x01:      /* BGEZ */
220                         if((long)rs >= 0)
221                                 return ur->pc+4 + offset;
222                         return ur->pc + 8;
223                 default:
224                         return 0;
225                 }
226         case 3:                 /* JAL */
227                 ur->r31 = ur->pc+8;
228                 /* fall through */
229         case 2:                 /* JMP */
230                 npc = iw & ((1<<26)-1);
231                 npc <<= 2;
232                 return npc | (ur->pc&0xF0000000);
233         case 4:                 /* BEQ */
234                 if(rs == rt)
235                         return ur->pc+4 + offset;
236                 return ur->pc + 8;
237         case 5:                 /* BNE */
238                 if(rs != rt)
239                         return ur->pc+4 + offset;
240                 return ur->pc + 8;
241         case 6:                 /* BLEZ */
242                 if((long)rs <= 0)
243                         return ur->pc+4 + offset;
244                 return ur->pc + 8;
245         case 7:                 /* BGTZ */
246                 if((long)rs > 0)
247                         return ur->pc+4 + offset;
248                 return ur->pc + 8;
249         }
250         /*
251          * Floating point unit jumps
252          */
253         if((iw>>26) == 0x11)    /* COP1 */
254                 switch((iw>>16) & 0x3C1){
255                 case 0x101:     /* BCT */
256                 case 0x181:     /* BCT */
257                         if(fcr31 & (1<<23))
258                                 return ur->pc+4 + offset;
259                         return ur->pc + 8;
260                 case 0x100:     /* BCF */
261                 case 0x180:     /* BCF */
262                         if(!(fcr31 & (1<<23)))
263                                 return ur->pc+4 + offset;
264                         return ur->pc + 8;
265                 }
266         /* shouldn't get here */
267         return 0;
268 }