📄 fpustate64.java
字号:
/* JPC: A x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.0 A project from the Physics Dept, The University of Oxford Copyright (C) 2007 Isis Innovation Limited 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: www.physics.ox.ac.uk/jpc*/package org.jpc.emulator.processor.fpu64;// import java.math.BigDecimal;import org.jpc.emulator.processor.*;import java.io.*;public class FpuState64 extends FpuState{ public final static int FPU_SPECIAL_TAG_NONE = 0; public final static int FPU_SPECIAL_TAG_NAN = 1; public final static int FPU_SPECIAL_TAG_UNSUPPORTED = 2; public final static int FPU_SPECIAL_TAG_INFINITY = 3; public final static int FPU_SPECIAL_TAG_DENORMAL = 4; public final static int FPU_SPECIAL_TAG_SNAN = 5; public final static double UNDERFLOW_THRESHOLD = Math.pow(2.0, -1022.0); private final Processor cpu; double[] data; int[] tag; int[] specialTag; // status word private int statusWord; private boolean invalidOperation; private boolean denormalizedOperand; private boolean zeroDivide; private boolean overflow; private boolean underflow; private boolean precision; private boolean stackFault; public void dumpState(DataOutput output) throws IOException { output.writeInt(statusWord); output.writeInt(maskWord); output.writeInt(precisionControl); output.writeInt(roundingControl); output.writeBoolean(invalidOperation); output.writeBoolean(denormalizedOperand); output.writeBoolean(zeroDivide); output.writeBoolean(overflow); output.writeBoolean(underflow); output.writeBoolean(precision); output.writeBoolean(stackFault); output.writeInt(data.length); for (int i=0; i< data.length; i++) output.writeDouble(data[i]); output.writeInt(tag.length); for (int i=0; i< tag.length; i++) output.writeInt(tag[i]); output.writeInt(specialTag.length); for (int i=0; i< specialTag.length; i++) output.writeInt(specialTag[i]); } public void loadState(DataInput input) throws IOException { statusWord = input.readInt(); maskWord = input.readInt(); precisionControl = input.readInt(); roundingControl = input.readInt(); invalidOperation = input.readBoolean(); denormalizedOperand = input.readBoolean(); zeroDivide = input.readBoolean(); overflow = input.readBoolean(); underflow = input.readBoolean(); precision = input.readBoolean(); stackFault = input.readBoolean(); int len = input.readInt(); data = new double[len]; for (int i=0; i< data.length; i++) data[i] = input.readDouble(); len = input.readInt(); tag = new int[len]; for (int i=0; i< tag.length; i++) tag[i] = input.readInt(); len = input.readInt(); specialTag = new int[len]; for (int i=0; i< specialTag.length; i++) specialTag[i] = input.readInt(); } public boolean getInvalidOperation() { return ((statusWord & 0x01) != 0); } public boolean getDenormalizedOperand() { return ((statusWord&0x02) != 0); } public boolean getZeroDivide() { return ((statusWord & 0x04) != 0); } public boolean getOverflow() { return ((statusWord & 0x08) != 0); } public boolean getUnderflow() { return ((statusWord & 0x10) != 0); } public boolean getPrecision() { return ((statusWord & 0x20) != 0); } public boolean getStackFault() { return ((statusWord & 0x40) != 0); } public void setInvalidOperation() { statusWord |= 0x01;} public void setDenormalizedOperand() { statusWord |= 0x02;} public void setZeroDivide() { statusWord |= 0x04;} public void setOverflow() { statusWord |= 0x08;} public void setUnderflow() {statusWord |= 0x10;} public void setPrecision() { statusWord |= 0x20;} public void setStackFault() { statusWord |= 0x40;} public boolean getBusy() { return getErrorSummaryStatus(); } public boolean getErrorSummaryStatus() { // (note stack fault is a subset of invalid operation) return (((statusWord & 0x3f) & ~maskWord) != 0); } public void checkExceptions() throws ProcessorException { if (getErrorSummaryStatus()) cpu.reportFPUException(); } public void clearExceptions() { statusWord = 0; } // control word private int maskWord; private int precisionControl; private int roundingControl; public boolean getInvalidOperationMask() { return ((maskWord & 1) != 0); } public boolean getDenormalizedOperandMask() { return ((maskWord & 2) != 0);} public boolean getZeroDivideMask() { return ((maskWord & 4) != 0); } public boolean getOverflowMask() { return ((maskWord & 8) != 0); } public boolean getUnderflowMask() { return ((maskWord & 0x10) != 0); } public boolean getPrecisionMask() { return ((maskWord & 0x20) != 0); } public int getPrecisionControl() { return precisionControl; } public int getRoundingControl() { return roundingControl; } public void setInvalidOperationMask(boolean value) { if (value) maskWord |= 1; else maskWord &= ~1; } public void setDenormalizedOperandMask(boolean value) { if (value) maskWord |= 2; else maskWord &= ~2; } public void setZeroDivideMask(boolean value) { if (value) maskWord |= 4; else maskWord &= ~4; } public void setOverflowMask(boolean value) { if (value) maskWord |= 8; else maskWord &= ~8; } public void setUnderflowMask(boolean value) { if (value) maskWord |= 0x10; else maskWord &= ~0x10; } public void setPrecisionMask(boolean value) { if (value) maskWord |= 0x20; else maskWord &= ~0x20; } public void setAllMasks(boolean value) { if (value) maskWord |= 0x3f; else maskWord = 0; } public void setPrecisionControl(int value) { if (value != FPU_PRECISION_CONTROL_DOUBLE) { // trying to set precision to other than double System.err.println("WARNING: attempt to set non-double FP " + "precision in Fpu64 mode"); } precisionControl = FPU_PRECISION_CONTROL_DOUBLE; } public void setRoundingControl(int value) { if (value != FPU_ROUNDING_CONTROL_EVEN) { // trying to set directed or truncate rounding System.err.println("WARNING: attempt to set non-nearest rounding " + "in Fpu64 mode"); } roundingControl = FPU_ROUNDING_CONTROL_EVEN; } // constructor public FpuState64(Processor owner) { cpu = owner; data = new double[STACK_DEPTH]; tag = new int[STACK_DEPTH]; specialTag = new int[STACK_DEPTH]; init(); } public void init() { // tag word (and non-x87 special tags) for (int i = 0; i < STACK_DEPTH; ++i) tag[i] = FPU_TAG_EMPTY; for (int i = 0; i < STACK_DEPTH; ++i) specialTag[i] = FPU_SPECIAL_TAG_NONE; // status word clearExceptions(); conditionCode = 0; top = 0; // control word setAllMasks(true); infinityControl = false; setPrecisionControl(FPU_PRECISION_CONTROL_DOUBLE); // 64 bits default // (x87 uses 80-bit precision as default!) setRoundingControl(FPU_ROUNDING_CONTROL_EVEN); // default lastIP = lastData = lastOpcode = 0; } public int tagCode(double x) { if (x == 0.0) return FPU_TAG_ZERO; else if (Double.isNaN(x)||Double.isInfinite(x)) return FPU_TAG_SPECIAL; else return FPU_TAG_VALID; } public static boolean isDenormal(double x) { long n = Double.doubleToRawLongBits(x); int exponent = (int)((n >> 52) & 0x7ff); if (exponent != 0) return false; long fraction = (n & ~(0xfffL << 52)); if (fraction == 0L) return false; return true; } public static boolean isSNaN(long n) { // have to determine this based on 64-bit bit pattern, // since reassignment might cause Java to rationalize it to infinity int exponent = (int)((n >> 52) & 0x7ff); if (exponent != 0x7ff) return false; long fraction = (n & ~(0xfffL << 52)); if ((fraction & (1L << 51)) != 0) return false; return (fraction != 0L); } // SNaN's aren't generated internally by x87. Instead, they are // detected when they are read in from memory. So if you push() // from memory, find out before whether it's an SNaN, then push(), // then set the tag word accordingly. public static int specialTagCode(double x) { // decode special: NaN, unsupported, infinity, or denormal if (Double.isNaN(x)) return FPU_SPECIAL_TAG_NAN; // QNaN by default else if (Double.isInfinite(x)) return FPU_SPECIAL_TAG_INFINITY; //else if (Math.abs(x) < UNDERFLOW_THRESHOLD) else if (isDenormal(x)) return FPU_SPECIAL_TAG_DENORMAL; else return FPU_SPECIAL_TAG_NONE; } public void push(double x) throws ProcessorException { if (--top < 0) top = STACK_DEPTH - 1; if (tag[top] != FPU_TAG_EMPTY) { setInvalidOperation(); setStackFault(); conditionCode |= 2; // C1 set to indicate stack overflow checkExceptions(); // if IE is masked, then we just continue and overwrite } data[top] = x; tag[top] = tagCode(x); specialTag[top] = specialTagCode(x); }// public void pushBig(BigDecimal x) throws ProcessorException// {// push(x.doubleValue());// } public double pop() throws ProcessorException { if (tag[top] == FPU_TAG_EMPTY) { setInvalidOperation(); setStackFault(); conditionCode &= ~2; // C1 cleared to indicate stack underflow checkExceptions(); // TODO: if IE masked, do we just return whatever // random contents there are? That's what it seems // from the reference. } else if (specialTag[top] == FPU_SPECIAL_TAG_SNAN) { setInvalidOperation();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -