/// <summary> /// Evaluate a terminal (wires are instant, NOT gates are not) /// </summary> public override bool Eval(bool quick) { // Trace through wires (do not allow infinite recursion) OpCodeTerminal next = this; OpCodeTerminal final = this; int max = 32; while (next != null && next.Negate == OpState.Zero && --max >= 0) { final = next; next = next.Expression.Expr as OpCodeTerminal; } // Calculate new value OpState oldState = State; State = PrevState; PrevState = final.Expression.Expr.State ^ final.Negate; bool changed = PrevState != State || PrevState != oldState; // Wires are always quick (no time delay). if (final.Negate == OpState.Zero || quick) { State = PrevState; } return(changed); }
public override OpCode DeepClone(OpCode.VisitTerminalsDelegate copyTerm) { OpCodeTerminal term = (OpCodeTerminal)MemberwiseClone(); copyTerm(term); return(term); }
/// <summary> /// Non-recursively remove identities: /// a+!a = 1 /// a*!a = 0 /// a+a = a /// a*a = a /// </summary> OpCode RemoveIdentityNR(OpCode op) { if (op.Operands == null) { return(op); } int identity = 0; if (op is OpCodeOr) { identity = 1; } else if (!(op is OpCodeAnd)) { return(op); } for (int i = 0; i < op.Operands.Count; i++) { OpCodeTerminal t1 = op.Operands[i] as OpCodeTerminal; if (t1 == null) { continue; } for (int j = i + 1; j < op.Operands.Count; j++) { OpCodeTerminal t2 = op.Operands[j] as OpCodeTerminal; if (t2 == null) { continue; } // Follow wires to their terminal value OpCodeTerminal trTerm1 = TraceTerm(t1); OpCodeTerminal trTerm2 = TraceTerm(t2); // a+!a = 1 // a*!a = 0 if (trTerm1.Expression == trTerm2.Expression && (t1.Negate ^ t2.Negate) == OpState.One) { mIdentityToConst++; return(new OpCodeConst(identity)); } // a+a = a // a*a = a if (trTerm1.Expression == trTerm2.Expression && ((t1.Negate == OpState.Zero && t2.Negate == OpState.Zero) || (t1.Negate == OpState.One && t2.Negate == OpState.One))) { op.Operands.RemoveAt(j); j--; // Retry this operand mIdentityToSelf++; } } } return(op); }
public override bool Equals(object obj) { OpCodeTerminal op = obj as OpCodeTerminal; if (op == null) { return(false); } return(Expression.Index == op.Expression.Index && Expression.Name == op.Expression.Name && Negate == op.Negate); }
/// <summary> /// Scan assignment chain for the last expression /// (e.g. TraceTerm(a) on a = b, b = c, c = (x+c) returns c) /// </summary> OpCodeTerminal TraceTerm(OpCodeTerminal term) { int tries = 8; OpCodeTerminal trace = term.Expression.Expr as OpCodeTerminal; while (trace != null && trace.Expression.Expr.Negate == OpState.Zero && --tries != 0) { term = trace; trace = term.Expression.Expr as OpCodeTerminal; } return(term); }
/// <summary> /// Embed wires and constant wires /// </summary> OpCode EmbedWires(List <OpCodeExpr> expressions, OpCode op, int minOpt) { // Recurse down the expression tree if (op.Operands != null) { for (int i = 0; i < op.Operands.Count; i++) { op.Operands[i] = EmbedWires(expressions, op.Operands[i], minOpt); } } // Replace only terminal OpCodeTerminal term = op as OpCodeTerminal; if (term == null) { return(op); } // Replace wire expressions (if the wire doesn't point outside of minOpt) OpCodeTerminal wire = term.Expression.Expr as OpCodeTerminal; if (wire != null && term.Expression.Index >= minOpt) { // Replace this terminal with the wire's target // (i.e. follow the wire) term.Negate ^= wire.Negate; term.Expression = wire.Expression; mWires++; return(term); } // Replace constant expressions OpCodeConst constTerm = term.Expression.Expr as OpCodeConst; if (constTerm != null) { constTerm.Eval(true); if (constTerm.State == OpState.Zero || constTerm.State == OpState.One) { mConstWires++; return(new OpCodeConst(((int)term.Negate ^ (int)constTerm.State) & 1)); } } return(term); }
/// <summary> /// Embed expressions that have only been used once /// </summary> OpCode EmbedSingleUses(List <OpCodeExpr> expressions, int index, OpCode op, int[] timesUsed, int minOpt) { // Recurse down the expression tree if (op.Operands != null) { for (int i = 0; i < op.Operands.Count; i++) { op.Operands[i] = EmbedSingleUses(expressions, index, op.Operands[i], timesUsed, minOpt); } } // Embed terminal expressions that have only been used once, // and are within the optimization range, and are not this expression OpCodeTerminal term = op as OpCodeTerminal; if (term == null || timesUsed[term.Expression.Index] != 1 || term.Expression.Index < minOpt || index == term.Expression.Index) { return(op); } // Replace this terminal with the expression // (i.e. make it a sub-expression) OpCode newOp = expressions[term.Expression.Index].Expr; newOp.Negate ^= term.Negate; expressions[term.Expression.Index].Expr = null; expressions[term.Expression.Index] = null; term.Expression = null; mEmbeddedSingletons++; return(newOp); }