/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: LogicLevel.java * Written by Tom O'Neill, Sun Microsystems. * * Copyright (c) 2004 Sun Microsystems and Static Free Software * * Electric(tm) 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 3 of the License, or * (at your option) any later version. * * Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.simulation.test; /** * Class for setting Vdd and a logic level on a chip, when both values are * provided by power supplies. The logic level will be 0 V if false or equal to * Vdd if true. One use is for implementing master clear to an external pin. It * implements <code>PowerChannel</code> for Vdd, so that changes to Vdd in * <code>ChainTest</code> will also change the master clear voltage. * <p> * * Using this class ensures that the logic voltage tracks changes to Vdd if the * logic state is true. The changes in the two voltage levels occur * simultaneously, preventing either of the failure modes likely if the two * voltages were set separately: 1) Vdd temporarily exceeds the logic voltage, * resulting in an artificial "false" interpretation of the logic level; 2) the * logic voltage temporarily exceeds Vdd, resulting in the logic voltage trying * to power up the chip through its ESD diodes. These failure modes are * prevented if Vdd and the logic voltage are never allowed to differ by more * than about 0.5 Vdd or 0.7 V, respectively. * <p> * * Note: when using this class, the user should not use the * <code>PowerChannel</code> methods directly to control the voltages. * <p> * * To synchronize two logic levels with Vdd, create a <code>LogicLevel</code> * object for one and then use that as the vddChannel for a second * <code>LogicLevel</code> object. For example, for <code>PowerChannel</code> * objects <code>vddChannel</code>,<code>logicChannel</code>, and * <code>logicChannel2</code>, one can use: * * <pre> * LogicLevel level = new LogicLevel(vddChannel, logicChannel, false);LogicLevel level2 = new LogicLevel(level, logicChannel2, false); * * * * * * * * * </pre> * * In this case, the only methods one should invoke in the <code>level</code> * object are <code>isLogicStateHigh()</code> and <code>setLogicState()</code>. * I.e., control of Vdd should only be performed using <code>level2</code>. */ public class LogicLevel extends PowerChannel implements LogicSettable { /** Object for setting chip Vdd */ private final PowerChannel vddChannel; /** Object for setting voltage of the logic level */ private final PowerChannel logicChannel; /** Current state of the logic level */ private boolean logicState; /** * Maximum difference between Vdd and logic voltages when logic level is * true, used while ramping Vdd up or down. We set it small enough so that * it doesn't matter whether Vdd leads or trails the logic level. */ public final static float MAX_VOLTS_DEVIATION = 0.2f; /* Name of the logic signal */ private String logicName; /** * Instantiate a LogicLevel object in the specified <code>logicState</code>. * That is, the voltage on <code>logicChannel</code> is set to 0 V (if * <code>logicState==false</code>) or to the voltage on vddChannel (if * <code>logicState=true</code>). Requirements: <code>vddChannel</code> * and <code>logicChannel</code> must be instantiated, but do not need to * be channels on the same power supply. * * @param vddChannel * Channel of a power supply that supplies V_DD * @param logicChannel * Channel of a power supply that supplies V_DD * @param logicState * Desired initial state (high or low) of the logic level */ public LogicLevel(PowerChannel vddChannel, PowerChannel logicChannel, boolean logicState) { this.name = vddChannel.getName(); this.vddChannel = vddChannel; this.logicName = logicChannel.getName(); this.logicChannel = logicChannel; this.setLogicState(logicState); logInit("Initializing LogicLevel " + this.name + " with " + this.logicName + " in the " + logicState + " state"); } /** Obsolete, use getState() instead */ public String toString() { Infrastructure .nonfatal("Please change toString() reference to getState()"); return getState(); } /** * Returns the name and state (voltage, current) of the channel * * @return the name and state of the channel */ public String getState() { return super.getState() + "; " + getLogicName() + ": " + isLogicStateHigh(); } /** * Returns the name of the logic signal * * @return name of the logic signal */ public String getLogicName() { return logicName; } /** * Reads back the voltage provided by the Vdd channel of the power supply. * * @return voltage drawn over the Vdd channel, in Amps */ public float readVoltage() { return vddChannel.readVoltage(); } /** * Get the Vdd channel's voltage * * @return current voltage for the Vdd channel, in Volts */ public float getVoltageSetpoint() { return vddChannel.getVoltageSetpoint(); } /** * Set the Vdd channel's voltage to the value provided. If the logic level * is high, then we must ramp up the two voltages simultaneously to prevent * either of two problems: 1) the level exceeds Vdd, in which case the logic * pin may be trying to power the chip; 2) the level is below Vdd, in which * case it may erroneously appear false. * * @param volts * new voltage for the channel, in Volts */ public void setVoltageNoWait(float volts) { logSet("LogicLevel setting " + getName() + " to " + volts + " V (nowait)"); // If logicLevel is false, no impediment to setting the final Vdd if (this.isLogicStateHigh() == false) { this.vddChannel.setVoltageNoWait(volts); return; } // If logicLevel is true, must ramp the voltages simultaneously float vdd = this.vddChannel.getVoltageSetpoint(); float logicVolts = vdd; float step0; if ((volts - vdd) >= 0) { step0 = MAX_VOLTS_DEVIATION; } else { step0 = -MAX_VOLTS_DEVIATION; } float step = step0; System.out.print("LogicLevel setting " + getName() + " to " + volts + " V..."); while (Math.abs(vdd - volts) > MAX_VOLTS_DEVIATION) { vdd = nextVoltage(vdd, step, volts); this.vddChannel.setVoltageNoWait(vdd); step = 2 * step0; logicVolts = nextVoltage(logicVolts, step, volts); this.logicChannel.setVoltageNoWait(logicVolts); System.out.print("."); } // Want to achieve "volts" exactly, so take out of loop this.logicChannel.setVoltageNoWait(volts); this.vddChannel.setVoltageNoWait(volts); System.out.println(".done"); } /** * Compute next voltage value, without allowing overshoot. * * @param old * current voltage * @param step * voltage step size (may be negative) * @param end * final voltage */ private float nextVoltage(float old, float step, float end) { float next = old + step; if (step > 0) { next = Math.min(next, end); } else { next = Math.max(next, end); } return next; } /** * Set the channel's voltage and wait until it reaches requested value. * * @param volts * new voltage for the channel, in Volts */ public void setVoltageWait(float volts) { logSet("LogicLevel setting " + getName() + " to " + volts + " V (wait)"); setVoltageNoWait(volts); if (this.isLogicStateHigh()) { logicChannel.waitForVoltage(volts); } vddChannel.waitForVoltage(volts); } /** * Reads back the current provided by the Vdd channel of the power supply. * * @return current drawn over the Vdd channel, in Amps */ public float readCurrent() { return vddChannel.readCurrent(); } /** * Set the Vdd channel's current limit to the value provided * * @param amps * new current limit for the channel, in Amps */ public void setCurrent(float amps) { logSet("LogicLevel set " + getName() + " current limit to " + amps); vddChannel.setCurrent(amps); } /** * Get the Vdd channel's current limit setpoint * * @return current limit setpoint for the channel, in Amps */ public float getCurrentSetpoint() { return vddChannel.getCurrentSetpoint(); } /** * @return Current value for Logic State */ public boolean isLogicStateHigh() { return this.logicState; } /** * If logicState is true, sets voltage for logic level to same values as * Vdd. Otherwise sets it to zero. * * @param logicState * New value for logic state */ public void setLogicState(boolean logicState) { logSet("LogicLevel setting " + getLogicName() + " to " + logicState); this.logicState = logicState; if (logicState == false) { this.logicChannel.setVoltageWait(0.f); } else { float volts = this.vddChannel.getVoltageSetpoint(); this.logicChannel.setVoltageWait(volts); } } /** * Reads back the current provided by the logic channel of the power supply. * * @return current drawn over the logic channel, in Amps */ public float readLogicCurrent() { return logicChannel.readCurrent(); } /** * Get the logic channel's voltage * * @return current voltage for the logic channel, in Volts */ public float getLogicVoltageSetpoint() { return logicChannel.getVoltageSetpoint(); } /** * Unit test exhibits use with one power and two logic channels, then * exercises a single power/logic combination with a real power supply. * * @param args * ignored */ public static void main(String[] args) { // One power, two logic channels PowerChannel vddChannel = new ManualPowerChannel("vdd", false); PowerChannel logicChannel = new ManualPowerChannel("log1", false); PowerChannel logicChannel2 = new ManualPowerChannel("log2", false); LogicLevel level = new LogicLevel(vddChannel, logicChannel, false); LogicLevel level2 = new LogicLevel(level, logicChannel2, false); level.setLogicState(true); level2.setLogicState(true); level2.setVoltageWait(1.2f); level2.setLogicState(false); level.setLogicState(false); System.out.println("Hit return to move on to real supply:"); Infrastructure.readln(); Infrastructure.gpibControllers = new int[] { 1 }; // vddChannel = new Pst3202Channel("vdd", "hPst3202", 1); //logicChannel = new Pst3202Channel("log", "hPst3202", 3); vddChannel = new HP6624AChannel("vdd", "hHP6624A", 1); logicChannel = new HP6624AChannel("log", "hHP6624A", 3); // vddChannel = new ManualPowerChannel("vdd", false); // logicChannel = new ManualPowerChannel("log", false); level = new LogicLevel(vddChannel, logicChannel, false); System.out.println(level.getState()); level.setLogicState(false); level.setVoltageWait(1.0f); System.out.println("After false ramp down: " + level.getState()); System.out.println(" logic: " + logicChannel.getVoltageSetpoint() + " V, " + logicChannel.readCurrent() + " A"); level.setLogicState(true); level.setVoltageWait(1.75f); System.out.println("After true ramp up: " + level.getState()); System.out.println(" logic: " + logicChannel.getVoltageSetpoint() + " V, " + logicChannel.readCurrent() + " A"); level.setVoltageWait(1.1f); System.out.println("After true ramp down: " + level.getState()); System.out.println(" logic: " + logicChannel.getVoltageSetpoint() + " V, " + logicChannel.readCurrent() + " A"); } }