The "settling time problem"
Recently (end of April 2011) I spent more time looking into the problem of propagating undefined nodes in a simulated circuit. This led me to the discovery that my existing hack for handling multiple sources driving a single node. Where multiple sources drive a single network, the resistor network formed by the transistors is used to calculate the voltage at each part of that network. I had introduced the "settle" command as a hack to prevent IRSIM from setting the values in those type of networks to "unknown". Unfortunately, I did that to all parts of the network, forcing them all to generate an "unknown" value after the settling time, even when parts of the resistive network were calculated to be a definite logic value (and so should never be set to "unknown" at all).
While fixing this error, I looked again at the calculations that IRSIM makes when a node is driven by multiple sources. If a node is driven by multiple sources, then the voltage on that node changes according to the amount of current being sourced from VDD minus the current being sunk to VSS divided by the capacitance at the node, and multiplied by the amount of time: delta(V) = (Isource - Isink) * (1/C) * t. Setting delta(V) to the difference in voltage between the value at the previous logic state and the value at which the node is considered to be "unknown", one can easily solve for the time "t" to schedule the event that marks the node as undefined. In fact, this is what the linear method of IRSIM does, at least within a factor of two or so. In file "base/newrstep.c", procedure "scheduleDriven()" (line 368), at line 425 the time to schedule the node to be declared at an "unknown" state is: t = Rmin * C. Now, from the above equation, one can see that a better equation should be: t = (Rup - Rdown) * C, but that doesn't take into account that delta(V) < 1 (note that IRSIM defines VDD at 1 and GND at 0). Typically, the distance between a rail and the voltage at which a node is considered undefined is (1/2) to (1/3), so we have, roughly: t = (1/3)(Rup - Rdown) * C. For a typical process (including the one I was using to run tests on this code), (1/3)(Rup - Rdown) is not significantly different from Rmin (Rmin = MIN(Rup, Rdown); Rup is the resistance from the node to VDD, and Rdown is the resistance from the node to GND). So the equation is roughly correct. When a node is (briefly) driven by two sources, the node voltage begins to drift away from the rail, and the value on the node will become undefined if it is not forced to a rail in the interim.
Now, the usual case where this situation causes propagating undefined nodes is a 2-input multiplexer formed by two pass-gates. Because the pass-gates have opposite logic on their N and P transistors, the logic driving the pass-gate is inverted, so that one side of each pass-gate gets its input delayed by one inverter delay. During this short delay, both pass-gates are open. If the multiplexer thus formed has opposite values at its two inputs, then the value at the multiplexer output will begin to drift toward a middle point between VDD and GND (say, VDD/2, if the transistors are balanced). However, the inverter delay is (presumably) short, and the pass-gates should be fully switched well before the scheduled time to mark the node as "undefined", and the scheduled event therefore canceled. This is not happening. I found that even using the equation: t = Rmax * Cd (where Cd is the total capacitance, and is larger than C, the switching capacitance; and Rmax = MAX(Rup, Rdown)), which should greatly overestimate the time for the node to settle to an unknown state, did not prevent the node from going undefined. Only by using my ad-hoc "settle" value would prevent the node from going undefined (for context, the value of t being computed in my test example was about 30ps using Rmin * C, or about 60ps using Rmax * Cd, while forcing it to stop going undefined needed t around 1000ps.
So something is really wrong here. Intuition says that IRSIM makes the right calculation to determine how long a node is going to stay at a known logic state before competing drivers pull it to an unknown state. Practice says that this time value must be arbitrarily set many times larger. What is the real answer?
(May 11, 2011) Update: In the past few days, I tried to tackle issues of propagating undefined nodes. The actual problem with my circuit simulation turned out to be a netlist error. However, it is worth mentioning that this circuit simulation has the notorious passgate-based XOR and XNOR circuits, and I discovered a few things about the simulation in the process of tracking down the error. The first is that there are no fewer than three separate hacks required to get the circuit to simulate. The first is to adjust the logic threshold voltages (percentage of VDD) in the parameter file, the second to set a value for "settle", and the third is to run the "relax" command toward the start of simulation. The logic threshold may be a required feature, as the calculation of pass-transistor logic requires that drivers be strong enough to pull a contested node beyond one of the logic thresholds. In the XOR and XNOR circuits I have, the two inverters that invert the signal inputs are weak enough that they tend to get pulled by the pass-gates, and since IRSIM uses a linear resistor approximation for transistors, it doesn't understand the positive-feedback nature of the loops involved. IRSIM calculates the inverter output nodes to pull to about 0.68 times VDD, which will be interpreted as an "undefined" value unless the upper logic threshold is set to less than that (say, 0.6).
I thought about the problem some, and considered that one aspect of these circuits is that they are self-biased; that is, certain nodes are affected by their own voltage through feedback loops. If one can analyze that portion of the circuit for self biasing, one can determine when a specific logic value is reinforced by positive feedback. I used a simple method to set the node being solved for to logic 1 and logic 0, and to recompute the limits on the possible node voltage, and look for contradictions (for example, by forcing the node to logic 1, the possible range of voltages for the node are all << 1, which is a contradition; therefore, the node must be logic 0). This method, though, is not very general-purpose, and the limited number of cases it solved were not enough to make my simulation run. I did find, though, that it solved enough cases to allow me to drop the use of the "relax" command at the beginning of circuit simulation. So it's an improvement in some sense. I will keep thinking about it.