de2bfbaf359b1c36bab654fc086fc952eb5ad34a
[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     // Module Internals //////////////////////////////////////////////////////////////////////////////
326
327     public static class Module {
328         public void dump(String prefix) throws IOException {
329             PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
330             dump(pw, true);
331             pw.flush();
332             for(InstantiatedModule m : instantiatedModules.values())
333                 m.module.dump(prefix);
334         }
335         public int id = 0;
336         public final String name;
337         public String getName() { return name; }
338         public Port getPort(String name) { return ports.get(name); }
339
340         // order matters here
341         public LinkedHashMap<String,InstantiatedModule> instantiatedModules = new LinkedHashMap<String,InstantiatedModule>();
342
343         // order matters here
344         public LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
345         public final ArrayList<Event> events = new ArrayList<Event>();
346
347         // FIXME: always-alphabetical convention?
348         public final HashMap<String,Port> ports = new HashMap<String,Port>();
349         public final ArrayList<String> portorder = new ArrayList<String>();
350         public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
351         public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
352         public final HashMap<String,WireValue> wires = new HashMap<String,WireValue>();
353         
354         public Module(String name) { this.name = name; }
355
356         public SourcePort createInputPort(String name, int width) { return new SourcePort(name, width, true); }
357         public SinkPort createOutputPort(String name, int width) { return new SinkPort(name, width, true); }
358
359         // Latches and Wires //////////////////////////////////////////////////////////////////////////////
360
361         public class StateWire {
362             public final String name;
363             public final boolean initiallyFull;
364             public String getName() { return name; }
365             public Trigger isFull()  { return new SimpleTrigger("("+name+"==1)"); }
366             public Trigger isEmpty() { return new SimpleTrigger("("+name+"==0)"); }
367             public Action  doFill()  { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(1))); }
368             public Action  doDrain() { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(0))); }
369             public String  getResetCode() { return name+"<="+(initiallyFull?"1":"0")+";"; }
370             public StateWire(String name) { this(name, false); }
371             public StateWire(String name, boolean initiallyFull) {
372                 this.name = name;
373                 this.initiallyFull = initiallyFull;
374                 statewires.put(name, this);
375             }
376             public void dump(PrintWriter pw) {
377                 pw.println("  reg "+name+";");
378                 pw.println("  initial "+name+"="+(initiallyFull?"1":"0")+";");
379             }
380         }
381
382         public class Latch implements Assignable, Value {
383             public final String name;
384             public final int width;
385             public final long initial;
386             public Latch(String name, int width) { this(name, width, 0); }
387             public Latch(String name, int width, long initial) {
388                 this.width = width;
389                 this.name = name;
390                 this.initial = initial;
391                 latches.put(name, this);
392             }
393             public int getWidth() { return width; }
394             public String getVerilog() { return name; }
395             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
396             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
397             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
398             public String getResetCode() { return name+"<="+initial+";"; }
399             public void dump(PrintWriter pw) {
400                 pw.println("  reg ["+(width-1)+":0] "+name+";");
401                 pw.println("  initial "+name+"="+initial+";");
402             }
403             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
404         }
405
406         public class WireValue implements Value {
407             public final String name;
408             public final int width;
409             public final Value assign;
410             public WireValue(String name, int width, Value assign) {
411                 this.width = width;
412                 this.name = name;
413                 this.assign = assign;
414                 wires.put(name, this);
415             }
416             public int getWidth() { return width; }
417             public String getVerilog() { return name; }
418             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
419             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
420             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
421             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }        
422             public void dump(PrintWriter pw) { pw.println("  wire ["+(width-1)+":0] "+name+";"); }
423             public String getAssignments() { return "  assign "+name+" = "+assign.getVerilog()+";"; }
424         }
425
426         // Ports //////////////////////////////////////////////////////////////////////////////
427
428         public abstract class Port implements Action, Trigger {
429             final String name;
430             final int width;
431             final boolean external;
432             public Port(String name, int width, boolean external) {
433                 this.width = width;
434                 this.name = name;
435                 this.external = external;
436                 if (ports.get(name)!=null)
437                     throw new RuntimeException("port "+name+" already exists");
438                 ports.put(name, this);
439                 if (external)
440                     portorder.add(name);
441             }
442             public String getName() { return name; }
443             public int getWidth() { return width; }
444             public String getVerilog() { return name; }
445             String getAck() { return name+"_a"; }
446             String getReq() { return name+"_r"; }
447             public String isFull() { return "("+getReq()+" && !"+getAck()+")"; }
448             public abstract String getResetCode();
449             public abstract String getInterface();
450             public abstract String getSimpleInterface();
451             public abstract String getDeclaration();
452             public abstract String getAssignments();
453             public abstract String getCleanup();
454             public Trigger invert() { return new InvertedTrigger(this); }
455             public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
456         }
457
458         public class SourcePort extends Port implements Value {
459             private SinkPort driven = null;
460             public SourcePort(String name, int width, boolean external) { super(name, width, external); }
461             public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); }
462             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
463             public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); }
464             public String getVerilogTrigger() { return getReq() + " && !"+getAck(); }
465             public String getVerilogAction() { return getAck() + " <= 1;"; }
466             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
467             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
468             public String testBit(int index, boolean value) { return "("+name+"["+index+"]=="+(value?1:0)+")"; }
469             public String getDeclaration() {
470                 StringBuffer sb = new StringBuffer();
471                 if (external) {
472                     sb.append("input "  +                           name +"_r;\n");
473                     sb.append("output " +                           name +"_a_;\n");
474                     sb.append("input ["+Math.max(0,width-1)+":0]" + name +";\n");
475                 } else {
476                     sb.append("wire "  +                            name +"_r;\n");
477                     sb.append("wire ["+Math.max(0,width-1)+":0]"  + name +";\n");
478                 }
479                 if (driven!=null) {
480                     sb.append("wire "    +                 name +"_a;\n");
481                 } else {
482                     sb.append("reg "    +                  name +"_a;\n");
483                     sb.append("initial " +                 name +"_a = 0;\n");
484                 }
485                 return sb.toString();
486             }
487             public String getCleanup() { return driven==null ? "if (!"+getReq()+" && "+getAck()+") "+getAck()+"<=0;" : ""; }
488             public String getResetCode() { return driven==null ? name+"_a<=1;" : ""; }
489             public String getAssignments() {
490                 StringBuffer sb = new StringBuffer();
491                 if (external) {
492                     int a = REVERSE_LATENCY - 3;
493                     if (a<0 || a>16) {
494                         throw new RuntimeException("cannot offer latency of " + REVERSE_LATENCY +"-3");
495                     } else if (a==0) {
496                         sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
497                     } else {
498                         a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
499                         sb.append("SRL16E srl16_"+name+"_a\n");
500                         sb.append("              (.Q ("+name+"_a_),\n");
501                         sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
502                         sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
503                         sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
504                         sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
505                         sb.append("               .CE (1),\n");
506                         sb.append("               .CLK (clk),\n");
507                         sb.append("               .D ("+name+"_a));\n");
508                     }
509                 }
510                 return sb.toString();
511             }
512             public void connect(SinkPort driven) {
513                 if (driven.controlDriver!=null) throw new RuntimeException("driven net already has a driver");
514                 if (driven.latchDriver!=null) throw new RuntimeException("driven net already has a driver");
515                 if (this.driven!=null) throw new RuntimeException("driver already has a driven net");
516                 this.driven = driven;
517                 driven.controlDriver = this;
518                 driven.latchDriver = this;
519                 // FIXME
520                 // if (getWidth() != driven.getWidth())
521                 // throw new RuntimeException("width mismatch: " + getWidth() + " " + driven.getWidth());
522             }
523         }
524         
525         public class SinkPort extends Port implements Assignable {
526             SourcePort controlDriver = null;
527             Value latchDriver = null;
528             public SinkPort(String name, int width, boolean external) { super(name, width, external); }
529             public String getVerilogAction() { return getReq() + " <= 1;"; }
530             public String getVerilogTrigger() { return "!" + getReq() + " && !"+getAck(); }
531             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
532             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
533             public String getCleanup() { return controlDriver==null ? "if ("+getReq()+" && "+getAck()+") begin "+getReq()+"<=0; end" : ""; }
534             public Assignable getBits(Mask mask) { return new SimpleAssignable(name+"["+mask.valmaskmax+":"+mask.valmaskmin+"]"); }
535             public String getResetCode() { return controlDriver!=null ? "" : name+"_r<=0;"; }
536             public void connectControl(SourcePort controlDriver) {
537                 if (this.controlDriver != null) throw new RuntimeException("attempt to connect control twice");
538                 this.controlDriver = controlDriver;
539             }
540             public void connectValue(Value val) {
541                 //if (latchDriver!=null) throw new RuntimeException("attempt to re-assign via connectValue()");
542                 this.latchDriver = val;
543                 // FIXME
544                 //if (getWidth() != val.getWidth())
545                 //throw new RuntimeException("width mismatch: " + getWidth() + " " + val.getWidth());
546             }
547             public String getDeclaration() {
548                 StringBuffer sb = new StringBuffer();
549                 if (external) {
550                     sb.append("output "  +                           name +"_r_;\n");
551                     sb.append("input "   +                           name +"_a;\n");
552                     sb.append("output ["+Math.max(0,width-1)+":0]" + name +"_;\n");
553                 } else {
554                     sb.append("wire "   +                 name +"_a;\n");
555                 }
556                 if (controlDriver!=null) {
557                     sb.append("wire "    +                 name +"_r;\n");
558                     sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
559                 } else {
560                     sb.append("reg "    +                  name +"_r;\n");
561                     sb.append("initial " +                 name +"_r = 0;\n");
562                     if (latchDriver!=null) sb.append("wire   ["+Math.max(0,width-1)+":0]" + name +";\n");
563                     else                   sb.append("reg    ["+Math.max(0,width-1)+":0]" + name +";\n");
564                 }
565                 return sb.toString();
566             }
567             public String getAssignments() {
568                 StringBuffer sb = new StringBuffer();
569                 if (external) {
570                     int a = FORWARD_LATENCY - 1;
571                     if (a<0 || a>16) {
572                         throw new RuntimeException("cannot offer latency of " + FORWARD_LATENCY +"-1");
573                     } else if (a==0) {
574                         sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
575                     } else {
576                         a = a-1;  // CLK-to-Q gives us one cycle of latency anyways
577                         sb.append("SRL16E srl16_"+name+"_r\n");
578                         sb.append("              (.Q ("+name+"_r_),\n");
579                         sb.append("               .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n");
580                         sb.append("               .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n");
581                         sb.append("               .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n");
582                         sb.append("               .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n");
583                         sb.append("               .CE (1),\n");
584                         sb.append("               .CLK (clk),\n");
585                         sb.append("               .D ("+name+"_r));\n");
586                     }
587                     sb.append("assign " +                  name +"_ = " + name + ";\n");
588                 }
589                 if (controlDriver != null) {
590                     sb.append("assign " + name +"_r = " + controlDriver.name + "_r;\n");
591                     sb.append("assign " + controlDriver.name +"_a = " + name + "_a;\n");
592                     if (latchDriver==null)
593                         sb.append("assign " + name +"   = " + controlDriver.name + ";\n");
594                 }
595                 if (latchDriver != null)
596                     sb.append("assign " + name +"   = " + latchDriver.getVerilog() + ";\n");
597                 return sb.toString();
598             }
599         }
600
601         // InstantiatedModule //////////////////////////////////////////////////////////////////////////////
602
603         public static class InstantiatedModule {
604             public final Module module;
605             public final Module thisModule;
606             public final int id;
607             public final HashMap<String,Port> ports = new HashMap<String,Port>();
608             private final String name;
609             public String getName() { return name; }
610             public InstantiatedModule(Module thisModule, Module module) {
611                 this.thisModule = thisModule;
612                 this.module = module;
613                 // CRUDE
614                 int id = 0;
615                 while(thisModule.instantiatedModules.get(module.getName()+"_"+id)!=null) id++;
616                 this.id = id;
617                 this.name = module.getName()+"_"+id;
618                 thisModule.instantiatedModules.put(this.name, this);
619                 for(String s : module.portorder)
620                     getPort(s);
621             }
622             public void dump(PrintWriter pw) {
623                 pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
624                 for(String s : module.portorder)
625                     pw.println(", " + getPort(s).getSimpleInterface());
626                 for(PercolatedPort pp : module.percolatedPorts)
627                     pw.println("    , "+pp.name);
628                 pw.println("   );");
629             }
630             public Port getPort(String name) {
631                 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
632             }
633             public SinkPort getInputPort(String name) {
634                 int width = module.getPort(name).getWidth();
635                 SinkPort port = (SinkPort)ports.get(name);
636                 if (port == null) {
637                     port = thisModule.new SinkPort(getName()+"_"+name, width, false);
638                     ports.put(name, port);
639                 }
640                 return port;
641             }
642             public SourcePort getOutputPort(String name) {
643                 int width = module.getPort(name).getWidth();
644                 SourcePort port = (SourcePort)ports.get(name);
645                 if (port == null) {
646                     port = thisModule.new SourcePort(getName()+"_"+name, width, false);
647                     ports.put(name, port);
648                 }
649                 return port;
650             }
651         }
652
653         public void dump(PrintWriter pw, boolean fix) {
654                 if (!fix) throw new RuntimeException();
655             boolean isRoot = name.equals("main");
656             pw.print("module "+name);
657             pw.println(isRoot ? "(clk_pin, rst_pin " : "(clk, rst ");
658             for(String name : portorder) pw.println("    , " + ports.get(name).getInterface());
659             for (InstantiatedModule im : this.instantiatedModules.values())
660                 for(PercolatedPort pp : im.module.percolatedPorts)
661                     if (!isRoot || (!pp.name.startsWith("root_in_") && !pp.name.startsWith("rst_")))
662                         pw.println("    , "+pp.name);
663             pw.println("   );");
664             pw.println();
665
666             if (isRoot) {
667                 pw.println("  input clk_pin;");
668                 pw.println("  input rst_pin;");
669                 pw.println("  wire clk;");
670                 pw.println("  wire clk_fb;");
671                 pw.println("  wire clk_unbuffered;");
672                 pw.println("  assign clk_unbuffered = clk_pin;");
673                 //pw.println("  assign clk = clk_pin;");
674
675                 pw.println("  BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));");
676                 /*
677                 pw.println("  DCM");
678                 pw.println("   #(");
679                 pw.println("      .CLKFX_MULTIPLY(4),");
680                 pw.println("      .CLKFX_DIVIDE(8),");
681                 pw.println("      .CLKIN_PERIOD(\"10 ns\")");
682                 pw.println("    ) mydcm(");
683                 pw.println("      .CLKIN (clk_pin),");
684                 pw.println("      .CLKFB(clk_fb),");
685                 pw.println("      .CLKFX (clk_unbuffered),");
686                 pw.println("      .CLK0  (clk_fb)");
687                 pw.println("    );");
688                 */
689                 pw.println("  wire rst;");
690             } else {
691                 pw.println("    input clk;");
692                 pw.println("    input rst;");
693             }
694
695             for (InstantiatedModule im : this.instantiatedModules.values())
696                 for(PercolatedPort pp : im.module.percolatedPorts) {
697                     if (isRoot && (pp.name.startsWith("root_in_") || pp.name.startsWith("rst_")))
698                         pw.print("wire");
699                     else  switch(pp.type) {
700                             case UP:    pw.print("output"); break;
701                             case DOWN:  pw.print("input");  break;
702                             case INOUT: pw.print("inout");  break;
703                         }
704                     pw.print("  ");
705                     if (pp.width > 1)
706                         pw.print("["+(pp.width-1)+":0]");
707                     pw.print(" ");
708                     pw.print(pp.name);
709                     pw.println(";");
710                 }
711
712             if (isRoot) {
713                 pw.println("  assign rst    = rst_out;");
714                 pw.println("  assign rst_in = !rst_pin;");
715             }
716
717             for(String name : ports.keySet()) pw.println("    " + ports.get(name).getDeclaration());
718             for(StateWire sw : statewires.values()) sw.dump(pw);
719             for(Latch l : latches.values()) l.dump(pw);
720             for(WireValue wv : wires.values()) wv.dump(pw);
721             for(String name : ports.keySet()) pw.println("    " + ports.get(name).getAssignments());
722             for(WireValue wv : wires.values()) pw.println("    " + wv.getAssignments());
723             for(InstantiatedModule m : instantiatedModules.values()) m.dump(pw);
724             pw.println("always @(posedge clk) begin");
725             pw.println("  if (rst) begin");
726             for(Latch l : latches.values()) pw.println(l.getResetCode());
727             for(StateWire sw : statewires.values()) pw.println(sw.getResetCode());
728             for(Port p : ports.values()) pw.println(p.getResetCode());
729             pw.println("  end else begin");
730             for(Port p : ports.values()) pw.println(p.getCleanup());
731             for(Event a : events) a.dump(pw, fix);
732             pw.println("    begin end");
733             pw.println("    end");
734             pw.println("  end");
735             pw.println("endmodule");
736         }
737
738         public class Event {
739             public Object[]  triggers;
740             public Object[]  actions;
741             public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
742             public Event(Object[] triggers, Object[] actions) {
743                 Module.this.events.add(this);
744                 this.triggers = triggers;
745                 this.actions = actions;
746             }
747             public void dump(PrintWriter pw, boolean fix) {
748                 if (!fix) throw new RuntimeException();
749                 pw.print("if (1");
750                 for(Object o : triggers) {
751                     if (o instanceof Trigger) pw.print(" && " + ((Trigger)o).getVerilogTrigger());
752                     else                      pw.print(" && " + o);
753                 }
754                 pw.println(") begin ");
755                 for(Object a : actions) if (a!=null) pw.println(((Action)a).getVerilogAction());
756                 if (fix) pw.println("end /*else*/ ");
757                 else     pw.println("end else ");
758             }
759         }
760     }
761 }