/*
    JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine
    Release Version 2.4

    A project from the Physics Dept, The University of Oxford

    Copyright (C) 2007-2010 The University of Oxford

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as published by
    the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
    Details (including contact information) can be found at: 

    jpc.sourceforge.net
    or the developer website
    sourceforge.net/projects/jpc/

    Conceived and Developed by:
    Rhys Newman, Ian Preston, Chris Dennis

    End of licence header
*/


package org.jpc.emulator.processor.fpu64;

import org.jpc.emulator.processor.*;
import org.jpc.emulator.*;

public abstract class FpuState implements Hibernatable
{
    // stack depth (common to all x87 FPU's)
    public final static int STACK_DEPTH = 8;

    public static final int FPU_PRECISION_CONTROL_SINGLE = 0;
    public static final int FPU_PRECISION_CONTROL_DOUBLE = 2;
    public static final int FPU_PRECISION_CONTROL_EXTENDED = 3;

    public static final int FPU_ROUNDING_CONTROL_EVEN = 0;
    public static final int FPU_ROUNDING_CONTROL_DOWN = 1;
    public static final int FPU_ROUNDING_CONTROL_UP = 2;
    public static final int FPU_ROUNDING_CONTROL_TRUNCATE = 3;

    public static final int FPU_TAG_VALID = 0;
    public static final int FPU_TAG_ZERO = 1;
    public static final int FPU_TAG_SPECIAL = 2;
    public static final int FPU_TAG_EMPTY = 3;

    // status word
    // note exception bits are "sticky" - cleared only explicitly
    // accessors to flag an exception - these will set the bit,
    // check the mask, and throw a ProcessorException if unmasked
    public abstract void setC0(boolean val);
    public abstract void setC1(boolean val);
    public abstract void setC2(boolean val);
    public abstract void setC3(boolean val);
    public abstract void setInvalidOperation();
    public abstract void setDenormalizedOperand();
    public abstract void setZeroDivide();
    public abstract void setOverflow();
    public abstract void setUnderflow();
    public abstract void setPrecision();
    public abstract void setStackFault();
    public abstract void setTagEmpty(int index);
    public abstract void clearExceptions();
    public abstract void checkExceptions() throws ProcessorException;
    // read accessors
    public abstract boolean getInvalidOperation();
    public abstract boolean getDenormalizedOperand();
    public abstract boolean getZeroDivide();
    public abstract boolean getOverflow();
    public abstract boolean getUnderflow();
    public abstract boolean getPrecision();
    public abstract boolean getStackFault();
    public abstract boolean getErrorSummaryStatus(); // derived from other bits
    public abstract boolean getBusy();//same as fpuErrorSummaryStatus() (legacy)
    public int conditionCode; // 4 bits
    public int top; // top of stack pointer (3 bits)
    // control word
    public abstract boolean getInvalidOperationMask();
    public abstract boolean getDenormalizedOperandMask();
    public abstract boolean getZeroDivideMask();
    public abstract boolean getOverflowMask();
    public abstract boolean getUnderflowMask();
    public abstract boolean getPrecisionMask();
    public boolean infinityControl; // legacy:  not really used anymore
    public abstract int getPrecisionControl();  // 2 bits
    public abstract int getRoundingControl();   // 2 bits
    public abstract void setInvalidOperationMask(boolean value);
    public abstract void setDenormalizedOperandMask(boolean value);
    public abstract void setZeroDivideMask(boolean value);
    public abstract void setOverflowMask(boolean value);
    public abstract void setUnderflowMask(boolean value);
    public abstract void setPrecisionMask(boolean value);
    public abstract void setPrecisionControl(int value);
    public abstract void setRoundingControl(int value);
    public abstract void setAllMasks(boolean value);
    // other registers
    public long lastIP; // last instruction pointer
    public long lastData; // last data (operand) pointer
    public int lastOpcode; // 11 bits

    // x87 access
    public abstract void prepareFPU(Processor cpu, boolean checkExceptions);
    public abstract void init();
    public abstract void push(double x) throws ProcessorException;
    public abstract double pop() throws ProcessorException;
    public abstract double[] getStack();
    public abstract void setStack(double[] s);
    public abstract double round(double in);
    public abstract double ST(int index) throws ProcessorException;
    public abstract void setST(int index, double value);
//     public abstract void pushBig(BigDecimal x) throws ProcessorException;
//     public abstract BigDecimal popBig() throws ProcessorException;
//     public abstract BigDecimal bigST(int index) throws ProcessorException;
//     public abstract void setBigST(int index, BigDecimal value);
    public abstract int getStatus();
    public abstract void setStatus(int w);
    public abstract int getControl();
    public abstract void setControl(int w);
    public abstract int getTagWord();
    public abstract void setTagWord(int w);
    public abstract int getTag(int index);

    public void copyStateInto(FpuState copy)
    {
        copy.conditionCode = conditionCode;
        copy.top = top;
        copy.infinityControl = infinityControl;
        copy.lastIP = lastIP;
        copy.lastData = lastData;
        copy.lastOpcode = lastOpcode;
    }

    public boolean equals(Object another)
    {
        if (!(another instanceof FpuState))
            return false;
        FpuState s = (FpuState) another;
        if ((s.conditionCode != conditionCode) || (s.top != top) || (s.infinityControl != infinityControl) || (s.lastIP != lastIP) || (s.lastData != lastData) || (s.lastOpcode != lastOpcode))
            return false;

        return true;
    }
}
