linux/arch/arm/nwfpe/fpa11.c
<<
>>
Prefs
   1/*
   2    NetWinder Floating Point Emulator
   3    (c) Rebel.COM, 1998,1999
   4    (c) Philip Blundell, 2001
   5
   6    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21*/
  22
  23#include "fpa11.h"
  24#include "fpopcode.h"
  25
  26#include "fpmodule.h"
  27#include "fpmodule.inl"
  28
  29#include <linux/compiler.h>
  30#include <linux/string.h>
  31
  32/* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
  33static void resetFPA11(void)
  34{
  35        int i;
  36        FPA11 *fpa11 = GET_FPA11();
  37
  38        /* initialize the register type array */
  39        for (i = 0; i <= 7; i++) {
  40                fpa11->fType[i] = typeNone;
  41        }
  42
  43        /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
  44        fpa11->fpsr = FP_EMULATOR | BIT_AC;
  45}
  46
  47int8 SetRoundingMode(const unsigned int opcode)
  48{
  49        switch (opcode & MASK_ROUNDING_MODE) {
  50        default:
  51        case ROUND_TO_NEAREST:
  52                return float_round_nearest_even;
  53
  54        case ROUND_TO_PLUS_INFINITY:
  55                return float_round_up;
  56
  57        case ROUND_TO_MINUS_INFINITY:
  58                return float_round_down;
  59
  60        case ROUND_TO_ZERO:
  61                return float_round_to_zero;
  62        }
  63}
  64
  65int8 SetRoundingPrecision(const unsigned int opcode)
  66{
  67#ifdef CONFIG_FPE_NWFPE_XP
  68        switch (opcode & MASK_ROUNDING_PRECISION) {
  69        case ROUND_SINGLE:
  70                return 32;
  71
  72        case ROUND_DOUBLE:
  73                return 64;
  74
  75        case ROUND_EXTENDED:
  76                return 80;
  77
  78        default:
  79                return 80;
  80        }
  81#endif
  82        return 80;
  83}
  84
  85void nwfpe_init_fpa(union fp_state *fp)
  86{
  87        FPA11 *fpa11 = (FPA11 *)fp;
  88#ifdef NWFPE_DEBUG
  89        printk("NWFPE: setting up state.\n");
  90#endif
  91        memset(fpa11, 0, sizeof(FPA11));
  92        resetFPA11();
  93        fpa11->initflag = 1;
  94}
  95
  96/* Emulate the instruction in the opcode. */
  97unsigned int EmulateAll(unsigned int opcode)
  98{
  99        unsigned int code;
 100
 101#ifdef NWFPE_DEBUG
 102        printk("NWFPE: emulating opcode %08x\n", opcode);
 103#endif
 104        code = opcode & 0x00000f00;
 105        if (code == 0x00000100 || code == 0x00000200) {
 106                /* For coprocessor 1 or 2 (FPA11) */
 107                code = opcode & 0x0e000000;
 108                if (code == 0x0e000000) {
 109                        if (opcode & 0x00000010) {
 110                                /* Emulate conversion opcodes. */
 111                                /* Emulate register transfer opcodes. */
 112                                /* Emulate comparison opcodes. */
 113                                return EmulateCPRT(opcode);
 114                        } else {
 115                                /* Emulate monadic arithmetic opcodes. */
 116                                /* Emulate dyadic arithmetic opcodes. */
 117                                return EmulateCPDO(opcode);
 118                        }
 119                } else if (code == 0x0c000000) {
 120                        /* Emulate load/store opcodes. */
 121                        /* Emulate load/store multiple opcodes. */
 122                        return EmulateCPDT(opcode);
 123                }
 124        }
 125
 126        /* Invalid instruction detected.  Return FALSE. */
 127        return 0;
 128}
 129