1/* Accurate fp support for CGEN-based simulators.
2   Copyright (C) 1999 Cygnus Solutions.
3
4   This implemention assumes:
5   typedef USI SF;
6   typedef UDI DF;
7
8   TODO:
9   - lazy encoding/decoding
10   - checking return code (say by callback)
11   - proper rounding
12*/
13
14#include "sim-main.h"
15#include "sim-fpu.h"
16
17/* SF mode support */
18
19static SF
20addsf (CGEN_FPU* fpu, SF x, SF y)
21{
22  sim_fpu op1;
23  sim_fpu op2;
24  sim_fpu ans;
25  unsigned32 res;
26  sim_fpu_status status;
27
28  sim_fpu_32to (&op1, x);
29  sim_fpu_32to (&op2, y);
30  status = sim_fpu_add (&ans, &op1, &op2);
31  if (status != 0)
32    (*fpu->ops->error) (fpu, status);
33  sim_fpu_to32 (&res, &ans);
34
35  return res;
36}
37
38static SF
39subsf (CGEN_FPU* fpu, SF x, SF y)
40{
41  sim_fpu op1;
42  sim_fpu op2;
43  sim_fpu ans;
44  unsigned32 res;
45  sim_fpu_status status;
46
47  sim_fpu_32to (&op1, x);
48  sim_fpu_32to (&op2, y);
49  status = sim_fpu_sub (&ans, &op1, &op2);
50  if (status != 0)
51    (*fpu->ops->error) (fpu, status);
52  sim_fpu_to32 (&res, &ans);
53
54  return res;
55}
56
57static SF
58mulsf (CGEN_FPU* fpu, SF x, SF y)
59{
60  sim_fpu op1;
61  sim_fpu op2;
62  sim_fpu ans;
63  unsigned32 res;
64  sim_fpu_status status;
65
66  sim_fpu_32to (&op1, x);
67  sim_fpu_32to (&op2, y);
68  status = sim_fpu_mul (&ans, &op1, &op2);
69  if (status != 0)
70    (*fpu->ops->error) (fpu, status);
71  sim_fpu_to32 (&res, &ans);
72
73  return res;
74}
75
76static SF
77divsf (CGEN_FPU* fpu, SF x, SF y)
78{
79  sim_fpu op1;
80  sim_fpu op2;
81  sim_fpu ans;
82  unsigned32 res;
83  sim_fpu_status status;
84
85  sim_fpu_32to (&op1, x);
86  sim_fpu_32to (&op2, y);
87  status = sim_fpu_div (&ans, &op1, &op2);
88  if (status != 0)
89    (*fpu->ops->error) (fpu, status);
90  sim_fpu_to32 (&res, &ans);
91
92  return res;
93}
94
95static SF
96negsf (CGEN_FPU* fpu, SF x)
97{
98  sim_fpu op1;
99  sim_fpu ans;
100  unsigned32 res;
101  sim_fpu_status status;
102
103  sim_fpu_32to (&op1, x);
104  status = sim_fpu_neg (&ans, &op1);
105  if (status != 0)
106    (*fpu->ops->error) (fpu, status);
107  sim_fpu_to32 (&res, &ans);
108
109  return res;
110}
111
112static SF
113abssf (CGEN_FPU* fpu, SF x)
114{
115  sim_fpu op1;
116  sim_fpu ans;
117  unsigned32 res;
118  sim_fpu_status status;
119
120  sim_fpu_32to (&op1, x);
121  status = sim_fpu_abs (&ans, &op1);
122  if (status != 0)
123    (*fpu->ops->error) (fpu, status);
124  sim_fpu_to32 (&res, &ans);
125
126  return res;
127}
128
129static SF
130sqrtsf (CGEN_FPU* fpu, SF x)
131{
132  sim_fpu op1;
133  sim_fpu ans;
134  unsigned32 res;
135  sim_fpu_status status;
136
137  sim_fpu_32to (&op1, x);
138  status = sim_fpu_sqrt (&ans, &op1);
139  if (status != 0)
140    (*fpu->ops->error) (fpu, status);
141  sim_fpu_to32 (&res, &ans);
142
143  return res;
144}
145
146static SF
147invsf (CGEN_FPU* fpu, SF x)
148{
149  sim_fpu op1;
150  sim_fpu ans;
151  unsigned32 res;
152  sim_fpu_status status;
153
154  sim_fpu_32to (&op1, x);
155  status = sim_fpu_inv (&ans, &op1);
156  if (status != 0)
157    (*fpu->ops->error) (fpu, status);
158  sim_fpu_to32 (&res, &ans);
159
160  return res;
161}
162
163static SF
164minsf (CGEN_FPU* fpu, SF x, SF y)
165{
166  sim_fpu op1;
167  sim_fpu op2;
168  sim_fpu ans;
169  unsigned32 res;
170  sim_fpu_status status;
171
172  sim_fpu_32to (&op1, x);
173  sim_fpu_32to (&op2, y);
174  status = sim_fpu_min (&ans, &op1, &op2);
175  if (status != 0)
176    (*fpu->ops->error) (fpu, status);
177  sim_fpu_to32 (&res, &ans);
178
179  return res;
180}
181
182static SF
183maxsf (CGEN_FPU* fpu, SF x, SF y)
184{
185  sim_fpu op1;
186  sim_fpu op2;
187  sim_fpu ans;
188  unsigned32 res;
189  sim_fpu_status status;
190
191  sim_fpu_32to (&op1, x);
192  sim_fpu_32to (&op2, y);
193  status = sim_fpu_max (&ans, &op1, &op2);
194  if (status != 0)
195    (*fpu->ops->error) (fpu, status);
196  sim_fpu_to32 (&res, &ans);
197
198  return res;
199}
200
201static CGEN_FP_CMP
202cmpsf (CGEN_FPU* fpu, SF x, SF y)
203{
204  sim_fpu op1;
205  sim_fpu op2;
206
207  sim_fpu_32to (&op1, x);
208  sim_fpu_32to (&op2, y);
209
210  if (sim_fpu_is_nan (&op1)
211      || sim_fpu_is_nan (&op2))
212    return FP_CMP_NAN;
213
214  if (x < y)
215    return FP_CMP_LT;
216  if (x > y)
217    return FP_CMP_GT;
218  return FP_CMP_EQ;
219}
220
221static int
222eqsf (CGEN_FPU* fpu, SF x, SF y)
223{
224  sim_fpu op1;
225  sim_fpu op2;
226
227  sim_fpu_32to (&op1, x);
228  sim_fpu_32to (&op2, y);
229  return sim_fpu_is_eq (&op1, &op2);
230}
231
232static int
233nesf (CGEN_FPU* fpu, SF x, SF y)
234{
235  sim_fpu op1;
236  sim_fpu op2;
237
238  sim_fpu_32to (&op1, x);
239  sim_fpu_32to (&op2, y);
240  return sim_fpu_is_ne (&op1, &op2);
241}
242
243static int
244ltsf (CGEN_FPU* fpu, SF x, SF y)
245{
246  sim_fpu op1;
247  sim_fpu op2;
248
249  sim_fpu_32to (&op1, x);
250  sim_fpu_32to (&op2, y);
251  return sim_fpu_is_lt (&op1, &op2);
252}
253
254static int
255lesf (CGEN_FPU* fpu, SF x, SF y)
256{
257  sim_fpu op1;
258  sim_fpu op2;
259
260  sim_fpu_32to (&op1, x);
261  sim_fpu_32to (&op2, y);
262  return sim_fpu_is_le (&op1, &op2);
263}
264
265static int
266gtsf (CGEN_FPU* fpu, SF x, SF y)
267{
268  sim_fpu op1;
269  sim_fpu op2;
270
271  sim_fpu_32to (&op1, x);
272  sim_fpu_32to (&op2, y);
273  return sim_fpu_is_gt (&op1, &op2);
274}
275
276static int
277gesf (CGEN_FPU* fpu, SF x, SF y)
278{
279  sim_fpu op1;
280  sim_fpu op2;
281
282  sim_fpu_32to (&op1, x);
283  sim_fpu_32to (&op2, y);
284  return sim_fpu_is_ge (&op1, &op2);
285}
286
287static DF
288fextsfdf (CGEN_FPU* fpu, SF x)
289{
290  sim_fpu op1;
291  unsigned64 res;
292
293  sim_fpu_32to (&op1, x);
294  sim_fpu_to64 (&res, &op1);
295
296  return res;
297}
298
299static SF
300ftruncdfsf (CGEN_FPU* fpu, DF x)
301{
302  sim_fpu op1;
303  unsigned32 res;
304
305  sim_fpu_64to (&op1, x);
306  sim_fpu_to32 (&res, &op1);
307
308  return res;
309}
310
311static SF
312floatsisf (CGEN_FPU* fpu, SI x)
313{
314  sim_fpu ans;
315  unsigned32 res;
316
317  sim_fpu_i32to (&ans, x, sim_fpu_round_near);
318  sim_fpu_to32 (&res, &ans);
319  return res;
320}
321
322static DF
323floatsidf (CGEN_FPU* fpu, SI x)
324{
325  sim_fpu ans;
326  unsigned64 res;
327
328  sim_fpu_i32to (&ans, x, sim_fpu_round_near);
329  sim_fpu_to64 (&res, &ans);
330  return res;
331}
332
333static SF
334ufloatsisf (CGEN_FPU* fpu, USI x)
335{
336  sim_fpu ans;
337  unsigned32 res;
338
339  sim_fpu_u32to (&ans, x, sim_fpu_round_near);
340  sim_fpu_to32 (&res, &ans);
341  return res;
342}
343
344static SI
345fixsfsi (CGEN_FPU* fpu, SF x)
346{
347  sim_fpu op1;
348  unsigned32 res;
349
350  sim_fpu_32to (&op1, x);
351  sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
352  return res;
353}
354
355static SI
356fixdfsi (CGEN_FPU* fpu, DF x)
357{
358  sim_fpu op1;
359  unsigned32 res;
360
361  sim_fpu_64to (&op1, x);
362  sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
363  return res;
364}
365
366static USI
367ufixsfsi (CGEN_FPU* fpu, SF x)
368{
369  sim_fpu op1;
370  unsigned32 res;
371
372  sim_fpu_32to (&op1, x);
373  sim_fpu_to32u (&res, &op1, sim_fpu_round_near);
374  return res;
375}
376
377/* DF mode support */
378
379static DF
380adddf (CGEN_FPU* fpu, DF x, DF y)
381{
382  sim_fpu op1;
383  sim_fpu op2;
384  sim_fpu ans;
385  unsigned64 res;
386  sim_fpu_status status;
387
388  sim_fpu_64to (&op1, x);
389  sim_fpu_64to (&op2, y);
390  status = sim_fpu_add (&ans, &op1, &op2);
391  if (status != 0)
392    (*fpu->ops->error) (fpu, status);
393  sim_fpu_to64 (&res, &ans);
394
395  return res;
396}
397
398static DF
399subdf (CGEN_FPU* fpu, DF x, DF y)
400{
401  sim_fpu op1;
402  sim_fpu op2;
403  sim_fpu ans;
404  unsigned64 res;
405  sim_fpu_status status;
406
407  sim_fpu_64to (&op1, x);
408  sim_fpu_64to (&op2, y);
409  status = sim_fpu_sub (&ans, &op1, &op2);
410  if (status != 0)
411    (*fpu->ops->error) (fpu, status);
412  sim_fpu_to64 (&res, &ans);
413
414  return res;
415}
416
417static DF
418muldf (CGEN_FPU* fpu, DF x, DF y)
419{
420  sim_fpu op1;
421  sim_fpu op2;
422  sim_fpu ans;
423  unsigned64 res;
424  sim_fpu_status status;
425
426  sim_fpu_64to (&op1, x);
427  sim_fpu_64to (&op2, y);
428  status = sim_fpu_mul (&ans, &op1, &op2);
429  if (status != 0)
430    (*fpu->ops->error) (fpu, status);
431  sim_fpu_to64 (&res, &ans);
432
433  return res;
434}
435
436static DF
437divdf (CGEN_FPU* fpu, DF x, DF y)
438{
439  sim_fpu op1;
440  sim_fpu op2;
441  sim_fpu ans;
442  unsigned64 res;
443  sim_fpu_status status;
444
445  sim_fpu_64to (&op1, x);
446  sim_fpu_64to (&op2, y);
447  status = sim_fpu_div (&ans, &op1, &op2);
448  if (status != 0)
449    (*fpu->ops->error) (fpu, status);
450  sim_fpu_to64 (&res, &ans);
451
452  return res;
453}
454
455static DF
456negdf (CGEN_FPU* fpu, DF x)
457{
458  sim_fpu op1;
459  sim_fpu ans;
460  unsigned64 res;
461  sim_fpu_status status;
462
463  sim_fpu_64to (&op1, x);
464  status = sim_fpu_neg (&ans, &op1);
465  if (status != 0)
466    (*fpu->ops->error) (fpu, status);
467  sim_fpu_to64 (&res, &ans);
468
469  return res;
470}
471
472static DF
473absdf (CGEN_FPU* fpu, DF x)
474{
475  sim_fpu op1;
476  sim_fpu ans;
477  unsigned64 res;
478  sim_fpu_status status;
479
480  sim_fpu_64to (&op1, x);
481  status = sim_fpu_abs (&ans, &op1);
482  if (status != 0)
483    (*fpu->ops->error) (fpu, status);
484  sim_fpu_to64 (&res, &ans);
485
486  return res;
487}
488
489static DF
490sqrtdf (CGEN_FPU* fpu, DF x)
491{
492  sim_fpu op1;
493  sim_fpu ans;
494  unsigned64 res;
495  sim_fpu_status status;
496
497  sim_fpu_64to (&op1, x);
498  status = sim_fpu_sqrt (&ans, &op1);
499  if (status != 0)
500    (*fpu->ops->error) (fpu, status);
501  sim_fpu_to64 (&res, &ans);
502
503  return res;
504}
505
506static DF
507invdf (CGEN_FPU* fpu, DF x)
508{
509  sim_fpu op1;
510  sim_fpu ans;
511  unsigned64 res;
512  sim_fpu_status status;
513
514  sim_fpu_64to (&op1, x);
515  status = sim_fpu_inv (&ans, &op1);
516  if (status != 0)
517    (*fpu->ops->error) (fpu, status);
518  sim_fpu_to64 (&res, &ans);
519
520  return res;
521}
522
523static DF
524mindf (CGEN_FPU* fpu, DF x, DF y)
525{
526  sim_fpu op1;
527  sim_fpu op2;
528  sim_fpu ans;
529  unsigned64 res;
530  sim_fpu_status status;
531
532  sim_fpu_64to (&op1, x);
533  sim_fpu_64to (&op2, y);
534  status = sim_fpu_min (&ans, &op1, &op2);
535  if (status != 0)
536    (*fpu->ops->error) (fpu, status);
537  sim_fpu_to64 (&res, &ans);
538
539  return res;
540}
541
542static DF
543maxdf (CGEN_FPU* fpu, DF x, DF y)
544{
545  sim_fpu op1;
546  sim_fpu op2;
547  sim_fpu ans;
548  unsigned64 res;
549  sim_fpu_status status;
550
551  sim_fpu_64to (&op1, x);
552  sim_fpu_64to (&op2, y);
553  status = sim_fpu_max (&ans, &op1, &op2);
554  if (status != 0)
555    (*fpu->ops->error) (fpu, status);
556  sim_fpu_to64 (&res, &ans);
557
558  return res;
559}
560
561static CGEN_FP_CMP
562cmpdf (CGEN_FPU* fpu, DF x, DF y)
563{
564  sim_fpu op1;
565  sim_fpu op2;
566
567  sim_fpu_64to (&op1, x);
568  sim_fpu_64to (&op2, y);
569
570  if (sim_fpu_is_nan (&op1)
571      || sim_fpu_is_nan (&op2))
572    return FP_CMP_NAN;
573
574  if (x < y)
575    return FP_CMP_LT;
576  if (x > y)
577    return FP_CMP_GT;
578  return FP_CMP_EQ;
579}
580
581static int
582eqdf (CGEN_FPU* fpu, DF x, DF y)
583{
584  sim_fpu op1;
585  sim_fpu op2;
586
587  sim_fpu_64to (&op1, x);
588  sim_fpu_64to (&op2, y);
589  return sim_fpu_is_eq (&op1, &op2);
590}
591
592static int
593nedf (CGEN_FPU* fpu, DF x, DF y)
594{
595  sim_fpu op1;
596  sim_fpu op2;
597
598  sim_fpu_64to (&op1, x);
599  sim_fpu_64to (&op2, y);
600  return sim_fpu_is_ne (&op1, &op2);
601}
602
603static int
604ltdf (CGEN_FPU* fpu, DF x, DF y)
605{
606  sim_fpu op1;
607  sim_fpu op2;
608
609  sim_fpu_64to (&op1, x);
610  sim_fpu_64to (&op2, y);
611  return sim_fpu_is_lt (&op1, &op2);
612}
613
614static int
615ledf (CGEN_FPU* fpu, DF x, DF y)
616{
617  sim_fpu op1;
618  sim_fpu op2;
619
620  sim_fpu_64to (&op1, x);
621  sim_fpu_64to (&op2, y);
622  return sim_fpu_is_le (&op1, &op2);
623}
624
625static int
626gtdf (CGEN_FPU* fpu, DF x, DF y)
627{
628  sim_fpu op1;
629  sim_fpu op2;
630
631  sim_fpu_64to (&op1, x);
632  sim_fpu_64to (&op2, y);
633  return sim_fpu_is_gt (&op1, &op2);
634}
635
636static int
637gedf (CGEN_FPU* fpu, DF x, DF y)
638{
639  sim_fpu op1;
640  sim_fpu op2;
641
642  sim_fpu_64to (&op1, x);
643  sim_fpu_64to (&op2, y);
644  return sim_fpu_is_ge (&op1, &op2);
645}
646
647/* Initialize FP_OPS to use accurate library.  */
648
649void
650cgen_init_accurate_fpu (SIM_CPU* cpu, CGEN_FPU* fpu, CGEN_FPU_ERROR_FN* error)
651{
652  CGEN_FP_OPS* o;
653
654  fpu->owner = cpu;
655  /* ??? small memory leak, not freed by sim_close */
656  fpu->ops = (CGEN_FP_OPS*) xmalloc (sizeof (CGEN_FP_OPS));
657
658  o = fpu->ops;
659  memset (o, 0, sizeof (*o));
660
661  o->error = error;
662
663  o->addsf = addsf;
664  o->subsf = subsf;
665  o->mulsf = mulsf;
666  o->divsf = divsf;
667  o->negsf = negsf;
668  o->abssf = abssf;
669  o->sqrtsf = sqrtsf;
670  o->invsf = invsf;
671  o->minsf = minsf;
672  o->maxsf = maxsf;
673  o->cmpsf = cmpsf;
674  o->eqsf = eqsf;
675  o->nesf = nesf;
676  o->ltsf = ltsf;
677  o->lesf = lesf;
678  o->gtsf = gtsf;
679  o->gesf = gesf;
680
681  o->adddf = adddf;
682  o->subdf = subdf;
683  o->muldf = muldf;
684  o->divdf = divdf;
685  o->negdf = negdf;
686  o->absdf = absdf;
687  o->sqrtdf = sqrtdf;
688  o->invdf = invdf;
689  o->mindf = mindf;
690  o->maxdf = maxdf;
691  o->cmpdf = cmpdf;
692  o->eqdf = eqdf;
693  o->nedf = nedf;
694  o->ltdf = ltdf;
695  o->ledf = ledf;
696  o->gtdf = gtdf;
697  o->gedf = gedf;
698  o->fextsfdf = fextsfdf;
699  o->ftruncdfsf = ftruncdfsf;
700  o->floatsisf = floatsisf;
701  o->floatsidf = floatsidf;
702  o->ufloatsisf = ufloatsisf;
703  o->fixsfsi = fixsfsi;
704  o->fixdfsi = fixdfsi;
705  o->ufixsfsi = ufixsfsi;
706}
707