major overhaul of FPGA code to support both ML509 and Bee2 at the same time
[fleet.git] / src / edu / berkeley / fleet / fpga / verilog / Verilog.java
index 39c9035..44d02e5 100644 (file)
 package edu.berkeley.fleet.fpga.verilog;
 import edu.berkeley.fleet.api.*;
 import edu.berkeley.fleet.two.*;
+import edu.berkeley.fleet.util.*;
 import edu.berkeley.fleet.*;
 import java.lang.reflect.*;
-import edu.berkeley.sbp.chr.*;
-import edu.berkeley.sbp.misc.*;
-import edu.berkeley.sbp.meta.*;
-import edu.berkeley.sbp.util.*;
 import java.util.*;
 import java.io.*;
 import static edu.berkeley.fleet.two.FleetTwoFleet.*;
 
+/*
+
+- ideally: want to merge Fpga.dump() with this... but have to resolve
+  the handling of flushing first.
+
+- eliminate uses of SimpleXXX
+   - force width parameter in remaining uses
+   - re-enable width checking (add zero-extend and sign-extend)
+
+- ideally: make getVerilog() package-private somehow
+
+- change Event constructors from Object[] to Event[]/Action[]
+- change portorder to LinkedHashMap
+
+=> mangle the names given for strings
+=> ensure uniquification of percolated ports
+
+=> later: scan chain
+*/
+
+/**
+ *  Among the benefits are:
+ *    - automatic scan-chain insertion
+ *    - better error-checking (for example, width mismatches) than Verilog provides
+ *    - pin percolation
+ *
+ *  One of the most annoying things about Verilog is that you cannot
+ *  "double-slice" a value; in other words, foo[10:2] is valid
+ *  Verilog, but foo[10:2][4:3] is not; the programmer must write
+ *  foo[4+2:3+2].  This lack of compositionality is the reason for
+ *  most of the complexity in the Value class.
+ */
 public class Verilog {
 
+    public static final int FORWARD_LATENCY = 6;  // must be >=1
+    public static final int REVERSE_LATENCY = 4;  // must be >=3
+
+    public static interface Value {
+        public String  getVerilog();
+        public Value   getBits(int high, int low);
+        public Value   getBits(Mask mask);
+        public Trigger testMask(Mask mask);
+        public Value   invertBits();
+        public int     getWidth();
+    }
+
     public static class SimpleValue implements Value {
         public final String s;
-        public SimpleValue(String s) { this.s = s; }
-        public SimpleValue(String s, int high, int low) { this.s = s+"["+high+":"+low+"]"; }
-        public Value getBits(int high, int low) { return new SimpleValue(s, high, low); }
-        public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
-        public String getVerilogName() { return s; }
-        public String toString() { return s; }
+        private final String s0;
+        private final int high;
+        private final int low;
+        private final int width;
+        public SimpleValue(String s) { this(s, -1); }
+        public SimpleValue(String s, int width) {
+            this.s = s;
+            this.s0 = s;
+            this.high = -1;
+            this.low = -1;
+            this.width = width;
+        }
+        public SimpleValue(String s, int high, int low) {
+            this.s = s+"["+high+":"+low+"]";
+            this.s0 = s;
+            this.high = high;
+            this.low = low;
+            this.width = 1+high-low;
+        }
+        public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+        public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
+        public Value getBits(int high, int low) {
+            if (this.high==-1 && this.low==-1) return new SimpleValue(s, high, low);
+            if (high+this.low > this.high) throw new RuntimeException("out of range");
+            return new SimpleValue(s0, high+this.low, low+this.low);
+        }
+        public String getVerilog() { return s; }
+        public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",width); }
+        public int getWidth() {
+            if (width==-1) throw new RuntimeException("not implemented");
+            return width;
+        }
+    }
+
+    public static class MuxValue implements Value {
+        private final Trigger sel;
+        private final Value if0;
+        private final Value if1;
+        public MuxValue(Trigger sel, Value if1, Value if0) {
+            this.sel = sel;
+            this.if0 = if0;
+            this.if1 = if1;
+            if (if0.getWidth() != if1.getWidth())
+                throw new RuntimeException("width mismatch; "+if0+"="+if0.getWidth()+", "+if1+"="+if1.getWidth());
+        }
+        public int getWidth() { return if0.getWidth(); }
+        public String getVerilog() { return "("+sel.getVerilogTrigger()+" ? "+if1.getVerilog()+" : "+if0.getVerilog()+")"; }
+        public Value getBits(int high, int low) { return new MuxValue(sel, if1.getBits(high,low), if0.getBits(high,low)); }
+        public Value getBits(Mask mask) { return new MuxValue(sel, if1.getBits(mask), if0.getBits(mask)); }
+        public Value invertBits() { return new MuxValue(sel, if1.invertBits(), if0.invertBits()); }
+        public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
+    }
+
+    public static class ConstantValue implements Value {
+        private final BitVector bits;
+        public ConstantValue(BitVector bits) { this.bits = bits; }
+        public Value getBits(int high, int low) { return new ConstantValue(bits.get(high, low)); }
+        public Value getBits(Mask mask) { throw new RuntimeException("FIXME"); }
+        public Value invertBits() {
+            BitVector ret = new BitVector(bits.length());
+            for(int i=0; i<bits.length(); i++) ret.set(i, !bits.get(i));
+            return new ConstantValue(ret);
+        }
+        public String getVerilog() {
+            StringBuffer sb = new StringBuffer();
+            sb.append(bits.length());
+            sb.append("'b");
+            for(int i=bits.length()-1; i>=0; i--)
+                sb.append(bits.get(i) ? '1' : '0');
+            return sb.toString();
+        }
+        public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
+        public int getWidth() { return bits.length(); }
     }
 
     public static class CatValue implements Value {
         private final Value[] values;
         public CatValue(Value[] values) { this.values = values; }
-        public Value getBits(int high, int low) {
-            throw new RuntimeException();
-        }
-        public Assignable getAssignableBits(int high, int low) {
-            throw new RuntimeException();
+        public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+        public Value getBits(int high, int low) { throw new RuntimeException(); }
+        public int getWidth() {
+            int ret = 0;
+            for (Value val : values) ret += val.getWidth();
+            return ret;
         }
-        public String toString() { return getVerilogName(); }
-        public String getVerilogName() {
+        public String getVerilog() {
             StringBuffer sb = new StringBuffer();
             sb.append("{ ");
             boolean first = true;
             for(int i=0; i<values.length; i++) {
                 if (values[i]==null) continue;
                 if (!first) sb.append(", ");
-                sb.append(values[i].getVerilogName());
+                sb.append(values[i].getVerilog());
                 first = false;
             }
             sb.append(" }");
             return sb.toString();
         }
+        public Value invertBits() {
+            Value[] newvals = new Value[values.length];
+            for(int i=0; i<values.length; i++)
+                newvals[i] = values[i].invertBits();
+            return new CatValue(newvals);
+        }
+        public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
     }
 
-    public static interface Action {
-        public String getVerilogAction();
+    public static class LogicValue implements Value {
+        public static enum LogicType { OR, AND };
+        private final Value v1;
+        private final Value v2;
+        private final LogicType tt;
+        public LogicValue(Value v1, LogicType tt, Value v2) {
+            this.v1 = v1;
+            this.v2 = v2;
+            this.tt = tt;
+            // FIXME: check width match
+        }
+        public String  getVerilog() {
+            switch(tt) {
+                case OR:  return "("+v1.getVerilog()+"||"+v2.getVerilog()+")";
+                case AND: return "("+v1.getVerilog()+"&&"+v2.getVerilog()+")";
+            }
+            throw new RuntimeException("impossible");
+        }
+        public Value   getBits(int high, int low) { return new LogicValue(v1.getBits(high,low),tt,v2.getBits(high,low)); }
+        public Value   getBits(Mask mask) { return new LogicValue(v1.getBits(mask),tt,v2.getBits(mask)); }
+        public Trigger testMask(Mask mask) { throw new RuntimeException("FIXME"); }
+        public Value   invertBits() { 
+            switch(tt) {
+                case OR:  return new LogicValue(v1.invertBits(), LogicType.AND, v2.invertBits());
+                case AND: return new LogicValue(v1.invertBits(), LogicType.OR, v2.invertBits());
+            }
+            throw new RuntimeException("impossible");
+        }
+        public int     getWidth() { return v1.getWidth(); }
+    }
+
+    public static class TestValue implements Value, Trigger {
+        public static enum TestType { NE, EQ, LT, GT, LE, GE };
+        private final Value v1;
+        private final Value v2;
+        private final TestType tt;
+        public TestValue(Value v1, TestType tt, Value v2) {
+            this.v1 = v1;
+            this.v2 = v2;
+            this.tt = tt;
+            // FIXME: check width match
+        }
+        public String  getVerilogTrigger() { return getVerilog(); }
+        public String  getVerilog() {
+            switch(tt) {
+                case NE: return "("+v1.getVerilog()+"!="+v2.getVerilog()+")";
+                case EQ: return "("+v1.getVerilog()+"=="+v2.getVerilog()+")";
+                case LE: return "("+v1.getVerilog()+"<="+v2.getVerilog()+")";
+                case GE: return "("+v1.getVerilog()+">="+v2.getVerilog()+")";
+                case LT: return "("+v1.getVerilog()+"<" +v2.getVerilog()+")";
+                case GT: return "("+v1.getVerilog()+">" +v2.getVerilog()+")";
+            }
+            throw new RuntimeException("impossible");
+        }
+        public Value   getBits(int high, int low) { throw new RuntimeException("you probably didn't mean to do this"); }
+        public Value   getBits(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); }
+        public Trigger testMask(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); }
+        public Trigger invert() { return invertMe(); }
+        public Value   invertBits() { return invertMe(); }
+        private TestValue invertMe() {
+            switch(tt) {
+                case NE: return new TestValue(v1, TestType.EQ, v2);
+                case EQ: return new TestValue(v1, TestType.NE, v2);
+                case LE: return new TestValue(v1, TestType.GT, v2);
+                case GE: return new TestValue(v1, TestType.LT, v2);
+                case LT: return new TestValue(v1, TestType.GE, v2);
+                case GT: return new TestValue(v1, TestType.LE, v2);
+            }
+            throw new RuntimeException("impossible");
+        }
+        public int     getWidth() { return 1; }
     }
 
+    // Triggers //////////////////////////////////////////////////////////////////////////////
+
     public static interface Trigger {
         public String getVerilogTrigger();
+        public Trigger invert();
     }
 
-    public static interface Assignable {
-        public String getVerilogName();
-        public Assignable getAssignableBits(int high, int low);
+    public static class SimpleTrigger implements Trigger {
+        private final String s;
+        public SimpleTrigger(String s) { this.s = s; }
+        public String getVerilogTrigger() { return s; }
+        public Trigger invert() { return new SimpleTrigger("!("+s+")"); }
     }
 
-    public static interface Value extends Assignable {
-        public String getVerilogName();
-        public Value getBits(int high, int low);
+    public static class AndTrigger implements Trigger {
+        private final Trigger t1, t2;
+        public AndTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; }
+        public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" && "+t2.getVerilogTrigger()+")"; }
+        public Trigger invert() { return new InvertedTrigger(this); }
     }
 
-    public static class ConditionalAction implements Action {
-        public String condition;
-        public Action action;
-        public ConditionalAction(String condition, Action action) {
-            this.condition = condition;
-            this.action = action;
-        }
-        public String toString() { return getVerilogAction(); }
-        public String getVerilogAction() { return "if ("+condition+") begin "+action.getVerilogAction()+" end"; }
+    public static class OrTrigger implements Trigger {
+        private final Trigger t1, t2;
+        public OrTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; }
+        public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" || "+t2.getVerilogTrigger()+")"; }
+        public Trigger invert() { return new InvertedTrigger(this); }
+    }
+
+    public static class InvertedTrigger implements Trigger {
+        private final Trigger original;
+        public InvertedTrigger(Trigger original) { this.original = original; }
+        public String getVerilogTrigger() { return "!("+original.getVerilogTrigger()+")"; }
+        public Trigger invert() { return original; }
     }
 
     public static class ConditionalTrigger implements Trigger {
-        public String condition;
+        public Trigger condition;
         public Trigger trigger;
-        public ConditionalTrigger(String condition, Trigger trigger) {
+        public ConditionalTrigger(Trigger condition, Trigger trigger) {
             this.condition = condition;
             this.trigger = trigger;
-            if (trigger instanceof Module.Port)
-                ((Module.Port)trigger).hasLatch = true;
         }
         public String getVerilogTrigger() {
-            return "&& (("+condition+") ? (1 " + trigger.getVerilogTrigger() + ") : 1)";
+            return "(("+condition.getVerilogTrigger()+") ? (" + trigger.getVerilogTrigger() + ") : 1)";
         }
+        public Trigger invert() { return new InvertedTrigger(this); }
     }
 
-    public static class SimpleAssignable implements Assignable {
-        public final String s;
-        public SimpleAssignable(String s) { this.s = s; }
-        public String getVerilogName() { return s; }
-        public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
+    // Actions //////////////////////////////////////////////////////////////////////////////
+
+    public static interface Action {
+        public String getVerilogAction();
+    }
+
+    public static class ConditionalAction implements Action {
+        public Trigger condition;
+        public Action action;
+        public ConditionalAction(Trigger condition, Action action) {
+            this.condition = condition;
+            this.action = action;
+        }
+        public String getVerilogAction() { return "if ("+condition.getVerilogTrigger()+") begin "+action.getVerilogAction()+" end"; }
     }
 
     public static class AssignAction implements Action {
-        public String left;
-        public String right;
+        public Assignable left;
+        public Value right;
         public AssignAction(Assignable left, Value right) {
-            this.left = left.getVerilogName();
-            this.right = right.getVerilogName().toString();
-        }
-        public AssignAction(Assignable left, String right) {
-            this.left = left.getVerilogName();
+            this.left = left;
             this.right = right;
         }
-        public String getVerilogAction() { return left + "<=" + right + ";"; }
-        public String toString() { return getVerilogAction(); }
+        public String getVerilogAction() { return left.getVerilog() + "<=" + right.getVerilog() + ";"; }
     }
-    
-    public static class SimpleAction implements Action {
-        public final String verilog;
-        public SimpleAction(String verilog) { this.verilog = verilog; }
-        public String getVerilogAction() { return verilog; }
-        public String toString() { return verilog; }
+
+    // Assignables //////////////////////////////////////////////////////////////////////////////
+
+    public static interface Assignable {
+        public String getVerilog();
     }
 
+    public static class SimpleAssignable implements Assignable {
+        public final String s;
+        public SimpleAssignable(String s) { this.s = s; }
+        public String getVerilog() { return s; }
+    }
+
+    // Module Internals //////////////////////////////////////////////////////////////////////////////
+
     public static class Module {
+        // order matters here
+        public LinkedHashMap<String,InstantiatedModule> instantiatedModules = new LinkedHashMap<String,InstantiatedModule>();
+
         public void dump(String prefix) throws IOException {
             PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
             dump(pw, true);
             pw.flush();
-            for(InstantiatedModule m : instantiatedModules)
+            for(InstantiatedModule m : instantiatedModules.values())
                 m.module.dump(prefix);
         }
         public int id = 0;
@@ -133,7 +340,8 @@ public class Verilog {
         public String getName() { return name; }
         public Port getPort(String name) { return ports.get(name); }
 
-        public HashSet<InstantiatedModule> instantiatedModules = new HashSet<InstantiatedModule>();
+        // order matters here
+        public LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
         public final ArrayList<Event> events = new ArrayList<Event>();
 
         // FIXME: always-alphabetical convention?
@@ -141,53 +349,24 @@ public class Verilog {
         public final ArrayList<String> portorder = new ArrayList<String>();
         public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
         public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
+        public final HashMap<String,WireValue> wires = new HashMap<String,WireValue>();
         
-        public StringBuffer crap = new StringBuffer();
-        public StringBuffer precrap = new StringBuffer();
-        //public void addCrap(String s) { crap.append(s); crap.append('\n'); }
-        public void addPreCrap(String s) { precrap.append(s); precrap.append('\n'); }
-        public void addPreCrap0(String s) { precrap.append(s); }
-
-        public Module(String name) {
-            this.name = name;
-        }
+        public Module(String name) { this.name = name; }
 
-        public SourcePort createInputPort(String name, int width) {
-            if (ports.get(name)!=null) throw new RuntimeException();
-            return new SourcePort(name, width, true);
-        }
-        public SourcePort getInputPort(String name) {
-            SourcePort ret = (SourcePort)ports.get(name);
-            if (ret==null) throw new RuntimeException();
-            return ret;
-        }
-        public SinkPort createOutputPort(String name, int width, String resetBehavior) {
-            if (ports.get(name)!=null) throw new RuntimeException();
-            return new SinkPort(name, width, true, resetBehavior);
-        }
-        public SinkPort createWirePort(String name, int width) {
-            if (ports.get(name)!=null) throw new RuntimeException();
-            return new SinkPort(name, width, false, "");
-        }
-        public SourcePort createWireSourcePort(String name, int width) {
-            if (ports.get(name)!=null) throw new RuntimeException();
-            return new SourcePort(name, width, false);
-        }
-        public SinkPort getOutputPort(String name) {
-            SinkPort ret = (SinkPort)ports.get(name);
-            if (ret==null) throw new RuntimeException();
-            return ret;
-        }
+        public SourcePort createInputPort(String name, int width) { return new SourcePort(name, width, true); }
+        public SinkPort createOutputPort(String name, int width) { return new SinkPort(name, width, true); }
+
+        // Latches and Wires //////////////////////////////////////////////////////////////////////////////
 
         public class StateWire {
             public final String name;
             public final boolean initiallyFull;
             public String getName() { return name; }
-            public Action isFull()  { return new SimpleAction(name+"==1"); }
-            public Action isEmpty() { return new SimpleAction(name+"==0"); }
-            public Action doFill()  { return new SimpleAction(name+"<=1;"); }
-            public Action doDrain() { return new SimpleAction(name+"<=0;"); }
-            public String doReset() { return name+"<="+(initiallyFull?"1":"0")+";"; }
+            public Trigger isFull()  { return new SimpleTrigger("("+name+"==1)"); }
+            public Trigger isEmpty() { return new SimpleTrigger("("+name+"==0)"); }
+            public Action  doFill()  { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(1))); }
+            public Action  doDrain() { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(0))); }
+            public String  getResetCode() { return name+"<="+(initiallyFull?"1":"0")+";"; }
             public StateWire(String name) { this(name, false); }
             public StateWire(String name, boolean initiallyFull) {
                 this.name = name;
@@ -211,378 +390,346 @@ public class Verilog {
                 this.initial = initial;
                 latches.put(name, this);
             }
-            public String getVerilogName() { return name; }
-            public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
-            public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
-            public String doReset() { return name+"<="+initial+";"; }
+            public int getWidth() { return width; }
+            public String getVerilog() { return name; }
+            public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
+            public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+            public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
+            public String getResetCode() { return name+"<="+initial+";"; }
             public void dump(PrintWriter pw) {
                 pw.println("  reg ["+(width-1)+":0] "+name+";");
                 pw.println("  initial "+name+"="+initial+";");
             }
-            public void connect(SinkPort driven) {
-                driven.latchDriver = this;
-            }
+            public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
         }
 
-        public abstract class Port implements Action, Assignable, Trigger {
-            public abstract String doReset();
+        public class WireValue implements Value {
             public final String name;
-            public String getName() { return name; }
             public final int width;
+            public final Value assign;
+            public WireValue(String name, int width, Value assign) {
+                this.width = width;
+                this.name = name;
+                this.assign = assign;
+                wires.put(name, this);
+            }
             public int getWidth() { return width; }
-            public boolean hasLatch = false;
-            public boolean external;
+            public String getVerilog() { return name; }
+            public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
+            public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+            public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
+            public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
+            public void dump(PrintWriter pw) { pw.println("  wire ["+(width-1)+":0] "+name+";"); }
+            public String getAssignments() { return "  assign "+name+" = "+assign.getVerilog()+";"; }
+        }
+
+        // Ports //////////////////////////////////////////////////////////////////////////////
+
+        public abstract class Port implements Action, Trigger {
+            final String name;
+            final int width;
+            final boolean external;
             public Port(String name, int width, boolean external) {
                 this.width = width;
                 this.name = name;
                 this.external = external;
+                if (ports.get(name)!=null)
+                    throw new RuntimeException("port "+name+" already exists");
                 ports.put(name, this);
                 if (external)
                     portorder.add(name);
             }
-            public String getVerilogName() { return name; }
+            public String getName() { return name; }
+            public int getWidth() { return width; }
+            public String getVerilog() { return name; }
             String getAck() { return name+"_a"; }
             String getReq() { return name+"_r"; }
-            public String isFull() { return "("+name+"_r"+" && !"+name+"_a)"; }
+            public String isFull() { return "("+getReq()+" && !"+getAck()+")"; }
+            public abstract String getResetCode();
             public abstract String getInterface();
             public abstract String getSimpleInterface();
             public abstract String getDeclaration();
             public abstract String getAssignments();
-            public abstract void   connect(SinkPort driven);
-        }
-
-        public static class InstantiatedModule {
-            public final Module module;
-            public final Module thisModule;
-            public final int id;
-            public final HashMap<String,Port> ports = new HashMap<String,Port>();
-            public String getName() { return module.getName()+"_"+id; }
-            public InstantiatedModule(Module thisModule, Module module) {
-                this.thisModule = thisModule;
-                this.module = module;
-                this.id = thisModule.id++;
-                thisModule.instantiatedModules.add(this);
-            }
-            public void dump(PrintWriter pw) {
-                pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
-                for(String s : module.portorder)
-                    pw.println(", " + getPort(s).getSimpleInterface());
-                if (module.name.equals("dram")) {
-                    pw.println("    , dram_addr");
-                    pw.println("    , dram_addr_r");
-                    pw.println("    , dram_addr_a");
-                    pw.println("    , dram_isread");
-                    pw.println("    , dram_write_data");
-                    pw.println("    , dram_write_data_push");
-                    pw.println("    , dram_write_data_full");
-                    pw.println("    , dram_read_data");
-                    pw.println("    , dram_read_data_pop");
-                    pw.println("    , dram_read_data_empty");
-                    pw.println("    , dram_read_data_latency");
-                }
-                if (module.name.equals("ddr2")) {
-                    pw.println("    , ddr2_addr");
-                    pw.println("    , ddr2_addr_r");
-                    pw.println("    , ddr2_addr_a");
-                    pw.println("    , ddr2_isread");
-                    pw.println("    , ddr2_write_data");
-                    pw.println("    , ddr2_write_data_push");
-                    pw.println("    , ddr2_write_data_full");
-                    pw.println("    , ddr2_read_data");
-                    pw.println("    , ddr2_read_data_pop");
-                    pw.println("    , ddr2_read_data_empty");
-                    pw.println("    , ddr2_read_data_latency");
-                }
-                if (module.name.equals("video")) {
-                    pw.println("    , vga_clk");
-                    pw.println("    , vga_psave");
-                    pw.println("    , vga_hsync");
-                    pw.println("    , vga_vsync");
-                    pw.println("    , vga_sync");
-                    pw.println("    , vga_blank");
-                    pw.println("    , vga_r");
-                    pw.println("    , vga_g");
-                    pw.println("    , vga_b");
-                    pw.println("    , vga_clkout");
-                }
-                pw.println("   );");
-            }
-            public Port getPort(String name) {
-                return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
-            }
-            public SinkPort getInputPort(String name) {
-                int width = module.getPort(name).getWidth();
-                SinkPort port = (SinkPort)ports.get(name);
-                if (port == null) {
-                    port = thisModule.new SinkPort(getName()+"_"+name, width, false, "");
-                    ports.put(name, port);
-                }
-                return port;
-            }
-            public SourcePort getOutputPort(String name) {
-                int width = module.getPort(name).getWidth();
-                SourcePort port = (SourcePort)ports.get(name);
-                if (port == null) {
-                    port = thisModule.new SourcePort(getName()+"_"+name, width, false);
-                    ports.put(name, port);
-                }
-                return port;
-            }
+            public abstract String getCleanup();
+            public Trigger invert() { return new InvertedTrigger(this); }
+            public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
         }
 
         public class SourcePort extends Port implements Value {
-            public SourcePort(String name, int width, boolean external) { 
-                super(name, width, external); }
-            public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
-            public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
-            public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
+            private SinkPort driven = null;
+            public SourcePort(String name, int width, boolean external) { super(name, width, external); }
+            public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
+            public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+            public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
+            public String getVerilogTrigger() { return getReq() + " && !"+getAck(); }
             public String getVerilogAction() { return getAck() + " <= 1;"; }
             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
-            public String testBit(int index, boolean value) {
-                return "("+name+"["+index+"]=="+(value?1:0)+")";
-            }
+            public String testBit(int index, boolean value) { return "("+name+"["+index+"]=="+(value?1:0)+")"; }
             public String getDeclaration() {
                 StringBuffer sb = new StringBuffer();
                 if (external) {
-                    sb.append("input "  +                 name +"_r;\n");
-                    sb.append("output " +                 name +"_a_;\n");
-                    if (width>0)
-                        sb.append("input ["+(width-1)+":0]" + name +";\n");
-                    else
-                        sb.append("input [0:0]" + name +";\n"); // waste a bit, I guess
+                    sb.append("input "  +                           name +"_r;\n");
+                    sb.append("output " +                           name +"_a_;\n");
+                    sb.append("input ["+Math.max(0,width-1)+":0]" + name +";\n");
                 } else {
-                    sb.append("wire "  +                 name +"_r;\n");
-                    if (width>0)
-                        sb.append("wire ["+(width-1)+":0]" + name +";\n");
+                    sb.append("wire "  +                            name +"_r;\n");
+                    sb.append("wire ["+Math.max(0,width-1)+":0]"  + name +";\n");
                 }
-                if (!hasLatch) {
+                if (driven!=null) {
                     sb.append("wire "    +                 name +"_a;\n");
                 } else {
-                    sb.append("reg "    +                 name +"_a;\n");
-                    sb.append("initial " +                name +"_a = 0;\n");
+                    sb.append("reg "    +                  name +"_a;\n");
+                    sb.append("initial " +                 name +"_a = 0;\n");
                 }
                 return sb.toString();
             }
-            public String doReset() { return hasLatch ? name+"_a<=1;" : ""; }
+            public String getCleanup() { return driven==null ? "if (!"+getReq()+" && "+getAck()+") "+getAck()+"<=0;" : ""; }
+            public String getResetCode() { return driven==null ? name+"_a<=1;" : ""; }
             public String getAssignments() {
                 StringBuffer sb = new StringBuffer();
-                if (external)
-                    sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
+                if (external) {
+                    int a = REVERSE_LATENCY - 3;
+                    if (a<0 || a>16) {
+                        throw new RuntimeException("cannot offer latency of " + REVERSE_LATENCY +"-3");
+                    } else if (a==0) {
+                        sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
+                    } else {
+                        a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
+                        sb.append("SRL16E srl16_"+name+"_a\n");
+                        sb.append("              (.Q ("+name+"_a_),\n");
+                        sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .CE (1),\n");
+                        sb.append("               .CLK (clk),\n");
+                        sb.append("               .D ("+name+"_a));\n");
+                    }
+                }
                 return sb.toString();
             }
             public void connect(SinkPort driven) {
-                driven.driver = this;
+                if (driven.controlDriver!=null) throw new RuntimeException("driven net already has a driver");
+                if (driven.latchDriver!=null) throw new RuntimeException("driven net already has a driver");
+                if (this.driven!=null) throw new RuntimeException("driver already has a driven net");
+                this.driven = driven;
+                driven.controlDriver = this;
+                driven.latchDriver = this;
+                // FIXME
+                // if (getWidth() != driven.getWidth())
+                // throw new RuntimeException("width mismatch: " + getWidth() + " " + driven.getWidth());
             }
         }
-        public class SinkPort extends Port {
-            public SourcePort driver = null;
-            public boolean forceNoLatch = false;
-            public SinkPort driven = null;
-            public Latch latchDriver = null;
-            public boolean noDriveLatches = false;
-            public final String resetBehavior;
-            public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
+        
+        public class SinkPort extends Port implements Assignable {
+            SourcePort controlDriver = null;
+            Value latchDriver = null;
+            public SinkPort(String name, int width, boolean external) { super(name, width, external); }
             public String getVerilogAction() { return getReq() + " <= 1;"; }
-            public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); }
-            public SinkPort(String name, int width, boolean external, String resetBehavior) {
-                super(name, width, external); this.resetBehavior=resetBehavior; }
-            public String getResetBehavior() { return resetBehavior; }
+            public String getVerilogTrigger() { return "!" + getReq() + " && !"+getAck(); }
             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
+            public String getCleanup() { return controlDriver==null ? "if ("+getReq()+" && "+getAck()+") begin "+getReq()+"<=0; end" : ""; }
+            public Assignable getBits(Mask mask) { return new SimpleAssignable(name+"["+mask.valmaskmax+":"+mask.valmaskmin+"]"); }
+            public String getResetCode() { return controlDriver!=null ? "" : name+"_r<=0;"; }
+            public void connectControl(SourcePort controlDriver) {
+                if (this.controlDriver != null) throw new RuntimeException("attempt to connect control twice");
+                this.controlDriver = controlDriver;
+            }
+            public void connectValue(Value val) {
+                //if (latchDriver!=null) throw new RuntimeException("attempt to re-assign via connectValue()");
+                this.latchDriver = val;
+                // FIXME
+                //if (getWidth() != val.getWidth())
+                //throw new RuntimeException("width mismatch: " + getWidth() + " " + val.getWidth());
+            }
             public String getDeclaration() {
                 StringBuffer sb = new StringBuffer();
                 if (external) {
-                    sb.append("output "  +                 name +"_r_;\n");
-                    sb.append("input "   +                 name +"_a;\n");
-                    if (width>0)
-                        sb.append("output ["+(width-1)+":0]" + name +"_;\n");
-                    else
-                        sb.append("output [0:0]" + name +"_;\n"); // waste a bit, I guess
+                    sb.append("output "  +                           name +"_r_;\n");
+                    sb.append("input "   +                           name +"_a;\n");
+                    sb.append("output ["+Math.max(0,width-1)+":0]" + name +"_;\n");
                 } else {
                     sb.append("wire "   +                 name +"_a;\n");
                 }
-
-                if (forceNoLatch ||  latchDriver!=null) {
-                    sb.append("reg "    +                  name +"_r;\n");
-                    sb.append("initial " +                 name +"_r = 0;\n");
-                    if (width>0)
-                        sb.append("wire   ["+(width-1)+":0]" + name +";\n");
-                } else if (!hasLatch) {
+                if (controlDriver!=null) {
                     sb.append("wire "    +                 name +"_r;\n");
-                    if (width>0)
-                        sb.append("wire   ["+(width-1)+":0]" + name +";\n");
+                    sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
                 } else {
                     sb.append("reg "    +                  name +"_r;\n");
                     sb.append("initial " +                 name +"_r = 0;\n");
-                    if (width>0) {
-                        sb.append("reg    ["+(width-1)+":0]" + name +";\n");
-                        if (!"/*NORESET*/".equals(resetBehavior))
-                            sb.append("initial " +                 name +" = 0;\n");
-                    }
+                    if (latchDriver!=null) sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
+                    else                   sb.append("reg    ["+Math.max(0,width-1)+":0]" + name +";\n");
                 }
                 return sb.toString();
             }
-            public String doReset() {
-                return (forceNoLatch||latchDriver!=null||width==0)
-                    ? name+"_r<=0;"
-                    : hasLatch
-                    ? (name+"_r<=0; "+("/*NORESET*/".equals(resetBehavior) ? "" : (name+"<=0;")))
-                    : "";
-            }
             public String getAssignments() {
                 StringBuffer sb = new StringBuffer();
                 if (external) {
-                    sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
-                    if (width>0)
-                        sb.append("assign " +                  name +"_ = " + name + ";\n");
-                }
-                if (driven != null) {
-                    sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
-                    sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
-                    if (width>0)
-                        sb.append("assign " + driven.name +"   = " + name + ";\n");
-                }
-                if (driver != null) {
-                    sb.append("assign " + name +"_r = " + driver.name + "_r;\n");
-                    sb.append("assign " + driver.name +"_a = " + name + "_a;\n");
-                    if (width>0 && !noDriveLatches)
-                        sb.append("assign " + name +"   = " + driver.name + ";\n");
+                    int a = FORWARD_LATENCY - 1;
+                    if (a<0 || a>16) {
+                        throw new RuntimeException("cannot offer latency of " + FORWARD_LATENCY +"-1");
+                    } else if (a==0) {
+                        sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
+                    } else {
+                        a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
+                        sb.append("SRL16E srl16_"+name+"_r\n");
+                        sb.append("              (.Q ("+name+"_r_),\n");
+                        sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
+                        sb.append("               .CE (1),\n");
+                        sb.append("               .CLK (clk),\n");
+                        sb.append("               .D ("+name+"_r));\n");
+                    }
+                    sb.append("assign " +                  name +"_ = " + name + ";\n");
                 }
-                if (latchDriver != null) {
-                    if (width>0)
-                        sb.append("assign " + name +"   = " + latchDriver.name + ";\n");
+                if (controlDriver != null) {
+                    sb.append("assign " + name +"_r = " + controlDriver.name + "_r;\n");
+                    sb.append("assign " + controlDriver.name +"_a = " + name + "_a;\n");
+                    if (latchDriver==null)
+                        sb.append("assign " + name +"   = " + controlDriver.name + ";\n");
                 }
+                if (latchDriver != null)
+                    sb.append("assign " + name +"   = " + latchDriver.getVerilog() + ";\n");
                 return sb.toString();
             }
-            public void connect(SinkPort driven) {
-                this.driven = driven;
-                throw new RuntimeException();
-            }
         }
 
-        public void dump(PrintWriter pw, boolean fix) {
-            pw.println("module "+name+"(clk, rst ");
-            for(String name : portorder) {
-                Port p = ports.get(name);
-                pw.println("    , " + p.getInterface());
+        // InstantiatedModule //////////////////////////////////////////////////////////////////////////////
+
+        public static class InstantiatedModule {
+            public final Module module;
+            public final Module thisModule;
+            public final int id;
+            public final HashMap<String,Port> ports = new HashMap<String,Port>();
+            private final String name;
+            public String getName() { return name; }
+            public InstantiatedModule(Module thisModule, Module module) {
+                this.thisModule = thisModule;
+                this.module = module;
+                // CRUDE
+                int id = 0;
+                while(thisModule.instantiatedModules.get(module.getName()+"_"+id)!=null) id++;
+                this.id = id;
+                this.name = module.getName()+"_"+id;
+                thisModule.instantiatedModules.put(this.name, this);
+                for(String s : module.portorder)
+                    getPort(s);
+            }
+            public void dump(PrintWriter pw) {
+                pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
+                for(String s : module.portorder)
+                    pw.println(", " + getPort(s).getSimpleInterface());
+                for(PercolatedPort pp : module.percolatedPorts)
+                    pw.println("    , "+pp.name);
+                pw.println("   );");
             }
-            if (this.name.equals("root")) {
-                pw.println("    , dram_addr");
-                pw.println("    , dram_addr_r");
-                pw.println("    , dram_addr_a");
-                pw.println("    , dram_isread");
-                pw.println("    , dram_write_data");
-                pw.println("    , dram_write_data_push");
-                pw.println("    , dram_write_data_full");
-                pw.println("    , dram_read_data");
-                pw.println("    , dram_read_data_pop");
-                pw.println("    , dram_read_data_empty");
-                pw.println("    , dram_read_data_latency");
-                pw.println("    , vga_clk");
-                pw.println("    , vga_psave");
-                pw.println("    , vga_hsync");
-                pw.println("    , vga_vsync");
-                pw.println("    , vga_sync");
-                pw.println("    , vga_blank");
-                pw.println("    , vga_r");
-                pw.println("    , vga_g");
-                pw.println("    , vga_b");
-                pw.println("    , vga_clkout");
-                pw.println("    , ddr2_addr");
-                pw.println("    , ddr2_addr_r");
-                pw.println("    , ddr2_addr_a");
-                pw.println("    , ddr2_isread");
-                pw.println("    , ddr2_write_data");
-                pw.println("    , ddr2_write_data_push");
-                pw.println("    , ddr2_write_data_full");
-                pw.println("    , ddr2_read_data");
-                pw.println("    , ddr2_read_data_pop");
-                pw.println("    , ddr2_read_data_empty");
-                pw.println("    , ddr2_read_data_latency");
+            public Port getPort(String name) {
+                return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
             }
-            pw.println("   );");
-            pw.println();
-            pw.println("    input clk;");
-            pw.println("    input rst;");
-            if (this.name.equals("root")) {
-                pw.println("output  [31:0] dram_addr;");
-                pw.println("output         dram_addr_r;");
-                pw.println("input          dram_addr_a;");
-                pw.println("output         dram_isread;");
-                pw.println("output  [63:0] dram_write_data;");
-                pw.println("output         dram_write_data_push;");
-                pw.println("input          dram_write_data_full;");
-                pw.println("input   [63:0] dram_read_data;");
-                pw.println("output         dram_read_data_pop;");
-                pw.println("input          dram_read_data_empty;");
-                pw.println("input   [1:0]  dram_read_data_latency;");
-                pw.println("output  [31:0] ddr2_addr;");
-                pw.println("output         ddr2_addr_r;");
-                pw.println("input          ddr2_addr_a;");
-                pw.println("output         ddr2_isread;");
-                pw.println("output  [63:0] ddr2_write_data;");
-                pw.println("output         ddr2_write_data_push;");
-                pw.println("input          ddr2_write_data_full;");
-                pw.println("input   [63:0] ddr2_read_data;");
-                pw.println("output         ddr2_read_data_pop;");
-                pw.println("input          ddr2_read_data_empty;");
-                pw.println("input   [1:0]  ddr2_read_data_latency;");
-                pw.println("input          vga_clk;");
-                pw.println("output         vga_psave;");
-                pw.println("output         vga_hsync;");
-                pw.println("output         vga_vsync;");
-                pw.println("output         vga_sync;");
-                pw.println("output         vga_blank;");
-                pw.println("output   [7:0] vga_r;");
-                pw.println("output   [7:0] vga_g;");
-                pw.println("output   [7:0] vga_b;");
-                pw.println("output         vga_clkout;");
+            public SinkPort getInputPort(String name) {
+                int width = module.getPort(name).getWidth();
+                SinkPort port = (SinkPort)ports.get(name);
+                if (port == null) {
+                    port = thisModule.new SinkPort(getName()+"_"+name, width, false);
+                    ports.put(name, port);
+                }
+                return port;
             }
-            for(String name : ports.keySet()) {
-                Port p = ports.get(name);
-                pw.println("    " + p.getDeclaration());
+            public SourcePort getOutputPort(String name) {
+                int width = module.getPort(name).getWidth();
+                SourcePort port = (SourcePort)ports.get(name);
+                if (port == null) {
+                    port = thisModule.new SourcePort(getName()+"_"+name, width, false);
+                    ports.put(name, port);
+                }
+                return port;
             }
-            for(StateWire sw : statewires.values())
-                sw.dump(pw);
-            for(Latch l : latches.values())
-                l.dump(pw);
-            for(String name : ports.keySet()) {
-                Port p = ports.get(name);
-                pw.println("    " + p.getAssignments());
+        }
+
+        public void dump(PrintWriter pw, boolean fix) {
+                if (!fix) throw new RuntimeException();
+            boolean isRoot = name.equals("main");
+            pw.print("module "+name);
+            pw.println(isRoot ? "(rst_pin " : "(clk, rst ");
+            for(String name : portorder) pw.println("    , " + ports.get(name).getInterface());
+            for (InstantiatedModule im : this.instantiatedModules.values())
+                for(PercolatedPort pp : im.module.percolatedPorts)
+                    if (!isRoot || (!pp.name.startsWith("root_in_") && !pp.name.startsWith("rst_")))
+                        pw.println("    , "+pp.name);
+            pw.println("   );");
+            pw.println();
+
+            if (isRoot) {
+                pw.println("  input rst_pin;");
+                pw.println("  wire clk;");
+                pw.println("  wire clk_fb;");
+                pw.println("  wire clk_unbuffered;");
+
+                /*
+                pw.println("  DCM");
+                pw.println("   #(");
+                pw.println("      .CLKFX_MULTIPLY(4),");
+                pw.println("      .CLKFX_DIVIDE(8),");
+                pw.println("      .CLKIN_PERIOD(\"10 ns\")");
+                pw.println("    ) mydcm(");
+                pw.println("      .CLKIN (clk_pin),");
+                pw.println("      .CLKFB(clk_fb),");
+                pw.println("      .CLKFX (clk_unbuffered),");
+                pw.println("      .CLK0  (clk_fb)");
+                pw.println("    );");
+                */
+                pw.println("  wire rst;");
+            } else {
+                pw.println("    input clk;");
+                pw.println("    input rst;");
             }
-            for(InstantiatedModule m : instantiatedModules) {
-                m.dump(pw);
+
+            for (InstantiatedModule im : this.instantiatedModules.values())
+                for(PercolatedPort pp : im.module.percolatedPorts) {
+                    if (isRoot && (pp.name.startsWith("root_in_") || pp.name.startsWith("rst_")))
+                        pw.print("wire");
+                    else  switch(pp.type) {
+                            case UP:    pw.print("output"); break;
+                            case DOWN:  pw.print("input");  break;
+                            case INOUT: pw.print("inout");  break;
+                        }
+                    pw.print("  ");
+                    if (pp.width > 1)
+                        pw.print("["+(pp.width-1)+":0]");
+                    pw.print(" ");
+                    pw.print(pp.name);
+                    pw.println(";");
+                }
+
+            if (isRoot) {
+                pw.println("  assign rst    = rst_out;");
+                pw.println("  assign rst_in = !rst_pin;");
+                pw.println("  BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));");
+                pw.println("  assign clk_unbuffered = clk_out;");
             }
-            pw.println(precrap);
+
+            for(String name : ports.keySet()) pw.println("    " + ports.get(name).getDeclaration());
+            for(StateWire sw : statewires.values()) sw.dump(pw);
+            for(Latch l : latches.values()) l.dump(pw);
+            for(WireValue wv : wires.values()) wv.dump(pw);
+            for(String name : ports.keySet()) pw.println("    " + ports.get(name).getAssignments());
+            for(WireValue wv : wires.values()) pw.println("    " + wv.getAssignments());
+            for(InstantiatedModule m : instantiatedModules.values()) m.dump(pw);
             pw.println("always @(posedge clk) begin");
-            pw.println("  if (!rst) begin");
-            for(Latch l : latches.values())
-                pw.println(l.doReset());
-            for(StateWire sw : statewires.values())
-                pw.println(sw.doReset());
-            for(Port p : ports.values())
-                pw.println(p.doReset());
+            pw.println("  if (rst) begin");
+            for(Latch l : latches.values()) pw.println(l.getResetCode());
+            for(StateWire sw : statewires.values()) pw.println(sw.getResetCode());
+            for(Port p : ports.values()) pw.println(p.getResetCode());
             pw.println("  end else begin");
-            for(Port p : ports.values()) {
-                if (p instanceof SourcePort) {
-                    SourcePort ip = (SourcePort)p;
-                    if (ip.hasLatch)
-                        pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;");
-                } else {
-                    SinkPort op = (SinkPort)p;
-                    if (op.hasLatch)
-                        pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+
-                                   op.getReq()+"<=0; "+
-                                   op.getResetBehavior()+" end");
-                }
-            }
+            for(Port p : ports.values()) pw.println(p.getCleanup());
             for(Event a : events) a.dump(pw, fix);
             pw.println("    begin end");
             pw.println("    end");
             pw.println("  end");
-
-            pw.println(crap);
             pw.println("endmodule");
         }
 
@@ -594,14 +741,12 @@ public class Verilog {
                 Module.this.events.add(this);
                 this.triggers = triggers;
                 this.actions = actions;
-                for(int i=0; i<triggers.length; i++)
-                    if (triggers[i] instanceof Port)
-                        ((Port)triggers[i]).hasLatch = true;
             }
             public void dump(PrintWriter pw, boolean fix) {
+                if (!fix) throw new RuntimeException();
                 pw.print("if (1");
                 for(Object o : triggers) {
-                    if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
+                    if (o instanceof Trigger) pw.print(" && " + ((Trigger)o).getVerilogTrigger());
                     else                      pw.print(" && " + o);
                 }
                 pw.println(") begin ");