/* FCSRRegister.java * * This class models the Floating Point Control and Status Register * (c) 2007 Massimo Trubia * * This file is part of the EduMIPS64 project, and is released under the GNU * General Public License. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.edumips64.core; import org.edumips64.core.fpu.FPDivideByZeroException; import org.edumips64.core.fpu.FPInvalidOperationException; import org.edumips64.core.fpu.FPOverflowException; import org.edumips64.core.fpu.FPUnderflowException; import org.edumips64.utils.IrregularStringOfBitsException; /** This class models the Floating Point Control and Status Register * @author Massimo Trubia * */ public class FCSRRegister extends BitSet32 { //SETTING PROPERTIES ---------------------------------------------------------- /** * Sets the FCSR Enables bits (the numeration of the bitset bits goes in this way 0 1 .... 30 31 * 31 30 29 28 27 26 25 | 24 | 23 | 22 21 | 20 19 18 |17 16 15 14 13 12 | 11 10 9 8 7 | 6 5 4 3 2 | 1 0 * FCC | FS | FCC| Impl | 000 | Cause | Enables | Flags | RM * 7 6 5 4 3 2 1 | 0 | V Z O U I | V Z O U I * * @param tag a string value between V Z O U I * @param value a binary value */ private void setFCSREnables(String tag, int value) throws IrregularStringOfBitsException { if (tag.compareToIgnoreCase("V") == 0) { setBits(String.valueOf(value), 20); } else if (tag.compareToIgnoreCase("Z") == 0) { setBits(String.valueOf(value), 21); } else if (tag.compareToIgnoreCase("O") == 0) { setBits(String.valueOf(value), 22); } else if (tag.compareToIgnoreCase("U") == 0) { setBits(String.valueOf(value), 23); } else if (tag.compareToIgnoreCase("I") == 0) { //not implemented setBits(String.valueOf(value), 24); } } /** * Sets the flags bits of the FCSR * * @param tag a string value between V Z O U I * @param value a binary value */ public void setFCSRFlags(String tag, int value) throws IrregularStringOfBitsException { if (tag.compareToIgnoreCase("V") == 0) { setBits(String.valueOf(value), 25); } else if (tag.compareToIgnoreCase("Z") == 0) { setBits(String.valueOf(value), 26); } else if (tag.compareToIgnoreCase("O") == 0) { setBits(String.valueOf(value), 27); } else if (tag.compareToIgnoreCase("U") == 0) { setBits(String.valueOf(value), 28); } else if (tag.compareToIgnoreCase("I") == 0) { // not implemented setBits(String.valueOf(value), 29); } } /** * Sets the flags bits of the FCSR * * @param tag a string value between V Z O U I * @param value a binary value */ public void setFCSRCause(String tag, int value) throws IrregularStringOfBitsException { if (tag.compareToIgnoreCase("V") == 0) { setBits(String.valueOf(value), 15); } else if (tag.compareToIgnoreCase("Z") == 0) { setBits(String.valueOf(value), 16); } else if (tag.compareToIgnoreCase("O") == 0) { setBits(String.valueOf(value), 17); } else if (tag.compareToIgnoreCase("U") == 0) { setBits(String.valueOf(value), 18); } else if (tag.compareToIgnoreCase("I") == 0) { // not implemented setBits(String.valueOf(value), 19); } } /** * Sets the selected condition bit of the FCSR * * @param cc condition code is an int value in the range [0,7] * @param condition the binary value of the relative bit */ void setFCSRConditionCode(int cc, int condition) throws IrregularStringOfBitsException { final int FCC0 = 8; final int DISCONTINUITY = 1; final int OFFSET = FCC0 - DISCONTINUITY; if (cc == 0) { setBits(String.valueOf(condition), FCC0); } else { setBits(String.valueOf(condition), OFFSET - cc); } } /** * Sets the current rouding mode * * @param rm a constant that belongs to the following values TO_NEAREST ,TOWARD_ZERO,TOWARDS_PLUS_INFINITY,TOWARDS_MINUS_INFINITY */ void setFCSRRoundingMode(CPU.FPRoundingMode rm) throws IrregularStringOfBitsException { final int FCSR_RM_FIELD_INIT = 30; switch (rm) { case TO_NEAREST: setBits("00", FCSR_RM_FIELD_INIT); break; case TOWARD_ZERO: setBits("01", FCSR_RM_FIELD_INIT); break; case TOWARDS_PLUS_INFINITY: setBits("10", FCSR_RM_FIELD_INIT); break; case TOWARDS_MINUS_INFINITY: setBits("11", FCSR_RM_FIELD_INIT); break; } } /** * Sets the floating point unit enabled exceptions * * @param exceptionName the exception name to set * @param value boolean that is true in order to enable that exception or false for disabling it */ public void setFPExceptions(CPU.FPExceptions exceptionName, boolean value) { try { switch (exceptionName) { case DIVIDE_BY_ZERO: setFCSREnables("Z", (value) ? 1 : 0); break; case OVERFLOW: setFCSREnables("O", (value) ? 1 : 0); break; case UNDERFLOW: setFCSREnables("U", (value) ? 1 : 0); break; case INVALID_OPERATION: setFCSREnables("V", (value) ? 1 : 0); break; } } catch (IrregularStringOfBitsException e) { // Should never happen. e.printStackTrace(); } } // GETTING PROPERTIES --------------------------------------------------------------------- /** * Gets the selected flag bit of the FCSR * * @param tag a string value between V=Invalid Z=Divide by zero O=Overflow U=Underflow I=Inexact (not implemented) */ private boolean getFCSREnables(String tag) { if (tag.compareToIgnoreCase("V") == 0) { return (getBinString().charAt(20) == '1'); } if (tag.compareToIgnoreCase("Z") == 0) { return (getBinString().charAt(21) == '1'); } if (tag.compareToIgnoreCase("O") == 0) { return (getBinString().charAt(22) == '1'); } if (tag.compareToIgnoreCase("U") == 0) { return (getBinString().charAt(23) == '1'); } //not implemented return tag.compareToIgnoreCase("I") == 0 && (getBinString().charAt(24) == '1'); } /** * Gets the selected FCC bit of the FCSR * * @param cc condition code is an int value in the range [0,7] */ public int getFCSRConditionCode(int cc) { final int FCC0 = 8; final int DISCONTINUITY = 1; final int OFFSET = FCC0 - DISCONTINUITY; if (cc == 0) { return (Integer.valueOf(getBinString().substring(FCC0, FCC0 + 1))); } else { return (Integer.valueOf(getBinString().substring(OFFSET - cc, OFFSET - cc + 1))); } } CPU.FPRoundingMode getFCSRRoundingMode() { final int FCSR_RM_FIELD_INIT = 30; if (getBinString().substring(FCSR_RM_FIELD_INIT, size).compareTo("00") == 0) { return CPU.FPRoundingMode.TO_NEAREST; } if (getBinString().substring(FCSR_RM_FIELD_INIT, size).compareTo("01") == 0) { return CPU.FPRoundingMode.TOWARD_ZERO; } if (getBinString().substring(FCSR_RM_FIELD_INIT, size).compareTo("10") == 0) { return CPU.FPRoundingMode.TOWARDS_PLUS_INFINITY; } if (getBinString().substring(FCSR_RM_FIELD_INIT, size).compareTo("11") == 0) { return CPU.FPRoundingMode.TOWARDS_MINUS_INFINITY; } return null; } /** * Gets the floating point unit enabled exceptions * * @return true if exceptionName is enabled, false in the other case */ public boolean getFPExceptions(CPU.FPExceptions exceptionName) { //return this.fpEnabledExceptions.get(exceptionName); switch (exceptionName) { case DIVIDE_BY_ZERO: return getFCSREnables("Z"); case OVERFLOW: return getFCSREnables("O"); case UNDERFLOW: return getFCSREnables("U"); case INVALID_OPERATION: return getFCSREnables("V"); } return false; } private String getFlag(CPU.FPExceptions exceptionName) { switch (exceptionName) { case DIVIDE_BY_ZERO: return "Z"; case OVERFLOW: return "O"; case UNDERFLOW: return "U"; case INVALID_OPERATION: return "V"; } // Can't happen. return null; } public void setFlagsOrRaiseException(CPU.FPExceptions exceptionName) throws FPDivideByZeroException, FPOverflowException, FPUnderflowException, FPInvalidOperationException { String flag = getFlag(exceptionName); // Before raising the exception, we set the cause bit. try { setFCSRCause(flag, 1); } catch (IrregularStringOfBitsException e) { // Should never happen. 1 is a valid value to pass to setFCSRCause. e.printStackTrace(); } // If exceptions are enabled, throw the corresponding one. if (getFPExceptions(exceptionName)) { switch (exceptionName) { case DIVIDE_BY_ZERO: throw new FPDivideByZeroException(); case OVERFLOW: throw new FPOverflowException(); case UNDERFLOW: throw new FPUnderflowException(); case INVALID_OPERATION: throw new FPInvalidOperationException(); } // Otherwise, just set the corresponding FCSR flag. try { setFCSRFlags(flag, 1); } catch (IrregularStringOfBitsException e) { // Should never happen. 1 is a valid value to pass to setFCSRFlags. e.printStackTrace(); } } } }