implement port percolation
[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 => get rid of getInputPort(String) and instead use members
13 => get rid of addcrap
14 => automatic width-setting/checking on ports
15 => mangle the names given for strings
16 */
17
18 public class Verilog {
19
20     public static class PercolatedPort {
21         public static enum PortType { UP, DOWN, INOUT };
22         public final String name;
23         public final int width;
24         public final PortType type;
25         public PercolatedPort(String name, int width, PortType type) {
26             this.name = name;
27             this.width = width;
28             this.type = type;
29         }
30     }
31
32     public static class SimpleValue implements Value {
33         public final String s;
34         public SimpleValue(String s) { this.s = s; }
35         public SimpleValue(String s, int high, int low) { this.s = s+"["+high+":"+low+"]"; }
36         public Value getBits(int high, int low) { return new SimpleValue(s, high, low); }
37         public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
38         public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
39         public String getVerilogName() { return s; }
40         public String toString() { return s; }
41         public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
42     }
43
44     public static class CatValue implements Value {
45         private final Value[] values;
46         public CatValue(Value[] values) { this.values = values; }
47         public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
48         public Value getBits(int high, int low) {
49             throw new RuntimeException();
50         }
51         public Assignable getAssignableBits(int high, int low) {
52             throw new RuntimeException();
53         }
54         public String toString() { return getVerilogName(); }
55         public String getVerilogName() {
56             StringBuffer sb = new StringBuffer();
57             sb.append("{ ");
58             boolean first = true;
59             for(int i=0; i<values.length; i++) {
60                 if (values[i]==null) continue;
61                 if (!first) sb.append(", ");
62                 sb.append(values[i].getVerilogName());
63                 first = false;
64             }
65             sb.append(" }");
66             return sb.toString();
67         }
68         public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
69     }
70
71     public static interface Action {
72         public String getVerilogAction();
73     }
74
75     public static interface Trigger {
76         public String getVerilogTrigger();
77         public Trigger invert();
78     }
79
80     public static class InvertedTrigger implements Trigger {
81         private final Trigger original;
82         public InvertedTrigger(Trigger original) { this.original = original; }
83         public String getVerilogTrigger() { return "!("+original.getVerilogTrigger()+")"; }
84         public Trigger invert() { return original; }
85     }
86
87     public static interface Assignable {
88         public String getVerilogName();
89         public Assignable getAssignableBits(int high, int low);
90     }
91
92     public static interface Value extends Assignable {
93         public String getVerilogName();
94         public Value getBits(int high, int low);
95         public Value getBits(Mask mask);
96         public Value invertBits();
97     }
98
99     public static class ConditionalAction implements Action {
100         public String condition;
101         public Action action;
102         public ConditionalAction(String condition, Action action) {
103             this.condition = condition;
104             this.action = action;
105         }
106         public String toString() { return getVerilogAction(); }
107         public String getVerilogAction() { return "if ("+condition+") begin "+action.getVerilogAction()+" end"; }
108     }
109
110     public static class ConditionalTrigger implements Trigger {
111         public String condition;
112         public Trigger trigger;
113         public ConditionalTrigger(String condition, Trigger trigger) {
114             this.condition = condition;
115             this.trigger = trigger;
116             if (trigger instanceof Module.Port)
117                 ((Module.Port)trigger).hasLatch = true;
118         }
119         public String getVerilogTrigger() {
120             return "&& (("+condition+") ? (1 " + trigger.getVerilogTrigger() + ") : 1)";
121         }
122         public Trigger invert() { return new InvertedTrigger(this); }
123     }
124
125     public static class SimpleAssignable implements Assignable {
126         public final String s;
127         public SimpleAssignable(String s) { this.s = s; }
128         public String getVerilogName() { return s; }
129         public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
130         public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
131     }
132
133     public static class AssignAction implements Action {
134         public String left;
135         public String right;
136         public AssignAction(Assignable left, Value right) {
137             this.left = left.getVerilogName();
138             this.right = right.getVerilogName().toString();
139         }
140         public AssignAction(Assignable left, String right) {
141             this.left = left.getVerilogName();
142             this.right = right;
143         }
144         public String getVerilogAction() { return left + "<=" + right + ";"; }
145         public String toString() { return getVerilogAction(); }
146     }
147     
148     public static class SimpleAction implements Action {
149         public final String verilog;
150         public SimpleAction(String verilog) { this.verilog = verilog; }
151         public String getVerilogAction() { return verilog; }
152         public String toString() { return verilog; }
153     }
154
155     public static class Module {
156         public void dump(String prefix) throws IOException {
157             PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
158             dump(pw, true);
159             pw.flush();
160             for(InstantiatedModule m : instantiatedModules)
161                 m.module.dump(prefix);
162         }
163         public int id = 0;
164         public final String name;
165         public String getName() { return name; }
166         public Port getPort(String name) { return ports.get(name); }
167
168         // order matters here
169         public LinkedList<InstantiatedModule> instantiatedModules = new LinkedList<InstantiatedModule>();
170
171         // order matters here
172         public LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
173         public final ArrayList<Event> events = new ArrayList<Event>();
174
175         // FIXME: always-alphabetical convention?
176         public final HashMap<String,Port> ports = new HashMap<String,Port>();
177         public final ArrayList<String> portorder = new ArrayList<String>();
178         public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
179         public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
180         
181         public StringBuffer crap = new StringBuffer();
182         public StringBuffer precrap = new StringBuffer();
183         //public void addCrap(String s) { crap.append(s); crap.append('\n'); }
184         public void addPreCrap(String s) { precrap.append(s); precrap.append('\n'); }
185         public void addPreCrap0(String s) { precrap.append(s); }
186
187         public Module(String name) {
188             this.name = name;
189         }
190
191         public SourcePort createInputPort(String name, int width) {
192             if (ports.get(name)!=null) throw new RuntimeException();
193             return new SourcePort(name, width, true);
194         }
195         public SourcePort getInputPort(String name) {
196             SourcePort ret = (SourcePort)ports.get(name);
197             if (ret==null) throw new RuntimeException();
198             return ret;
199         }
200         public SinkPort createOutputPort(String name, int width, String resetBehavior) {
201             if (ports.get(name)!=null) throw new RuntimeException();
202             return new SinkPort(name, width, true, resetBehavior);
203         }
204         public SinkPort createWirePort(String name, int width) {
205             if (ports.get(name)!=null) throw new RuntimeException();
206             return new SinkPort(name, width, false, "");
207         }
208         public SourcePort createWireSourcePort(String name, int width) {
209             if (ports.get(name)!=null) throw new RuntimeException();
210             return new SourcePort(name, width, false);
211         }
212         public SinkPort getOutputPort(String name) {
213             SinkPort ret = (SinkPort)ports.get(name);
214             if (ret==null) throw new RuntimeException();
215             return ret;
216         }
217
218         public class StateWire {
219             public final String name;
220             public final boolean initiallyFull;
221             public String getName() { return name; }
222             public Action isFull()  { return new SimpleAction(name+"==1"); }
223             public Action isEmpty() { return new SimpleAction(name+"==0"); }
224             public Action doFill()  { return new SimpleAction(name+"<=1;"); }
225             public Action doDrain() { return new SimpleAction(name+"<=0;"); }
226             public String doReset() { return name+"<="+(initiallyFull?"1":"0")+";"; }
227             public StateWire(String name) { this(name, false); }
228             public StateWire(String name, boolean initiallyFull) {
229                 this.name = name;
230                 this.initiallyFull = initiallyFull;
231                 statewires.put(name, this);
232             }
233             public void dump(PrintWriter pw) {
234                 pw.println("  reg "+name+";");
235                 pw.println("  initial "+name+"="+(initiallyFull?"1":"0")+";");
236             }
237         }
238
239         public class Latch implements Assignable, Value {
240             public final String name;
241             public final int width;
242             public final long initial;
243             public Latch(String name, int width) { this(name, width, 0); }
244             public Latch(String name, int width, long initial) {
245                 this.width = width;
246                 this.name = name;
247                 this.initial = initial;
248                 latches.put(name, this);
249             }
250             public String getVerilogName() { return name; }
251             public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
252             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
253             public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
254             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
255             public String doReset() { return name+"<="+initial+";"; }
256             public void dump(PrintWriter pw) {
257                 pw.println("  reg ["+(width-1)+":0] "+name+";");
258                 pw.println("  initial "+name+"="+initial+";");
259             }
260             public void connect(SinkPort driven) {
261                 driven.latchDriver = this;
262             }
263         }
264
265         public abstract class Port implements Action, Assignable, Trigger {
266             public abstract String doReset();
267             public final String name;
268             public String getName() { return name; }
269             public final int width;
270             public int getWidth() { return width; }
271             public boolean hasLatch = false;
272             public boolean external;
273             public Port(String name, int width, boolean external) {
274                 this.width = width;
275                 this.name = name;
276                 this.external = external;
277                 ports.put(name, this);
278                 if (external)
279                     portorder.add(name);
280             }
281             public String getVerilogName() { return name; }
282             String getAck() { return name+"_a"; }
283             String getReq() { return name+"_r"; }
284             public String isFull() { return "("+name+"_r"+" && !"+name+"_a)"; }
285             public abstract String getInterface();
286             public abstract String getSimpleInterface();
287             public abstract String getDeclaration();
288             public abstract String getAssignments();
289             public abstract void   connect(SinkPort driven);
290             public Trigger invert() { return new InvertedTrigger(this); }
291         }
292
293         public static class InstantiatedModule {
294             public final Module module;
295             public final Module thisModule;
296             public final int id;
297             public final HashMap<String,Port> ports = new HashMap<String,Port>();
298             public String getName() { return module.getName()+"_"+id; }
299             public InstantiatedModule(Module thisModule, Module module) {
300                 this.thisModule = thisModule;
301                 this.module = module;
302                 this.id = thisModule.id++;
303                 thisModule.instantiatedModules.add(this);
304             }
305             public void dump(PrintWriter pw) {
306                 pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
307                 for(String s : module.portorder)
308                     pw.println(", " + getPort(s).getSimpleInterface());
309                 for(PercolatedPort pp : module.percolatedPorts)
310                     pw.println("    , "+pp.name);
311                 pw.println("   );");
312             }
313             public Port getPort(String name) {
314                 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
315             }
316             public SinkPort getInputPort(String name) {
317                 int width = module.getPort(name).getWidth();
318                 SinkPort port = (SinkPort)ports.get(name);
319                 if (port == null) {
320                     port = thisModule.new SinkPort(getName()+"_"+name, width, false, "");
321                     ports.put(name, port);
322                 }
323                 return port;
324             }
325             public SourcePort getOutputPort(String name) {
326                 int width = module.getPort(name).getWidth();
327                 SourcePort port = (SourcePort)ports.get(name);
328                 if (port == null) {
329                     port = thisModule.new SourcePort(getName()+"_"+name, width, false);
330                     ports.put(name, port);
331                 }
332                 return port;
333             }
334         }
335
336         public class SourcePort extends Port implements Value {
337             public SourcePort(String name, int width, boolean external) { 
338                 super(name, width, external); }
339             public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
340             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
341             public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
342             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
343             public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
344             public String getVerilogAction() { return getAck() + " <= 1;"; }
345             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
346             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
347             public String testBit(int index, boolean value) {
348                 return "("+name+"["+index+"]=="+(value?1:0)+")";
349             }
350             public String getDeclaration() {
351                 StringBuffer sb = new StringBuffer();
352                 if (external) {
353                     sb.append("input "  +                 name +"_r;\n");
354                     sb.append("output " +                 name +"_a_;\n");
355                     if (width>0)
356                         sb.append("input ["+(width-1)+":0]" + name +";\n");
357                     else
358                         sb.append("input [0:0]" + name +";\n"); // waste a bit, I guess
359                 } else {
360                     sb.append("wire "  +                 name +"_r;\n");
361                     if (width>0)
362                         sb.append("wire ["+(width-1)+":0]" + name +";\n");
363                 }
364                 if (!hasLatch) {
365                     sb.append("wire "    +                 name +"_a;\n");
366                 } else {
367                     sb.append("reg "    +                 name +"_a;\n");
368                     sb.append("initial " +                name +"_a = 0;\n");
369                 }
370                 return sb.toString();
371             }
372             public String doReset() { return hasLatch ? name+"_a<=1;" : ""; }
373             public String getAssignments() {
374                 StringBuffer sb = new StringBuffer();
375                 if (external)
376                     sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
377                 return sb.toString();
378             }
379             public void connect(SinkPort driven) {
380                 driven.driver = this;
381             }
382         }
383         public class SinkPort extends Port {
384             public SourcePort driver = null;
385             public boolean forceNoLatch = false;
386             public SinkPort driven = null;
387             public Value latchDriver = null;
388             public boolean noDriveLatches = false;
389             public final String resetBehavior;
390             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
391             public String getVerilogAction() { return getReq() + " <= 1;"; }
392             public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); }
393             public SinkPort(String name, int width, boolean external, String resetBehavior) {
394                 super(name, width, external); this.resetBehavior=resetBehavior; }
395             public String getResetBehavior() { return resetBehavior; }
396             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
397             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
398             public String getDeclaration() {
399                 StringBuffer sb = new StringBuffer();
400                 if (external) {
401                     sb.append("output "  +                 name +"_r_;\n");
402                     sb.append("input "   +                 name +"_a;\n");
403                     if (width>0)
404                         sb.append("output ["+(width-1)+":0]" + name +"_;\n");
405                     else
406                         sb.append("output [0:0]" + name +"_;\n"); // waste a bit, I guess
407                 } else {
408                     sb.append("wire "   +                 name +"_a;\n");
409                 }
410
411                 if (forceNoLatch ||  latchDriver!=null) {
412                     sb.append("reg "    +                  name +"_r;\n");
413                     sb.append("initial " +                 name +"_r = 0;\n");
414                     if (width>0)
415                         sb.append("wire   ["+(width-1)+":0]" + name +";\n");
416                 } else if (!hasLatch) {
417                     sb.append("wire "    +                 name +"_r;\n");
418                     if (width>0)
419                         sb.append("wire   ["+(width-1)+":0]" + name +";\n");
420                 } else {
421                     sb.append("reg "    +                  name +"_r;\n");
422                     sb.append("initial " +                 name +"_r = 0;\n");
423                     if (width>0) {
424                         sb.append("reg    ["+(width-1)+":0]" + name +";\n");
425                         if (!"/*NORESET*/".equals(resetBehavior))
426                             sb.append("initial " +                 name +" = 0;\n");
427                     }
428                 }
429                 return sb.toString();
430             }
431             public String doReset() {
432                 return (forceNoLatch||latchDriver!=null||width==0)
433                     ? name+"_r<=0;"
434                     : hasLatch
435                     ? (name+"_r<=0; "+("/*NORESET*/".equals(resetBehavior) ? "" : (name+"<=0;")))
436                     : "";
437             }
438             public String getAssignments() {
439                 StringBuffer sb = new StringBuffer();
440                 if (external) {
441                     sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
442                     if (width>0)
443                         sb.append("assign " +                  name +"_ = " + name + ";\n");
444                 }
445                 if (driven != null) {
446                     sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
447                     sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
448                     if (width>0)
449                         sb.append("assign " + driven.name +"   = " + name + ";\n");
450                 }
451                 if (driver != null) {
452                     sb.append("assign " + name +"_r = " + driver.name + "_r;\n");
453                     sb.append("assign " + driver.name +"_a = " + name + "_a;\n");
454                     if (width>0 && !noDriveLatches && latchDriver==null)
455                         sb.append("assign " + name +"   = " + driver.name + ";\n");
456                 }
457                 if (latchDriver != null) {
458                     if (width>0)
459                         sb.append("assign " + name +"   = " + latchDriver.getVerilogName() + ";\n");
460                 }
461                 return sb.toString();
462             }
463             public void connect(SinkPort driven) {
464                 this.driven = driven;
465                 throw new RuntimeException();
466             }
467         }
468
469         public void dump(PrintWriter pw, boolean fix) {
470             boolean isRoot = name.equals("main");
471             pw.print("module "+name);
472             if (isRoot) {
473                 pw.println("(clk_pin, rst_pin ");
474             } else {
475                 pw.println("(clk, rst ");
476             }
477             for(String name : portorder) {
478                 Port p = ports.get(name);
479                 pw.println("    , " + p.getInterface());
480             }
481             for (InstantiatedModule im : this.instantiatedModules)
482                 for(PercolatedPort pp : im.module.percolatedPorts)
483                     if (!isRoot || (!pp.name.startsWith("root_in_") && !pp.name.startsWith("rst_")))
484                         pw.println("    , "+pp.name);
485             pw.println("   );");
486             pw.println();
487
488             if (isRoot) {
489                 pw.println("  input clk_pin;");
490                 pw.println("  input rst_pin;");
491                 pw.println("  wire clk;");
492                 pw.println("  wire clk_fb;");
493                 pw.println("  wire clk_unbuffered;");
494                 pw.println("  BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));");
495                 pw.println("  DCM");
496                 pw.println("   #(");
497                 pw.println("      .CLKFX_MULTIPLY(4),");
498                 pw.println("      .CLKFX_DIVIDE(8),");
499                 pw.println("      .CLKIN_PERIOD(\"10 ns\")");
500                 pw.println("    ) mydcm(");
501                 pw.println("      .CLKIN (clk_pin),");
502                 pw.println("      .CLKFB(clk_fb),");
503                 pw.println("      .CLKFX (clk_unbuffered),");
504                 pw.println("      .CLK0  (clk_fb)");
505                 pw.println("    );");
506                 pw.println("  wire rst;");
507             } else {
508                 pw.println("    input clk;");
509                 pw.println("    input rst;");
510             }
511
512             for (InstantiatedModule im : this.instantiatedModules)
513                 for(PercolatedPort pp : im.module.percolatedPorts) {
514                     if (isRoot && (pp.name.startsWith("root_in_") || pp.name.startsWith("rst_")))
515                         pw.print("wire");
516                     else  switch(pp.type) {
517                             case UP:    pw.print("output"); break;
518                             case DOWN:  pw.print("input");  break;
519                             case INOUT: pw.print("inout");  break;
520                         }
521                     pw.print("  ");
522                     if (pp.width > 1)
523                         pw.print("["+(pp.width-1)+":0]");
524                     pw.print(" ");
525                     pw.print(pp.name);
526                     pw.println(";");
527                 }
528
529             if (isRoot) {
530                 pw.println("  assign rst    = rst_out;");
531                 pw.println("  assign rst_in = rst_pin;");
532             }
533
534             for(String name : ports.keySet()) {
535                 Port p = ports.get(name);
536                 pw.println("    " + p.getDeclaration());
537             }
538             for(StateWire sw : statewires.values())
539                 sw.dump(pw);
540             for(Latch l : latches.values())
541                 l.dump(pw);
542             for(String name : ports.keySet()) {
543                 Port p = ports.get(name);
544                 pw.println("    " + p.getAssignments());
545             }
546             for(InstantiatedModule m : instantiatedModules) {
547                 m.dump(pw);
548             }
549             pw.println(precrap);
550             pw.println("always @(posedge clk) begin");
551             pw.println("  if (!rst) begin");
552             for(Latch l : latches.values())
553                 pw.println(l.doReset());
554             for(StateWire sw : statewires.values())
555                 pw.println(sw.doReset());
556             for(Port p : ports.values())
557                 pw.println(p.doReset());
558             pw.println("  end else begin");
559             for(Port p : ports.values()) {
560                 if (p instanceof SourcePort) {
561                     SourcePort ip = (SourcePort)p;
562                     if (ip.hasLatch)
563                         pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;");
564                 } else {
565                     SinkPort op = (SinkPort)p;
566                     if (op.hasLatch)
567                         pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+
568                                    op.getReq()+"<=0; "+
569                                    op.getResetBehavior()+" end");
570                 }
571             }
572             for(Event a : events) a.dump(pw, fix);
573             pw.println("    begin end");
574             pw.println("    end");
575             pw.println("  end");
576
577             pw.println(crap);
578             pw.println("endmodule");
579         }
580
581         public class Event {
582             public Object[]  triggers;
583             public Object[]  actions;
584             public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
585             public Event(Object[] triggers, Object[] actions) {
586                 Module.this.events.add(this);
587                 this.triggers = triggers;
588                 this.actions = actions;
589                 for(int i=0; i<triggers.length; i++)
590                     if (triggers[i] instanceof Port)
591                         ((Port)triggers[i]).hasLatch = true;
592             }
593             public void dump(PrintWriter pw, boolean fix) {
594                 pw.print("if (1");
595                 for(Object o : triggers) {
596                     if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
597                     else                      pw.print(" && " + o);
598                 }
599                 pw.println(") begin ");
600                 for(Object a : actions) if (a!=null) pw.println(((Action)a).getVerilogAction());
601                 if (fix) pw.println("end /*else*/ ");
602                 else     pw.println("end else ");
603             }
604         }
605     }
606 }