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