more predictable instance naming in Verilog.java
[fleet.git] / src / edu / berkeley / fleet / fpga / verilog / Verilog.java
1 package edu.berkeley.fleet.fpga.verilog;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.fleet.two.*;
4 import edu.berkeley.fleet.util.*;
5 import edu.berkeley.fleet.*;
6 import java.lang.reflect.*;
7 import java.util.*;
8 import java.io.*;
9 import static edu.berkeley.fleet.two.FleetTwoFleet.*;
10
11 /*
12
13 - ideally: want to merge Fpga.dump() with this... but have to resolve
14   the handling of flushing first.
15
16 - eliminate uses of SimpleXXX
17    - force width parameter in remaining uses
18    - re-enable width checking (add zero-extend and sign-extend)
19
20 - ideally: make getVerilog() package-private somehow
21
22 - change Event constructors from Object[] to Event[]/Action[]
23 - change portorder to LinkedHashMap
24
25 => mangle the names given for strings
26 => ensure uniquification of percolated ports
27
28 => later: scan chain
29 */
30
31 /**
32  *  Among the benefits are:
33  *    - automatic scan-chain insertion
34  *    - better error-checking (for example, width mismatches) than Verilog provides
35  *    - pin percolation
36  *
37  *  One of the most annoying things about Verilog is that you cannot
38  *  "double-slice" a value; in other words, foo[10:2] is valid
39  *  Verilog, but foo[10:2][4:3] is not; the programmer must write
40  *  foo[4+2:3+2].  This lack of compositionality is the reason for
41  *  most of the complexity in the Value class.
42  */
43 public class Verilog {
44
45     public static final int FORWARD_LATENCY = 6;  // must be >=1
46     public static final int REVERSE_LATENCY = 4;  // must be >=3
47
48     public static interface Value {
49         public String  getVerilog();
50         public Value   getBits(int high, int low);
51         public Value   getBits(Mask mask);
52         public Trigger testMask(Mask mask);
53         public Value   invertBits();
54         public int     getWidth();
55     }
56
57     public static class SimpleValue implements Value {
58         public final String s;
59         private final String s0;
60         private final int high;
61         private final int low;
62         private final int width;
63         public SimpleValue(String s) { this(s, -1); }
64         public SimpleValue(String s, int width) {
65             this.s = s;
66             this.s0 = s;
67             this.high = -1;
68             this.low = -1;
69             this.width = width;
70         }
71         public SimpleValue(String s, int high, int low) {
72             this.s = s+"["+high+":"+low+"]";
73             this.s0 = s;
74             this.high = high;
75             this.low = low;
76             this.width = 1+high-low;
77         }
78         public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
79         public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
80         public Value getBits(int high, int low) {
81             if (this.high==-1 && this.low==-1) return new SimpleValue(s, high, low);
82             if (high+this.low > this.high) throw new RuntimeException("out of range");
83             return new SimpleValue(s0, high+this.low, low+this.low);
84         }
85         public String getVerilog() { return s; }
86         public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",width); }
87         public int getWidth() {
88             if (width==-1) throw new RuntimeException("not implemented");
89             return width;
90         }
91     }
92
93     public static class MuxValue implements Value {
94         private final Trigger sel;
95         private final Value if0;
96         private final Value if1;
97         public MuxValue(Trigger sel, Value if1, Value if0) {
98             this.sel = sel;
99             this.if0 = if0;
100             this.if1 = if1;
101             if (if0.getWidth() != if1.getWidth())
102                 throw new RuntimeException("width mismatch; "+if0+"="+if0.getWidth()+", "+if1+"="+if1.getWidth());
103         }
104         public int getWidth() { return if0.getWidth(); }
105         public String getVerilog() { return "("+sel.getVerilogTrigger()+" ? "+if1.getVerilog()+" : "+if0.getVerilog()+")"; }
106         public Value getBits(int high, int low) { return new MuxValue(sel, if1.getBits(high,low), if0.getBits(high,low)); }
107         public Value getBits(Mask mask) { return new MuxValue(sel, if1.getBits(mask), if0.getBits(mask)); }
108         public Value invertBits() { return new MuxValue(sel, if1.invertBits(), if0.invertBits()); }
109         public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
110     }
111
112     public static class ConstantValue implements Value {
113         private final BitVector bits;
114         public ConstantValue(BitVector bits) { this.bits = bits; }
115         public Value getBits(int high, int low) { return new ConstantValue(bits.get(high, low)); }
116         public Value getBits(Mask mask) { throw new RuntimeException("FIXME"); }
117         public Value invertBits() {
118             BitVector ret = new BitVector(bits.length());
119             for(int i=0; i<bits.length(); i++) ret.set(i, !bits.get(i));
120             return new ConstantValue(ret);
121         }
122         public String getVerilog() {
123             StringBuffer sb = new StringBuffer();
124             sb.append(bits.length());
125             sb.append("'b");
126             for(int i=bits.length()-1; i>=0; i--)
127                 sb.append(bits.get(i) ? '1' : '0');
128             return sb.toString();
129         }
130         public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
131         public int getWidth() { return bits.length(); }
132     }
133
134     public static class CatValue implements Value {
135         private final Value[] values;
136         public CatValue(Value[] values) { this.values = values; }
137         public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
138         public Value getBits(int high, int low) { throw new RuntimeException(); }
139         public int getWidth() {
140             int ret = 0;
141             for (Value val : values) ret += val.getWidth();
142             return ret;
143         }
144         public String getVerilog() {
145             StringBuffer sb = new StringBuffer();
146             sb.append("{ ");
147             boolean first = true;
148             for(int i=0; i<values.length; i++) {
149                 if (values[i]==null) continue;
150                 if (!first) sb.append(", ");
151                 sb.append(values[i].getVerilog());
152                 first = false;
153             }
154             sb.append(" }");
155             return sb.toString();
156         }
157         public Value invertBits() {
158             Value[] newvals = new Value[values.length];
159             for(int i=0; i<values.length; i++)
160                 newvals[i] = values[i].invertBits();
161             return new CatValue(newvals);
162         }
163         public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
164     }
165
166     public static class LogicValue implements Value {
167         public static enum LogicType { OR, AND };
168         private final Value v1;
169         private final Value v2;
170         private final LogicType tt;
171         public LogicValue(Value v1, LogicType tt, Value v2) {
172             this.v1 = v1;
173             this.v2 = v2;
174             this.tt = tt;
175             // FIXME: check width match
176         }
177         public String  getVerilog() {
178             switch(tt) {
179                 case OR:  return "("+v1.getVerilog()+"||"+v2.getVerilog()+")";
180                 case AND: return "("+v1.getVerilog()+"&&"+v2.getVerilog()+")";
181             }
182             throw new RuntimeException("impossible");
183         }
184         public Value   getBits(int high, int low) { return new LogicValue(v1.getBits(high,low),tt,v2.getBits(high,low)); }
185         public Value   getBits(Mask mask) { return new LogicValue(v1.getBits(mask),tt,v2.getBits(mask)); }
186         public Trigger testMask(Mask mask) { throw new RuntimeException("FIXME"); }
187         public Value   invertBits() { 
188             switch(tt) {
189                 case OR:  return new LogicValue(v1.invertBits(), LogicType.AND, v2.invertBits());
190                 case AND: return new LogicValue(v1.invertBits(), LogicType.OR, v2.invertBits());
191             }
192             throw new RuntimeException("impossible");
193         }
194         public int     getWidth() { return v1.getWidth(); }
195     }
196
197     public static class TestValue implements Value, Trigger {
198         public static enum TestType { NE, EQ, LT, GT, LE, GE };
199         private final Value v1;
200         private final Value v2;
201         private final TestType tt;
202         public TestValue(Value v1, TestType tt, Value v2) {
203             this.v1 = v1;
204             this.v2 = v2;
205             this.tt = tt;
206             // FIXME: check width match
207         }
208         public String  getVerilogTrigger() { return getVerilog(); }
209         public String  getVerilog() {
210             switch(tt) {
211                 case NE: return "("+v1.getVerilog()+"!="+v2.getVerilog()+")";
212                 case EQ: return "("+v1.getVerilog()+"=="+v2.getVerilog()+")";
213                 case LE: return "("+v1.getVerilog()+"<="+v2.getVerilog()+")";
214                 case GE: return "("+v1.getVerilog()+">="+v2.getVerilog()+")";
215                 case LT: return "("+v1.getVerilog()+"<" +v2.getVerilog()+")";
216                 case GT: return "("+v1.getVerilog()+">" +v2.getVerilog()+")";
217             }
218             throw new RuntimeException("impossible");
219         }
220         public Value   getBits(int high, int low) { throw new RuntimeException("you probably didn't mean to do this"); }
221         public Value   getBits(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); }
222         public Trigger testMask(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); }
223         public Trigger invert() { return invertMe(); }
224         public Value   invertBits() { return invertMe(); }
225         private TestValue invertMe() {
226             switch(tt) {
227                 case NE: return new TestValue(v1, TestType.EQ, v2);
228                 case EQ: return new TestValue(v1, TestType.NE, v2);
229                 case LE: return new TestValue(v1, TestType.GT, v2);
230                 case GE: return new TestValue(v1, TestType.LT, v2);
231                 case LT: return new TestValue(v1, TestType.GE, v2);
232                 case GT: return new TestValue(v1, TestType.LE, v2);
233             }
234             throw new RuntimeException("impossible");
235         }
236         public int     getWidth() { return 1; }
237     }
238
239     // Triggers //////////////////////////////////////////////////////////////////////////////
240
241     public static interface Trigger {
242         public String getVerilogTrigger();
243         public Trigger invert();
244     }
245
246     public static class SimpleTrigger implements Trigger {
247         private final String s;
248         public SimpleTrigger(String s) { this.s = s; }
249         public String getVerilogTrigger() { return s; }
250         public Trigger invert() { return new SimpleTrigger("!("+s+")"); }
251     }
252
253     public static class AndTrigger implements Trigger {
254         private final Trigger t1, t2;
255         public AndTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; }
256         public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" && "+t2.getVerilogTrigger()+")"; }
257         public Trigger invert() { return new InvertedTrigger(this); }
258     }
259
260     public static class OrTrigger implements Trigger {
261         private final Trigger t1, t2;
262         public OrTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; }
263         public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" || "+t2.getVerilogTrigger()+")"; }
264         public Trigger invert() { return new InvertedTrigger(this); }
265     }
266
267     public static class InvertedTrigger implements Trigger {
268         private final Trigger original;
269         public InvertedTrigger(Trigger original) { this.original = original; }
270         public String getVerilogTrigger() { return "!("+original.getVerilogTrigger()+")"; }
271         public Trigger invert() { return original; }
272     }
273
274     public static class ConditionalTrigger implements Trigger {
275         public Trigger condition;
276         public Trigger trigger;
277         public ConditionalTrigger(Trigger condition, Trigger trigger) {
278             this.condition = condition;
279             this.trigger = trigger;
280         }
281         public String getVerilogTrigger() {
282             return "(("+condition.getVerilogTrigger()+") ? (" + trigger.getVerilogTrigger() + ") : 1)";
283         }
284         public Trigger invert() { return new InvertedTrigger(this); }
285     }
286
287     // Actions //////////////////////////////////////////////////////////////////////////////
288
289     public static interface Action {
290         public String getVerilogAction();
291     }
292
293     public static class ConditionalAction implements Action {
294         public Trigger condition;
295         public Action action;
296         public ConditionalAction(Trigger condition, Action action) {
297             this.condition = condition;
298             this.action = action;
299         }
300         public String getVerilogAction() { return "if ("+condition.getVerilogTrigger()+") begin "+action.getVerilogAction()+" end"; }
301     }
302
303     public static class AssignAction implements Action {
304         public Assignable left;
305         public Value right;
306         public AssignAction(Assignable left, Value right) {
307             this.left = left;
308             this.right = right;
309         }
310         public String getVerilogAction() { return left.getVerilog() + "<=" + right.getVerilog() + ";"; }
311     }
312
313     // Assignables //////////////////////////////////////////////////////////////////////////////
314
315     public static interface Assignable {
316         public String getVerilog();
317     }
318
319     public static class SimpleAssignable implements Assignable {
320         public final String s;
321         public SimpleAssignable(String s) { this.s = s; }
322         public String getVerilog() { return s; }
323     }
324
325     // Percolated Ports //////////////////////////////////////////////////////////////////////////////
326     
327     /**
328      *  A PercolatedPort is a connection to a top-level pin; it is
329      *  propagated up or down the hierarchy
330      */
331     public static class PercolatedPort {
332         public static enum PortType { UP, DOWN, INOUT };
333         public final String name;
334         public final int width;
335         public final PortType type;
336         public PercolatedPort(String name, int width, PortType type) {
337             this.name = name;
338             this.width = width;
339             this.type = type;
340         }
341     }
342
343
344     // Module Internals //////////////////////////////////////////////////////////////////////////////
345
346     public static class Module {
347         public void dump(String prefix) throws IOException {
348             PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
349             dump(pw, true);
350             pw.flush();
351             for(InstantiatedModule m : instantiatedModules)
352                 m.module.dump(prefix);
353         }
354         public int id = 0;
355         public final String name;
356         public String getName() { return name; }
357         public Port getPort(String name) { return ports.get(name); }
358
359         // order matters here
360         public LinkedList<InstantiatedModule> instantiatedModules = new LinkedList<InstantiatedModule>();
361
362         // order matters here
363         public LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
364         public final ArrayList<Event> events = new ArrayList<Event>();
365
366         // FIXME: always-alphabetical convention?
367         public final HashMap<String,Port> ports = new HashMap<String,Port>();
368         public final ArrayList<String> portorder = new ArrayList<String>();
369         public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
370         public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
371         public final HashMap<String,WireValue> wires = new HashMap<String,WireValue>();
372         
373         public Module(String name) { this.name = name; }
374
375         public SourcePort createInputPort(String name, int width) { return new SourcePort(name, width, true); }
376         public SinkPort createOutputPort(String name, int width) { return new SinkPort(name, width, true); }
377
378         // Latches and Wires //////////////////////////////////////////////////////////////////////////////
379
380         public class StateWire {
381             public final String name;
382             public final boolean initiallyFull;
383             public String getName() { return name; }
384             public Trigger isFull()  { return new SimpleTrigger("("+name+"==1)"); }
385             public Trigger isEmpty() { return new SimpleTrigger("("+name+"==0)"); }
386             public Action  doFill()  { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(1))); }
387             public Action  doDrain() { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(0))); }
388             public String  getResetCode() { return name+"<="+(initiallyFull?"1":"0")+";"; }
389             public StateWire(String name) { this(name, false); }
390             public StateWire(String name, boolean initiallyFull) {
391                 this.name = name;
392                 this.initiallyFull = initiallyFull;
393                 statewires.put(name, this);
394             }
395             public void dump(PrintWriter pw) {
396                 pw.println("  reg "+name+";");
397                 pw.println("  initial "+name+"="+(initiallyFull?"1":"0")+";");
398             }
399         }
400
401         public class Latch implements Assignable, Value {
402             public final String name;
403             public final int width;
404             public final long initial;
405             public Latch(String name, int width) { this(name, width, 0); }
406             public Latch(String name, int width, long initial) {
407                 this.width = width;
408                 this.name = name;
409                 this.initial = initial;
410                 latches.put(name, this);
411             }
412             public int getWidth() { return width; }
413             public String getVerilog() { return name; }
414             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
415             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
416             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
417             public String getResetCode() { return name+"<="+initial+";"; }
418             public void dump(PrintWriter pw) {
419                 pw.println("  reg ["+(width-1)+":0] "+name+";");
420                 pw.println("  initial "+name+"="+initial+";");
421             }
422             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
423         }
424
425         public class WireValue implements Value {
426             public final String name;
427             public final int width;
428             public final Value assign;
429             public WireValue(String name, int width, Value assign) {
430                 this.width = width;
431                 this.name = name;
432                 this.assign = assign;
433                 wires.put(name, this);
434             }
435             public int getWidth() { return width; }
436             public String getVerilog() { return name; }
437             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
438             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
439             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
440             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
441             public void dump(PrintWriter pw) { pw.println("  wire ["+(width-1)+":0] "+name+";"); }
442             public String getAssignments() { return "  assign "+name+" = "+assign.getVerilog()+";"; }
443         }
444
445         // Ports //////////////////////////////////////////////////////////////////////////////
446
447         public abstract class Port implements Action, Trigger {
448             final String name;
449             final int width;
450             final boolean external;
451             public Port(String name, int width, boolean external) {
452                 this.width = width;
453                 this.name = name;
454                 this.external = external;
455                 if (ports.get(name)!=null)
456                     throw new RuntimeException("port "+name+" already exists");
457                 ports.put(name, this);
458                 if (external)
459                     portorder.add(name);
460             }
461             public String getName() { return name; }
462             public int getWidth() { return width; }
463             public String getVerilog() { return name; }
464             String getAck() { return name+"_a"; }
465             String getReq() { return name+"_r"; }
466             public String isFull() { return "("+getReq()+" && !"+getAck()+")"; }
467             public abstract String getResetCode();
468             public abstract String getInterface();
469             public abstract String getSimpleInterface();
470             public abstract String getDeclaration();
471             public abstract String getAssignments();
472             public abstract String getCleanup();
473             public Trigger invert() { return new InvertedTrigger(this); }
474             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
475         }
476
477         public class SourcePort extends Port implements Value {
478             private SinkPort driven = null;
479             public SourcePort(String name, int width, boolean external) { super(name, width, external); }
480             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
481             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
482             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
483             public String getVerilogTrigger() { return getReq() + " && !"+getAck(); }
484             public String getVerilogAction() { return getAck() + " <= 1;"; }
485             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
486             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
487             public String testBit(int index, boolean value) { return "("+name+"["+index+"]=="+(value?1:0)+")"; }
488             public String getDeclaration() {
489                 StringBuffer sb = new StringBuffer();
490                 if (external) {
491                     sb.append("input "  +                           name +"_r;\n");
492                     sb.append("output " +                           name +"_a_;\n");
493                     sb.append("input ["+Math.max(0,width-1)+":0]" + name +";\n");
494                 } else {
495                     sb.append("wire "  +                            name +"_r;\n");
496                     sb.append("wire ["+Math.max(0,width-1)+":0]"  + name +";\n");
497                 }
498                 if (driven!=null) {
499                     sb.append("wire "    +                 name +"_a;\n");
500                 } else {
501                     sb.append("reg "    +                  name +"_a;\n");
502                     sb.append("initial " +                 name +"_a = 0;\n");
503                 }
504                 return sb.toString();
505             }
506             public String getCleanup() { return driven==null ? "if (!"+getReq()+" && "+getAck()+") "+getAck()+"<=0;" : ""; }
507             public String getResetCode() { return driven==null ? name+"_a<=1;" : ""; }
508             public String getAssignments() {
509                 StringBuffer sb = new StringBuffer();
510                 if (external) {
511                     int a = REVERSE_LATENCY - 3;
512                     if (a<0 || a>16) {
513                         throw new RuntimeException("cannot offer latency of " + REVERSE_LATENCY +"-3");
514                     } else if (a==0) {
515                         sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
516                     } else {
517                         a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
518                         sb.append("SRL16E srl16_"+name+"_a\n");
519                         sb.append("              (.Q ("+name+"_a_),\n");
520                         sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
521                         sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
522                         sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
523                         sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
524                         sb.append("               .CE (1),\n");
525                         sb.append("               .CLK (clk),\n");
526                         sb.append("               .D ("+name+"_a));\n");
527                     }
528                 }
529                 return sb.toString();
530             }
531             public void connect(SinkPort driven) {
532                 if (driven.controlDriver!=null) throw new RuntimeException("driven net already has a driver");
533                 if (driven.latchDriver!=null) throw new RuntimeException("driven net already has a driver");
534                 if (this.driven!=null) throw new RuntimeException("driver already has a driven net");
535                 this.driven = driven;
536                 driven.controlDriver = this;
537                 driven.latchDriver = this;
538                 // FIXME
539                 // if (getWidth() != driven.getWidth())
540                 // throw new RuntimeException("width mismatch: " + getWidth() + " " + driven.getWidth());
541             }
542         }
543         
544         public class SinkPort extends Port implements Assignable {
545             SourcePort controlDriver = null;
546             Value latchDriver = null;
547             public SinkPort(String name, int width, boolean external) { super(name, width, external); }
548             public String getVerilogAction() { return getReq() + " <= 1;"; }
549             public String getVerilogTrigger() { return "!" + getReq() + " && !"+getAck(); }
550             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
551             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
552             public String getCleanup() { return controlDriver==null ? "if ("+getReq()+" && "+getAck()+") begin "+getReq()+"<=0; end" : ""; }
553             public Assignable getBits(Mask mask) { return new SimpleAssignable(name+"["+mask.valmaskmax+":"+mask.valmaskmin+"]"); }
554             public String getResetCode() { return controlDriver!=null ? "" : name+"_r<=0;"; }
555             public void connectControl(SourcePort controlDriver) {
556                 if (this.controlDriver != null) throw new RuntimeException("attempt to connect control twice");
557                 this.controlDriver = controlDriver;
558             }
559             public void connectValue(Value val) {
560                 //if (latchDriver!=null) throw new RuntimeException("attempt to re-assign via connectValue()");
561                 this.latchDriver = val;
562                 // FIXME
563                 //if (getWidth() != val.getWidth())
564                 //throw new RuntimeException("width mismatch: " + getWidth() + " " + val.getWidth());
565             }
566             public String getDeclaration() {
567                 StringBuffer sb = new StringBuffer();
568                 if (external) {
569                     sb.append("output "  +                           name +"_r_;\n");
570                     sb.append("input "   +                           name +"_a;\n");
571                     sb.append("output ["+Math.max(0,width-1)+":0]" + name +"_;\n");
572                 } else {
573                     sb.append("wire "   +                 name +"_a;\n");
574                 }
575                 if (controlDriver!=null) {
576                     sb.append("wire "    +                 name +"_r;\n");
577                     sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
578                 } else {
579                     sb.append("reg "    +                  name +"_r;\n");
580                     sb.append("initial " +                 name +"_r = 0;\n");
581                     if (latchDriver!=null) sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
582                     else                   sb.append("reg    ["+Math.max(0,width-1)+":0]" + name +";\n");
583                 }
584                 return sb.toString();
585             }
586             public String getAssignments() {
587                 StringBuffer sb = new StringBuffer();
588                 if (external) {
589                     int a = FORWARD_LATENCY - 1;
590                     if (a<0 || a>16) {
591                         throw new RuntimeException("cannot offer latency of " + FORWARD_LATENCY +"-1");
592                     } else if (a==0) {
593                         sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
594                     } else {
595                         a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
596                         sb.append("SRL16E srl16_"+name+"_r\n");
597                         sb.append("              (.Q ("+name+"_r_),\n");
598                         sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
599                         sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
600                         sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
601                         sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
602                         sb.append("               .CE (1),\n");
603                         sb.append("               .CLK (clk),\n");
604                         sb.append("               .D ("+name+"_r));\n");
605                     }
606                     sb.append("assign " +                  name +"_ = " + name + ";\n");
607                 }
608                 if (controlDriver != null) {
609                     sb.append("assign " + name +"_r = " + controlDriver.name + "_r;\n");
610                     sb.append("assign " + controlDriver.name +"_a = " + name + "_a;\n");
611                     if (latchDriver==null)
612                         sb.append("assign " + name +"   = " + controlDriver.name + ";\n");
613                 }
614                 if (latchDriver != null)
615                     sb.append("assign " + name +"   = " + latchDriver.getVerilog() + ";\n");
616                 return sb.toString();
617             }
618         }
619
620         // InstantiatedModule //////////////////////////////////////////////////////////////////////////////
621
622         public static class InstantiatedModule {
623             public final Module module;
624             public final Module thisModule;
625             public final int id;
626             public final HashMap<String,Port> ports = new HashMap<String,Port>();
627             public String getName() { return module.getName()+"_"+id; }
628             public InstantiatedModule(Module thisModule, Module module) {
629                 this.thisModule = thisModule;
630                 this.module = module;
631                 // CRUDE
632                 int id = 0;
633                 OUTER: while(true) {
634                     for (InstantiatedModule im : thisModule.instantiatedModules)
635                         if (im.getName().equals(module.getName()+"_"+id)) {
636                             id++;
637                             continue OUTER;
638                         }
639                     break;
640                 }
641                 this.id = id;
642                 thisModule.instantiatedModules.add(this);
643                 for(String s : module.portorder)
644                     getPort(s);
645             }
646             public void dump(PrintWriter pw) {
647                 pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
648                 for(String s : module.portorder)
649                     pw.println(", " + getPort(s).getSimpleInterface());
650                 for(PercolatedPort pp : module.percolatedPorts)
651                     pw.println("    , "+pp.name);
652                 pw.println("   );");
653             }
654             public Port getPort(String name) {
655                 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
656             }
657             public SinkPort getInputPort(String name) {
658                 int width = module.getPort(name).getWidth();
659                 SinkPort port = (SinkPort)ports.get(name);
660                 if (port == null) {
661                     port = thisModule.new SinkPort(getName()+"_"+name, width, false);
662                     ports.put(name, port);
663                 }
664                 return port;
665             }
666             public SourcePort getOutputPort(String name) {
667                 int width = module.getPort(name).getWidth();
668                 SourcePort port = (SourcePort)ports.get(name);
669                 if (port == null) {
670                     port = thisModule.new SourcePort(getName()+"_"+name, width, false);
671                     ports.put(name, port);
672                 }
673                 return port;
674             }
675         }
676
677         public void dump(PrintWriter pw, boolean fix) {
678                 if (!fix) throw new RuntimeException();
679             boolean isRoot = name.equals("main");
680             pw.print("module "+name);
681             pw.println(isRoot ? "(clk_pin, rst_pin " : "(clk, rst ");
682             for(String name : portorder) pw.println("    , " + ports.get(name).getInterface());
683             for (InstantiatedModule im : this.instantiatedModules)
684                 for(PercolatedPort pp : im.module.percolatedPorts)
685                     if (!isRoot || (!pp.name.startsWith("root_in_") && !pp.name.startsWith("rst_")))
686                         pw.println("    , "+pp.name);
687             pw.println("   );");
688             pw.println();
689
690             if (isRoot) {
691                 pw.println("  input clk_pin;");
692                 pw.println("  input rst_pin;");
693                 pw.println("  wire clk;");
694                 pw.println("  wire clk_fb;");
695                 pw.println("  wire clk_unbuffered;");
696                 pw.println("  assign clk_unbuffered = clk_pin;");
697                 //pw.println("  assign clk = clk_pin;");
698
699                 pw.println("  BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));");
700                 /*
701                 pw.println("  DCM");
702                 pw.println("   #(");
703                 pw.println("      .CLKFX_MULTIPLY(4),");
704                 pw.println("      .CLKFX_DIVIDE(8),");
705                 pw.println("      .CLKIN_PERIOD(\"10 ns\")");
706                 pw.println("    ) mydcm(");
707                 pw.println("      .CLKIN (clk_pin),");
708                 pw.println("      .CLKFB(clk_fb),");
709                 pw.println("      .CLKFX (clk_unbuffered),");
710                 pw.println("      .CLK0  (clk_fb)");
711                 pw.println("    );");
712                 */
713                 pw.println("  wire rst;");
714             } else {
715                 pw.println("    input clk;");
716                 pw.println("    input rst;");
717             }
718
719             for (InstantiatedModule im : this.instantiatedModules)
720                 for(PercolatedPort pp : im.module.percolatedPorts) {
721                     if (isRoot && (pp.name.startsWith("root_in_") || pp.name.startsWith("rst_")))
722                         pw.print("wire");
723                     else  switch(pp.type) {
724                             case UP:    pw.print("output"); break;
725                             case DOWN:  pw.print("input");  break;
726                             case INOUT: pw.print("inout");  break;
727                         }
728                     pw.print("  ");
729                     if (pp.width > 1)
730                         pw.print("["+(pp.width-1)+":0]");
731                     pw.print(" ");
732                     pw.print(pp.name);
733                     pw.println(";");
734                 }
735
736             if (isRoot) {
737                 pw.println("  assign rst    = rst_out;");
738                 pw.println("  assign rst_in = !rst_pin;");
739             }
740
741             for(String name : ports.keySet()) pw.println("    " + ports.get(name).getDeclaration());
742             for(StateWire sw : statewires.values()) sw.dump(pw);
743             for(Latch l : latches.values()) l.dump(pw);
744             for(WireValue wv : wires.values()) wv.dump(pw);
745             for(String name : ports.keySet()) pw.println("    " + ports.get(name).getAssignments());
746             for(WireValue wv : wires.values()) pw.println("    " + wv.getAssignments());
747             for(InstantiatedModule m : instantiatedModules) m.dump(pw);
748             pw.println("always @(posedge clk) begin");
749             pw.println("  if (rst) begin");
750             for(Latch l : latches.values()) pw.println(l.getResetCode());
751             for(StateWire sw : statewires.values()) pw.println(sw.getResetCode());
752             for(Port p : ports.values()) pw.println(p.getResetCode());
753             pw.println("  end else begin");
754             for(Port p : ports.values()) pw.println(p.getCleanup());
755             for(Event a : events) a.dump(pw, fix);
756             pw.println("    begin end");
757             pw.println("    end");
758             pw.println("  end");
759             pw.println("endmodule");
760         }
761
762         public class Event {
763             public Object[]  triggers;
764             public Object[]  actions;
765             public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
766             public Event(Object[] triggers, Object[] actions) {
767                 Module.this.events.add(this);
768                 this.triggers = triggers;
769                 this.actions = actions;
770             }
771             public void dump(PrintWriter pw, boolean fix) {
772                 if (!fix) throw new RuntimeException();
773                 pw.print("if (1");
774                 for(Object o : triggers) {
775                     if (o instanceof Trigger) pw.print(" && " + ((Trigger)o).getVerilogTrigger());
776                     else                      pw.print(" && " + o);
777                 }
778                 pw.println(") begin ");
779                 for(Object a : actions) if (a!=null) pw.println(((Action)a).getVerilogAction());
780                 if (fix) pw.println("end /*else*/ ");
781                 else     pw.println("end else ");
782             }
783         }
784     }
785 }